Skip to content

Commit 54aed8f

Browse files
Add ability to build extension VSIX and swap for built-in extension (#805)
Co-authored-by: Copilot <[email protected]>
1 parent 2379148 commit 54aed8f

File tree

6 files changed

+5035
-431
lines changed

6 files changed

+5035
-431
lines changed

.github/ls-screenshot.png

66 KB
Loading

Herebyfile.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const { values: options } = parseArgs({
5555
fix: { type: "boolean" },
5656
debug: { type: "boolean" },
5757

58+
insiders: { type: "boolean" },
59+
5860
race: { type: "boolean", default: parseEnvBoolean("RACE") },
5961
noembed: { type: "boolean", default: parseEnvBoolean("NOEMBED") },
6062
concurrentTestPrograms: { type: "boolean", default: parseEnvBoolean("CONCURRENT_TEST_PROGRAMS") },
@@ -348,6 +350,17 @@ export const testAll = task({
348350
},
349351
});
350352

353+
export const installExtension = task({
354+
name: "install-extension",
355+
run: async () => {
356+
await $({ cwd: path.join(__dirname, "_extension") })`npm run package`;
357+
await $({ cwd: path.join(__dirname, "_extension") })`${options.insiders ? "code-insiders" : "code"} --install-extension typescript-lsp.vsix`;
358+
console.log(pc.yellowBright("\nExtension installed. ") + "Add the following to your workspace or user settings.json:\n");
359+
console.log(pc.whiteBright(` "typescript-go.executablePath": "${path.join(__dirname, "built", "local", process.platform === "win32" ? "tsgo.exe" : "tsgo")}"\n`));
360+
console.log("Select 'TypeScript: Use TypeScript Go (Experimental)' in the command palette to enable the extension and disable built-in TypeScript support.\n");
361+
},
362+
});
363+
351364
const customLinterPath = "./_tools/custom-gcl";
352365
const customLinterHashPath = customLinterPath + ".hash";
353366

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,18 @@ This is mainly a testing entry point; for higher fidelity with regular `tsc`, ru
4545

4646
### Running LSP Prototype
4747

48-
To try the prototype LSP experience:
48+
* Run `hereby build` to build the LSP server
49+
* Run `hereby install-extension` to build and install the VS Code extension. (Use `--insiders` to target `code-insiders` instead of `code`.)
50+
* Copy the `"typescript-go.executablePath"` setting printed by `hereby install-extension` to your VS Code settings.
51+
* Select "TypeScript: Use TypeScript Go (Experimental)" from the VS Code command palette (or set `"typescript.experimental.useTsgo"` in your VS Code settings).
52+
53+
Alternatively, to debug and run the VS Code extension without installing it globally:
4954

5055
* Run VS Code in the repo workspace (`code .`)
5156
* Copy `.vscode/launch.template.json` to `.vscode/launch.json`
5257
* <kbd>F5</kbd> (or `Debug: Start Debugging` from the command palette)
5358

54-
This will launch a new VS Code instance which uses the Corsa LS as the backend. If correctly set up, you should see "typescript-go" as an option in the Output pane:
59+
This will launch a new VS Code instance which uses the Corsa LS as the backend. If correctly set up, you should see "tsgo" in the status bar when a TypeScript or JavaScript file is open:
5560

5661
![LSP Prototype Screenshot](.github/ls-screenshot.png)
5762

_extension/package.json

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
"private": true,
88
"version": "0.0.0",
99
"type": "commonjs",
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/microsoft/typescript-go"
13+
},
1014
"engines": {
1115
"vscode": "^1.91.0"
1216
},
@@ -34,33 +38,48 @@
3438
"typescript-go.pprofDir": {
3539
"type": "string",
3640
"description": "Directory to write pprof profiles to."
41+
},
42+
"typescript-go.executablePath": {
43+
"type": "string",
44+
"description": "Path to the tsgo binary. If not specified, the extension will look for it in the default location."
3745
}
3846
}
3947
}
4048
],
4149
"commands": [
4250
{
4351
"command": "typescript-go.restart",
44-
"title": "TypeScript Go: Restart Language Server"
52+
"title": "TypeScript Go: Restart Language Server",
53+
"enablement": "typescript-go.serverRunning"
4554
}
4655
],
4756
"menus": {
4857
"commandPalette": [
4958
{
50-
"command": "typescript-go.restart"
59+
"command": "typescript-go.restart",
60+
"when": "typescript-go.serverRunning"
5161
}
5262
]
5363
}
5464
},
5565
"main": "./dist/extension.js",
66+
"files": [
67+
"dist"
68+
],
5669
"scripts": {
5770
"build": "tsc",
58-
"watch": "tsc --watch"
71+
"watch": "tsc --watch",
72+
"build:prod": "esbuild src/extension.ts --bundle --external:vscode --platform=node --format=cjs --outfile=dist/extension.js --minify",
73+
"package": "vsce package --skip-license --no-dependencies --out typescript-lsp.vsix",
74+
"install-extension": "code --install-extension typescript-lsp.vsix",
75+
"vscode:prepublish": "npm run build:prod"
5976
},
6077
"dependencies": {
6178
"vscode-languageclient": "^9.0.1"
6279
},
6380
"devDependencies": {
64-
"@types/vscode": "^1.96.0"
81+
"@types/vscode": "^1.91.0",
82+
"@vscode/vsce": "^3.3.2",
83+
"esbuild": "^0.25.2"
6584
}
6685
}

