src/vs/workbench/services/search/common/fileSearchManager.ts

429 LOC · 385 covered · 44 uncovered · 85 ranges · 60 concepts · 17 introducers · 32 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/workbench/api/common/extHostSearch.ts · 232 LOCcommon/extHostSearch.tssrc/vs/workbench/api/common/extHostUriTransformerService.ts · 37 LOCcommon/extHostUriTransfo…src/vs/workbench/api/node/extHostSearch.ts · 167 LOCnode/extHostSearch.tssrc/vs/workbench/api/test/common/testRPCProtocol.ts · 173 LOCcommon/testRPCProtocol.t…src/vs/workbench/services/search/common/search.ts · 880 LOCcommon/search.tssrc/vs/workbench/services/search/common/searchExtConversionTypes.ts · 567 LOCcommon/searchExtConversi…src/vs/workbench/services/search/node/fileSearch.ts · 770 LOCnode/fileSearch.tssrc/vs/workbench/services/search/node/rawSearchService.ts · 449 LOCnode/rawSearchService.tssrc/vs/workbench/services/search/node/ripgrepSearchProvider.ts · 73 LOCnode/ripgrepSearchProvid…src/vs/workbench/services/search/node/textSearchAdapter.ts · 61 LOCnode/textSearchAdapter.t…glob.ts ×1 · 4 introduced LOCglob.ts ×1extHostSearch.test|title=ExtHostSearch File: multiroot sibling exclude clause|occurrence=1 · 0 introduced LOCextHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: basic sibling clause|occurrence=1 · 0 introduced LOCextHostSearch.test|title…search.ts ×3 · 13 introduced LOCsearch.ts ×3extHostSearch.test|title=ExtHostSearch File: include, sibling exclude, and subfolder|occurrence=1 · 0 introduced LOCextHostSearch.test|title…fileSearchManager.ts ×2 · 4 introduced LOCfileSearchManager.ts ×2extHostSearch.test|title=ExtHostSearch File: basic sibling exclude clause|occurrence=1 · 0 introduced LOCextHostSearch.test|title…search.ts ×3 · 13 introduced LOCsearch.ts ×3fileSearchManager.ts ×9 · 57 introduced LOCfileSearchManager.ts ×9search.ts ×1 · 1 introduced LOCsearch.ts ×1textSearchManager.ts ×1 · 2 introduced LOCtextSearchManager.ts ×1extHostSearch.test|title=ExtHostSearch Text: max results = 2|occurrence=1 · 0 introduced LOCextHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: max results = 1|occurrence=1 · 0 introduced LOCextHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: provider returns maxResults exactly|occurrence=1 · 0 introduced LOCextHostSearch.test|title…textSearchManager.ts ×2 · 8 introduced LOCtextSearchManager.ts ×2extHostSearch.test|title=ExtHostSearch Text: basic results|occurrence=1, extHostSearch.test|title=ExtHostSearch Text: provider returns early with limitHit|occurrence=1 · 0 introduced LOCextHostSearch.test|title…excludes combined|occurrence=1 · 0 introduced LOCexcludes combined|occurr…textSearchManager.ts ×1 · 1 introduced LOCtextSearchManager.ts ×1extHostSearch.test|title=ExtHostSearch File: multiroot max results|occurrence=1 · 0 introduced LOCextHostSearch.test|title…textSearchManager.ts ×1 · 3 introduced LOCtextSearchManager.ts ×1search.ts ×1 · 7 introduced LOCsearch.ts ×1search.ts ×1 · 2 introduced LOCsearch.ts ×1excludes resolved correctly|occurrence=1 · 0 introduced LOCexcludes resolved correc…fileSearchManager.ts ×1 · 3 introduced LOCfileSearchManager.ts ×1searchExtConversionTypes.ts ×10 · 60 introduced LOCsearchExtConversionTypes…extHostSearch.test|title=ExtHostSearch File: provider returns maxResults exactly|occurrence=1 · 0 introduced LOCextHostSearch.test|title…fileSearchManager.ts ×1 · 2 introduced LOCfileSearchManager.ts ×1excludes combined|occurrence=1 · 0 introduced LOCexcludes combined|occurr…extHostSearch.test|title=ExtHostSearch File: simple results|occurrence=1 · 0 introduced LOCextHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: works with non-file schemes|occurrence=1 · 0 introduced LOCextHostSearch.test|title…fileSearchManager.ts ×1 · 5 introduced LOCfileSearchManager.ts ×1fileSearchManager.ts ×10 · 32 introduced LOCfileSearchManager.ts ×10excludes|occurrence=1 · 0 introduced LOCexcludes|occurrence=1excludes|occurrence=1 · 0 introduced LOCexcludes|occurrence=1excludes resolved correctly|occurrence=1 · 0 introduced LOCexcludes resolved correc…textSearchManager.ts ×1 · 2 introduced LOCtextSearchManager.ts ×1fileSearchManager.ts ×2 · 3 introduced LOCfileSearchManager.ts ×2search.ts ×2 · 2 introduced LOCsearch.ts ×2fileSearchManager.ts ×4 · 25 introduced LOCfileSearchManager.ts ×4fileSearchManager.ts ×1 · 4 introduced LOCfileSearchManager.ts ×1search.ts ×2 · 7 introduced LOCsearch.ts ×2search.ts ×1 · 4 introduced LOCsearch.ts ×1extHostSearch.test|title=ExtHostSearch File: no results|occurrence=1, extHostSearch.test|title=ExtHostSearch File: provider returns null|occurrence=1 · 0 introduced LOCextHostSearch.test|title…fileSearchManager.ts ×3 · 15 introduced LOCfileSearchManager.ts ×3search.ts ×2 · 2 introduced LOCsearch.ts ×2extHostSearch.test|title=ExtHostSearch Text: no results|occurrence=1 · 0 introduced LOCextHostSearch.test|title…fileSearchManager.ts ×1 · 5 introduced LOCfileSearchManager.ts ×1search.ts ×1 · 3 introduced LOCsearch.ts ×1fileSearchManager.ts ×5 · 42 introduced LOCfileSearchManager.ts ×5searchExtConversionTypes.ts ×2 · 9 introduced LOCsearchExtConversionTypes…textSearchManager.ts ×1 · 3 introduced LOCtextSearchManager.ts ×1search.ts ×1 · 2 introduced LOCsearch.ts ×1search.ts ×1 · 2 introduced LOCsearch.ts ×1searchExtConversionTypes.ts ×6 · 60 introduced LOCsearchExtConversionTypes…extHostSearch.ts ×1 · 3 introduced LOCextHostSearch.ts ×1extHostSearch.test|title=ExtHostSearch File: if onlyFileScheme is set, do not call custom schemes|occurrence=1 · 0 introduced LOCextHostSearch.test|title…fileSearchManager.ts ×5 · 19 introduced LOCfileSearchManager.ts ×5fileSearchManager.ts ×1 · 2 introduced LOCfileSearchManager.ts ×1fileSearchManager.ts ×20 · 133 introduced LOCfileSearchManager.ts ×20fileSearch.ts ×31 · 624 introduced LOCfileSearch.ts ×31extHostSearch.test|title=ExtHostSearch File: Search canceled|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: Search canceled|occurrence=1extHostSearch.test|title…excludes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: all provider calls get global include/excludes|occurrence=1excludes|occurrence=1extHostSearch.test|title=ExtHostSearch File: basic sibling exclude clause|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: basic sibling exclude clause|occurrence=1extHostSearch.test|title…excludes combined|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: global/local include/excludes combined|occurrence=1excludes combined|occurr…extHostSearch.test|title=ExtHostSearch File: if onlyFileScheme is set, do not call custom schemes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: if onlyFileScheme is set, do not call custom schemes|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: include, sibling exclude, and subfolder|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: include, sibling exclude, and subfolder|occurrence=1extHostSearch.test|title…excludes resolved correctly|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: include/excludes resolved correctly|occurrence=1excludes resolved correc…extHostSearch.test|title=ExtHostSearch File: max results = 1|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: max results = 1|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: max results = 2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: max results = 2|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: multiroot max results|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: multiroot max results|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: multiroot sibling exclude clause|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: multiroot sibling exclude clause|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: no results|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: no results|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: provider returns maxResults exactly|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: provider returns maxResults exactly|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: provider returns null|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: provider returns null|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: session cancellation should work|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: session cancellation should work|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: simple results|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: simple results|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch File: works with non-file schemes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch File: works with non-file schemes|occurrence=1extHostSearch.test|title…excludes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: all provider calls get global include/excludes|occurrence=1excludes|occurrence=1extHostSearch.test|title=ExtHostSearch Text: basic results|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: basic results|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: basic sibling clause|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: basic sibling clause|occurrence=1extHostSearch.test|title…excludes combined|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: global/local include/excludes combined|occurrence=1excludes combined|occurr…extHostSearch.test|title=ExtHostSearch Text: include pattern applied|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: include pattern applied|occurrence=1extHostSearch.test|title…excludes resolved correctly|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: include/excludes resolved correctly|occurrence=1excludes resolved correc…extHostSearch.test|title=ExtHostSearch Text: max results = 1|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: max results = 1|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: max results = 2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: max results = 2|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: multiroot max results|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: multiroot max results|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: multiroot sibling clause|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: multiroot sibling clause|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: no results|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: no results|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: provider fail|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: provider fail|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: provider returns early with limitHit|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: provider returns early with limitHit|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: provider returns maxResults exactly|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: provider returns maxResults exactly|occurrence=1extHostSearch.test|title…extHostSearch.test|title=ExtHostSearch Text: works with non-file schemes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/node/extHostSearch.test|title=ExtHostSearch Text: works with non-file schemes|occurrence=1extHostSearch.test|title…Focused file · src/vs/workbench/services/search/common/fileSearchManager.ts · 429 LOCcommon/fileSearchManager…

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- fileSearch.ts ×31
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 path from '../../../../base/common/path.js';
7 > import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
8 > import { toErrorMessage } from '../../../../base/common/errorMessage.js';
9 > import * as strings from '../../../../base/common/strings.js';
10 > import * as glob from '../../../../base/common/glob.js';
11 > import * as resources from '../../../../base/common/resources.js';
12 > import { StopWatch } from '../../../../base/common/stopwatch.js';
13 > import { URI } from '../../../../base/common/uri.js';
14 > import { IFileMatch, IFileSearchProviderStats, IFolderQuery, ISearchCompleteStats, IFileQuery, QueryGlobTester, resolvePatternsForProvider, hasSiblingFn, excludeToGlobPattern, DEFAULT_MAX_SEARCH_RESULTS } from './search.js';
15 > import { FileSearchProviderFolderOptions, FileSearchProvider2, FileSearchProviderOptions } from './searchExtTypes.js';
16 > import { OldFileSearchProviderConverter } from './searchExtConversionTypes.js';
17 > import { FolderQuerySearchTree } from './folderQuerySearchTree.js';
18 >
19 > interface IInternalFileMatch {
20 > base: URI;
21 > original?: URI;
22 > relativePath?: string; // Not present for extraFiles or absolute path matches
23 > basename: string;
24 > size?: number;
25 > }
26 >
27 > interface IDirectoryEntry {
28 > base: URI;
29 > relativePath: string;
30 > basename: string;
31 > }
32 >
33 > interface FolderQueryInfo {
34 > queryTester: QueryGlobTester;
35 > noSiblingsClauses: boolean;
36 > folder: URI;
37 > tree: IDirectoryTree;
38 > }
39 >
40 > interface IDirectoryTree {
41 > rootEntries: IDirectoryEntry[];
42 > pathToEntries: { [relativePath: string]: IDirectoryEntry[] };
43 > }
44 >
45 > class FileSearchEngine {
46 > private filePattern?: string;
47 > private includePattern?: glob.ParsedExpression;
48 > private maxResults?: number;
49 > private exists?: boolean;
50 > private isLimitHit = false;
51 > private resultCount = 0;
52 > private isCanceled = false;
53 >
54 > private activeCancellationTokens: Set<CancellationTokenSource>;
55 >
56 > private globalExcludePattern?: glob.ParsedExpression;
57 >
58 > constructor(private config: IFileQuery, private provider: FileSearchProvider2, private sessionLifecycle?: SessionLifecycle) {
59 > this.filePattern = config.filePattern; fileSearchManager.ts ×20
60 > const globOptions = config.ignoreGlobCase ? { ignoreCase: true } : undefined;
61 > this.includePattern = config.includePattern && glob.parse(config.includePattern, globOptions);
62 > this.maxResults = config.maxResults || undefined;
63 > this.exists = config.exists;
64 > this.activeCancellationTokens = new Set<CancellationTokenSource>();
65 >
66 > this.globalExcludePattern = config.excludePattern && glob.parse(config.excludePattern, globOptions);
67 > }
69 > cancel(): void {
70 > this.isCanceled = true; fileSearchManager.ts ×1
71 > this.activeCancellationTokens.forEach(t => t.cancel());
72 > this.activeCancellationTokens = new Set();
73 > }
75 > search(_onResult: (match: IInternalFileMatch) => void): Promise<IInternalSearchComplete> {
76 > const folderQueries = this.config.folderQueries || []; fileSearchManager.ts ×20
77 >
78 > return new Promise((resolve, reject) => {
79 > const onResult = (match: IInternalFileMatch) => {
80 > this.resultCount++; fileSearchManager.ts ×10
81 > _onResult(match);
82 > };
84 > // Support that the file pattern is a full path to a file that exists
85 > if (this.isCanceled) {
86 return resolve({ limitHit: this.isLimitHit });
87 }
89 > // For each extra file
90 > if (this.config.extraFileResources) {
91 this.config.extraFileResources
92 .forEach(extraFile => {
93 const extraFileStr = extraFile.toString(); // ?
94 const basename = path.basename(extraFileStr);
95 if (this.globalExcludePattern && this.globalExcludePattern(extraFileStr, basename)) {
96 return; // excluded
97 }
98
99 // File: Check for match on file pattern and include pattern
100 this.matchFile(onResult, { base: extraFile, basename });
101 });
102 }
104 > // For each root folder'
105 >
106 > // NEW: can just call with an array of folder info
107 > this.doSearch(folderQueries, onResult).then(stats => {
108 > resolve({
109 > limitHit: this.isLimitHit,
110 > stats: stats || undefined // Only looking at single-folder workspace stats...
111 > });
112 > }, (err: Error) => {
113 reject(new Error(toErrorMessage(err)));
115 > });
116 > }
118 >
119 > private async doSearch(fqs: IFolderQuery<URI>[], onResult: (match: IInternalFileMatch) => void): Promise<IFileSearchProviderStats | null> {
120 > const cancellation = new CancellationTokenSource(); fileSearchManager.ts ×20
121 > const folderOptions = fqs.map(fq => this.getSearchOptionsForFolder(fq));
122 > const session = this.provider instanceof OldFileSearchProviderConverter ? this.sessionLifecycle?.tokenSource.token : this.sessionLifecycle?.obj;
123 > const options: FileSearchProviderOptions = {
124 > folderOptions,
125 > maxResults: this.config.maxResults ?? DEFAULT_MAX_SEARCH_RESULTS,
126 > session
127 > };
128 >
129 >
130 > const getFolderQueryInfo = (fq: IFolderQuery) => {
131 > const queryTester = new QueryGlobTester(this.config, fq); fileSearchManager.ts ×5
132 > const noSiblingsClauses = !queryTester.hasSiblingExcludeClauses();
133 > return { queryTester, noSiblingsClauses, folder: fq.folder, tree: this.initDirectoryTree() };
134 > };
136 > const folderMappings: FolderQuerySearchTree<FolderQueryInfo> = new FolderQuerySearchTree<FolderQueryInfo>(fqs, getFolderQueryInfo);
137 >
138 > let providerSW: StopWatch;
139 >
140 > try {
141 > this.activeCancellationTokens.add(cancellation);
142 >
143 > providerSW = StopWatch.create();
144 > const results = await this.provider.provideFileSearchResults(
145 > this.config.filePattern || '',
146 > options,
147 > cancellation.token);
148 > const providerTime = providerSW.elapsed();
149 > const postProcessSW = StopWatch.create();
150 >
151 > if (this.isCanceled && !this.isLimitHit) {
152 > return null; fileSearchManager.ts ×2
153 > }
155 >
156 > if (results) {
157 > results.forEach(result => {
158 > const fqFolderInfo = folderMappings.findQueryFragmentAwareSubstr(result)!; fileSearchManager.ts ×10
159 > const relativePath = path.posix.relative(fqFolderInfo.folder.path, result.path);
160 >
161 > if (fqFolderInfo.noSiblingsClauses) {
162 > const basename = path.basename(result.path); fileSearchManager.ts ×1
163 > this.matchFile(onResult, { base: fqFolderInfo.folder, relativePath, basename });
164 >
165 > return;
166 > }
168 > // TODO: Optimize siblings clauses with ripgrep here.
169 > this.addDirectoryEntries(fqFolderInfo.tree, fqFolderInfo.folder, relativePath, onResult);
171 > }
172 >
173 > if (this.isCanceled && !this.isLimitHit) { fileSearchManager.ts ×20
174 return null;
175 }
177 > folderMappings.forEachFolderQueryInfo(e => {
178 > this.matchDirectoryTree(e.tree, e.queryTester, onResult); fileSearchManager.ts ×3
180 >
181 > return {
182 > providerTime,
183 > postProcessTime: postProcessSW.elapsed()
184 > };
185 > } finally { fileSearchManager.ts ×20
186 > cancellation.dispose();
187 > this.activeCancellationTokens.delete(cancellation);
188 > }
189 > }
191 > private getSearchOptionsForFolder(fq: IFolderQuery<URI>): FileSearchProviderFolderOptions {
192 > const includes = resolvePatternsForProvider(this.config.includePattern, fq.includePattern); fileSearchManager.ts ×5
193 > let excludePattern = fq.excludePattern?.map(e => ({
194 > folder: e.folder, fileSearchManager.ts ×1
195 > patterns: resolvePatternsForProvider(this.config.excludePattern, e.pattern)
197 > if (!excludePattern?.length) {
198 > excludePattern = [{ fileSearchManager.ts ×1
199 > folder: undefined,
200 > patterns: resolvePatternsForProvider(this.config.excludePattern, undefined)
201 > }];
202 > }
203 > const excludes = excludeToGlobPattern(excludePattern); fileSearchManager.ts ×5
204 >
205 > return {
206 > folder: fq.folder,
207 > excludes,
208 > includes,
209 > useIgnoreFiles: {
210 > local: !fq.disregardIgnoreFiles,
211 > parent: !fq.disregardParentIgnoreFiles,
212 > global: !fq.disregardGlobalIgnoreFiles
213 > },
214 > followSymlinks: !fq.ignoreSymlinks,
215 > };
216 > }
218 > private initDirectoryTree(): IDirectoryTree {
219 > const tree: IDirectoryTree = { fileSearchManager.ts ×5
220 > rootEntries: [],
221 > pathToEntries: Object.create(null)
222 > };
223 > tree.pathToEntries['.'] = tree.rootEntries;
224 > return tree;
225 > }
227 > private addDirectoryEntries({ pathToEntries }: IDirectoryTree, base: URI, relativeFile: string, onResult: (result: IInternalFileMatch) => void) {
228 > // Support relative paths to files from a root resource (ignores excludes) fileSearchManager.ts ×9
229 > if (this.filePattern && strings.equals(relativeFile, this.filePattern, this.config.ignoreGlobCase)) {
230 const basename = path.basename(this.filePattern);
231 this.matchFile(onResult, { base: base, relativePath: this.filePattern, basename });
232 }
234 > function add(relativePath: string) {
235 > const basename = path.basename(relativePath);
236 > const dirname = path.dirname(relativePath);
237 > let entries = pathToEntries[dirname];
238 > if (!entries) {
239 > entries = pathToEntries[dirname] = []; fileSearchManager.ts ×2
240 > add(dirname);
241 > }
242 > entries.push({ fileSearchManager.ts ×9
243 > base,
244 > relativePath,
245 > basename
246 > });
247 > }
248 >
249 > add(relativeFile);
250 > }
252 > private matchDirectoryTree({ rootEntries, pathToEntries }: IDirectoryTree, queryTester: QueryGlobTester, onResult: (result: IInternalFileMatch) => void) {
253 > const self = this; fileSearchManager.ts ×3
254 > const filePattern = this.filePattern;
255 > const ignoreGlobCase = this.config.ignoreGlobCase;
256 > function matchDirectory(entries: IDirectoryEntry[]) {
257 > const hasSibling = hasSiblingFn(() => entries.map(entry => entry.basename));
258 > for (let i = 0, n = entries.length; i < n; i++) {
259 > const entry = entries[i]; fileSearchManager.ts ×9
260 > const { relativePath, basename } = entry;
261 >
262 > // Check exclude pattern
263 > // If the user searches for the exact file name, we adjust the glob matching
264 > // to ignore filtering by siblings because the user seems to know what they
265 > // are searching for and we want to include the result in that case anyway
266 > if (queryTester.matchesExcludesSync(relativePath, basename, !strings.equals(filePattern, basename, ignoreGlobCase) ? hasSibling : undefined)) {
267 > continue; search.ts ×3
268 > }
270 > const sub = pathToEntries[relativePath];
271 > if (sub) {
272 > matchDirectory(sub); fileSearchManager.ts ×2
273 > } else { fileSearchManager.ts ×9
274 > if (strings.equals(relativePath, filePattern, ignoreGlobCase)) {
275 continue; // ignore file if its path matches with the file pattern because that is already matched above
276 }
278 > self.matchFile(onResult, entry);
279 > }
280 >
281 > if (self.isLimitHit) {
282 break;
283 }
286 > matchDirectory(rootEntries);
287 > }
289 > private matchFile(onResult: (result: IInternalFileMatch) => void, candidate: IInternalFileMatch): void {
290 > if (!this.includePattern || (candidate.relativePath && this.includePattern(candidate.relativePath, candidate.basename))) { fileSearchManager.ts ×10
291 > if (this.exists || (this.maxResults && this.resultCount >= this.maxResults)) {
292 > this.isLimitHit = true; fileSearchManager.ts ×1
293 > this.cancel();
294 > }
296 > if (!this.isLimitHit) {
297 > onResult(candidate);
298 > }
299 > }
300 > }
302 >
303 > interface IInternalSearchComplete {
304 > limitHit: boolean;
305 > stats?: IFileSearchProviderStats;
306 > }
307 >
308 > /**
309 > * For backwards compatibility, store both a cancellation token and a session object. The session object is the new implementation, where
310 > */
311 > class SessionLifecycle {
312 > private _obj: object | undefined;
313 > public readonly tokenSource: CancellationTokenSource;
314 >
315 > constructor() {
316 > this._obj = new Object(); fileSearchManager.ts ×4
317 > this.tokenSource = new CancellationTokenSource();
318 > }
320 > public get obj() {
321 if (this._obj) {
322 return this._obj;
323 }
324
325 throw new Error('Session object has been dereferenced.');
326 }
328 > cancel() {
329 > this.tokenSource.cancel(); fileSearchManager.ts ×4
330 > this._obj = undefined; // dereference
331 > }
333 >
334 > export class FileSearchManager {
335 >
336 > private static readonly BATCH_SIZE = 512;
337 >
338 > private readonly sessions = new Map<string, SessionLifecycle>();
339 >
340 > fileSearch(config: IFileQuery, provider: FileSearchProvider2, onBatch: (matches: IFileMatch[]) => void, token: CancellationToken): Promise<ISearchCompleteStats> {
341 > const sessionTokenSource = this.getSessionTokenSource(config.cacheKey); fileSearchManager.ts ×20
342 > const engine = new FileSearchEngine(config, provider, sessionTokenSource);
343 >
344 > let resultCount = 0;
345 > const onInternalResult = (batch: IInternalFileMatch[]) => {
346 > resultCount += batch.length; fileSearchManager.ts ×10
347 > onBatch(batch.map(m => this.rawMatchToSearchItem(m)));
348 > };
350 > return this.doSearch(engine, FileSearchManager.BATCH_SIZE, onInternalResult, token).then(
351 > result => {
352 > return {
353 > limitHit: result.limitHit,
354 > stats: result.stats ? {
355 > fromCache: false, fileSearchManager.ts ×5
356 > type: 'fileSearchProvider',
357 > resultCount,
358 > detailStats: result.stats
359 > } : undefined, fileSearchManager.ts ×20
360 > messages: []
361 > };
362 > });
363 > }
365 > clearCache(cacheKey: string): void {
366 > // cancel the token fileSearchManager.ts ×4
367 > this.sessions.get(cacheKey)?.cancel();
368 > // with no reference to this, it will be removed from WeakMaps
369 > this.sessions.delete(cacheKey);
370 > }
372 > private getSessionTokenSource(cacheKey: string | undefined): SessionLifecycle | undefined {
373 > if (!cacheKey) { fileSearchManager.ts ×20
374 > return undefined; fileSearchManager.ts ×1
375 > }
377 > if (!this.sessions.has(cacheKey)) {
378 > this.sessions.set(cacheKey, new SessionLifecycle());
379 > }
380 >
381 > return this.sessions.get(cacheKey);
384 > private rawMatchToSearchItem(match: IInternalFileMatch): IFileMatch {
385 > if (match.relativePath) { fileSearchManager.ts ×10
386 > return {
387 > resource: resources.joinPath(match.base, match.relativePath)
388 > };
389 > } else {
390 // extraFileResources
391 return {
392 resource: match.base
393 };
394 }
397 > private doSearch(engine: FileSearchEngine, batchSize: number, onResultBatch: (matches: IInternalFileMatch[]) => void, token: CancellationToken): Promise<IInternalSearchComplete> {
398 > const listener = token.onCancellationRequested(() => { fileSearchManager.ts ×20
399 > engine.cancel(); fileSearchManager.ts ×2
401 >
402 > const _onResult = (match: IInternalFileMatch) => {
403 > if (match) { fileSearchManager.ts ×10
404 > batch.push(match);
405 > if (batchSize > 0 && batch.length >= batchSize) {
406 onResultBatch(batch);
407 batch = [];
408 }
410 > };
412 > let batch: IInternalFileMatch[] = [];
413 > return engine.search(_onResult).then(result => {
414 > if (batch.length) {
415 > onResultBatch(batch); fileSearchManager.ts ×10
416 > }
418 > listener.dispose();
419 > return result;
420 > }, error => {
421 if (batch.length) {
422 onResultBatch(batch);
423 }
424
425 listener.dispose();
426 return Promise.reject(error);
428 > }