Skip to content

Commit 4577982

Browse files
author
sutong.527608
committed
Use standard LSP code actions instead of custom commands
Replace custom workspace/executeCommand with standard textDocument/codeAction. This follows the LSP spec and works with VS Code's built-in Organize Imports. Changes: - Remove custom command implementation from extension - Remove executeCommand handler from LSP server - Add textDocument/codeAction handler with source.organizeImports kind - Declare CodeActionProvider in server capabilities - No client-side changes needed - uses VS Code built-in command
1 parent 137ea43 commit 4577982

File tree

4 files changed

+48
-110
lines changed

4 files changed

+48
-110
lines changed

_extension/package.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,6 @@
8585
"title": "Show LSP Trace",
8686
"enablement": "typescript.native-preview.serverRunning",
8787
"category": "TypeScript Native Preview"
88-
},
89-
{
90-
"command": "typescript.native-preview.sortImports",
91-
"title": "Sort Imports",
92-
"enablement": "typescript.native-preview.serverRunning && editorLangId =~ /^(javascript|typescript|javascriptreact|typescriptreact)$/",
93-
"category": "TypeScript Native Preview"
9488
}
9589
]
9690
},

_extension/src/client.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,4 @@ export class Client {
158158
this.client.restart();
159159
return new vscode.Disposable(() => {});
160160
}
161-
162-
async executeCommand(command: string, ...args: any[]): Promise<any> {
163-
if (!this.client) {
164-
throw new Error("Language client is not initialized");
165-
}
166-
return this.client.sendRequest("workspace/executeCommand", {
167-
command,
168-
arguments: args,
169-
});
170-
}
171161
}

_extension/src/commands.ts

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ export function registerLanguageCommands(context: vscode.ExtensionContext, clien
3333

3434
disposables.push(vscode.commands.registerCommand("typescript.native-preview.showMenu", showCommands));
3535

36-
disposables.push(vscode.commands.registerCommand("typescript.native-preview.sortImports", async () => {
37-
return sortImports(client);
38-
}));
39-
4036
return disposables;
4137
}
4238

@@ -57,42 +53,11 @@ async function updateUseTsgoSetting(enable: boolean): Promise<void> {
5753
await vscode.commands.executeCommand("workbench.action.restartExtensionHost");
5854
}
5955