_extension/src/extension.ts

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,30 @@ import {
1111
} from "vscode-languageclient/node";
1212

1313
let client: LanguageClient;
14+
let statusBarItem: vscode.StatusBarItem;
15+
16+
const BUILTIN_TS_EXTENSION_ID = "vscode.typescript-language-features";
1417

1518
export function activate(context: vscode.ExtensionContext) {
16-
context.subscriptions.push(vscode.commands.registerCommand("typescript-go.restart", () => {
17-
client.restart();
18-
}));
19+
const tsExtension = vscode.extensions.getExtension(BUILTIN_TS_EXTENSION_ID);
20+
if (tsExtension?.isActive && !vscode.workspace.getConfiguration("typescript").get<boolean>("experimental.useTsgo")) {
21+
return;
22+
}
1923

2024
const output = vscode.window.createOutputChannel("typescript-go", "log");
2125
const traceOutput = vscode.window.createOutputChannel("typescript-go (LSP)");
2226

23-
const exe = context.asAbsolutePath(
27+
setupStatusBar(context);
28+
registerCommands(context, output, traceOutput);
29+
30+
const config = vscode.workspace.getConfiguration("typescript-go");
31+
32+
const exe = config.get<string>("executablePath") || context.asAbsolutePath(
2433
path.join("../", "built", "local", `tsgo${process.platform === "win32" ? ".exe" : ""}`),
2534
);
2635

2736
output.appendLine(`Resolved to ${exe}`);
2837

29-
const config = vscode.workspace.getConfiguration("typescript-go");
30-
3138
// Get pprofDir
3239
const pprofDir = config.get<string>("pprofDir");
3340
const pprofArgs = pprofDir ? ["-pprofDir", pprofDir] : [];
@@ -115,13 +122,86 @@ export function activate(context: vscode.ExtensionContext) {
115122

116123
output.appendLine(`Starting language server...`);
117124
client.start();
125+
vscode.commands.executeCommand("setContext", "typescript-go.serverRunning", true);
126+
}
127+
128+
/**
129+
* Sets up the status bar item for TypeScript Go
130+
* @param context Extension context
131+
*/
132+
function setupStatusBar(context: vscode.ExtensionContext): void {
133+
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
134+
statusBarItem.text = "$(beaker) tsgo";
135+
statusBarItem.tooltip = "TypeScript Go Language Server";
136+
statusBarItem.command = "typescript-go.showMenu";
137+
statusBarItem.backgroundColor = new vscode.ThemeColor("statusBarItem.warningBackground");
138+
statusBarItem.show();
139+
context.subscriptions.push(statusBarItem);
140+
}
141+
142+
/**
143+
* Registers all commands for the extension
144+
* @param context Extension context
145+
*/
146+
function registerCommands(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel): void {
147+
context.subscriptions.push(vscode.commands.registerCommand("typescript-go.restart", async () => {
148+
await client.restart();
149+
}));
150+
151+
context.subscriptions.push(vscode.commands.registerCommand("typescript-go.output.focus", () => {
152+
outputChannel.show();
153+
}));
154+
155+
context.subscriptions.push(vscode.commands.registerCommand("typescript-go.lsp-trace.focus", () => {
156+
traceOutputChannel.show();
157+
}));
158+
159+
context.subscriptions.push(vscode.commands.registerCommand("typescript-go.showMenu", showQuickPickMenu));
118160
}
119161

120-
export function deactivate(): Thenable<void> | undefined {
162+
/**
163+
* Shows the quick pick menu for TypeScript Go options
164+
*/
165+
async function showQuickPickMenu(): Promise<void> {
166+
const selected = await vscode.window.showQuickPick([
167+
{ label: "$(refresh) Restart Server", description: "Restart the TypeScript Go language server" },
168+
{ label: "$(output) Show TS Server Log", description: "Show the TypeScript Go server log" },
169+
{ label: "$(debug-console) Show LSP Messages", description: "Show the LSP communication trace" },
170+
{ label: "$(stop-circle) Disable TypeScript Go", description: "Switch back to the built-in TypeScript extension" },
171+
], {
172+
placeHolder: "TypeScript Go Options",
173+
});
174+
175+
if (selected) {
176+
if (selected.label.includes("Restart Server")) {
177+
await vscode.commands.executeCommand("typescript-go.restart");
178+
}
179+
else if (selected.label.includes("Show TS Server Log")) {
180+
await vscode.commands.executeCommand("typescript-go.output.focus");
181+
}
182+
else if (selected.label.includes("Show LSP Messages")) {
183+
await vscode.commands.executeCommand("typescript-go.lsp-trace.focus");
184+
}
185+
else if (selected.label.includes("Disable TypeScript Go")) {
186+
// Fire and forget, because this command will restart the whole extension host
187+
// and awaiting it shows a weird cancellation error.
188+
vscode.commands.executeCommand("typescript.experimental.disableTsgo");
189+
}
190+
}
191+
}
192+
193+
export async function deactivate(): Promise<void> {
194+
// Dispose of status bar item
195+
if (statusBarItem) {
196+
statusBarItem.dispose();
197+
}
198+
121199
if (!client) {
122-
return undefined;
200+
return;
123201
}
124-
return client.stop();
202+
203+
await client.stop();
204+
return vscode.commands.executeCommand("setContext", "typescript-go.serverRunning", false);
125205
}
126206

127207
function getLanguageForUri(uri: vscode.Uri): string | undefined {

0 commit comments

Comments
 (0)