Skip to content

Commit f255e3e

Browse files
authored
Merge pull request #110573 from microsoft/joh/tsQuickRename
Implement on-type-rename for TypeScript
2 parents 8b192ae + 793b679 commit f255e3e

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { Kind } from '../protocol.const';
8+
import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService';
9+
import { conditionalRegistration, requireSomeCapability } from '../utils/dependentRegistration';
10+
import { DocumentSelector } from '../utils/documentSelector';
11+
import * as typeConverters from '../utils/typeConverters';
12+
13+
14+
class TypeScriptOnTypeRenameProvider implements vscode.OnTypeRenameRangeProvider {
15+
16+
private static enabledKinds = new Set<string>([
17+
Kind.let, Kind.const, Kind.localVariable, Kind.parameter, Kind.typeParameter
18+
]);
19+
20+
public constructor(
21+
private readonly client: ITypeScriptServiceClient
22+
) { }
23+
24+
public async provideOnTypeRenameRanges(
25+
document: vscode.TextDocument,
26+
position: vscode.Position,
27+
token: vscode.CancellationToken
28+
): Promise<vscode.OnTypeRenameRanges | undefined> {
29+
const file = this.client.toOpenedFilePath(document);
30+
if (!file) {
31+
return undefined;
32+
}
33+
const args = typeConverters.Position.toFileLocationRequestArgs(file, position);
34+
//
35+
36+
const quickInfoResponse = await this.client.interruptGetErr(() => this.client.execute('quickinfo', args, token));
37+
if (quickInfoResponse.type !== 'response' || !quickInfoResponse.body) {
38+
return undefined;
39+
}
40+
41+
if (!TypeScriptOnTypeRenameProvider.enabledKinds.has(quickInfoResponse.body.kind)) {
42+
return undefined;
43+
}
44+
45+
const renameResponse = await this.client.execute('rename', args, token);
46+
if (!renameResponse || renameResponse.type !== 'response' || !renameResponse.body) {
47+
return undefined;
48+
}
49+
50+
if (renameResponse.body.locs.length !== 1 || renameResponse.body.locs[0].file !== file) {
51+
return undefined; // not a local?
52+
}
53+
54+
const ranges = renameResponse.body.locs[0].locs.map(typeConverters.Range.fromTextSpan);
55+
if (ranges.length <= 1) {
56+
return undefined; // not enough usages
57+
}
58+
return new vscode.OnTypeRenameRanges(ranges);
59+
}
60+
61+
}
62+
63+
export function register(
64+
selector: DocumentSelector,
65+
client: ITypeScriptServiceClient
66+
): vscode.Disposable {
67+
return conditionalRegistration([
68+
requireSomeCapability(client, ClientCapability.EnhancedSyntax, ClientCapability.Semantic),
69+
], () => {
70+
return vscode.languages.registerOnTypeRenameRangeProvider(selector.syntax,
71+
new TypeScriptOnTypeRenameProvider(client));
72+
});
73+
}

extensions/typescript-language-features/src/languageProvider.ts

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export default class LanguageProvider extends Disposable {
7676
import('./languageFeatures/references').then(provider => this._register(provider.register(selector, this.client))),
7777
import('./languageFeatures/codeLens/referencesCodeLens').then(provider => this._register(provider.register(selector, this.description.id, this.client, cachedResponse))),
7878
import('./languageFeatures/rename').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager))),
79+
import('./languageFeatures/renameOnType').then(provider => this._register(provider.register(selector, this.client))),
7980
import('./languageFeatures/smartSelect').then(provider => this._register(provider.register(selector, this.client))),
8081
import('./languageFeatures/signatureHelp').then(provider => this._register(provider.register(selector, this.client))),
8182
import('./languageFeatures/tagClosing').then(provider => this._register(provider.register(selector, this.description.id, this.client))),

0 commit comments

Comments
 (0)