Skip to content
This repository has been archived by the owner on Nov 5, 2021. It is now read-only.

Add a rename provider #39

Merged
merged 1 commit into from Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/languageFeatures.ts
Expand Up @@ -631,3 +631,48 @@ export class FormatOnTypeAdapter extends FormatHelper implements monaco.language
});
}
}

// --- rename ----

export class RenameAdapter extends Adapter implements monaco.languages.RenameProvider {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another optional method resolveRenameLocation in the interface which I didn't implement. What is the purpose of this method and do we need that?


async provideRenameEdits(model: monaco.editor.ITextModel, position: Position, newName: string, token: CancellationToken): Promise<monaco.languages.WorkspaceEdit & monaco.languages.Rejection> {
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)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot use monaco.Uri.file here; it leads to the error "bad edit - model not found".

};
fileNameToResourceTextEditMap[renameLocation.fileName] = resourceTextEdit;
edits.push(resourceTextEdit);
}

fileNameToResourceTextEditMap[renameLocation.fileName].edits.push({
range: this._textSpanToRange(resource, renameLocation.textSpan),
text: newName
});
}

return { edits };
}
}
1 change: 1 addition & 0 deletions src/tsMode.ts
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions src/tsWorker.ts
Expand Up @@ -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<readonly ts.RenameLocation[]> {
return Promise.resolve(this._languageService.findRenameLocations(fileName, positon, findInStrings, findInComments, providePrefixAndSuffixTextForRename));
}

getRenameInfo(fileName: string, positon: number, options: ts.RenameInfoOptions): Promise<ts.RenameInfo> {
return Promise.resolve(this._languageService.getRenameInfo(fileName, positon, options));
}

getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
return Promise.resolve(this._languageService.getEmitOutput(fileName));
}
Expand Down