1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import type * as Proto from '../../protocol';
import * as PConst from '../../protocol.const';
import { CachedResponse } from '../../tsServer/cachedResponse';
import { ExecutionTarget } from '../../tsServer/server';
import { ClientCapability, ITypeScriptServiceClient } from '../../typescriptService';
import { conditionalRegistration, requireGlobalConfiguration, requireSomeCapability } from '../../utils/dependentRegistration';
import { DocumentSelector } from '../../utils/documentSelector';
import { LanguageDescription } from '../../utils/languageDescription';
import * as typeConverters from '../../utils/typeConverters';
import { ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider';
const localize = nls.loadMessageBundle();
export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider {
public constructor(
client: ITypeScriptServiceClient,
protected _cachedResponse: CachedResponse<Proto.NavTreeResponse>,
private readonly language: LanguageDescription
) {
super(client, _cachedResponse);
}
public async resolveCodeLens(codeLens: ReferencesCodeLens, token: vscode.CancellationToken): Promise<vscode.CodeLens> {
const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start);
const response = await this.client.execute('references', args, token, {
lowPriority: true,
executionTarget: ExecutionTarget.Semantic,
cancelOnResourceChange: codeLens.document,
});
if (response.type !== 'response' || !response.body) {
codeLens.command = response.type === 'cancelled'
? TypeScriptBaseCodeLensProvider.cancelledCommand
: TypeScriptBaseCodeLensProvider.errorCommand;
return codeLens;
}
const locations = response.body.refs
.filter(reference => !reference.isDefinition)
.map(reference =>
typeConverters.Location.fromTextSpan(this.client.toResource(reference.file), reference));
codeLens.command = {
title: this.getCodeLensLabel(locations),
command: locations.length ? 'editor.action.showReferences' : '',
arguments: [codeLens.document, codeLens.range.start, locations]
};
return codeLens;
}
private getCodeLensLabel(locations: ReadonlyArray<vscode.Location>): string {
return locations.length === 1
? localize('oneReferenceLabel', '1 reference')
: localize('manyReferenceLabel', '{0} references', locations.length);
}
protected extractSymbol(
item: Proto.NavigationTree,
parent: Proto.NavigationTree | undefined
): vscode.Range | undefined {
if (!item.nameSpan) {
return undefined;
}
const itemSpan = typeConverters.Range.fromTextSpan(item.nameSpan);
if (parent && parent.kind === PConst.Kind.enum) {
return itemSpan;
}
switch (item.kind) {
case PConst.Kind.function: {
const showOnAllFunctions = vscode.workspace.getConfiguration(this.language.id).get<boolean>('referencesCodeLens.showOnAllFunctions');
if (showOnAllFunctions) {
return itemSpan;
}
}
// fallthrough
case PConst.Kind.const:
case PConst.Kind.let:
case PConst.Kind.variable:
// Only show references for exported variables
if (/\bexport\b/.test(item.kindModifiers)) {
return itemSpan;
}
break;
case PConst.Kind.class:
if (item.text === '<class>') {
break;
}
return itemSpan;
case PConst.Kind.interface:
case PConst.Kind.type:
case PConst.Kind.enum:
return itemSpan;
case PConst.Kind.method:
case PConst.Kind.memberGetAccessor:
case PConst.Kind.memberSetAccessor:
case PConst.Kind.constructorImplementation:
case PConst.Kind.memberVariable:
// Don't show if child and parent have same start
// For https://github.com/microsoft/vscode/issues/90396
if (parent &&
typeConverters.Position.fromLocation(parent.spans[0].start).isEqual(typeConverters.Position.fromLocation(item.spans[0].start))
) {
return undefined;
}
// Only show if parent is a class type object (not a literal)
switch (parent?.kind) {
case PConst.Kind.class:
case PConst.Kind.interface:
case PConst.Kind.type:
return itemSpan;
}
break;
}
return undefined;
}
}
export function register(
selector: DocumentSelector,
language: LanguageDescription,
client: ITypeScriptServiceClient,
cachedResponse: CachedResponse<Proto.NavTreeResponse>,
) {
return conditionalRegistration([
requireGlobalConfiguration(language.id, 'referencesCodeLens.enabled'),
requireSomeCapability(client, ClientCapability.Semantic),
], () => {
return vscode.languages.registerCodeLensProvider(selector.semantic,
new TypeScriptReferencesCodeLensProvider(client, cachedResponse, language));
});
}
|