mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(vscode): fix commands by reverting commit 259a47b (#8819)
closes #8787 commit: https://github.com/oxc-project/oxc/commit/259a47b
This commit is contained in:
parent
36f7933a9e
commit
5041cb39a1
5 changed files with 164 additions and 178 deletions
|
|
@ -6,7 +6,7 @@ export class ConfigService implements IDisposable {
|
||||||
private static readonly _namespace = 'oxc';
|
private static readonly _namespace = 'oxc';
|
||||||
private readonly _disposables: IDisposable[] = [];
|
private readonly _disposables: IDisposable[] = [];
|
||||||
|
|
||||||
public readonly config: Config;
|
public config: Config;
|
||||||
|
|
||||||
public onConfigChange:
|
public onConfigChange:
|
||||||
| ((this: ConfigService, config: ConfigurationChangeEvent) => void)
|
| ((this: ConfigService, config: ConfigurationChangeEvent) => void)
|
||||||
|
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
import { CodeAction, Command, commands, Disposable, window, workspace } from 'vscode';
|
|
||||||
|
|
||||||
import { CodeActionRequest, CodeActionTriggerKind, LanguageClient, Position, Range } from 'vscode-languageclient/node';
|
|
||||||
import { Config } from './Config';
|
|
||||||
|
|
||||||
const commandPrefix = 'oxc';
|
|
||||||
|
|
||||||
export const enum OxcCommands {
|
|
||||||
RestartServer = `${commandPrefix}.restartServer`,
|
|
||||||
ApplyAllFixesFile = `${commandPrefix}.applyAllFixesFile`,
|
|
||||||
ShowOutputChannel = `${commandPrefix}.showOutputChannel`,
|
|
||||||
ToggleEnable = `${commandPrefix}.toggleEnable`,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const restartServerCommand = (client: LanguageClient): Disposable => {
|
|
||||||
return commands.registerCommand(
|
|
||||||
OxcCommands.RestartServer,
|
|
||||||
async () => {
|
|
||||||
if (!client) {
|
|
||||||
window.showErrorMessage('oxc client not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (client.isRunning()) {
|
|
||||||
await client.restart();
|
|
||||||
|
|
||||||
window.showInformationMessage('oxc server restarted.');
|
|
||||||
} else {
|
|
||||||
await client.start();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
client.error('Restarting client failed', err, 'force');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const showOutputChannelCommand = (client: LanguageClient): Disposable => {
|
|
||||||
return commands.registerCommand(
|
|
||||||
OxcCommands.ShowOutputChannel,
|
|
||||||
() => {
|
|
||||||
client.outputChannel.show();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const toggleEnabledCommand = (config: Config): Disposable => {
|
|
||||||
return commands.registerCommand(
|
|
||||||
OxcCommands.ToggleEnable,
|
|
||||||
() => {
|
|
||||||
config.updateEnable(!config.enable);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const applyAllFixesFileCommand = (client: LanguageClient): Disposable => {
|
|
||||||
return commands.registerCommand(
|
|
||||||
OxcCommands.ApplyAllFixesFile,
|
|
||||||
async () => {
|
|
||||||
if (!client) {
|
|
||||||
window.showErrorMessage('oxc client not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const textEditor = window.activeTextEditor;
|
|
||||||
if (!textEditor) {
|
|
||||||
window.showErrorMessage('active text editor not found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastLine = textEditor.document.lineAt(textEditor.document.lineCount - 1);
|
|
||||||
const codeActionResult = await client.sendRequest(CodeActionRequest.type, {
|
|
||||||
textDocument: {
|
|
||||||
uri: textEditor.document.uri.toString(),
|
|
||||||
},
|
|
||||||
range: Range.create(Position.create(0, 0), lastLine.range.end),
|
|
||||||
context: {
|
|
||||||
diagnostics: [],
|
|
||||||
only: [],
|
|
||||||
triggerKind: CodeActionTriggerKind.Invoked,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const commandsOrCodeActions = await client.protocol2CodeConverter.asCodeActionResult(codeActionResult || []);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
commandsOrCodeActions
|
|
||||||
.map(async (codeActionOrCommand) => {
|
|
||||||
// Commands are always applied. Regardless of whether it's a Command or CodeAction#command.
|
|
||||||
if (isCommand(codeActionOrCommand)) {
|
|
||||||
await commands.executeCommand(codeActionOrCommand.command, codeActionOrCommand.arguments);
|
|
||||||
} else {
|
|
||||||
// Only preferred edits are applied
|
|
||||||
// LSP states edits must be run first, then commands
|
|
||||||
if (codeActionOrCommand.edit && codeActionOrCommand.isPreferred) {
|
|
||||||
await workspace.applyEdit(codeActionOrCommand.edit);
|
|
||||||
}
|
|
||||||
if (codeActionOrCommand.command) {
|
|
||||||
await commands.executeCommand(
|
|
||||||
codeActionOrCommand.command.command,
|
|
||||||
codeActionOrCommand.command.arguments,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
function isCommand(codeActionOrCommand: CodeAction | Command): codeActionOrCommand is Command {
|
|
||||||
return typeof codeActionOrCommand.command === 'string';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,26 +1,41 @@
|
||||||
import { ExtensionContext, StatusBarAlignment, StatusBarItem, ThemeColor, window, workspace } from 'vscode';
|
import { promises as fsPromises } from 'node:fs';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Executable,
|
CodeAction,
|
||||||
LanguageClient,
|
Command,
|
||||||
LanguageClientOptions,
|
commands,
|
||||||
|
ExtensionContext,
|
||||||
|
StatusBarAlignment,
|
||||||
|
StatusBarItem,
|
||||||
|
ThemeColor,
|
||||||
|
window,
|
||||||
|
workspace,
|
||||||
|
} from 'vscode';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CodeActionRequest,
|
||||||
|
CodeActionTriggerKind,
|
||||||
MessageType,
|
MessageType,
|
||||||
ServerOptions,
|
Position,
|
||||||
|
Range,
|
||||||
ShowMessageNotification,
|
ShowMessageNotification,
|
||||||
} from 'vscode-languageclient/node';
|
} from 'vscode-languageclient';
|
||||||
|
|
||||||
import {
|
import { Executable, LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node';
|
||||||
applyAllFixesFileCommand,
|
|
||||||
OxcCommands,
|
import { join } from 'node:path';
|
||||||
restartServerCommand,
|
|
||||||
showOutputChannelCommand,
|
|
||||||
toggleEnabledCommand,
|
|
||||||
} from './commands';
|
|
||||||
import { ConfigService } from './ConfigService';
|
import { ConfigService } from './ConfigService';
|
||||||
import findBinary from './findBinary';
|
|
||||||
|
|
||||||
const languageClientName = 'oxc';
|
const languageClientName = 'oxc';
|
||||||
const outputChannelName = 'Oxc';
|
const outputChannelName = 'Oxc';
|
||||||
|
const commandPrefix = 'oxc';
|
||||||
|
|
||||||
|
const enum OxcCommands {
|
||||||
|
RestartServer = `${commandPrefix}.restartServer`,
|
||||||
|
ApplyAllFixesFile = `${commandPrefix}.applyAllFixesFile`,
|
||||||
|
ShowOutputChannel = `${commandPrefix}.showOutputChannel`,
|
||||||
|
ToggleEnable = `${commandPrefix}.toggleEnable`,
|
||||||
|
}
|
||||||
|
|
||||||
let client: LanguageClient;
|
let client: LanguageClient;
|
||||||
|
|
||||||
|
|
@ -28,18 +43,146 @@ let myStatusBarItem: StatusBarItem;
|
||||||
|
|
||||||
export async function activate(context: ExtensionContext) {
|
export async function activate(context: ExtensionContext) {
|
||||||
const configService = new ConfigService();
|
const configService = new ConfigService();
|
||||||
|
const restartCommand = commands.registerCommand(
|
||||||
|
OxcCommands.RestartServer,
|
||||||
|
async () => {
|
||||||
|
if (!client) {
|
||||||
|
window.showErrorMessage('oxc client not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (client.isRunning()) {
|
||||||
|
await client.restart();
|
||||||
|
|
||||||
|
window.showInformationMessage('oxc server restarted.');
|
||||||
|
} else {
|
||||||
|
await client.start();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
client.error('Restarting client failed', err, 'force');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const showOutputCommand = commands.registerCommand(
|
||||||
|
OxcCommands.ShowOutputChannel,
|
||||||
|
() => {
|
||||||
|
client?.outputChannel?.show();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleEnable = commands.registerCommand(
|
||||||
|
OxcCommands.ToggleEnable,
|
||||||
|
() => {
|
||||||
|
configService.config.updateEnable(!configService.config.enable);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const applyAllFixesFile = commands.registerCommand(
|
||||||
|
OxcCommands.ApplyAllFixesFile,
|
||||||
|
async () => {
|
||||||
|
if (!client) {
|
||||||
|
window.showErrorMessage('oxc client not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const textEditor = window.activeTextEditor;
|
||||||
|
if (!textEditor) {
|
||||||
|
window.showErrorMessage('active text editor not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastLine = textEditor.document.lineAt(textEditor.document.lineCount - 1);
|
||||||
|
const codeActionResult = await client.sendRequest(CodeActionRequest.type, {
|
||||||
|
textDocument: {
|
||||||
|
uri: textEditor.document.uri.toString(),
|
||||||
|
},
|
||||||
|
range: Range.create(Position.create(0, 0), lastLine.range.end),
|
||||||
|
context: {
|
||||||
|
diagnostics: [],
|
||||||
|
only: [],
|
||||||
|
triggerKind: CodeActionTriggerKind.Invoked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const commandsOrCodeActions = await client.protocol2CodeConverter.asCodeActionResult(codeActionResult || []);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
commandsOrCodeActions
|
||||||
|
.map(async (codeActionOrCommand) => {
|
||||||
|
// Commands are always applied. Regardless of whether it's a Command or CodeAction#command.
|
||||||
|
if (isCommand(codeActionOrCommand)) {
|
||||||
|
await commands.executeCommand(codeActionOrCommand.command, codeActionOrCommand.arguments);
|
||||||
|
} else {
|
||||||
|
// Only preferred edits are applied
|
||||||
|
// LSP states edits must be run first, then commands
|
||||||
|
if (codeActionOrCommand.edit && codeActionOrCommand.isPreferred) {
|
||||||
|
await workspace.applyEdit(codeActionOrCommand.edit);
|
||||||
|
}
|
||||||
|
if (codeActionOrCommand.command) {
|
||||||
|
await commands.executeCommand(
|
||||||
|
codeActionOrCommand.command.command,
|
||||||
|
codeActionOrCommand.command.arguments,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
function isCommand(codeActionOrCommand: CodeAction | Command): codeActionOrCommand is Command {
|
||||||
|
return typeof codeActionOrCommand.command === 'string';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
applyAllFixesFileCommand(client),
|
applyAllFixesFile,
|
||||||
restartServerCommand(client),
|
restartCommand,
|
||||||
showOutputChannelCommand(client),
|
showOutputCommand,
|
||||||
toggleEnabledCommand(configService.config),
|
toggleEnable,
|
||||||
configService,
|
configService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const outputChannel = window.createOutputChannel(outputChannelName, { log: true });
|
const outputChannel = window.createOutputChannel(outputChannelName, { log: true });
|
||||||
|
|
||||||
const command = await findBinary(context, configService.config);
|
async function findBinary(): Promise<string> {
|
||||||
|
let bin = configService.config.binPath;
|
||||||
|
if (bin) {
|
||||||
|
try {
|
||||||
|
await fsPromises.access(bin);
|
||||||
|
return bin;
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceFolders = workspace.workspaceFolders;
|
||||||
|
const isWindows = process.platform === 'win32';
|
||||||
|
|
||||||
|
if (workspaceFolders?.length && !isWindows) {
|
||||||
|
try {
|
||||||
|
return await Promise.any(
|
||||||
|
workspaceFolders.map(async (folder) => {
|
||||||
|
const binPath = join(
|
||||||
|
folder.uri.fsPath,
|
||||||
|
'node_modules',
|
||||||
|
'.bin',
|
||||||
|
'oxc_language_server',
|
||||||
|
);
|
||||||
|
|
||||||
|
await fsPromises.access(binPath);
|
||||||
|
return binPath;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ext = isWindows ? '.exe' : '';
|
||||||
|
// NOTE: The `./target/release` path is aligned with the path defined in .github/workflows/release_vscode.yml
|
||||||
|
return (
|
||||||
|
process.env.SERVER_PATH_DEV ??
|
||||||
|
join(context.extensionPath, `./target/release/oxc_language_server${ext}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = await findBinary();
|
||||||
const run: Executable = {
|
const run: Executable = {
|
||||||
command: command!,
|
command: command!,
|
||||||
options: {
|
options: {
|
||||||
|
|
@ -89,7 +232,6 @@ export async function activate(context: ExtensionContext) {
|
||||||
serverOptions,
|
serverOptions,
|
||||||
clientOptions,
|
clientOptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
client.onNotification(ShowMessageNotification.type, (params) => {
|
client.onNotification(ShowMessageNotification.type, (params) => {
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case MessageType.Debug:
|
case MessageType.Debug:
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { promises as fsPromises } from 'node:fs';
|
|
||||||
import { join } from 'node:path';
|
|
||||||
|
|
||||||
import { ExtensionContext, workspace } from 'vscode';
|
|
||||||
|
|
||||||
import { Config } from './Config';
|
|
||||||
|
|
||||||
export default async function findBinary(context: ExtensionContext, config: Config): Promise<string> {
|
|
||||||
let bin = config.binPath;
|
|
||||||
if (bin) {
|
|
||||||
try {
|
|
||||||
await fsPromises.access(bin);
|
|
||||||
return bin;
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const workspaceFolders = workspace.workspaceFolders;
|
|
||||||
const isWindows = process.platform === 'win32';
|
|
||||||
|
|
||||||
if (workspaceFolders?.length && !isWindows) {
|
|
||||||
try {
|
|
||||||
return await Promise.any(
|
|
||||||
workspaceFolders.map(async (folder) => {
|
|
||||||
const binPath = join(
|
|
||||||
folder.uri.fsPath,
|
|
||||||
'node_modules',
|
|
||||||
'.bin',
|
|
||||||
'oxc_language_server',
|
|
||||||
);
|
|
||||||
|
|
||||||
await fsPromises.access(binPath);
|
|
||||||
return binPath;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ext = isWindows ? '.exe' : '';
|
|
||||||
// NOTE: The `./target/release` path is aligned with the path defined in .github/workflows/release_vscode.yml
|
|
||||||
return (
|
|
||||||
process.env.SERVER_PATH_DEV ??
|
|
||||||
join(context.extensionPath, `./target/release/oxc_language_server${ext}`)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -140,7 +140,7 @@
|
||||||
"server:build:debug": "cargo build -p oxc_language_server",
|
"server:build:debug": "cargo build -p oxc_language_server",
|
||||||
"server:build:release": "cross-env CARGO_TARGET_DIR=./target cargo build -p oxc_language_server --release",
|
"server:build:release": "cross-env CARGO_TARGET_DIR=./target cargo build -p oxc_language_server --release",
|
||||||
"lint": "npx oxlint --config=oxlint.json --tsconfig=tsconfig.json",
|
"lint": "npx oxlint --config=oxlint.json --tsconfig=tsconfig.json",
|
||||||
"test": "esbuild \"client/*.spec.ts\" --bundle --outdir=out --external:vscode --format=cjs --platform=node --target=node16 --minify --sourcemap && vscode-test",
|
"test": "esbuild client/config.spec.ts --bundle --outfile=out/config.spec.js --external:vscode --format=cjs --platform=node --target=node16 --minify --sourcemap && vscode-test",
|
||||||
"type-check": "tsc --noEmit"
|
"type-check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue