Skip to content

feature: make number of ripgrep threads configurable #213511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 69 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
63ba89f
feature: add threads property
SimonSiefke May 26, 2024
43ddea0
add setting
SimonSiefke May 26, 2024
82da18b
use setting
SimonSiefke May 26, 2024
c1f5e28
debug
SimonSiefke May 26, 2024
029a542
add option
SimonSiefke May 26, 2024
36c54b5
fix types
SimonSiefke May 26, 2024
7f56456
use commonquery
SimonSiefke May 26, 2024
5123567
rename argument
SimonSiefke May 26, 2024
b41019e
remove comma
SimonSiefke May 26, 2024
37977b0
add threads for file search
SimonSiefke May 26, 2024
3db497f
set threads to undefined
SimonSiefke May 27, 2024
1f9028d
Merge branch 'main' into feature/ripgrep-threads
SimonSiefke May 30, 2024
5a3d152
update description
SimonSiefke May 30, 2024
aa93896
remove unused code
SimonSiefke May 30, 2024
118a9a6
remove unused code
SimonSiefke May 30, 2024
7977989
Update src/vs/workbench/services/search/node/ripgrepFileSearch.ts
SimonSiefke May 30, 2024
e10e9ae
Update src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts
SimonSiefke May 30, 2024
dbf93b1
use ICommonQueryBuilderOptions
SimonSiefke May 30, 2024
a8df3e8
set threads property from caller
SimonSiefke May 30, 2024
782aaba
simplify code
SimonSiefke May 30, 2024
e35ce48
Discard changes to src/vs/workbench/contrib/search/browser/anythingQu…
SimonSiefke May 30, 2024
d1b74c8
Discard changes to src/vs/workbench/contrib/searchEditor/browser/sear…
SimonSiefke May 30, 2024
c1f070b
remove unused code
SimonSiefke May 30, 2024
ddc3155
Discard changes to src/vs/workbench/services/search/common/textSearch…
SimonSiefke May 30, 2024
a3d2c37
add back code
SimonSiefke May 30, 2024
953862f
fix types
SimonSiefke May 30, 2024
02f2a65
update formatting
SimonSiefke May 30, 2024
79e5388
add semicolon
SimonSiefke May 30, 2024
130d8a1
rename setting
SimonSiefke May 31, 2024
dbc6fe4
use different way to pass numThreads to ripgrep
SimonSiefke May 31, 2024
bd8e2a9
Merge branch 'main' into feature/ripgrep-threads
SimonSiefke May 31, 2024
a5fe5d8
Discard changes to src/vs/workbench/services/search/common/queryBuild…
SimonSiefke May 31, 2024
b59df64
Discard changes to src/vs/workbench/services/search/common/search.ts
SimonSiefke May 31, 2024
306ee73
tsc
SimonSiefke May 31, 2024
0e8ed12
tsc
SimonSiefke May 31, 2024
07961b8
tsc
SimonSiefke May 31, 2024
b194e92
fix imports
SimonSiefke May 31, 2024
abfad64
use configuration service
SimonSiefke Jun 1, 2024
67a944b
tsc
SimonSiefke Jun 1, 2024
0cfb200
tsc
SimonSiefke Jun 1, 2024
681baf6
tsc
SimonSiefke Jun 1, 2024
5fec2b7
Merge remote-tracking branch 'origin/main' into feature/ripgrep-threads
SimonSiefke Jun 3, 2024
6263b32
improve types
SimonSiefke Jun 3, 2024
5ef320e
Update src/vs/workbench/contrib/search/browser/search.contribution.ts
SimonSiefke Jun 3, 2024
22b7557
simplify type
SimonSiefke Jun 3, 2024
a68af22
rename types
SimonSiefke Jun 3, 2024
0c6418c
move numThreads parameter last
SimonSiefke Jun 3, 2024
676cd51
simplify code
SimonSiefke Jun 3, 2024
c0fd9b3
Merge remote-tracking branch 'origin/main' into feature/ripgrep-threads
SimonSiefke Jun 4, 2024
f57ecd5
Update src/vs/workbench/services/search/common/textSearchManager.ts
SimonSiefke Jun 4, 2024
bc2cfaa
Update src/vs/workbench/services/search/common/searchExtTypesInternal.ts
SimonSiefke Jun 4, 2024
0e5f694
Discard changes to src/vs/workbench/services/search/test/node/rawSear…
SimonSiefke Jun 4, 2024
53643a3
fix typo
SimonSiefke Jun 4, 2024
a91edad
fix types
SimonSiefke Jun 4, 2024
f8e8f3a
Merge remote-tracking branch 'origin/main' into feature/ripgrep-threads
SimonSiefke Jun 4, 2024
b6c3171
Discard changes to src/vs/monaco.d.ts
SimonSiefke Jun 4, 2024
4efeb73
Merge remote-tracking branch 'origin/main' into feature/ripgrep-threads
SimonSiefke Jun 5, 2024
38bcbbb
rename interface
SimonSiefke Jun 5, 2024
6bef66d
rename variable
SimonSiefke Jun 5, 2024
9029984
rename setting
SimonSiefke Jun 5, 2024
b91f2b8
rename setting
SimonSiefke Jun 5, 2024
32a68d6
update settings
SimonSiefke Jun 5, 2024
cbffb5d
tsc
SimonSiefke Jun 5, 2024
8ef7b31
fix: pass threads property also below
SimonSiefke Jun 5, 2024
1306f94
Merge branch 'main' into feature/ripgrep-threads
SimonSiefke Jun 5, 2024
8fd3e11
Merge branch 'main' into feature/ripgrep-threads
SimonSiefke Jun 6, 2024
e890453
cache setting
SimonSiefke Jun 6, 2024
21e5b71
use affectsConfiguration
SimonSiefke Jun 6, 2024
9d9bab4
fix test
SimonSiefke Jun 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions src/vs/workbench/api/node/extHostSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import * as pfs from 'vs/base/node/pfs';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { ExtHostSearch, reviveQuery } from 'vs/workbench/api/common/extHostSearch';
Expand All @@ -29,24 +30,59 @@ export class NativeExtHostSearch extends ExtHostSearch implements IDisposable {

private _registeredEHSearchProvider = false;

private _numThreadsPromise: Promise<number | undefined> | undefined;

private readonly _disposables = new DisposableStore();

private isDisposed = false;

constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
@IURITransformerService _uriTransformer: IURITransformerService,
@IExtHostConfiguration private readonly configurationService: IExtHostConfiguration,
@ILogService _logService: ILogService,
) {
super(extHostRpc, _uriTransformer, _logService);

this.getNumThreads = this.getNumThreads.bind(this);
this.getNumThreadsCached = this.getNumThreadsCached.bind(this);
this.handleConfigurationChanged = this.handleConfigurationChanged.bind(this);
const outputChannel = new OutputChannel('RipgrepSearchUD', this._logService);
this._disposables.add(this.registerTextSearchProvider(Schemas.vscodeUserData, new RipgrepSearchProvider(outputChannel)));
this._disposables.add(this.registerTextSearchProvider(Schemas.vscodeUserData, new RipgrepSearchProvider(outputChannel, this.getNumThreadsCached)));
if (initData.remote.isRemote && initData.remote.authority) {
this._registerEHSearchProviders();
}

configurationService.getConfigProvider().then(provider => {
if (this.isDisposed) {
return;
}
this._disposables.add(provider.onDidChangeConfiguration(this.handleConfigurationChanged));
});
}

