MCPcopy Create free account
hub / github.com/microsoft/vscode-cpptools / FastFinder

Class FastFinder

Extension/src/Utility/Filesystem/ripgrep.ts:26–95  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

24}
25
26export class FastFinder implements AsyncIterable<string> {
27 private keepOnlyExecutables: boolean;
28 private executableExtensions = new Array<string>();
29 private processes = new Array<Instance<Process>>();
30 private pending = 0;
31 private readyToComplete = false;
32 private distinct = new Set<string>();
33
34 #files = accumulator<string>().autoComplete(false);
35
36 [Symbol.asyncIterator](): AsyncIterator<string> {
37 this.readyToComplete = true;
38 if (this.pending === 0) {
39 this.#files.complete();
40 }
41
42 return this.#files[Symbol.asyncIterator]();
43 }
44
45 constructor(private fileGlobs: string[], options?: { executable?: boolean; executableExtensions?: string[] }) {
46 strict(ripgrep, 'initRipGrep must be called before using FastFinder');
47
48 this.keepOnlyExecutables = options?.executable ?? false;
49 if (this.keepOnlyExecutables && process.platform === 'win32') {
50 this.executableExtensions = options?.executableExtensions ?? ['.exe', '.bat', '.cmd', '.ps1'];
51 }
52 }
53
54 /**
55 * Add one or more locations to scan, with an optionally specified depth.
56 *
57 * The scanning of those locations begins immediately and is done asynchronously.
58 *
59 */
60 scan(...location: string[]): FastFinder;
61 scan(depth: number, ...location: string[]): FastFinder;
62 scan(...location: (string | number)[]): FastFinder {
63 const depth = (typeof location[0] === 'number' ? location.shift() as number : 0) + 1;
64 const globs = this.executableExtensions.length ?
65 this.fileGlobs.map(glob => this.executableExtensions.map(ext => glob.includes('**') ? glob : `**/${glob}${ext}`)).flat() :
66 this.fileGlobs.map(glob => glob.includes('**') ? glob : `**/${glob}`);
67
68 // only search locations that exist
69 location = location.filter(each => existsSync(each.toString()));
70
71 // only search if there are globs and locations to search
72 if (globs.length && location.length) {
73 this.pending++;
74 void ripgrep!(...globs.map(each => ['--glob', each]).flat(), '--max-depth', depth, '--null-data', '--no-messages', '-L', '--files', ...location.map(each => each.toString())).then(async proc => {
75 const process = proc as unknown as Instance<Process>;
76 this.processes.push(process);
77 for await (const line of process.stdio) {
78 if (this.distinct.has(line)) {
79 continue;
80 }
81 this.distinct.add(line);
82 if (!this.keepOnlyExecutables || await filepath.isExecutable(line)) {
83 this.#files.add(line);

Callers

nothing calls this directly

Calls 1

accumulatorFunction · 0.90

Tested by

no test coverage detected