From 063273b5d24028f4052e79bd8e5fc7880ba09281 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Thu, 7 May 2026 06:56:54 -0400 Subject: [PATCH 1/2] Try use code fix resolver to improve code fix trigger reliability --- packages/compiler/src/server/constants.ts | 4 -- packages/compiler/src/server/server.ts | 2 +- packages/compiler/src/server/serverlib.ts | 50 ++++++++++------------- packages/compiler/src/server/types.ts | 3 +- 4 files changed, 23 insertions(+), 36 deletions(-) diff --git a/packages/compiler/src/server/constants.ts b/packages/compiler/src/server/constants.ts index 65ffde94c19..24024b7ddfc 100644 --- a/packages/compiler/src/server/constants.ts +++ b/packages/compiler/src/server/constants.ts @@ -8,7 +8,3 @@ export const serverOptions: CompilerOptions = { docs: true, }, }; - -export const Commands = { - APPLY_CODE_FIX: "typespec.applyCodeFix", -}; diff --git a/packages/compiler/src/server/server.ts b/packages/compiler/src/server/server.ts index c07b2de7dce..20aa781198b 100644 --- a/packages/compiler/src/server/server.ts +++ b/packages/compiler/src/server/server.ts @@ -136,7 +136,7 @@ function main() { connection.onHover(profile(s.getHover)); connection.onSignatureHelp(profile(s.getSignatureHelp)); connection.onCodeAction(profile(s.getCodeActions)); - connection.onExecuteCommand(profile(s.executeCommand)); + connection.onCodeActionResolve(profile(s.resolveCodeAction)); connection.languages.semanticTokens.on(profile(s.buildSemanticTokens)); connection.workspace.onDidRenameFiles(profile(s.renameFiles)); diff --git a/packages/compiler/src/server/serverlib.ts b/packages/compiler/src/server/serverlib.ts index 767a9c8cb49..48525a79f4a 100644 --- a/packages/compiler/src/server/serverlib.ts +++ b/packages/compiler/src/server/serverlib.ts @@ -16,7 +16,6 @@ import { DocumentHighlightParams, DocumentSymbol, DocumentSymbolParams, - ExecuteCommandParams, FileChangeType, FoldingRange, FoldingRangeParams, @@ -104,7 +103,6 @@ import { getSemanticTokens } from "./classify.js"; import { ClientConfigProvider } from "./client-config-provider.js"; import { createCompileService } from "./compile-service.js"; import { resolveCompletion } from "./completion.js"; -import { Commands } from "./constants.js"; import { convertDiagnosticToLsp } from "./diagnostics.js"; import { createFileService } from "./file-service.js"; import { createFileSystemCache } from "./file-system-cache.js"; @@ -177,7 +175,7 @@ export function createServer( log, clientConfigsProvider, }); - const currentDiagnosticIndex = new Map(); + let currentDiagnosticIndex = new Map(); let diagnosticIdCounter = 0; let workspaceFolders: ServerWorkspaceFolder[] = []; @@ -214,7 +212,7 @@ export function createServer( getSignatureHelp, getDocumentSymbols, getCodeActions, - executeCommand, + resolveCodeAction, log, reportDiagnostics, @@ -283,9 +281,7 @@ export function createServer( }, codeActionProvider: { codeActionKinds: ["quickfix"], - }, - executeCommandProvider: { - commands: [Commands.APPLY_CODE_FIX], + resolveProvider: true, }, }; @@ -716,7 +712,7 @@ export function createServer( if (!document) return undefined; if (isTspConfigFile(document)) return undefined; - currentDiagnosticIndex.clear(); + const newDiagnosticIndex = new Map(); // Group diagnostics by file. // // Initialize diagnostics for all source files in program to empty array @@ -789,10 +785,14 @@ export function createServer( "Diagnostic reported against a source file that was not added to the program.", ); diagnostics.push(diagnostic); - currentDiagnosticIndex.set(diagnostic.data.id, each); + newDiagnosticIndex.set(diagnostic.data.id, each); } } + // Atomically swap the diagnostic index so that in-flight code action resolves + // referencing old diagnostic IDs can still find their entries until new diagnostics are sent. + currentDiagnosticIndex = newDiagnosticIndex; + for (const [document, diagnostics] of diagnosticMap) { sendDiagnostics(document, diagnostics); } @@ -1303,16 +1303,10 @@ export function createServer( for (const fix of tspDiag.codefixes ?? []) { const codeAction: CodeAction = { - ...CodeAction.create( - fix.label, - { - title: fix.label, - command: Commands.APPLY_CODE_FIX, - arguments: [params.textDocument.uri, vsDiag.data?.id, fix.id], - }, - CodeActionKind.QuickFix, - ), + title: fix.label, + kind: CodeActionKind.QuickFix, diagnostics: [vsDiag], + data: { diagId: vsDiag.data?.id, fixId: fix.id }, }; actions.push(codeAction); } @@ -1321,19 +1315,17 @@ export function createServer( return actions; } - async function executeCommand(params: ExecuteCommandParams) { - if (params.command === Commands.APPLY_CODE_FIX) { - const [, diagId, fixId] = params.arguments ?? []; - if (diagId && fixId) { - const diag = currentDiagnosticIndex.get(diagId); - const codeFix = diag?.codefixes?.find((x) => x.id === fixId); - if (codeFix) { - const edits = await resolveCodeFix(codeFix); - const vsEdits = convertCodeFixEdits(edits); - await host.applyEdit({ documentChanges: vsEdits }); - } + async function resolveCodeAction(codeAction: CodeAction): Promise { + const { diagId, fixId } = codeAction.data ?? {}; + if (diagId !== undefined && fixId) { + const diag = currentDiagnosticIndex.get(diagId); + const codeFix = diag?.codefixes?.find((x) => x.id === fixId); + if (codeFix) { + const edits = await resolveCodeFix(codeFix); + codeAction.edit = { documentChanges: convertCodeFixEdits(edits) }; } } + return codeAction; } function convertCodeFixEdits(edits: CodeFixEdit[]) { diff --git a/packages/compiler/src/server/types.ts b/packages/compiler/src/server/types.ts index cd02a461bb5..89e155cf2f8 100644 --- a/packages/compiler/src/server/types.ts +++ b/packages/compiler/src/server/types.ts @@ -12,7 +12,6 @@ import { DocumentHighlightParams, DocumentSymbol, DocumentSymbolParams, - ExecuteCommandParams, FoldingRange, FoldingRangeParams, Hover, @@ -126,7 +125,7 @@ export interface Server { documentClosed(change: TextDocumentChangeEvent): void; documentOpened(change: TextDocumentChangeEvent): void; getCodeActions(params: CodeActionParams): Promise; - executeCommand(params: ExecuteCommandParams): Promise; + resolveCodeAction(codeAction: CodeAction): Promise; reportDiagnostics({ program, document, optionsFromConfig }: CompileResult): void; log(log: ServerLog): void; From 198f52a8a5cf10db65fbe21f481b8ff08d8f9405 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Thu, 7 May 2026 06:57:55 -0400 Subject: [PATCH 2/2] chg --- .../fix-better-code-fix-trigger-2026-4-7-6-57-21.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .chronus/changes/fix-better-code-fix-trigger-2026-4-7-6-57-21.md diff --git a/.chronus/changes/fix-better-code-fix-trigger-2026-4-7-6-57-21.md b/.chronus/changes/fix-better-code-fix-trigger-2026-4-7-6-57-21.md new file mode 100644 index 00000000000..f9e49b4c811 --- /dev/null +++ b/.chronus/changes/fix-better-code-fix-trigger-2026-4-7-6-57-21.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@typespec/compiler" +--- + +[LSP] Fix code fixes often not running when selected