From ceff666ed17e285a4058cddb60391d63bd6a2e7f Mon Sep 17 00:00:00 2001 From: Sebastian Pahnke Date: Wed, 14 Aug 2019 11:44:48 +0200 Subject: [PATCH] Add a rename provider --- src/languageFeatures.ts | 45 +++++++++++++++++++++++++++++++++++++++++ src/tsMode.ts | 1 + src/tsWorker.ts | 8 ++++++++ 3 files changed, 54 insertions(+) diff --git a/src/languageFeatures.ts b/src/languageFeatures.ts index fe344ce..474a859 100644 --- a/src/languageFeatures.ts +++ b/src/languageFeatures.ts @@ -631,3 +631,48 @@ export class FormatOnTypeAdapter extends FormatHelper implements monaco.language }); } } + +// --- rename ---- + +export class RenameAdapter extends Adapter implements monaco.languages.RenameProvider { + + async provideRenameEdits(model: monaco.editor.ITextModel, position: Position, newName: string, token: CancellationToken): Promise { + const resource = model.uri; + const fileName = resource.toString(); + const offset = this._positionToOffset(resource, position); + const worker = await this._worker(resource); + + const renameInfo = await worker.getRenameInfo(fileName, offset, { allowRenameOfImportPath: false }); + if (renameInfo.canRename === false) { // use explicit comparison so that the discriminated union gets resolved properly + return { + edits: [], + rejectReason: renameInfo.localizedErrorMessage + }; + } + if (renameInfo.fileToRename !== undefined) { + throw new Error("Renaming files is not supported."); + } + + const renameLocations = await worker.findRenameLocations(fileName, offset, /*strings*/ false, /*comments*/ false, /*prefixAndSuffix*/ false); + const fileNameToResourceTextEditMap: { [fileName: string]: monaco.languages.ResourceTextEdit } = {}; + + const edits: monaco.languages.ResourceTextEdit[] = []; + for (const renameLocation of renameLocations) { + if (!(renameLocation.fileName in fileNameToResourceTextEditMap)) { + const resourceTextEdit = { + edits: [], + resource: monaco.Uri.parse(renameLocation.fileName) + }; + fileNameToResourceTextEditMap[renameLocation.fileName] = resourceTextEdit; + edits.push(resourceTextEdit); + } + + fileNameToResourceTextEditMap[renameLocation.fileName].edits.push({ + range: this._textSpanToRange(resource, renameLocation.textSpan), + text: newName + }); + } + + return { edits }; + } +} \ No newline at end of file diff --git a/src/tsMode.ts b/src/tsMode.ts index ce9caec..4647b3d 100644 --- a/src/tsMode.ts +++ b/src/tsMode.ts @@ -64,6 +64,7 @@ function setupMode(defaults: LanguageServiceDefaultsImpl, modeId: string): (firs monaco.languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker)); monaco.languages.registerDocumentRangeFormattingEditProvider(modeId, new languageFeatures.FormatAdapter(worker)); monaco.languages.registerOnTypeFormattingEditProvider(modeId, new languageFeatures.FormatOnTypeAdapter(worker)); + monaco.languages.registerRenameProvider(modeId, new languageFeatures.RenameAdapter(worker)); new languageFeatures.DiagnostcsAdapter(defaults, modeId, worker); return worker; diff --git a/src/tsWorker.ts b/src/tsWorker.ts index fd2b280..654fdb3 100644 --- a/src/tsWorker.ts +++ b/src/tsWorker.ts @@ -196,6 +196,14 @@ export class TypeScriptWorker implements ts.LanguageServiceHost { return Promise.resolve(this._languageService.getFormattingEditsAfterKeystroke(fileName, postion, ch, options)); } + findRenameLocations(fileName: string, positon: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename: boolean): Promise { + return Promise.resolve(this._languageService.findRenameLocations(fileName, positon, findInStrings, findInComments, providePrefixAndSuffixTextForRename)); + } + + getRenameInfo(fileName: string, positon: number, options: ts.RenameInfoOptions): Promise { + return Promise.resolve(this._languageService.getRenameInfo(fileName, positon, options)); + } + getEmitOutput(fileName: string): Promise { return Promise.resolve(this._languageService.getEmitOutput(fileName)); }