Add "Sort Imports" & "Remove Unused Imports" commands to VS Code extension#3305
Add "Sort Imports" & "Remove Unused Imports" commands to VS Code extension#3305
Conversation
…s to VS Code extension Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/045863e2-6044-4847-8156-7e044e313d98 Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
|
|
||
| this.disposables.push(vscode.commands.registerCommand("typescript.native-preview.organizeImports", async () => { | ||
| await vscode.commands.executeCommand("editor.action.organizeImports"); | ||
| })); |
There was a problem hiding this comment.
We don't need this, it's already wired up to the language client.
…uage client Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/413800a1-0e85-4c97-bf25-4df34fdfea1c Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds explicit command palette entries in the VS Code “TypeScript (Native Preview)” extension for actions the LSP server already supports (source.sortImports and source.removeUnusedImports), by delegating to VS Code’s built-in editor.action.sourceAction.
Changes:
- Contribute two new commands (
typescript.native-preview.sortImports,typescript.native-preview.removeUnusedImports) gated ontypescript.native-preview.serverRunning. - Register command handlers that invoke
editor.action.sourceActionwith the correspondingkind(source.sortImports/source.removeUnusedImports).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
_extension/src/session.ts |
Registers two new commands and delegates execution to VS Code source actions for sort/remove-unused-imports. |
_extension/package.json |
Declares the two new commands with enablement tied to the native preview server running. |
| "command": "typescript.native-preview.sortImports", | ||
| "title": "Sort Imports", | ||
| "enablement": "typescript.native-preview.serverRunning", | ||
| "category": "TypeScript Native Preview" | ||
| }, | ||
| { | ||
| "command": "typescript.native-preview.removeUnusedImports", | ||
| "title": "Remove Unused Imports", | ||
| "enablement": "typescript.native-preview.serverRunning", | ||
| "category": "TypeScript Native Preview" | ||
| } |
There was a problem hiding this comment.
@copilot give it a try. Also format when you're done.
There was a problem hiding this comment.
Updated in 4c4a395 to register the same command IDs as the main extension: typescript.sortImports, javascript.sortImports, typescript.removeUnusedImports, and javascript.removeUnusedImports. Also matched apply: 'first' to be consistent with the main extension's behavior, and ran formatting.
There was a problem hiding this comment.
Just tested it. If you do that while useTsgo is off, you weirdly get
Activating extension 'TypeScriptTeam.native-preview' failed: command 'typescript.sortImports' already exists.
There was a problem hiding this comment.
I think the main extension should just be updated.
There was a problem hiding this comment.
Removed the command declarations from package.json in 67ea746. The commands are now only registered at runtime in session.ts, so there's no conflict with the main extension's declarations when useTsgo is off.
There was a problem hiding this comment.
If you disable this extension, the built-in extension will have issues:
rejected promise not handled within 1 second: Error: command 'typescript.sortImports' already exists
Seems like the command is not properly being unregistered.
There was a problem hiding this comment.
Fixed in 87a11ca. The issue was that Session.dispose() was awaiting two setContext calls before disposing the command registrations. Those awaits yield control to the event loop, giving VS Code a chance to activate the built-in extension (which tries to register the same commands). Reordered to dispose registrations first — the d.dispose() calls in .map() run synchronously before any await yields.
…palette entries Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/b3fccc6c-5163-4d72-8e28-b67bfc857ff2 Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
|
|
||
| for (const command of ["typescript.sortImports", "javascript.sortImports"]) { | ||
| this.disposables.push(vscode.commands.registerCommand(command, async () => { | ||
| await vscode.commands.executeCommand("editor.action.sourceAction", { |
There was a problem hiding this comment.
I don't think you need to await, you can just make this non-async and return or fire-and-forget).
There was a problem hiding this comment.
Fixed in 67ea746 — handlers now just return the executeCommand call (non-async, fire-and-forget).
…sync Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/7e5f78a1-e55d-424f-b346-df40585a513e Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
…nt loop Agent-Logs-Url: https://github.com/microsoft/typescript-go/sessions/5fea471c-8900-4781-a94f-2c1368620df9 Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
|
Azure Pipelines: 1 pipeline(s) were filtered out due to trigger conditions. |
| // Dispose registrations first so that commands (e.g. typescript.sortImports) | ||
| // are synchronously unregistered before yielding to the event loop. This | ||
| // avoids "command already exists" errors when the built-in TS extension | ||
| // activates after this extension is disabled. | ||
| await Promise.all(this.disposables.map(d => d.dispose())); |
There was a problem hiding this comment.
I don't really understand how moving this upward achieves this goal.

The LSP server already supports
source.sortImportsandsource.removeUnusedImportscode action kinds, but the extension never registered corresponding command handlers._extension/src/session.ts: Register runtime command handlers for the main TypeScript extension's command IDs (typescript.sortImports,javascript.sortImports,typescript.removeUnusedImports,javascript.removeUnusedImports) that delegate to VS Code's built-ineditor.action.sourceAction_extension/src/session.ts: ReorderSession.dispose()to unregister commands before yielding to the event loop, preventing "command already exists" race conditions when the built-in TypeScript extension reactivatesThe commands are registered only at runtime (not declared in
package.json) to avoid "command already exists" conflicts whenuseTsgois off and the main TypeScript extension is also loaded. By reusing the main extension's command IDs, the native preview extension seamlessly takes over those commands when tsgo is active. Disposal is ordered so that command registrations are synchronously removed before anyawaityields control, ensuring the built-in extension can cleanly re-register them when the native preview extension is disabled. The existing "Organize Imports" command is already wired up through the language client and does not need a separate entry.