60-
async function sortImports(client: Client): Promise<void> {
61-
const editor = vscode.window.activeTextEditor;
62-
if (!editor) {
63-
vscode.window.showErrorMessage("No active editor");
64-
return;
65-
}
66-
67-
const document = editor.document;
68-
const languageId = document.languageId;
69-
70-
// Check if the file is TypeScript or JavaScript
71-
if (!["typescript", "javascript", "typescriptreact", "javascriptreact"].includes(languageId)) {
72-
vscode.window.showErrorMessage("Sort Imports is only available for TypeScript and JavaScript files");
73-
return;
74-
}
75-
76-
try {
77-
// Execute the sort imports command on the server via LSP
78-
await client.executeCommand(
79-
"typescript-go.organizeImports",
80-
document.uri.toString(),
81-
);
82-
vscode.window.showInformationMessage("Imports sorted successfully");
83-
}
84-
catch (error) {
85-
vscode.window.showErrorMessage(`Failed to sort imports: ${error}`);
86-
}
87-
}
88-
56+
/**
57+
* Shows the quick pick menu for TypeScript Native Preview commands
58+
*/
8959
async function showCommands(): Promise<void> {
9060
const commands: readonly { label: string; description: string; command: string; }[] = [
91-
{
92-
label: "$(symbol-namespace) Sort Imports",
93-
description: "Sort imports in the current file",
94-
command: "typescript.native-preview.sortImports",
95-
},
9661
{
9762
label: "$(refresh) Restart Server",
9863
description: "Restart the TypeScript Native Preview language server",

internal/lsp/server.go

Lines changed: 45 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ var handlers = sync.OnceValue(func() handlerMap {
463463
registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentDocumentHighlightInfo, (*Server).handleDocumentHighlight)
464464
registerRequestHandler(handlers, lsproto.WorkspaceSymbolInfo, (*Server).handleWorkspaceSymbol)
465465
registerRequestHandler(handlers, lsproto.CompletionItemResolveInfo, (*Server).handleCompletionItemResolve)
466-
registerRequestHandler(handlers, lsproto.WorkspaceExecuteCommandInfo, (*Server).handleExecuteCommand)
466+
registerLanguageServiceDocumentRequestHandler(handlers, lsproto.TextDocumentCodeActionInfo, (*Server).handleCodeAction)
467467

468468
return handlers
469469
})
@@ -641,9 +641,11 @@ func (s *Server) handleInitialize(ctx context.Context, params *lsproto.Initializ
641641
DocumentHighlightProvider: &lsproto.BooleanOrDocumentHighlightOptions{
642642
Boolean: ptrTo(true),
643643
},
644-
ExecuteCommandProvider: &lsproto.ExecuteCommandOptions{
645-
Commands: []string{
646-
"typescript-go.organizeImports",
644+
CodeActionProvider: &lsproto.BooleanOrCodeActionOptions{
645+
CodeActionOptions: &lsproto.CodeActionOptions{
646+
CodeActionKinds: &[]lsproto.CodeActionKind{
647+
lsproto.CodeActionKindSourceOrganizeImports,
648+
},
647649
},
648650
},
649651
},
@@ -850,64 +852,51 @@ func (s *Server) handleDocumentHighlight(ctx context.Context, ls *ls.LanguageSer
850852
return ls.ProvideDocumentHighlights(ctx, params.TextDocument.Uri, params.Position)
851853
}
852854

853-
func (s *Server) handleExecuteCommand(ctx context.Context, params *lsproto.ExecuteCommandParams, _ *lsproto.RequestMessage) (lsproto.ExecuteCommandResponse, error) {
854-
switch params.Command {
855-
case "typescript-go.organizeImports":
856-
return s.handleOrganizeImportsCommand(ctx, params)
857-
default:
858-
return lsproto.LSPAnyOrNull{}, fmt.Errorf("unknown command: %s", params.Command)
859-
}
860-
}
861-
862-
func (s *Server) handleOrganizeImportsCommand(ctx context.Context, params *lsproto.ExecuteCommandParams) (lsproto.ExecuteCommandResponse, error) {
863-
if params.Arguments == nil || len(*params.Arguments) == 0 {
864-
return lsproto.LSPAnyOrNull{}, errors.New("organizeImports command requires a document URI argument")
865-
}
866-
867-
var documentURI lsproto.DocumentUri
868-
argBytes, err := json.Marshal((*params.Arguments)[0])
869-
if err != nil {
870-
return lsproto.LSPAnyOrNull{}, fmt.Errorf("failed to marshal argument: %w", err)
871-
}
872-
err = json.Unmarshal(argBytes, &documentURI)
873-
if err != nil {
874-
return lsproto.LSPAnyOrNull{}, fmt.Errorf("invalid document URI: %w", err)
875-
}
876-
877-
languageService, err := s.session.GetLanguageService(ctx, documentURI)
878-
if err != nil {
879-
return lsproto.LSPAnyOrNull{}, err
880-
}
881-
882-
edits, err := languageService.OrganizeImports(ctx, documentURI, ls.OrganizeImportsModeAll)
883-
if err != nil {
884-
return lsproto.LSPAnyOrNull{}, err
885-
}
886-
887-
if len(edits) == 0 {
888-
return lsproto.LSPAnyOrNull{}, nil
855+
func (s *Server) handleCodeAction(ctx context.Context, languageService *ls.LanguageService, params *lsproto.CodeActionParams) (lsproto.CodeActionResponse, error) {
856+
// Check if the client is requesting source.organizeImports
857+
requestedOrganizeImports := false
858+
if params.Context != nil && params.Context.Only != nil {
859+
for _, kind := range *params.Context.Only {
860+
if kind == lsproto.CodeActionKindSourceOrganizeImports || kind == lsproto.CodeActionKindSource {
861+
requestedOrganizeImports = true
862+
break
863+
}
864+
}
865+
} else {
866+
// If no specific kinds are requested, include organize imports
867+
requestedOrganizeImports = true
889868
}
890869

891-
editPtrs := make([]*lsproto.TextEdit, len(edits))
892-
for i := range edits {
893-
editPtrs[i] = &edits[i]
894-
}
870+
var actions []lsproto.CommandOrCodeAction
871+
if requestedOrganizeImports {
872+
edits, err := languageService.OrganizeImports(ctx, params.TextDocument.Uri, ls.OrganizeImportsModeAll)
873+
if err != nil {
874+
return lsproto.CommandOrCodeActionArrayOrNull{}, err
875+
}
895876

896-
workspaceEdit := &lsproto.WorkspaceEdit{
897-
Changes: &map[lsproto.DocumentUri][]*lsproto.TextEdit{
898-
documentURI: editPtrs,
899-
},
900-
}
877+
if len(edits) > 0 {
878+
editPtrs := make([]*lsproto.TextEdit, len(edits))
879+
for i := range edits {
880+
editPtrs[i] = &edits[i]
881+
}
901882

902-
_, err = s.sendRequest(ctx, lsproto.MethodWorkspaceApplyEdit, &lsproto.ApplyWorkspaceEditParams{
903-
Label: ptrTo("Organize Imports"),
904-
Edit: workspaceEdit,
905-
})
906-
if err != nil {
907-
return lsproto.LSPAnyOrNull{}, fmt.Errorf("failed to apply workspace edit: %w", err)
883+
kind := lsproto.CodeActionKindSourceOrganizeImports
884+
action := lsproto.CommandOrCodeAction{
885+
CodeAction: &lsproto.CodeAction{
886+
Title: "Organize Imports",
887+
Kind: &kind,
888+
Edit: &lsproto.WorkspaceEdit{
889+
Changes: &map[lsproto.DocumentUri][]*lsproto.TextEdit{
890+
params.TextDocument.Uri: editPtrs,
891+
},
892+
},
893+
},
894+
}
895+
actions = append(actions, action)
896+
}
908897
}
909898

910-
return lsproto.LSPAnyOrNull{}, nil
899+
return lsproto.CommandOrCodeActionArrayOrNull{CommandOrCodeActionArray: &actions}, nil
911900
}
912901

913902
func (s *Server) Log(msg ...any) {

0 commit comments

Comments
 (0)