-
Notifications
You must be signed in to change notification settings - Fork 650
Prepare VS Code extension for marketplace preview #884
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
andrewbranch
merged 7 commits into
microsoft:jabaile/native-preview
from
andrewbranch:extension-build
May 21, 2025
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
80092fd
Update strings, resolve exe from directory/package
andrewbranch 3f1b111
Organize imports
andrewbranch c6c0a6a
Use Uri.toString() for import call arg
andrewbranch 09dbbb6
Remove stray path.join
andrewbranch 0c14359
Reevaluate exe path on server restart, show message instead of automa…
andrewbranch 2045773
Change config value where it exists
andrewbranch f65a27b
Update herebyfile instructions
andrewbranch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import * as vscode from "vscode"; | ||
import { | ||
LanguageClient, | ||
LanguageClientOptions, | ||
NotebookDocumentFilter, | ||
ServerOptions, | ||
TextDocumentFilter, | ||
TransportKind, | ||
} from "vscode-languageclient/node"; | ||
import { | ||
ExeInfo, | ||
getExe, | ||
jsTsLanguageModes, | ||
} from "./util"; | ||
import { getLanguageForUri } from "./util"; | ||
|
||
export class Client { | ||
private outputChannel: vscode.OutputChannel; | ||
private traceOutputChannel: vscode.OutputChannel; | ||
private clientOptions: LanguageClientOptions; | ||
private client?: LanguageClient; | ||
private exe: ExeInfo | undefined; | ||
private onStartedCallbacks: Set<() => void> = new Set(); | ||
|
||
constructor(outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel) { | ||
this.outputChannel = outputChannel; | ||
this.traceOutputChannel = traceOutputChannel; | ||
this.clientOptions = { | ||
documentSelector: [ | ||
...jsTsLanguageModes.map(language => ({ scheme: "file", language })), | ||
...jsTsLanguageModes.map(language => ({ scheme: "untitled", language })), | ||
], | ||
outputChannel: this.outputChannel, | ||
traceOutputChannel: this.traceOutputChannel, | ||
diagnosticPullOptions: { | ||
onChange: true, | ||
onSave: true, | ||
onTabs: true, | ||
match(documentSelector, resource) { | ||
// This function is called when diagnostics are requested but | ||
// only the URI itself is known (e.g. open but not yet focused tabs), | ||
// so will not be present in vscode.workspace.textDocuments. | ||
// See if this file matches without consulting vscode.languages.match | ||
// (which requires a TextDocument). | ||
|
||
const language = getLanguageForUri(resource); | ||
|
||
for (const selector of documentSelector) { | ||
if (typeof selector === "string") { | ||
if (selector === language) { | ||
return true; | ||
} | ||
continue; | ||
} | ||
if (NotebookDocumentFilter.is(selector)) { | ||
continue; | ||
} | ||
if (TextDocumentFilter.is(selector)) { | ||
if (selector.language !== undefined && selector.language !== language) { | ||
continue; | ||
} | ||
|
||
if (selector.scheme !== undefined && selector.scheme !== resource.scheme) { | ||
continue; | ||
} | ||
|
||
if (selector.pattern !== undefined) { | ||
// VS Code's glob matcher is not available via the API; | ||
// see: https://github.com/microsoft/vscode/issues/237304 | ||
// But, we're only called on selectors passed above, so just ignore this for now. | ||
throw new Error("Not implemented"); | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
async initialize(context: vscode.ExtensionContext): Promise<void> { | ||
const exe = await getExe(context); | ||
this.start(context, exe); | ||
} | ||
|
||
async start(context: vscode.ExtensionContext, exe: { path: string; version: string; }): Promise<void> { | ||
this.exe = exe; | ||
this.outputChannel.appendLine(`Resolved to ${this.exe.path}`); | ||
|
||
// Get pprofDir | ||
const config = vscode.workspace.getConfiguration("typescript.native-preview"); | ||
const pprofDir = config.get<string>("pprofDir"); | ||
const pprofArgs = pprofDir ? ["--pprofDir", pprofDir] : []; | ||
|
||
const serverOptions: ServerOptions = { | ||
run: { | ||
command: this.exe.path, | ||
args: ["--lsp", ...pprofArgs], | ||
transport: TransportKind.stdio, | ||
}, | ||
debug: { | ||
command: this.exe.path, | ||
args: ["--lsp", ...pprofArgs], | ||
transport: TransportKind.stdio, | ||
}, | ||
}; | ||
|
||
this.client = new LanguageClient( | ||
"typescript.native-preview", | ||
"typescript.native-preview-lsp", | ||
serverOptions, | ||
this.clientOptions, | ||
); | ||
|
||
this.outputChannel.appendLine(`Starting language server...`); | ||
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); | ||
}), | ||
); | ||
} | ||
|
||
getCurrentExe(): { path: string; version: string; } | undefined { | ||
return this.exe; | ||
} | ||
|
||
onStarted(callback: () => void): vscode.Disposable { | ||
if (this.exe) { | ||
callback(); | ||
return new vscode.Disposable(() => {}); | ||
} | ||
|
||
this.onStartedCallbacks.add(callback); | ||
return new vscode.Disposable(() => { | ||
this.onStartedCallbacks.delete(callback); | ||
}); | ||
} | ||
|
||
async restart(context: vscode.ExtensionContext): Promise<void> { | ||
if (!this.client) { | ||
return Promise.reject(new Error("Language client is not initialized")); | ||
} | ||
const exe = await getExe(context); | ||
if (exe.path !== this.exe?.path) { | ||
this.outputChannel.appendLine(`Executable path changed from ${this.exe?.path} to ${exe.path}`); | ||
this.outputChannel.appendLine(`Restarting language server with new executable...`); | ||
return this.start(context, exe); | ||
} | ||
|
||
this.outputChannel.appendLine(`Restarting language server...`); | ||
return this.client.restart(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import * as vscode from "vscode"; | ||
import { Client } from "./client"; | ||
|
||
export function registerCommands(context: vscode.ExtensionContext, client: Client, outputChannel: vscode.OutputChannel, traceOutputChannel: vscode.OutputChannel): 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); | ||
})); | ||
|
||
context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.disable", () => { | ||
// Fire and forget, because this will restart the extension host and cause an error if we await | ||
updateUseTsgoSetting(false); | ||
})); | ||
|
||
context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.restart", () => { | ||
return client.restart(context); | ||
})); | ||
|
||
context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.output.focus", () => { | ||
outputChannel.show(); | ||
})); | ||
|
||
context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.lsp-trace.focus", () => { | ||
traceOutputChannel.show(); | ||
})); | ||
|
||
context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.selectVersion", async () => { | ||
})); | ||
|
||
context.subscriptions.push(vscode.commands.registerCommand("typescript.native-preview.showMenu", showCommands)); | ||
} | ||
|
||
/** | ||
* Updates the TypeScript Native Preview setting and reloads extension host. | ||
*/ | ||
async function updateUseTsgoSetting(enable: boolean): Promise<void> { | ||
const tsConfig = vscode.workspace.getConfiguration("typescript"); | ||
let target: vscode.ConfigurationTarget | undefined; | ||
const useTsgo = tsConfig.inspect("experimental.useTsgo"); | ||
if (useTsgo) { | ||
target = useTsgo.workspaceFolderValue !== undefined ? vscode.ConfigurationTarget.WorkspaceFolder : | ||
useTsgo.workspaceValue !== undefined ? vscode.ConfigurationTarget.Workspace : | ||
useTsgo.globalValue !== undefined ? vscode.ConfigurationTarget.Global : undefined; | ||
} | ||
// Update the setting and restart the extension host (needed to change the state of the built-in TS extension) | ||
await tsConfig.update("experimental.useTsgo", enable, target); | ||
await vscode.commands.executeCommand("workbench.action.restartExtensionHost"); | ||
} | ||
|
||
/** | ||
* Shows the quick pick menu for TypeScript Native Preview commands | ||
*/ | ||
async function showCommands(): Promise<void> { | ||
const commands: readonly { label: string; description: string; command: string; }[] = [ | ||
{ | ||
label: "$(refresh) Restart Server", | ||
description: "Restart the TypeScript Native Preview language server", | ||
command: "typescript.native-preview.restart", | ||
}, | ||
{ | ||
label: "$(output) Show TS Server Log", | ||
description: "Show the TypeScript Native Preview server log", | ||
command: "typescript.native-preview.output.focus", | ||
}, | ||
{ | ||
label: "$(debug-console) Show LSP Messages", | ||
description: "Show the LSP communication trace", | ||
command: "typescript.native-preview.lsp-trace.focus", | ||
}, | ||
{ | ||
label: "$(stop-circle) Disable TypeScript Native Preview", | ||
description: "Switch back to the built-in TypeScript extension", | ||
command: "typescript.native-preview.disable", | ||
}, | ||
]; | ||
|
||
const selected = await vscode.window.showQuickPick(commands, { | ||
placeHolder: "TypeScript Native Preview Commands", | ||
}); | ||
|
||
if (selected) { | ||
await vscode.commands.executeCommand(selected.command); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this going to be the final setting name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's hardcoded in https://github.com/microsoft/vscode/blob/35d9d31a8c96ba3e545a1db67a91dc9876551cc9/extensions/typescript-language-features/src/extension.ts#L37 so we can't really change it immediately
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjbvz can we at least change how this looks on the UI so
Tsgo
is not awkwardly Pascal-cased?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mentioned here that extensions may not be able to change it: microsoft/vscode#73374
@rzhao271 Can let the TS team know if there's a way around the auto casing in the settings UI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the Tsgo setting in the package.json file.
There's no workaround yet. What is the expected display name, "Use TS Go"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth noting users don’t need to see this setting if they use this
