Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/node/extHostSearch.ts
3296 views
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 { DisposableStore, IDisposable, toDisposable } from '../../../base/common/lifecycle.js';
7
import { Schemas } from '../../../base/common/network.js';
8
import { URI } from '../../../base/common/uri.js';
9
import * as pfs from '../../../base/node/pfs.js';
10
import { ILogService } from '../../../platform/log/common/log.js';
11
import { IExtHostConfiguration } from '../common/extHostConfiguration.js';
12
import { IExtHostInitDataService } from '../common/extHostInitDataService.js';
13
import { IExtHostRpcService } from '../common/extHostRpcService.js';
14
import { ExtHostSearch, reviveQuery } from '../common/extHostSearch.js';
15
import { IURITransformerService } from '../common/extHostUriTransformerService.js';
16
import { IFileQuery, IRawFileQuery, ISearchCompleteStats, ISerializedSearchProgressItem, isSerializedFileMatch, ITextQuery } from '../../services/search/common/search.js';
17
import { TextSearchManager } from '../../services/search/common/textSearchManager.js';
18
import { SearchService } from '../../services/search/node/rawSearchService.js';
19
import { RipgrepSearchProvider } from '../../services/search/node/ripgrepSearchProvider.js';
20
import { OutputChannel } from '../../services/search/node/ripgrepSearchUtils.js';
21
import { NativeTextSearchManager } from '../../services/search/node/textSearchManager.js';
22
import type * as vscode from 'vscode';
23
24
export class NativeExtHostSearch extends ExtHostSearch implements IDisposable {
25
26
protected _pfs: typeof pfs = pfs; // allow extending for tests
27
28
private _internalFileSearchHandle: number = -1;
29
private _internalFileSearchProvider: SearchService | null = null;
30
31
private _registeredEHSearchProvider = false;
32
33
private _numThreadsPromise: Promise<number | undefined> | undefined;
34
35
private readonly _disposables = new DisposableStore();
36
37
private isDisposed = false;
38
39
constructor(
40
@IExtHostRpcService extHostRpc: IExtHostRpcService,
41
@IExtHostInitDataService initData: IExtHostInitDataService,
42
@IURITransformerService _uriTransformer: IURITransformerService,
43
@IExtHostConfiguration private readonly configurationService: IExtHostConfiguration,
44
@ILogService _logService: ILogService,
45
) {
46
super(extHostRpc, _uriTransformer, _logService);
47
this.getNumThreads = this.getNumThreads.bind(this);
48
this.getNumThreadsCached = this.getNumThreadsCached.bind(this);
49
this.handleConfigurationChanged = this.handleConfigurationChanged.bind(this);
50
const outputChannel = new OutputChannel('RipgrepSearchUD', this._logService);
51
this._disposables.add(this.registerTextSearchProvider(Schemas.vscodeUserData, new RipgrepSearchProvider(outputChannel, this.getNumThreadsCached)));
52
if (initData.remote.isRemote && initData.remote.authority) {
53
this._registerEHSearchProviders();
54
}
55
56
configurationService.getConfigProvider().then(provider => {
57
if (this.isDisposed) {
58
return;
59
}
60
this._disposables.add(provider.onDidChangeConfiguration(this.handleConfigurationChanged));
61
});
62
}
63
64
private handleConfigurationChanged(event: vscode.ConfigurationChangeEvent) {
65
if (!event.affectsConfiguration('search')) {
66
return;
67
}
68
this._numThreadsPromise = undefined;
69
}
70
71
async getNumThreads(): Promise<number | undefined> {
72
const configProvider = await this.configurationService.getConfigProvider();
73
const numThreads = configProvider.getConfiguration('search').get<number>('ripgrep.maxThreads');
74
return numThreads;
75
}
76
77
async getNumThreadsCached(): Promise<number | undefined> {
78
if (!this._numThreadsPromise) {
79
this._numThreadsPromise = this.getNumThreads();
80
}
81
return this._numThreadsPromise;
82
}
83
84
dispose(): void {
85
this.isDisposed = true;
86
this._disposables.dispose();
87
}
88
89
override $enableExtensionHostSearch(): void {
90
this._registerEHSearchProviders();
91
}
92
93
private _registerEHSearchProviders(): void {
94
if (this._registeredEHSearchProvider) {
95
return;
96
}
97
98
this._registeredEHSearchProvider = true;
99
const outputChannel = new OutputChannel('RipgrepSearchEH', this._logService);
100
this._disposables.add(this.registerTextSearchProvider(Schemas.file, new RipgrepSearchProvider(outputChannel, this.getNumThreadsCached)));
101
this._disposables.add(this.registerInternalFileSearchProvider(Schemas.file, new SearchService('fileSearchProvider', this.getNumThreadsCached)));
102
}
103
104
private registerInternalFileSearchProvider(scheme: string, provider: SearchService): IDisposable {
105
const handle = this._handlePool++;
106
this._internalFileSearchProvider = provider;
107
this._internalFileSearchHandle = handle;
108
this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme));
109
return toDisposable(() => {
110
this._internalFileSearchProvider = null;
111
this._proxy.$unregisterProvider(handle);
112
});
113
}
114
115
override $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: vscode.CancellationToken): Promise<ISearchCompleteStats> {
116
const query = reviveQuery(rawQuery);
117
if (handle === this._internalFileSearchHandle) {
118
const start = Date.now();
119
return this.doInternalFileSearch(handle, session, query, token).then(result => {
120
const elapsed = Date.now() - start;
121
this._logService.debug(`Ext host file search time: ${elapsed}ms`);
122
return result;
123
});
124
}
125
126
return super.$provideFileSearchResults(handle, session, rawQuery, token);
127
}
128
129
override async doInternalFileSearchWithCustomCallback(rawQuery: IFileQuery, token: vscode.CancellationToken, handleFileMatch: (data: URI[]) => void): Promise<ISearchCompleteStats> {
130
const onResult = (ev: ISerializedSearchProgressItem) => {
131
if (isSerializedFileMatch(ev)) {
132
ev = [ev];
133
}
134
135
if (Array.isArray(ev)) {
136
handleFileMatch(ev.map(m => URI.file(m.path)));
137
return;
138
}
139
140
if (ev.message) {
141
this._logService.debug('ExtHostSearch', ev.message);
142
}
143
};
144
145
if (!this._internalFileSearchProvider) {
146
throw new Error('No internal file search handler');
147
}
148
const numThreads = await this.getNumThreadsCached();
149
return <Promise<ISearchCompleteStats>>this._internalFileSearchProvider.doFileSearch(rawQuery, numThreads, onResult, token);
150
}
151
152
private async doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: vscode.CancellationToken): Promise<ISearchCompleteStats> {
153
return this.doInternalFileSearchWithCustomCallback(rawQuery, token, (data) => {
154
this._proxy.$handleFileMatch(handle, session, data);
155
});
156
}
157
158
override $clearCache(cacheKey: string): Promise<void> {
159
this._internalFileSearchProvider?.clearCache(cacheKey);
160
161
return super.$clearCache(cacheKey);
162
}
163
164
protected override createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider2): TextSearchManager {
165
return new NativeTextSearchManager(query, provider, undefined, 'textSearchProvider');
166
}
167
}
168
169