diff --git a/README.md b/README.md index 8754fb5..19ebf0e 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ To enable it as your default formatter, use a VS Code `settings.json` like: } ``` -To run Oxc formatting through VS Code code actions on save, configure `editor.codeActionsOnSave`: +To run Oxc formatting through VS Code code actions on save, configure `editor.codeActionsOnSave`. No need to set `editor.defaultFormatter`: ```json { @@ -52,12 +52,12 @@ To run Oxc formatting through VS Code code actions on save, configure `editor.co } ``` -Running formatting as a code action on save, allows to define the order of changes when both formatting and lint fixes are applied on save. For example, the below configuration will run the formatter first, and then apply lint fixes: +Running formatting as a code action on save allows to define the order of changes when both formatting and lint fixes are applied on save. For example, the below configuration will run the formatter first, and then apply lint fixes: ```json { - "editor.defaultFormatter": "oxc.oxc-vscode", - "editor.formatOnSave": false, // disable default behavior + "editor.defaultFormatter": "oxc.oxc-vscode", // optional, recommended for manual formatting + "editor.formatOnSave": false, "editor.codeActionsOnSave": { "source.format.oxc": "always", // run formatter first "source.fixAll.oxc": "always" // run lint fixes after diff --git a/client/commands.ts b/client/commands.ts index 006ead1..fc29bf4 100644 --- a/client/commands.ts +++ b/client/commands.ts @@ -18,6 +18,7 @@ export const enum OxcCommands { // only for formatter.ts usage RestartServerFmt = `${commandPrefix}.restartServerFormatter`, ToggleEnableFmt = `${commandPrefix}.toggleEnableFormatter`, + FormatDocument = `${commandPrefix}.formatDocument`, // always available CopyDebugInfo = `${commandPrefix}.copyDebugInfo`, diff --git a/client/tools/formatter.ts b/client/tools/formatter.ts index ab5b60f..1264669 100644 --- a/client/tools/formatter.ts +++ b/client/tools/formatter.ts @@ -7,12 +7,16 @@ import { ConfigurationChangeEvent, languages, LogOutputChannel, + TextEdit, Uri, + window, workspace, + WorkspaceEdit, } from "vscode"; import { ConfigurationParams, + DocumentFormattingRequest, DocumentSelector, ShowMessageNotification, } from "vscode-languageclient"; @@ -37,9 +41,9 @@ const formatCodeActionKind = CodeActionKind.Source.append("format.oxc"); const formatCodeAction = new CodeAction("Format Document", formatCodeActionKind); formatCodeAction.command = { - command: "editor.action.formatDocument", + command: OxcCommands.FormatDocument, title: "Format Document", - tooltip: "Format the document using the default formatter", + tooltip: "Format the document with oxfmt", }; // This list is not used as-is for implementation to determine whether formatting processing is possible. @@ -314,11 +318,8 @@ export default class FormatterTool implements ToolInterface { const formatAction = languages.registerCodeActionsProvider( this.documentSelectors, { - provideCodeActions: (doc) => { - if ( - configService.vsCodeConfig.enableOxfmt === false || - workspace.getConfiguration("editor", doc).get("defaultFormatter") !== "oxc.oxc-vscode" - ) { + provideCodeActions: (_doc) => { + if (configService.vsCodeConfig.enableOxfmt === false) { return []; } return [formatCodeAction]; @@ -374,6 +375,31 @@ export default class FormatterTool implements ToolInterface { // Create the language client and start the client. this.client = new LanguageClient(languageClientName, serverOptions, clientOptions); + const formatCommand = commands.registerCommand(OxcCommands.FormatDocument, async () => { + const editor = window.activeTextEditor; + if (!editor || !this.client) return; + + const doc = editor.document; + const editorConfig = workspace.getConfiguration("editor", doc); + const tabSize = editorConfig.get("tabSize") ?? 4; + const insertSpaces = editorConfig.get("insertSpaces") ?? true; + + try { + const edits = await this.client.sendRequest(DocumentFormattingRequest.type, { + textDocument: { uri: doc.uri.toString() }, + options: { tabSize, insertSpaces }, + }); + + if (edits && edits.length > 0) { + const edit = new WorkspaceEdit(); + edit.set(doc.uri, edits as TextEdit[]); + await workspace.applyEdit(edit); + } + } catch { + // Server might not support formatting for this document type + } + }); + const onNotificationDispose = this.client.onNotification( ShowMessageNotification.type, (params) => { @@ -386,6 +412,7 @@ export default class FormatterTool implements ToolInterface { restartCommand.dispose(); toggleEnable.dispose(); formatAction.dispose(); + formatCommand.dispose(); onNotificationDispose.dispose(); };