private handleConfigurationChanged(event: vscode.ConfigurationChangeEvent) {
if (!event.affectsConfiguration('search')) {
return;
}
this._numThreadsPromise = undefined;
}

async getNumThreads(): Promise<number | undefined> {
const configProvider = await this.configurationService.getConfigProvider();
const numThreads = configProvider.getConfiguration('search').get<number>('ripgrep.maxThreads');
return numThreads;
}

async getNumThreadsCached(): Promise<number | undefined> {
if (!this._numThreadsPromise) {
this._numThreadsPromise = this.getNumThreads();
}
return this._numThreadsPromise;
}

dispose(): void {
this.isDisposed = true;
this._disposables.dispose();
}

Expand All @@ -61,8 +97,8 @@ export class NativeExtHostSearch extends ExtHostSearch implements IDisposable {

this._registeredEHSearchProvider = true;
const outputChannel = new OutputChannel('RipgrepSearchEH', this._logService);
this._disposables.add(this.registerTextSearchProvider(Schemas.file, new RipgrepSearchProvider(outputChannel)));
this._disposables.add(this.registerInternalFileSearchProvider(Schemas.file, new SearchService('fileSearchProvider')));
this._disposables.add(this.registerTextSearchProvider(Schemas.file, new RipgrepSearchProvider(outputChannel, this.getNumThreadsCached)));
this._disposables.add(this.registerInternalFileSearchProvider(Schemas.file, new SearchService('fileSearchProvider', this.getNumThreadsCached)));
}

