diff --git a/server/src/server.ts b/server/src/server.ts index db44c7309..c339e1d86 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -19,8 +19,8 @@ import * as chokidar from "chokidar"; import { assert } from "console"; import { fileURLToPath } from "url"; import { ChildProcess } from "child_process"; -import { Location } from "vscode-languageserver"; -import { SymbolInformation } from "vscode-languageserver"; +import { WorkspaceEdit } from "vscode-languageserver"; +import { TextEdit } from "vscode-languageserver-types"; // https://microsoft.github.io/language-server-protocol/specification#initialize // According to the spec, there could be requests before the 'initialize' request. Link in comment tells how to handle them. @@ -307,6 +307,7 @@ function onMessage(msg: m.Message) { hoverProvider: true, definitionProvider: true, referencesProvider: true, + renameProvider: true, documentSymbolProvider: false, completionProvider: { triggerCharacters: [".", ">", "@", "~"] }, }, @@ -386,19 +387,40 @@ function onMessage(msg: m.Message) { // error: code and message set in case an exception happens during the definition request. }; send(definitionResponse); + } else if (msg.method === p.RenameRequest.method) { + // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename + let params = msg.params as p.RenameParams; + let filePath = fileURLToPath(params.textDocument.uri); + let locations: p.Location[] | null = utils.getReferencesForPosition(filePath, params.position); + let result: WorkspaceEdit | null; + if (locations === null) { + result = null; + } else { + let changes: { [uri: string]: TextEdit[] } = {}; + locations.forEach(({ uri, range }) => { + let textEdit: TextEdit = {range, newText: params.newName}; + if (uri in changes) { + changes[uri].push(textEdit); + } else { + changes[uri] = [textEdit] + } + }); + + result = {changes}; + } + + let renameResponse: m.ResponseMessage = { + jsonrpc: c.jsonrpcVersion, + id: msg.id, + result, + }; + + send(renameResponse); } else if (msg.method === p.ReferencesRequest.method) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references let params = msg.params as p.ReferenceParams; let filePath = fileURLToPath(params.textDocument.uri); - let result: typeof p.ReferencesRequest.type = utils.runAnalysisAfterSanityCheck( - filePath, - [ - "references", - filePath, - params.position.line, - params.position.character, - ] - ); + let result: typeof p.ReferencesRequest.type = utils.getReferencesForPosition(filePath, params.position); let definitionResponse: m.ResponseMessage = { jsonrpc: c.jsonrpcVersion, id: msg.id, diff --git a/server/src/utils.ts b/server/src/utils.ts index c657b1cb4..f1b59f353 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -144,6 +144,9 @@ export let runAnalysisAfterSanityCheck = ( return JSON.parse(stdout.toString()); }; +export let getReferencesForPosition = (filePath: p.DocumentUri, position: p.Position) => + runAnalysisAfterSanityCheck(filePath, ['references', filePath, position.line, position.character]); + export let replaceFileExtension = (filePath: string, ext: string): string => { let name = path.basename(filePath, path.extname(filePath)); return path.format({ dir: path.dirname(filePath), name, ext })