diff --git a/_extension/src/client.ts b/_extension/src/client.ts index 46fd90ebb0..b759501e97 100644 --- a/_extension/src/client.ts +++ b/_extension/src/client.ts @@ -81,12 +81,12 @@ export class Client { }; } - async initialize(context: vscode.ExtensionContext): Promise { + async initialize(context: vscode.ExtensionContext): Promise { const exe = await getExe(context); - this.start(context, exe); + return this.start(context, exe); } - async start(context: vscode.ExtensionContext, exe: { path: string; version: string; }): Promise { + async start(context: vscode.ExtensionContext, exe: { path: string; version: string; }): Promise { this.exe = exe; this.outputChannel.appendLine(`Resolved to ${this.exe.path}`); @@ -119,14 +119,12 @@ export class Client { await this.client.start(); vscode.commands.executeCommand("setContext", "typescript.native-preview.serverRunning", true); this.onStartedCallbacks.forEach(callback => callback()); - context.subscriptions.push( - new vscode.Disposable(() => { - if (this.client) { - this.client.stop(); - } - vscode.commands.executeCommand("setContext", "typescript.native-preview.serverRunning", false); - }), - ); + return new vscode.Disposable(() => { + if (this.client) { + this.client.stop(); + } + vscode.commands.executeCommand("setContext", "typescript.native-preview.serverRunning", false); + }); } getCurrentExe(): { path: string; version: string; } | undefined { @@ -145,7 +143,7 @@ export class Client { }); } - async restart(context: vscode.ExtensionContext): Promise { + async restart(context: vscode.ExtensionContext): Promise { if (!this.client) { return Promise.reject(new Error("Language client is not initialized")); } @@ -157,6 +155,7 @@ export class Client { } this.outputChannel.appendLine(`Restarting language server...`); - return this.client.restart(); + this.client.restart(); + return new vscode.Disposable(() => {}); } } diff --git a/_extension/src/commands.ts b/_extension/src/commands.ts index 364377a1f1..ef44a12b76 100644 --- a/_extension/src/commands.ts +++ b/_extension/src/commands.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import { Client } from "./client"; -export function registerCommands(context: vscode.ExtensionContext, client: Client, outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel): void { +export function registerEnablementCommands(context: vscode.ExtensionContext): void { context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.enable", () => { // Fire and forget, because this will restart the extension host and cause an error if we await updateUseTsgoSetting(true); @@ -11,23 +11,29 @@ export function registerCommands(context: vscode.ExtensionContext, client: Clien // Fire and forget, because this will restart the extension host and cause an error if we await updateUseTsgoSetting(false); })); +} + +export function registerLanguageCommands(context: vscode.ExtensionContext, client: Client, outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel): vscode.Disposable[] { + const disposables: vscode.Disposable[] = []; - context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.restart", () => { + disposables.push(vscode.commands.registerCommand("typescript.native-preview.restart", () => { return client.restart(context); })); - context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.output.focus", () => { + disposables.push(vscode.commands.registerCommand("typescript.native-preview.output.focus", () => { outputChannel.show(); })); - context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.lsp-trace.focus", () => { + disposables.push(vscode.commands.registerCommand("typescript.native-preview.lsp-trace.focus", () => { traceOutputChannel.show(); })); - context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.selectVersion", async () => { + disposables.push(vscode.commands.registerCommand("typescript.native-preview.selectVersion", async () => { })); - context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.showMenu", showCommands)); + disposables.push(vscode.commands.registerCommand("typescript.native-preview.showMenu", showCommands)); + + return disposables; } /** diff --git a/_extension/src/extension.ts b/_extension/src/extension.ts index 784ebee7fc..7830134623 100644 --- a/_extension/src/extension.ts +++ b/_extension/src/extension.ts @@ -1,28 +1,48 @@ import * as vscode from "vscode"; import { Client } from "./client"; -import { registerCommands } from "./commands"; +import { + registerEnablementCommands, + registerLanguageCommands, +} from "./commands"; import { setupStatusBar } from "./statusBar"; import { setupVersionStatusItem } from "./versionStatusItem"; export async function activate(context: vscode.ExtensionContext) { await vscode.commands.executeCommand("setContext", "typescript.native-preview.serverRunning", false); - + registerEnablementCommands(context); const output = vscode.window.createOutputChannel("typescript-native-preview", "log"); const traceOutput = vscode.window.createOutputChannel("typescript-native-preview (LSP)"); - const client = new Client(output, traceOutput); - registerCommands(context, client, output, traceOutput); + context.subscriptions.push(output, traceOutput); - context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(event => { + const majorVersion = parseInt(vscode.version.split(".")[0]); + const minorVersion = parseInt(vscode.version.split(".")[1]); + const needsExtHostRestartOnChange = majorVersion <= 1 && minorVersion < 105; + let disposeLanguageFeatures: vscode.Disposable | undefined; + + context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async event => { if (event.affectsConfiguration("typescript.experimental.useTsgo")) { - // Delay because the command to change the config setting will restart - // the extension host, so no need to show a message - setTimeout(async () => { - const selected = await vscode.window.showInformationMessage("TypeScript Native Preview setting has changed. Restart extensions to apply changes.", "Restart Extensions"); - if (selected) { - vscode.commands.executeCommand("workbench.action.restartExtensionHost"); + if (needsExtHostRestartOnChange) { + // Delay because the command to change the config setting will restart + // the extension host, so no need to show a message + setTimeout(async () => { + const selected = await vscode.window.showInformationMessage("TypeScript Native Preview setting has changed. Restart extensions to apply changes.", "Restart Extensions"); + if (selected) { + vscode.commands.executeCommand("workbench.action.restartExtensionHost"); + } + }, 100); + } + else { + const useTsgo = vscode.workspace.getConfiguration("typescript").get("experimental.useTsgo"); + if (useTsgo) { + disposeLanguageFeatures = await activateLanguageFeatures(context, output, traceOutput); + context.subscriptions.push(disposeLanguageFeatures); } - }, 100); + else { + disposeLanguageFeatures?.dispose(); + disposeLanguageFeatures = undefined; + } + } } })); @@ -41,10 +61,17 @@ export async function activate(context: vscode.ExtensionContext) { } } - await client.initialize(context); - setupStatusBar(context); - setupVersionStatusItem(context, client); + disposeLanguageFeatures = await activateLanguageFeatures(context, output, traceOutput); + context.subscriptions.push(disposeLanguageFeatures); } -export async function deactivate(): Promise { +async function activateLanguageFeatures(context: vscode.ExtensionContext, output: vscode.OutputChannel, traceOutput: vscode.OutputChannel): Promise { + const disposables: vscode.Disposable[] = []; + + const client = new Client(output, traceOutput); + disposables.push(...registerLanguageCommands(context, client, output, traceOutput)); + disposables.push(await client.initialize(context)); + disposables.push(setupStatusBar()); + disposables.push(...setupVersionStatusItem(client)); + return vscode.Disposable.from(...disposables); } diff --git a/_extension/src/statusBar.ts b/_extension/src/statusBar.ts index 1a23782dc8..37a54588d9 100644 --- a/_extension/src/statusBar.ts +++ b/_extension/src/statusBar.ts @@ -1,11 +1,11 @@ import * as vscode from "vscode"; -export function setupStatusBar(context: vscode.ExtensionContext): void { +export function setupStatusBar(): vscode.Disposable { const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); statusBarItem.text = "$(beaker) tsgo"; statusBarItem.tooltip = "TypeScript Native Preview Language Server"; statusBarItem.command = "typescript.native-preview.showMenu"; statusBarItem.backgroundColor = new vscode.ThemeColor("statusBarItem.warningBackground"); statusBarItem.show(); - context.subscriptions.push(statusBarItem); + return statusBarItem; } diff --git a/_extension/src/versionStatusItem.ts b/_extension/src/versionStatusItem.ts index d2329cd26b..e4c7d7ae5a 100644 --- a/_extension/src/versionStatusItem.ts +++ b/_extension/src/versionStatusItem.ts @@ -3,14 +3,15 @@ import { Client } from "./client"; import { jsTsLanguageModes } from "./util"; export function setupVersionStatusItem( - context: vscode.ExtensionContext, client: Client, -): void { +): vscode.Disposable[] { const statusItem = vscode.languages.createLanguageStatusItem("typescript.native-preview.version", jsTsLanguageModes); statusItem.name = "TypeScript Native Preview version"; statusItem.detail = "TypeScript Native Preview version"; - context.subscriptions.push(client.onStarted(() => { - statusItem.text = client.getCurrentExe()!.version; - })); - context.subscriptions.push(statusItem); + return [ + statusItem, + client.onStarted(() => { + statusItem.text = client.getCurrentExe()!.version; + }), + ]; }