private registerInternalFileSearchProvider(scheme: string, provider: SearchService): IDisposable {
Expand Down Expand Up @@ -90,7 +126,7 @@ export class NativeExtHostSearch extends ExtHostSearch implements IDisposable {
return super.$provideFileSearchResults(handle, session, rawQuery, token);
}

override doInternalFileSearchWithCustomCallback(rawQuery: IFileQuery, token: vscode.CancellationToken, handleFileMatch: (data: URI[]) => void): Promise<ISearchCompleteStats> {
override async doInternalFileSearchWithCustomCallback(rawQuery: IFileQuery, token: vscode.CancellationToken, handleFileMatch: (data: URI[]) => void): Promise<ISearchCompleteStats> {
const onResult = (ev: ISerializedSearchProgressItem) => {
if (isSerializedFileMatch(ev)) {
ev = [ev];
Expand All @@ -109,8 +145,8 @@ export class NativeExtHostSearch extends ExtHostSearch implements IDisposable {
if (!this._internalFileSearchProvider) {
throw new Error('No internal file search handler');
}

return <Promise<ISearchCompleteStats>>this._internalFileSearchProvider.doFileSearch(rawQuery, onResult, token);
const numThreads = await this.getNumThreadsCached();
return <Promise<ISearchCompleteStats>>this._internalFileSearchProvider.doFileSearch(rawQuery, numThreads, onResult, token);
}

private async doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: vscode.CancellationToken): Promise<ISearchCompleteStats> {
Expand Down
21 changes: 21 additions & 0 deletions src/vs/workbench/api/test/node/extHostSearch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { mock } from 'vs/base/test/common/mock';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { NullLogService } from 'vs/platform/log/common/log';
import { MainContext, MainThreadSearchShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration.js';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { Range } from 'vs/workbench/api/common/extHostTypes';
import { URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
Expand Down Expand Up @@ -144,6 +145,26 @@ suite('ExtHostSearch', () => {
rpcProtocol,
new class extends mock<IExtHostInitDataService>() { override remote = { isRemote: false, authority: undefined, connectionData: null }; },
new URITransformerService(null),
new class extends mock<IExtHostConfiguration>() {
override async getConfigProvider(): Promise<ExtHostConfigProvider> {
return {
onDidChangeConfiguration(_listener: (event: vscode.ConfigurationChangeEvent) => void) { },
getConfiguration(): vscode.WorkspaceConfiguration {
return {
get() { },
has() {
return false;
},
inspect() {
return undefined;
},
async update() { }
};
},

} as ExtHostConfigProvider;
}
},
logService
);
this._pfs = mockPFS as any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ configurationRegistry.registerConfiguration({
description: nls.localize('search.quickOpen.includeSymbols', "Whether to include results from a global symbol search in the file results for Quick Open."),
default: false
},
'search.ripgrep.maxThreads': {
type: 'number',
description: nls.localize('search.ripgrep.maxThreads', "Number of threads to use for searching. When set to 0, the engine automatically determines this value."),
default: 0
},
'search.quickOpen.includeHistory': {
type: 'boolean',
description: nls.localize('search.quickOpen.includeHistory', "Whether to include results from recently opened files in the file results for Quick Open."),
Expand Down
13 changes: 13 additions & 0 deletions src/vs/workbench/services/search/common/searchExtTypesInternal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { FileSearchOptions, TextSearchOptions } from './searchExtTypes';

interface RipgrepSearchOptionsCommon {
numThreads?: number;
}

export interface RipgrepTextSearchOptions extends TextSearchOptions, RipgrepSearchOptionsCommon { }

export interface RipgrepFileSearchOptions extends FileSearchOptions, RipgrepSearchOptionsCommon { }
14 changes: 8 additions & 6 deletions src/vs/workbench/services/search/node/fileSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class FileWalker {
killCmds.forEach(cmd => cmd());
}

walk(folderQueries: IFolderQuery[], extraFiles: URI[], onResult: (result: IRawFileMatch) => void, onMessage: (message: IProgressMessage) => void, done: (error: Error | null, isLimitHit: boolean) => void): void {
walk(folderQueries: IFolderQuery[], extraFiles: URI[], numThreads: number | undefined, onResult: (result: IRawFileMatch) => void, onMessage: (message: IProgressMessage) => void, done: (error: Error | null, isLimitHit: boolean) => void): void {
this.fileWalkSW = StopWatch.create(false);

// Support that the file pattern is a full path to a file that exists
Expand All @@ -128,7 +128,7 @@ export class FileWalker {

// For each root folder
this.parallel<IFolderQuery, void>(folderQueries, (folderQuery: IFolderQuery, rootFolderDone: (err: Error | null, result: void) => void) => {
this.call(this.cmdTraversal, this, folderQuery, onResult, onMessage, (err?: Error) => {
this.call(this.cmdTraversal, this, folderQuery, numThreads, onResult, onMessage, (err?: Error) => {
if (err) {
const errorMessage = toErrorMessage(err);
console.error(errorMessage);
Expand Down Expand Up @@ -181,7 +181,7 @@ export class FileWalker {
}
}

private cmdTraversal(folderQuery: IFolderQuery, onResult: (result: IRawFileMatch) => void, onMessage: (message: IProgressMessage) => void, cb: (err?: Error) => void): void {
private cmdTraversal(folderQuery: IFolderQuery, numThreads: number | undefined, onResult: (result: IRawFileMatch) => void, onMessage: (message: IProgressMessage) => void, cb: (err?: Error) => void): void {
const rootFolder = folderQuery.folder.fsPath;
const isMac = platform.isMacintosh;

Expand All @@ -196,7 +196,7 @@ export class FileWalker {
let leftover = '';
const tree = this.initDirectoryTree();

const ripgrep = spawnRipgrepCmd(this.config, folderQuery, this.config.includePattern, this.folderExcludePatterns.get(folderQuery.folder.fsPath)!.expression);
const ripgrep = spawnRipgrepCmd(this.config, folderQuery, this.config.includePattern, this.folderExcludePatterns.get(folderQuery.folder.fsPath)!.expression, numThreads);
const cmd = ripgrep.cmd;
const noSiblingsClauses = !Object.keys(ripgrep.siblingClauses).length;

Expand Down Expand Up @@ -628,16 +628,18 @@ export class Engine implements ISearchEngine<IRawFileMatch> {
private folderQueries: IFolderQuery[];
private extraFiles: URI[];
private walker: FileWalker;
private numThreads?: number;

constructor(config: IFileQuery) {
constructor(config: IFileQuery, numThreads?: number) {
this.folderQueries = config.folderQueries;
this.extraFiles = config.extraFileResources || [];
this.numThreads = numThreads;

this.walker = new FileWalker(config);
}

search(onResult: (result: IRawFileMatch) => void, onProgress: (progress: IProgressMessage) => void, done: (error: Error | null, complete: ISearchEngineSuccess) => void): void {
this.walker.walk(this.folderQueries, this.extraFiles, onResult, onProgress, (err: Error | null, isLimitHit: boolean) => {
this.walker.walk(this.folderQueries, this.extraFiles, this.numThreads, onResult, onProgress, (err: Error | null, isLimitHit: boolean) => {
done(err, {
limitHit: isLimitHit,
stats: this.walker.getStats(),
Expand Down
22 changes: 12 additions & 10 deletions src/vs/workbench/services/search/node/rawSearchService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ export class SearchService implements IRawSearchService {

private caches: { [cacheKey: string]: Cache } = Object.create(null);

constructor(private readonly processType: IFileSearchStats['type'] = 'searchProcess') { }
constructor(private readonly processType: IFileSearchStats['type'] = 'searchProcess', private readonly getNumThreads?: () => Promise<number | undefined>) { }

fileSearch(config: IRawFileQuery): Event<ISerializedSearchProgressItem | ISerializedSearchComplete> {
let promise: CancelablePromise<ISerializedSearchSuccess>;

const query = reviveQuery(config);
const emitter = new Emitter<ISerializedSearchProgressItem | ISerializedSearchComplete>({
onDidAddFirstListener: () => {
promise = createCancelablePromise(token => {
return this.doFileSearchWithEngine(FileSearchEngine, query, p => emitter.fire(p), token);
promise = createCancelablePromise(async token => {
const numThreads = await this.getNumThreads?.();
return this.doFileSearchWithEngine(FileSearchEngine, query, p => emitter.fire(p), token, SearchService.BATCH_SIZE, numThreads);
});

promise.then(
Expand Down Expand Up @@ -72,9 +73,10 @@ export class SearchService implements IRawSearchService {
return emitter.event;
}

private ripgrepTextSearch(config: ITextQuery, progressCallback: IProgressCallback, token: CancellationToken): Promise<ISerializedSearchSuccess> {
private async ripgrepTextSearch(config: ITextQuery, progressCallback: IProgressCallback, token: CancellationToken): Promise<ISerializedSearchSuccess> {
config.maxFileSize = this.getPlatformFileLimits().maxFileSize;
const engine = new TextSearchEngineAdapter(config);
const numThreads = await this.getNumThreads?.();
const engine = new TextSearchEngineAdapter(config, numThreads);

return engine.search(token, progressCallback, progressCallback);
}
Expand All @@ -85,11 +87,11 @@ export class SearchService implements IRawSearchService {
};
}

doFileSearch(config: IFileQuery, progressCallback: IProgressCallback, token?: CancellationToken): Promise<ISerializedSearchSuccess> {
return this.doFileSearchWithEngine(FileSearchEngine, config, progressCallback, token);
doFileSearch(config: IFileQuery, numThreads: number | undefined, progressCallback: IProgressCallback, token?: CancellationToken): Promise<ISerializedSearchSuccess> {
return this.doFileSearchWithEngine(FileSearchEngine, config, progressCallback, token, SearchService.BATCH_SIZE, numThreads);
}

doFileSearchWithEngine(EngineClass: { new(config: IFileQuery): ISearchEngine<IRawFileMatch> }, config: IFileQuery, progressCallback: IProgressCallback, token?: CancellationToken, batchSize = SearchService.BATCH_SIZE): Promise<ISerializedSearchSuccess> {
doFileSearchWithEngine(EngineClass: { new(config: IFileQuery, numThreads?: number | undefined): ISearchEngine<IRawFileMatch> }, config: IFileQuery, progressCallback: IProgressCallback, token?: CancellationToken, batchSize = SearchService.BATCH_SIZE, threads?: number): Promise<ISerializedSearchSuccess> {
let resultCount = 0;
const fileProgressCallback: IFileProgressCallback = progress => {
if (Array.isArray(progress)) {
Expand All @@ -107,7 +109,7 @@ export class SearchService implements IRawSearchService {
let sortedSearch = this.trySortedSearchFromCache(config, fileProgressCallback, token);
if (!sortedSearch) {
const walkerConfig = config.maxResults ? Object.assign({}, config, { maxResults: null }) : config;
const engine = new EngineClass(walkerConfig);
const engine = new EngineClass(walkerConfig, threads);
sortedSearch = this.doSortedSearch(engine, config, progressCallback, fileProgressCallback, token);
}

Expand All @@ -120,7 +122,7 @@ export class SearchService implements IRawSearchService {
});
}

const engine = new EngineClass(config);
const engine = new EngineClass(config, threads);

return this.doSearch(engine, fileProgressCallback, batchSize, token).then(complete => {
return {
Expand Down
10 changes: 7 additions & 3 deletions src/vs/workbench/services/search/node/ripgrepFileSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import { rgPath } from '@vscode/ripgrep';
// If @vscode/ripgrep is in an .asar file, then the binary is unpacked.
const rgDiskPath = rgPath.replace(/\bnode_modules\.asar\b/, 'node_modules.asar.unpacked');

export function spawnRipgrepCmd(config: IFileQuery, folderQuery: IFolderQuery, includePattern?: glob.IExpression, excludePattern?: glob.IExpression) {
const rgArgs = getRgArgs(config, folderQuery, includePattern, excludePattern);
export function spawnRipgrepCmd(config: IFileQuery, folderQuery: IFolderQuery, includePattern?: glob.IExpression, excludePattern?: glob.IExpression, numThreads?: number) {
const rgArgs = getRgArgs(config, folderQuery, includePattern, excludePattern, numThreads);
const cwd = folderQuery.folder.fsPath;
return {
cmd: cp.spawn(rgDiskPath, rgArgs.args, { cwd }),
Expand All @@ -29,7 +29,7 @@ export function spawnRipgrepCmd(config: IFileQuery, folderQuery: IFolderQuery, i
};
}

function getRgArgs(config: IFileQuery, folderQuery: IFolderQuery, includePattern?: glob.IExpression, excludePattern?: glob.IExpression) {
function getRgArgs(config: IFileQuery, folderQuery: IFolderQuery, includePattern?: glob.IExpression, excludePattern?: glob.IExpression, numThreads?: number) {
const args = ['--files', '--hidden', '--case-sensitive', '--no-require-git'];

// includePattern can't have siblingClauses
Expand Down Expand Up @@ -71,6 +71,10 @@ function getRgArgs(config: IFileQuery, folderQuery: IFolderQuery, includePattern
args.push('--quiet');
}

if (numThreads) {
args.push('--threads', `${numThreads}`);
}

args.push('--no-config');
if (folderQuery.disregardGlobalIgnoreFiles) {
args.push('--no-ignore-global');
Expand Down
18 changes: 12 additions & 6 deletions src/vs/workbench/services/search/node/ripgrepSearchProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,33 @@
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUtils';
import { RipgrepTextSearchEngine } from 'vs/workbench/services/search/node/ripgrepTextSearchEngine';
import { TextSearchProvider, TextSearchComplete, TextSearchResult, TextSearchQuery, TextSearchOptions } from 'vs/workbench/services/search/common/searchExtTypes';
import { TextSearchProvider, TextSearchComplete, TextSearchResult, TextSearchQuery, TextSearchOptions, } from 'vs/workbench/services/search/common/searchExtTypes';
import { Progress } from 'vs/platform/progress/common/progress';
import { Schemas } from 'vs/base/common/network';
import type { RipgrepTextSearchOptions } from 'vs/workbench/services/search/common/searchExtTypesInternal';

export class RipgrepSearchProvider implements TextSearchProvider {
private inProgress: Set<CancellationTokenSource> = new Set();

constructor(private outputChannel: OutputChannel) {
constructor(private outputChannel: OutputChannel, private getNumThreads: () => Promise<number | undefined>) {
process.once('exit', () => this.dispose());
}

provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress<TextSearchResult>, token: CancellationToken): Promise<TextSearchComplete> {
const engine = new RipgrepTextSearchEngine(this.outputChannel);
async provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: Progress<TextSearchResult>, token: CancellationToken): Promise<TextSearchComplete> {
const numThreads = await this.getNumThreads();
const engine = new RipgrepTextSearchEngine(this.outputChannel, numThreads);
const extendedOptions: RipgrepTextSearchOptions = {
...options,
numThreads,
};
if (options.folder.scheme === Schemas.vscodeUserData) {
// Ripgrep search engine can only provide file-scheme results, but we want to use it to search some schemes that are backed by the filesystem, but with some other provider as the frontend,
// case in point vscode-userdata. In these cases we translate the query to a file, and translate the results back to the frontend scheme.
const translatedOptions = { ...options, folder: options.folder.with({ scheme: Schemas.file }) };
const translatedOptions = { ...extendedOptions, folder: options.folder.with({ scheme: Schemas.file }) };
const progressTranslator = new Progress<TextSearchResult>(data => progress.report({ ...data, uri: data.uri.with({ scheme: options.folder.scheme }) }));
return this.withToken(token, token => engine.provideTextSearchResults(query, translatedOptions, progressTranslator, token));
} else {
return this.withToken(token, token => engine.provideTextSearchResults(query, options, progress, token));
return this.withToken(token, token => engine.provideTextSearchResults(query, extendedOptions, progress, token));
}
}

Expand Down
Loading
Loading