diff --git a/CHANGELOG.md b/CHANGELOG.md index e49e0b14e..7ecb4dc38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ #### :nail_care: Polish - Enhance variant constructor payload completion. https://github.com/rescript-lang/rescript-vscode/pull/946 +- Clean occasional dots from "insert missing fields" code action. https://github.com/rescript-lang/rescript-vscode/pull/948 +- Pick up code actions in incremental compilation. https://github.com/rescript-lang/rescript-vscode/pull/948 ## 1.48.0 diff --git a/server/src/codeActions.ts b/server/src/codeActions.ts index 045f06276..7d1c10100 100644 --- a/server/src/codeActions.ts +++ b/server/src/codeActions.ts @@ -5,8 +5,10 @@ import * as p from "vscode-languageserver-protocol"; import * as utils from "./utils"; import { fileURLToPath } from "url"; +export type fileCodeActions = { range: p.Range; codeAction: p.CodeAction }; + export type filesCodeActions = { - [key: string]: { range: p.Range; codeAction: p.CodeAction }[]; + [key: string]: fileCodeActions[]; }; interface findCodeActionsConfig { @@ -454,7 +456,12 @@ let addUndefinedRecordFieldsV11: codeActionExtractor = ({ range, }) => { if (line.startsWith("Some required record fields are missing:")) { - let recordFieldNames = line + let theLine = line; + if (theLine.endsWith(".")) { + theLine = theLine.slice(0, theLine.length - 2); + } + + let recordFieldNames = theLine .trim() .split("Some required record fields are missing: ")[1] ?.split(" "); @@ -465,6 +472,7 @@ let addUndefinedRecordFieldsV11: codeActionExtractor = ({ array.slice(index + 1).forEach((line) => { if (stop) return; + // Remove trailing dot, split the rest of the field names recordFieldNames.push(...line.trim().split(".")[0].split(" ")); if (line.includes(".")) { diff --git a/server/src/incrementalCompilation.ts b/server/src/incrementalCompilation.ts index 260f99344..3e2b57a97 100644 --- a/server/src/incrementalCompilation.ts +++ b/server/src/incrementalCompilation.ts @@ -9,6 +9,7 @@ import * as cp from "node:child_process"; import config, { send } from "./config"; import * as c from "./constants"; import * as chokidar from "chokidar"; +import { fileCodeActions } from "./codeActions"; function debug() { return ( @@ -65,6 +66,8 @@ type IncrementallyCompiledFileInfo = { /** The ReScript version. */ rescriptVersion: string; }; + /** Any code actions for this incremental file. */ + codeActions: Array; }; const incrementallyCompiledFileInfo: Map< @@ -368,6 +371,7 @@ function triggerIncrementalCompilationOfFile( buildNinja: null, compilation: null, killCompilationListeners: [], + codeActions: [], }; incrementalFileCacheEntry.project.callArgs = figureOutBscArgs( @@ -526,7 +530,30 @@ async function compileContents( } // Reset compilation status as this compilation finished entry.compilation = null; - const { result } = utils.parseCompilerLogOutput(`${stderr}\n#Done()`); + const { result, codeActions } = utils.parseCompilerLogOutput( + `${stderr}\n#Done()` + ); + + const actions = Object.values(codeActions)[0] ?? []; + + // Code actions will point to the locally saved incremental file, so we must remap + // them so the editor understand it's supposed to apply them to the unsaved doc, + // not the saved "dummy" incremental file. + actions.forEach((ca) => { + if ( + ca.codeAction.edit != null && + ca.codeAction.edit.changes != null + ) { + const change = Object.values(ca.codeAction.edit.changes)[0]; + + ca.codeAction.edit.changes = { + [pathToFileURL(entry.file.sourceFilePath).toString()]: change, + }; + } + }); + + entry.codeActions = actions; + const res = (Object.values(result)[0] ?? []) .map((d) => ({ ...d, @@ -628,3 +655,14 @@ export function handleClosedFile(filePath: string) { originalTypeFileToFilePath.delete(entry.file.originalTypeFileLocation); incrementalFilesWatcher.unwatch([entry.file.originalTypeFileLocation]); } + +export function getCodeActionsFromIncrementalCompilation( + filePath: string +): Array | null { + const entry = incrementallyCompiledFileInfo.get(filePath); + if (entry != null) { + return entry.codeActions; + } + + return null; +} diff --git a/server/src/server.ts b/server/src/server.ts index a1864209a..08ebd1714 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -668,9 +668,13 @@ function codeAction(msg: p.RequestMessage): p.ResponseMessage { let extension = path.extname(params.textDocument.uri); let tmpname = utils.createFileInTempDir(extension); - // Check local code actions coming from the diagnostics. + // Check local code actions coming from the diagnostics, or from incremental compilation. let localResults: v.CodeAction[] = []; - codeActionsFromDiagnostics[params.textDocument.uri]?.forEach( + const fromDiagnostics = + codeActionsFromDiagnostics[params.textDocument.uri] ?? []; + const fromIncrementalCompilation = + ic.getCodeActionsFromIncrementalCompilation(filePath) ?? []; + [...fromDiagnostics, ...fromIncrementalCompilation].forEach( ({ range, codeAction }) => { if (utils.rangeContainsRange(range, params.range)) { localResults.push(codeAction);