Skip to content

Commit 6192d75

Browse files
authored
feat: reference/implementation codelens (#2378)
#2130 Porting VSCode's implementation/reference code lens. This is not enabled by default. To enable this, you'll need to enable the typescript.implementationsCodeLens.enabled config or the typescript.referencesCodeLens.enabled config for lang="ts" and javascript.referencesCodeLens.enabled for js components. Note that we reuse config for ts/js files so it'll also enable the feature in ts/js files.
1 parent 88d7832 commit 6192d75

File tree

13 files changed

+767
-24
lines changed

13 files changed

+767
-24
lines changed

packages/language-server/src/ls-config.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ export interface TSUserConfig {
201201
suggest?: TSSuggestConfig;
202202
format?: TsFormatConfig;
203203
inlayHints?: TsInlayHintsConfig;
204+
referencesCodeLens?: TsReferenceCodeLensConfig;
205+
implementationsCodeLens?: TsImplementationCodeLensConfig;
204206
}
205207

206208
/**
@@ -252,6 +254,16 @@ export interface TsInlayHintsConfig {
252254
variableTypes: { enabled: boolean; suppressWhenTypeMatchesName: boolean } | undefined;
253255
}
254256

257+
export interface TsReferenceCodeLensConfig {
258+
showOnAllFunctions?: boolean | undefined;
259+
enabled: boolean;
260+
}
261+
262+
export interface TsImplementationCodeLensConfig {
263+
enabled: boolean;
264+
showOnInterfaceMethods?: boolean | undefined;
265+
}
266+
255267
export type TsUserConfigLang = 'typescript' | 'javascript';
256268

257269
/**
@@ -285,6 +297,11 @@ export class LSConfigManager {
285297
typescript: {},
286298
javascript: {}
287299
};
300+
private rawTsUserConfig: Record<TsUserConfigLang, TSUserConfig> = {
301+
typescript: {},
302+
javascript: {}
303+
};
304+
288305
private resolvedAutoImportExcludeCache = new FileMap<string[]>();
289306
private tsFormatCodeOptions: Record<TsUserConfigLang, ts.FormatCodeSettings> = {
290307
typescript: this.getDefaultFormatCodeOptions(),
@@ -396,6 +413,7 @@ export class LSConfigManager {
396413
(['typescript', 'javascript'] as const).forEach((lang) => {
397414
if (config[lang]) {
398415
this._updateTsUserPreferences(lang, config[lang]);
416+
this.rawTsUserConfig[lang] = config[lang];
399417
}
400418
});
401419
this.notifyListeners();
@@ -498,6 +516,10 @@ export class LSConfigManager {
498516
};
499517
}
500518

519+
getClientTsUserConfig(lang: TsUserConfigLang): TSUserConfig {
520+
return this.rawTsUserConfig[lang];
521+
}
522+
501523
updateCssConfig(config: CssConfig | undefined): void {
502524
this.cssConfig = config;
503525
this.notifyListeners();

packages/language-server/src/plugins/PluginHost.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
CancellationToken,
88
CodeAction,
99
CodeActionContext,
10+
CodeLens,
1011
Color,
1112
ColorInformation,
1213
ColorPresentation,
@@ -417,13 +418,14 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
417418
async findReferences(
418419
textDocument: TextDocumentIdentifier,
419420
position: Position,
420-
context: ReferenceContext
421+
context: ReferenceContext,
422+
cancellationToken?: CancellationToken
421423
): Promise<Location[] | null> {
422424
const document = this.getDocument(textDocument.uri);
423425

424426
return await this.execute<any>(
425427
'findReferences',
426-
[document, position, context],
428+
[document, position, context, cancellationToken],
427429
ExecuteMode.FirstNonNull,
428430
'high'
429431
);
@@ -525,13 +527,14 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
525527

526528
getImplementation(
527529
textDocument: TextDocumentIdentifier,
528-
position: Position
530+
position: Position,
531+
cancellationToken?: CancellationToken
529532
): Promise<Location[] | null> {
530533
const document = this.getDocument(textDocument.uri);
531534

532535
return this.execute<Location[] | null>(
533536
'getImplementation',
534-
[document, position],
537+
[document, position, cancellationToken],
535538
ExecuteMode.FirstNonNull,
536539
'high'
537540
);
@@ -605,6 +608,20 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
605608
);
606609
}
607610

611+
async getCodeLens(textDocument: TextDocumentIdentifier) {
612+
const document = this.getDocument(textDocument.uri);
613+
if (!document) {
614+
throw new Error('Cannot call methods on an unopened document');
615+
}
616+
617+
return await this.execute<CodeLens[]>(
618+
'getCodeLens',
619+
[document],
620+
ExecuteMode.FirstNonNull,
621+
'smart'
622+
);
623+
}
624+
608625
async getFoldingRanges(textDocument: TextDocumentIdentifier): Promise<FoldingRange[]> {
609626
const document = this.getDocument(textDocument.uri);
610627

@@ -620,6 +637,26 @@ export class PluginHost implements LSProvider, OnWatchFileChanges {
620637
return result;
621638
}
622639

640+
async resolveCodeLens(
641+
textDocument: TextDocumentIdentifier,
642+
codeLens: CodeLens,
643+
cancellationToken: CancellationToken
644+
) {
645+
const document = this.getDocument(textDocument.uri);
646+
if (!document) {
647+
throw new Error('Cannot call methods on an unopened document');
648+
}
649+
650+
return (
651+
(await this.execute<CodeLens>(
652+
'resolveCodeLens',
653+
[document, codeLens, cancellationToken],
654+
ExecuteMode.FirstNonNull,
655+
'smart'
656+
)) ?? codeLens
657+
);
658+
}
659+
623660
onWatchFileChanges(onWatchFileChangesParas: OnWatchFileChangesPara[]): void {
624661
for (const support of this.plugins) {
625662
support.onWatchFileChanges?.(onWatchFileChangesParas);

packages/language-server/src/plugins/interfaces.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
CallHierarchyOutgoingCall,
1414
CodeAction,
1515
CodeActionContext,
16+
CodeLens,
1617
Color,
1718
ColorInformation,
1819
ColorPresentation,
@@ -150,7 +151,8 @@ export interface FindReferencesProvider {
150151
findReferences(
151152
document: Document,
152153
position: Position,
153-
context: ReferenceContext
154+
context: ReferenceContext,
155+
cancellationToken?: CancellationToken
154156
): Promise<Location[] | null>;
155157
}
156158

@@ -187,7 +189,11 @@ export interface LinkedEditingRangesProvider {
187189
}
188190

189191
export interface ImplementationProvider {
190-
getImplementation(document: Document, position: Position): Resolvable<Location[] | null>;
192+
getImplementation(
193+
document: Document,
194+
position: Position,
195+
cancellationToken?: CancellationToken
196+
): Resolvable<Location[] | null>;
191197
}
192198

193199
export interface TypeDefinitionProvider {
@@ -211,6 +217,15 @@ export interface CallHierarchyProvider {
211217
): Resolvable<CallHierarchyOutgoingCall[] | null>;
212218
}
213219

220+
export interface CodeLensProvider {
221+
getCodeLens(document: Document): Resolvable<CodeLens[] | null>;
222+
resolveCodeLens(
223+
document: Document,
224+
codeLensToResolve: CodeLens,
225+
cancellationToken?: CancellationToken
226+
): Resolvable<CodeLens>;
227+
}
228+
214229
export interface OnWatchFileChangesPara {
215230
fileName: string;
216231
changeType: FileChangeType;
@@ -257,7 +272,8 @@ type ProviderBase = DiagnosticsProvider &
257272
TypeDefinitionProvider &
258273
InlayHintProvider &
259274
CallHierarchyProvider &
260-
FoldingRangeProvider;
275+
FoldingRangeProvider &
276+
CodeLensProvider;
261277

262278
export type LSProvider = ProviderBase & BackwardsCompatibleDefinitionsProvider;
263279

packages/language-server/src/plugins/typescript/TypeScriptPlugin.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
CancellationToken,
77
CodeAction,
88
CodeActionContext,
9+
CodeLens,
910
CompletionContext,
1011
CompletionList,
1112
DefinitionLink,
@@ -41,6 +42,7 @@ import {
4142
AppCompletionList,
4243
CallHierarchyProvider,
4344
CodeActionsProvider,
45+
CodeLensProvider,
4446
CompletionsProvider,
4547
DefinitionsProvider,
4648
DiagnosticsProvider,
@@ -65,7 +67,6 @@ import {
6567
} from '../interfaces';
6668
import { LSAndTSDocResolver } from './LSAndTSDocResolver';
6769
import { ignoredBuildDirectories } from './SnapshotManager';
68-
import { CallHierarchyProviderImpl } from './features/CallHierarchyProvider';
6970
import { CodeActionsProviderImpl } from './features/CodeActionsProvider';
7071
import { CompletionResolveInfo, CompletionsProviderImpl } from './features/CompletionProvider';
7172
import { DiagnosticsProviderImpl } from './features/DiagnosticsProvider';
@@ -97,6 +98,8 @@ import {
9798
isSvelteFilePath,
9899
symbolKindFromString
99100
} from './utils';
101+
import { CallHierarchyProviderImpl } from './features/CallHierarchyProvider';
102+
import { CodeLensProviderImpl } from './features/CodeLensProvider';
100103

101104
export class TypeScriptPlugin
102105
implements
@@ -118,6 +121,7 @@ export class TypeScriptPlugin
118121
InlayHintProvider,
119122
CallHierarchyProvider,
120123
FoldingRangeProvider,
124+
CodeLensProvider,
121125
OnWatchFileChanges,
122126
CompletionsProvider<CompletionResolveInfo>,
123127
UpdateTsOrJsFile
@@ -144,6 +148,7 @@ export class TypeScriptPlugin
144148
private readonly inlayHintProvider: InlayHintProviderImpl;
145149
private readonly foldingRangeProvider: FoldingRangeProviderImpl;
146150
private readonly callHierarchyProvider: CallHierarchyProviderImpl;
151+
private readonly codLensProvider: CodeLensProviderImpl;
147152

148153
constructor(
149154
configManager: LSConfigManager,
@@ -194,6 +199,12 @@ export class TypeScriptPlugin
194199
this.lsAndTsDocResolver,
195200
configManager
196201
);
202+
this.codLensProvider = new CodeLensProviderImpl(
203+
this.lsAndTsDocResolver,
204+
this.findReferencesProvider,
205+
this.implementationProvider,
206+
this.configManager
207+
);
197208
}
198209

199210
async getDiagnostics(
@@ -608,8 +619,12 @@ export class TypeScriptPlugin
608619
);
609620
}
610621

611-
async getImplementation(document: Document, position: Position): Promise<Location[] | null> {
612-
return this.implementationProvider.getImplementation(document, position);
622+
async getImplementation(
623+
document: Document,
624+
position: Position,
625+
cancellationToken?: CancellationToken
626+
): Promise<Location[] | null> {
627+
return this.implementationProvider.getImplementation(document, position, cancellationToken);
613628
}
614629

615630
async getTypeDefinition(document: Document, position: Position): Promise<Location[] | null> {
@@ -658,6 +673,18 @@ export class TypeScriptPlugin
658673
return this.foldingRangeProvider.getFoldingRanges(document);
659674
}
660675

676+
getCodeLens(document: Document): Promise<CodeLens[] | null> {
677+
return this.codLensProvider.getCodeLens(document);
678+
}
679+
680+
resolveCodeLens(
681+
document: Document,
682+
codeLensToResolve: CodeLens,
683+
cancellationToken?: CancellationToken
684+
): Promise<CodeLens> {
685+
return this.codLensProvider.resolveCodeLens(document, codeLensToResolve, cancellationToken);
686+
}
687+
661688
private featureEnabled(feature: keyof LSTypescriptConfig) {
662689
return (
663690
this.configManager.enabled('typescript.enable') &&

0 commit comments

Comments
 (0)