From 5f2ad12507ecb1555033acb19a19a3a886a99234 Mon Sep 17 00:00:00 2001 From: shulaoda Date: Sat, 28 Sep 2024 11:23:37 +0800 Subject: [PATCH 1/4] feat(editors/vscode): update VSCode extention to use project's language server --- editors/vscode/client/extension.ts | 113 +++++++++++++++++++---------- 1 file changed, 74 insertions(+), 39 deletions(-) diff --git a/editors/vscode/client/extension.ts b/editors/vscode/client/extension.ts index d8a554a05131f..67a702c5eaa01 100644 --- a/editors/vscode/client/extension.ts +++ b/editors/vscode/client/extension.ts @@ -1,3 +1,5 @@ +import { existsSync } from "node:fs"; + import { commands, ConfigurationTarget, @@ -7,23 +9,28 @@ import { ThemeColor, window, workspace, -} from 'vscode'; +} from "vscode"; -import { Executable, LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node'; +import { + Executable, + LanguageClient, + LanguageClientOptions, + ServerOptions, +} from "vscode-languageclient/node"; -import { join } from 'node:path'; +import { join } from "node:path"; -const languageClientId = 'oxc-vscode'; -const languageClientName = 'oxc'; -const outputChannelName = 'oxc_language_server'; -const traceOutputChannelName = 'oxc_language_server.trace'; +const languageClientId = "oxc-vscode"; +const languageClientName = "oxc"; +const outputChannelName = "oxc_language_server"; +const traceOutputChannelName = "oxc_language_server.trace"; const enum OxcCommands { - RestartServer = 'oxc.restartServer', - ApplyAllFixes = 'oxc.applyAllFixes', - ShowOutputChannel = 'oxc.showOutputChannel', - ShowTraceOutputChannel = 'oxc.showTraceOutputChannel', - ToggleEnable = 'oxc.toggleEnable', + RestartServer = "oxc.restartServer", + ApplyAllFixes = "oxc.applyAllFixes", + ShowOutputChannel = "oxc.showOutputChannel", + ShowTraceOutputChannel = "oxc.showTraceOutputChannel", + ToggleEnable = "oxc.toggleEnable", } let client: LanguageClient; @@ -35,7 +42,7 @@ export async function activate(context: ExtensionContext) { OxcCommands.RestartServer, async () => { if (!client) { - window.showErrorMessage('oxc client not found'); + window.showErrorMessage("oxc client not found"); return; } @@ -43,12 +50,12 @@ export async function activate(context: ExtensionContext) { if (client.isRunning()) { await client.restart(); - window.showInformationMessage('oxc server restarted.'); + window.showInformationMessage("oxc server restarted."); } else { await client.start(); } } catch (err) { - client.error('Restarting client failed', err, 'force'); + client.error("Restarting client failed", err, "force"); } }, ); @@ -71,12 +78,12 @@ export async function activate(context: ExtensionContext) { OxcCommands.ToggleEnable, () => { let enabled = workspace - .getConfiguration('oxc_language_server') - .get('enable'); + .getConfiguration("oxc_language_server") + .get("enable"); let nextState = !enabled; workspace - .getConfiguration('oxc_language_server') - .update('enable', nextState, ConfigurationTarget.Global); + .getConfiguration("oxc_language_server") + .update("enable", nextState, ConfigurationTarget.Global); }, ); @@ -90,16 +97,44 @@ export async function activate(context: ExtensionContext) { const outputChannel = window.createOutputChannel(outputChannelName); const traceOutputChannel = window.createOutputChannel(traceOutputChannelName); - const ext = process.platform === 'win32' ? '.exe' : ''; - // NOTE: The `./target/release` path is aligned with the path defined in .github/workflows/release_vscode.yml - const command = process.env.SERVER_PATH_DEV ?? - join(context.extensionPath, `./target/release/oxc_language_server${ext}`); + function findBinary(): string | null { + const cfg = workspace.getConfiguration("oxc"); + + let bin = cfg.get("binPath", ""); + if (bin && existsSync(bin)) { + return bin; + } + + const workspaceFolders = workspace.workspaceFolders; + if (workspaceFolders) { + for (const folder of workspaceFolders) { + const binPath = join( + folder.uri.fsPath, + "node_modules", + ".bin", + "oxc_language_server", + ); + if (existsSync(binPath)) { + return binPath; + } + } + } + + const ext = process.platform === "win32" ? ".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 = findBinary(); const run: Executable = { command: command!, options: { env: { ...process.env, - RUST_LOG: process.env.RUST_LOG || 'info', + RUST_LOG: process.env.RUST_LOG || "info", }, }, }; @@ -111,24 +146,24 @@ export async function activate(context: ExtensionContext) { // Otherwise the run options are used // Options to control the language client let clientConfig: any = JSON.parse( - JSON.stringify(workspace.getConfiguration('oxc_language_server')), + JSON.stringify(workspace.getConfiguration("oxc_language_server")), ); let clientOptions: LanguageClientOptions = { // Register the server for plain text documents documentSelector: [ - 'typescript', - 'javascript', - 'typescriptreact', - 'javascriptreact', - 'vue', - 'svelte', + "typescript", + "javascript", + "typescriptreact", + "javascriptreact", + "vue", + "svelte", ].map((lang) => ({ language: lang, - scheme: 'file', + scheme: "file", })), synchronize: { // Notify the server about file changes to '.clientrc files contained in the workspace - fileEvents: workspace.createFileSystemWatcher('**/.clientrc'), + fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), }, initializationOptions: { settings: clientConfig, @@ -145,15 +180,15 @@ export async function activate(context: ExtensionContext) { clientOptions, ); workspace.onDidChangeConfiguration((e) => { - let isAffected = e.affectsConfiguration('oxc_language_server'); + let isAffected = e.affectsConfiguration("oxc_language_server"); if (!isAffected) { return; } let settings: any = JSON.parse( - JSON.stringify(workspace.getConfiguration('oxc_language_server')), + JSON.stringify(workspace.getConfiguration("oxc_language_server")), ); updateStatsBar(settings.enable); - client.sendNotification('workspace/didChangeConfiguration', { settings }); + client.sendNotification("workspace/didChangeConfiguration", { settings }); }); function updateStatsBar(enable: boolean) { @@ -168,10 +203,10 @@ export async function activate(context: ExtensionContext) { } let bgColor = new ThemeColor( enable - ? 'statusBarItem.activeBackground' - : 'statusBarItem.errorBackground', + ? "statusBarItem.activeBackground" + : "statusBarItem.errorBackground", ); - myStatusBarItem.text = `oxc: ${enable ? '$(check-all)' : '$(circle-slash)'}`; + myStatusBarItem.text = `oxc: ${enable ? "$(check-all)" : "$(circle-slash)"}`; myStatusBarItem.backgroundColor = bgColor; } From 93448bde7af3cdbd223ed1b202a36e0540220ed6 Mon Sep 17 00:00:00 2001 From: shulaoda Date: Sat, 28 Sep 2024 11:30:04 +0800 Subject: [PATCH 2/4] fmt --- editors/vscode/.prettierrc | 3 + editors/vscode/client/extension.ts | 93 ++++++++++++++---------------- 2 files changed, 47 insertions(+), 49 deletions(-) diff --git a/editors/vscode/.prettierrc b/editors/vscode/.prettierrc index e69de29bb2d1d..544138be45652 100644 --- a/editors/vscode/.prettierrc +++ b/editors/vscode/.prettierrc @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/editors/vscode/client/extension.ts b/editors/vscode/client/extension.ts index 67a702c5eaa01..ffb3c79c942f9 100644 --- a/editors/vscode/client/extension.ts +++ b/editors/vscode/client/extension.ts @@ -1,4 +1,4 @@ -import { existsSync } from "node:fs"; +import { existsSync } from 'node:fs'; import { commands, @@ -9,28 +9,23 @@ import { ThemeColor, window, workspace, -} from "vscode"; +} from 'vscode'; -import { - Executable, - LanguageClient, - LanguageClientOptions, - ServerOptions, -} from "vscode-languageclient/node"; +import { Executable, LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/node'; -import { join } from "node:path"; +import { join } from 'node:path'; -const languageClientId = "oxc-vscode"; -const languageClientName = "oxc"; -const outputChannelName = "oxc_language_server"; -const traceOutputChannelName = "oxc_language_server.trace"; +const languageClientId = 'oxc-vscode'; +const languageClientName = 'oxc'; +const outputChannelName = 'oxc_language_server'; +const traceOutputChannelName = 'oxc_language_server.trace'; const enum OxcCommands { - RestartServer = "oxc.restartServer", - ApplyAllFixes = "oxc.applyAllFixes", - ShowOutputChannel = "oxc.showOutputChannel", - ShowTraceOutputChannel = "oxc.showTraceOutputChannel", - ToggleEnable = "oxc.toggleEnable", + RestartServer = 'oxc.restartServer', + ApplyAllFixes = 'oxc.applyAllFixes', + ShowOutputChannel = 'oxc.showOutputChannel', + ShowTraceOutputChannel = 'oxc.showTraceOutputChannel', + ToggleEnable = 'oxc.toggleEnable', } let client: LanguageClient; @@ -42,7 +37,7 @@ export async function activate(context: ExtensionContext) { OxcCommands.RestartServer, async () => { if (!client) { - window.showErrorMessage("oxc client not found"); + window.showErrorMessage('oxc client not found'); return; } @@ -50,12 +45,12 @@ export async function activate(context: ExtensionContext) { if (client.isRunning()) { await client.restart(); - window.showInformationMessage("oxc server restarted."); + window.showInformationMessage('oxc server restarted.'); } else { await client.start(); } } catch (err) { - client.error("Restarting client failed", err, "force"); + client.error('Restarting client failed', err, 'force'); } }, ); @@ -78,12 +73,12 @@ export async function activate(context: ExtensionContext) { OxcCommands.ToggleEnable, () => { let enabled = workspace - .getConfiguration("oxc_language_server") - .get("enable"); + .getConfiguration('oxc_language_server') + .get('enable'); let nextState = !enabled; workspace - .getConfiguration("oxc_language_server") - .update("enable", nextState, ConfigurationTarget.Global); + .getConfiguration('oxc_language_server') + .update('enable', nextState, ConfigurationTarget.Global); }, ); @@ -97,10 +92,10 @@ export async function activate(context: ExtensionContext) { const outputChannel = window.createOutputChannel(outputChannelName); const traceOutputChannel = window.createOutputChannel(traceOutputChannelName); - function findBinary(): string | null { - const cfg = workspace.getConfiguration("oxc"); + function findBinary(): string { + const cfg = workspace.getConfiguration('oxc'); - let bin = cfg.get("binPath", ""); + let bin = cfg.get('binPath', ''); if (bin && existsSync(bin)) { return bin; } @@ -110,9 +105,9 @@ export async function activate(context: ExtensionContext) { for (const folder of workspaceFolders) { const binPath = join( folder.uri.fsPath, - "node_modules", - ".bin", - "oxc_language_server", + 'node_modules', + '.bin', + 'oxc_language_server', ); if (existsSync(binPath)) { return binPath; @@ -120,11 +115,11 @@ export async function activate(context: ExtensionContext) { } } - const ext = process.platform === "win32" ? ".exe" : ""; + const ext = process.platform === 'win32' ? '.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}`) + join(context.extensionPath, `./target/release/oxc_language_server${ext}`) ); } @@ -134,7 +129,7 @@ export async function activate(context: ExtensionContext) { options: { env: { ...process.env, - RUST_LOG: process.env.RUST_LOG || "info", + RUST_LOG: process.env.RUST_LOG || 'info', }, }, }; @@ -146,24 +141,24 @@ export async function activate(context: ExtensionContext) { // Otherwise the run options are used // Options to control the language client let clientConfig: any = JSON.parse( - JSON.stringify(workspace.getConfiguration("oxc_language_server")), + JSON.stringify(workspace.getConfiguration('oxc_language_server')), ); let clientOptions: LanguageClientOptions = { // Register the server for plain text documents documentSelector: [ - "typescript", - "javascript", - "typescriptreact", - "javascriptreact", - "vue", - "svelte", + 'typescript', + 'javascript', + 'typescriptreact', + 'javascriptreact', + 'vue', + 'svelte', ].map((lang) => ({ language: lang, - scheme: "file", + scheme: 'file', })), synchronize: { // Notify the server about file changes to '.clientrc files contained in the workspace - fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), + fileEvents: workspace.createFileSystemWatcher('**/.clientrc'), }, initializationOptions: { settings: clientConfig, @@ -180,15 +175,15 @@ export async function activate(context: ExtensionContext) { clientOptions, ); workspace.onDidChangeConfiguration((e) => { - let isAffected = e.affectsConfiguration("oxc_language_server"); + let isAffected = e.affectsConfiguration('oxc_language_server'); if (!isAffected) { return; } let settings: any = JSON.parse( - JSON.stringify(workspace.getConfiguration("oxc_language_server")), + JSON.stringify(workspace.getConfiguration('oxc_language_server')), ); updateStatsBar(settings.enable); - client.sendNotification("workspace/didChangeConfiguration", { settings }); + client.sendNotification('workspace/didChangeConfiguration', { settings }); }); function updateStatsBar(enable: boolean) { @@ -203,10 +198,10 @@ export async function activate(context: ExtensionContext) { } let bgColor = new ThemeColor( enable - ? "statusBarItem.activeBackground" - : "statusBarItem.errorBackground", + ? 'statusBarItem.activeBackground' + : 'statusBarItem.errorBackground', ); - myStatusBarItem.text = `oxc: ${enable ? "$(check-all)" : "$(circle-slash)"}`; + myStatusBarItem.text = `oxc: ${enable ? '$(check-all)' : '$(circle-slash)'}`; myStatusBarItem.backgroundColor = bgColor; } From dd9b84726549e8f34b96ecca012c3f26489fe255 Mon Sep 17 00:00:00 2001 From: shulaoda Date: Sun, 29 Sep 2024 06:33:29 +0800 Subject: [PATCH 3/4] chore: follow the suggestions --- editors/vscode/.prettierrc | 3 --- editors/vscode/client/extension.ts | 30 ++++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) delete mode 100644 editors/vscode/.prettierrc diff --git a/editors/vscode/.prettierrc b/editors/vscode/.prettierrc deleted file mode 100644 index 544138be45652..0000000000000 --- a/editors/vscode/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "singleQuote": true -} diff --git a/editors/vscode/client/extension.ts b/editors/vscode/client/extension.ts index ffb3c79c942f9..b8e8da348a31d 100644 --- a/editors/vscode/client/extension.ts +++ b/editors/vscode/client/extension.ts @@ -1,4 +1,4 @@ -import { existsSync } from 'node:fs'; +import { promises as fsPromises } from 'node:fs'; import { commands, @@ -92,27 +92,41 @@ export async function activate(context: ExtensionContext) { const outputChannel = window.createOutputChannel(outputChannelName); const traceOutputChannel = window.createOutputChannel(traceOutputChannelName); - function findBinary(): string { + async function findBinary(): Promise { const cfg = workspace.getConfiguration('oxc'); let bin = cfg.get('binPath', ''); - if (bin && existsSync(bin)) { - return bin; + if (bin) { + try { + await fsPromises.access(bin); + return bin; + } catch {} } const workspaceFolders = workspace.workspaceFolders; if (workspaceFolders) { - for (const folder of workspaceFolders) { + const checks = workspaceFolders.map(async (folder) => { const binPath = join( folder.uri.fsPath, 'node_modules', '.bin', 'oxc_language_server', ); - if (existsSync(binPath)) { + + try { + await fsPromises.access(binPath); return binPath; + } catch { + return undefined; } - } + }); + + // Wait for all checks and return the first valid path + const result = (await Promise.all(checks)).find( + (path) => path !== undefined, + ); + + if (result) return result; } const ext = process.platform === 'win32' ? '.exe' : ''; @@ -123,7 +137,7 @@ export async function activate(context: ExtensionContext) { ); } - const command = findBinary(); + const command = await findBinary(); const run: Executable = { command: command!, options: { From 6b1f7187089fa602fb7a78bc092f118349f4b107 Mon Sep 17 00:00:00 2001 From: shulaoda Date: Mon, 30 Sep 2024 09:20:57 +0800 Subject: [PATCH 4/4] refactor: use promise.any instead --- editors/vscode/client/extension.ts | 35 ++++++++++++------------------ editors/vscode/tsconfig.json | 4 ++-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/editors/vscode/client/extension.ts b/editors/vscode/client/extension.ts index b8e8da348a31d..cd5210b91ac2d 100644 --- a/editors/vscode/client/extension.ts +++ b/editors/vscode/client/extension.ts @@ -105,28 +105,21 @@ export async function activate(context: ExtensionContext) { const workspaceFolders = workspace.workspaceFolders; if (workspaceFolders) { - const checks = workspaceFolders.map(async (folder) => { - const binPath = join( - folder.uri.fsPath, - 'node_modules', - '.bin', - 'oxc_language_server', + 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; + }), ); - - try { - await fsPromises.access(binPath); - return binPath; - } catch { - return undefined; - } - }); - - // Wait for all checks and return the first valid path - const result = (await Promise.all(checks)).find( - (path) => path !== undefined, - ); - - if (result) return result; + } catch {} } const ext = process.platform === 'win32' ? '.exe' : ''; diff --git a/editors/vscode/tsconfig.json b/editors/vscode/tsconfig.json index 572c7b6757b05..098e7ba6ef597 100644 --- a/editors/vscode/tsconfig.json +++ b/editors/vscode/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { "module": "commonjs", - "target": "es2020", - "lib": ["ES2020"], + "target": "es2021", + "lib": ["ES2021"], "outDir": "dist", "rootDir": "client", "sourceMap": true,