Skip to content

Commit b7229ea

Browse files
gabrittosnovader
authored andcommitted
Add option to exclude library symbols from navTo results (microsoft#55605)
1 parent e85b345 commit b7229ea

File tree

16 files changed

+246
-21
lines changed

16 files changed

+246
-21
lines changed

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9936,6 +9936,7 @@ export interface UserPreferences {
99369936
readonly organizeImportsNumericCollation?: boolean;
99379937
readonly organizeImportsAccentCollation?: boolean;
99389938
readonly organizeImportsCaseFirst?: "upper" | "lower" | false;
9939+
readonly excludeLibrarySymbolsInNavTo?: boolean;
99399940
}
99409941

99419942
/** Represents a bigint literal value without requiring bigint support */

src/harness/client.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,15 +314,25 @@ export class SessionClient implements LanguageService {
314314
return notImplemented();
315315
}
316316

317-
getNavigateToItems(searchValue: string): NavigateToItem[] {
317+
getNavigateToItems(searchValue: string, maxResultCount: number, file: string | undefined, _excludeDtsFiles: boolean | undefined, excludeLibFiles: boolean | undefined): NavigateToItem[] {
318318
const args: protocol.NavtoRequestArgs = {
319319
searchValue,
320-
file: this.host.getScriptFileNames()[0],
320+
file,
321+
currentFileOnly: !!file,
322+
maxResultCount,
321323
};
324+
const oldPreferences = this.preferences;
325+
if (excludeLibFiles) {
326+
this.configure({ excludeLibrarySymbolsInNavTo: true });
327+
}
322328

323329
const request = this.processRequest<protocol.NavtoRequest>(protocol.CommandTypes.Navto, args);
324330
const response = this.processResponse<protocol.NavtoResponse>(request);
325331

332+
if (excludeLibFiles) {
333+
this.configure(oldPreferences || {});
334+
}
335+
326336
return response.body!.map(entry => ({ // TODO: GH#18217
327337
name: entry.name,
328338
containerName: entry.containerName || "",
@@ -579,14 +589,13 @@ export class SessionClient implements LanguageService {
579589
const providePrefixAndSuffixTextForRename = typeof preferences === "boolean" ? preferences : preferences?.providePrefixAndSuffixTextForRename;
580590
const quotePreference = typeof preferences === "boolean" ? undefined : preferences?.quotePreference;
581591
if (providePrefixAndSuffixTextForRename !== undefined || quotePreference !== undefined) {
592+
const oldPreferences = this.preferences;
582593
// User preferences have to be set through the `Configure` command
583594
this.configure({ providePrefixAndSuffixTextForRename, quotePreference });
584595
// Options argument is not used, so don't pass in options
585596
this.getRenameInfo(fileName, position, /*preferences*/ {}, findInStrings, findInComments);
586597
// Restore previous user preferences
587-
if (this.preferences) {
588-
this.configure(this.preferences);
589-
}
598+
this.configure(oldPreferences || {});
590599
}
591600
else {
592601
this.getRenameInfo(fileName, position, /*preferences*/ {}, findInStrings, findInComments);
@@ -812,6 +821,7 @@ export class SessionClient implements LanguageService {
812821
kind?: string,
813822
includeInteractiveActions?: boolean,
814823
): ApplicableRefactorInfo[] {
824+
const oldPreferences = this.preferences;
815825
if (preferences) { // Temporarily set preferences
816826
this.configure(preferences);
817827
}
@@ -822,7 +832,7 @@ export class SessionClient implements LanguageService {
822832
const request = this.processRequest<protocol.GetApplicableRefactorsRequest>(protocol.CommandTypes.GetApplicableRefactors, args);
823833
const response = this.processResponse<protocol.GetApplicableRefactorsResponse>(request);
824834
if (preferences) { // Restore preferences
825-
this.configure(this.preferences || {});
835+
this.configure(oldPreferences || {});
826836
}
827837
return response.body!; // TODO: GH#18217
828838
}
@@ -844,6 +854,7 @@ export class SessionClient implements LanguageService {
844854
preferences: UserPreferences | undefined,
845855
interactiveRefactorArguments?: InteractiveRefactorArguments,
846856
): RefactorEditInfo {
857+
const oldPreferences = this.preferences;
847858
if (preferences) { // Temporarily set preferences
848859
this.configure(preferences);
849860
}
@@ -868,7 +879,7 @@ export class SessionClient implements LanguageService {
868879
}
869880

870881
if (preferences) { // Restore preferences
871-
this.configure(this.preferences || {});
882+
this.configure(oldPreferences || {});
872883
}
873884

874885
return {

src/harness/fourslashImpl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3765,9 +3765,9 @@ export class TestState {
37653765
}
37663766

37673767
public verifyNavigateTo(options: readonly FourSlashInterface.VerifyNavigateToOptions[]): void {
3768-
for (const { pattern, expected, fileName } of options) {
3768+
for (const { pattern, expected, fileName, excludeLibFiles } of options) {
37693769
const file = fileName && this.findFile(fileName).fileName;
3770-
const items = this.languageService.getNavigateToItems(pattern, /*maxResultCount*/ undefined, file);
3770+
const items = this.languageService.getNavigateToItems(pattern, /*maxResultCount*/ undefined, file, /*excludeDtsFiles*/ undefined, excludeLibFiles);
37713771
this.assertObjectsEqual(
37723772
items,
37733773
expected.map((e): ts.NavigateToItem => ({

src/harness/fourslashInterfaceImpl.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,7 @@ export interface VerifyNavigateToOptions {
18091809
readonly pattern: string;
18101810
readonly fileName?: string;
18111811
readonly expected: readonly ExpectedNavigateToItem[];
1812+
readonly excludeLibFiles?: boolean;
18121813
}
18131814

18141815
export interface ExpectedNavigateToItem {

src/server/protocol.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3599,6 +3599,11 @@ export interface UserPreferences {
35993599
* Indicates whether {@link ReferencesResponseItem.lineText} is supported.
36003600
*/
36013601
readonly disableLineTextInReferences?: boolean;
3602+
3603+
/**
3604+
* Indicates whether to exclude standard library and node_modules file symbols from navTo results.
3605+
*/
3606+
readonly excludeLibrarySymbolsInNavTo?: boolean;
36023607
}
36033608

36043609
export interface CompilerOptions {

src/server/session.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2613,6 +2613,7 @@ export class Session<TMessage = string> implements EventSender {
26132613
const { file, project } = this.getFileAndProject(args as protocol.FileRequestArgs);
26142614
return [{ project, navigateToItems: project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file) }];
26152615
}
2616+
const preferences = this.getHostPreferences();
26162617

26172618
const outputs: ProjectNavigateToItems[] = [];
26182619

@@ -2646,7 +2647,13 @@ export class Session<TMessage = string> implements EventSender {
26462647

26472648
// Mutates `outputs`
26482649
function addItemsForProject(project: Project) {
2649-
const projectItems = project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject());
2650+
const projectItems = project.getLanguageService().getNavigateToItems(
2651+
searchValue,
2652+
maxResultCount,
2653+
/*fileName*/ undefined,
2654+
/*excludeDts*/ project.isNonTsProject(),
2655+
/*excludeLibFiles*/ preferences.excludeLibrarySymbolsInNavTo,
2656+
);
26502657
const unseenItems = filter(projectItems, item => tryAddSeenItem(item) && !getMappedLocationForProject(documentSpanLocation(item), project));
26512658
if (unseenItems.length) {
26522659
outputs.push({ project, navigateToItems: unseenItems });

src/services/navigateTo.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
ImportClause,
1717
ImportEqualsDeclaration,
1818
ImportSpecifier,
19+
isInsideNodeModules,
1920
isPropertyAccessExpression,
2021
isPropertyNameLiteral,
2122
NavigateToItem,
@@ -37,11 +38,11 @@ interface RawNavigateToItem {
3738
}
3839

3940
/** @internal */
40-
export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number | undefined, excludeDtsFiles: boolean): NavigateToItem[] {
41+
export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number | undefined, excludeDtsFiles: boolean, excludeLibFiles?: boolean): NavigateToItem[] {
4142
const patternMatcher = createPatternMatcher(searchValue);
4243
if (!patternMatcher) return emptyArray;
4344
const rawItems: RawNavigateToItem[] = [];
44-
45+
const singleCurrentFile = sourceFiles.length === 1 ? sourceFiles[0] : undefined;
4546
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
4647
for (const sourceFile of sourceFiles) {
4748
cancellationToken.throwIfCancellationRequested();
@@ -50,16 +51,37 @@ export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker:
5051
continue;
5152
}
5253

54+
if (shouldExcludeFile(sourceFile, !!excludeLibFiles, singleCurrentFile)) {
55+
continue;
56+
}
57+
5358
sourceFile.getNamedDeclarations().forEach((declarations, name) => {
54-
getItemsFromNamedDeclaration(patternMatcher, name, declarations, checker, sourceFile.fileName, rawItems);
59+
getItemsFromNamedDeclaration(patternMatcher, name, declarations, checker, sourceFile.fileName, !!excludeLibFiles, singleCurrentFile, rawItems);
5560
});
5661
}
5762

5863
rawItems.sort(compareNavigateToItems);
5964
return (maxResultCount === undefined ? rawItems : rawItems.slice(0, maxResultCount)).map(createNavigateToItem);
6065
}
6166

62-
function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: string, declarations: readonly Declaration[], checker: TypeChecker, fileName: string, rawItems: RawNavigateToItem[]): void {
67+
/**
68+
* Exclude 'node_modules/' files and standard library files if 'excludeLibFiles' is true.
69+
* If we're in current file only mode, we don't exclude the current file, even if it is a library file.
70+
*/
71+
function shouldExcludeFile(file: SourceFile, excludeLibFiles: boolean, singleCurrentFile: SourceFile | undefined): boolean {
72+
return file !== singleCurrentFile && excludeLibFiles && (isInsideNodeModules(file.path) || file.hasNoDefaultLib);
73+
}
74+
75+
function getItemsFromNamedDeclaration(
76+
patternMatcher: PatternMatcher,
77+
name: string,
78+
declarations: readonly Declaration[],
79+
checker: TypeChecker,
80+
fileName: string,
81+
excludeLibFiles: boolean,
82+
singleCurrentFile: SourceFile | undefined,
83+
rawItems: RawNavigateToItem[],
84+
): void {
6385
// First do a quick check to see if the name of the declaration matches the
6486
// last portion of the (possibly) dotted name they're searching for.
6587
const match = patternMatcher.getMatchForLastSegmentOfPattern(name);
@@ -68,7 +90,7 @@ function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: stri
6890
}
6991

7092
for (const declaration of declarations) {
71-
if (!shouldKeepItem(declaration, checker)) continue;
93+
if (!shouldKeepItem(declaration, checker, excludeLibFiles, singleCurrentFile)) continue;
7294

7395
if (patternMatcher.patternContainsDots) {
7496
// If the pattern has dots in it, then also see if the declaration container matches as well.
@@ -83,14 +105,20 @@ function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: stri
83105
}
84106
}
85107

86-
function shouldKeepItem(declaration: Declaration, checker: TypeChecker): boolean {
108+
function shouldKeepItem(
109+
declaration: Declaration,
110+
checker: TypeChecker,
111+
excludeLibFiles: boolean,
112+
singleCurrentFile: SourceFile | undefined,
113+
): boolean {
87114
switch (declaration.kind) {
88115
case SyntaxKind.ImportClause:
89116
case SyntaxKind.ImportSpecifier:
90117
case SyntaxKind.ImportEqualsDeclaration:
91118
const importer = checker.getSymbolAtLocation((declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name!)!; // TODO: GH#18217
92119
const imported = checker.getAliasedSymbol(importer);
93-
return importer.escapedName !== imported.escapedName;
120+
return importer.escapedName !== imported.escapedName
121+
&& !imported.declarations?.every(d => shouldExcludeFile(d.getSourceFile(), excludeLibFiles, singleCurrentFile));
94122
default:
95123
return true;
96124
}

src/services/services.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,10 +2192,10 @@ export function createLanguageService(
21922192
return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map(FindAllReferences.toReferenceEntry);
21932193
}
21942194

2195-
function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false): NavigateToItem[] {
2195+
function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false, excludeLibFiles = false): NavigateToItem[] {
21962196
synchronizeHostData();
21972197
const sourceFiles = fileName ? [getValidSourceFile(fileName)] : program.getSourceFiles();
2198-
return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles);
2198+
return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles, excludeLibFiles);
21992199
}
22002200

22012201
function getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean) {

src/services/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ export interface LanguageService {
594594
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
595595
getFileReferences(fileName: string): ReferenceEntry[];
596596

597-
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
597+
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean, excludeLibFiles?: boolean): NavigateToItem[];
598598
getNavigationBarItems(fileName: string): NavigationBarItem[];
599599
getNavigationTree(fileName: string): NavigationTree;
600600

tests/baselines/reference/api/typescript.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2897,6 +2897,10 @@ declare namespace ts {
28972897
* Indicates whether {@link ReferencesResponseItem.lineText} is supported.
28982898
*/
28992899
readonly disableLineTextInReferences?: boolean;
2900+
/**
2901+
* Indicates whether to exclude standard library and node_modules file symbols from navTo results.
2902+
*/
2903+
readonly excludeLibrarySymbolsInNavTo?: boolean;
29002904
}
29012905
interface CompilerOptions {
29022906
allowJs?: boolean;
@@ -8640,6 +8644,7 @@ declare namespace ts {
86408644
readonly organizeImportsNumericCollation?: boolean;
86418645
readonly organizeImportsAccentCollation?: boolean;
86428646
readonly organizeImportsCaseFirst?: "upper" | "lower" | false;
8647+
readonly excludeLibrarySymbolsInNavTo?: boolean;
86438648
}
86448649
/** Represents a bigint literal value without requiring bigint support */
86458650
interface PseudoBigInt {
@@ -10396,7 +10401,7 @@ declare namespace ts {
1039610401
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
1039710402
getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined;
1039810403
getFileReferences(fileName: string): ReferenceEntry[];
10399-
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[];
10404+
getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean, excludeLibFiles?: boolean): NavigateToItem[];
1040010405
getNavigationBarItems(fileName: string): NavigationBarItem[];
1040110406
getNavigationTree(fileName: string): NavigationTree;
1040210407
prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined;

0 commit comments

Comments
 (0)