Skip to content

Commit c2aa3c4

Browse files
authored
let findfiles2new use an array of includes/excludes (microsoft#226103)
* let findfiles2new use an array of includes/excludes
1 parent 7e31cc0 commit c2aa3c4

File tree

3 files changed

+114
-71
lines changed

3 files changed

+114
-71
lines changed

extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ suite('vscode API - workspace', () => {
619619

620620
test('findFiles2, exclude', () => {
621621
return vscode.workspace.findFiles2('**/image.png', { exclude: '**/sub/**' }).then((res) => {
622+
res.forEach(r => console.log(r.toString()));
622623
assert.strictEqual(res.length, 1);
623624
});
624625
});

src/vs/workbench/api/common/extHost.api.impl.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -965,18 +965,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
965965
},
966966
findFiles2New: (filePattern: vscode.GlobPattern[], options?: vscode.FindFiles2OptionsNew, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> => {
967967
checkProposedApiEnabled(extension, 'findFiles2New');
968-
969-
const oldOptions = {
970-
exclude: options?.exclude && options.exclude.length > 0 ? options.exclude[0] : undefined,
971-
useDefaultExcludes: !options?.useExcludeSettings || (options?.useExcludeSettings === ExcludeSettingOptions.FilesExclude || options?.useExcludeSettings === ExcludeSettingOptions.SearchAndFilesExclude),
972-
useDefaultSearchExcludes: !options?.useExcludeSettings || (options?.useExcludeSettings === ExcludeSettingOptions.SearchAndFilesExclude),
973-
maxResults: options?.maxResults,
974-
useIgnoreFiles: options?.useIgnoreFiles?.local,
975-
useGlobalIgnoreFiles: options?.useIgnoreFiles?.global,
976-
useParentIgnoreFiles: options?.useIgnoreFiles?.parent,
977-
followSymlinks: options?.followSymlinks,
978-
};
979-
return extHostWorkspace.findFiles2(filePattern && filePattern.length > 0 ? filePattern[0] : undefined, oldOptions, extension.identifier, token);
968+
return extHostWorkspace.findFiles2New(filePattern, options, extension.identifier, token);
980969
},
981970
findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback: vscode.FindTextInFilesOptions | ((result: vscode.TextSearchResult) => void), callbackOrToken?: vscode.CancellationToken | ((result: vscode.TextSearchResult) => void), token?: vscode.CancellationToken) => {
982971
checkProposedApiEnabled(extension, 'findTextInFiles');

src/vs/workbench/api/common/extHostWorkspace.ts

Lines changed: 112 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
7979
index: number;
8080
}
8181

82-
interface QueryOptions {
83-
options: ITextQueryBuilderOptions;
82+
interface QueryOptions<T> {
83+
options: T;
8484
folder: URI | undefined;
8585
}
8686

@@ -466,12 +466,15 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
466466
excludeString = exclude.pattern;
467467
}
468468
}
469+
470+
// todo: consider exclude baseURI if available
469471
return this._findFilesImpl(include, undefined, {
470-
exclude: excludeString,
472+
exclude: [excludeString],
471473
maxResults,
472-
useDefaultExcludes: useFileExcludes,
473-
useDefaultSearchExcludes: false,
474-
useIgnoreFiles: false
474+
useExcludeSettings: useFileExcludes ? ExcludeSettingOptions.FilesExclude : ExcludeSettingOptions.None,
475+
useIgnoreFiles: {
476+
local: false
477+
}
475478
}, token);
476479
}
477480

@@ -480,74 +483,100 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
480483
extensionId: ExtensionIdentifier,
481484
token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
482485
this._logService.trace(`extHostWorkspace#findFiles2: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles2`);
483-
return this._findFilesImpl(undefined, filePattern, options, token);
486+
487+
488+
const useDefaultExcludes = options.useDefaultExcludes ?? true;
489+
const useDefaultSearchExcludes = options.useDefaultSearchExcludes ?? true;
490+
const excludeSetting = useDefaultExcludes ?
491+
(useDefaultSearchExcludes ? ExcludeSettingOptions.SearchAndFilesExclude : ExcludeSettingOptions.FilesExclude) :
492+
ExcludeSettingOptions.None;
493+
const newOptions: vscode.FindFiles2OptionsNew = {
494+
exclude: options.exclude ? [options.exclude] : undefined,
495+
useIgnoreFiles: {
496+
local: options.useIgnoreFiles,
497+
global: options.useGlobalIgnoreFiles,
498+
parent: options.useParentIgnoreFiles
499+
},
500+
useExcludeSettings: excludeSetting,
501+
followSymlinks: options.followSymlinks,
502+
maxResults: options.maxResults,
503+
};
504+
return this._findFilesImpl(undefined, filePattern !== undefined ? [filePattern] : [], newOptions, token);
505+
}
506+
507+
findFiles2New(filePatterns: vscode.GlobPattern[],
508+
options: vscode.FindFiles2OptionsNew = {},
509+
extensionId: ExtensionIdentifier,
510+
token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
511+
this._logService.trace(`extHostWorkspace#findFiles2New: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles2New`);
512+
return this._findFilesImpl(undefined, filePatterns, options, token);
484513
}
485514

486515
private async _findFilesImpl(
487516
// the old `findFiles` used `include` to query, but the new `findFiles2` uses `filePattern` to query.
488517
// `filePattern` is the proper way to handle this, since it takes less precedence than the ignore files.
489518
include: vscode.GlobPattern | undefined,
490-
filePattern: vscode.GlobPattern | undefined,
491-
options: vscode.FindFiles2Options,
519+
filePatterns: vscode.GlobPattern[] | undefined,
520+
options: vscode.FindFiles2OptionsNew,
492521
token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
493522
if (token && token.isCancellationRequested) {
494523
return Promise.resolve([]);
495524
}
496525

497-
const excludePattern = (typeof options.exclude === 'string') ? options.exclude :
498-
options.exclude ? options.exclude.pattern : undefined;
499526

500-
const fileQueries: IFileQueryBuilderOptions = {
501-
ignoreSymlinks: typeof options.followSymlinks === 'boolean' ? !options.followSymlinks : undefined,
502-
disregardIgnoreFiles: typeof options.useIgnoreFiles === 'boolean' ? !options.useIgnoreFiles : undefined,
503-
disregardGlobalIgnoreFiles: typeof options.useGlobalIgnoreFiles === 'boolean' ? !options.useGlobalIgnoreFiles : undefined,
504-
disregardParentIgnoreFiles: typeof options.useParentIgnoreFiles === 'boolean' ? !options.useParentIgnoreFiles : undefined,
505-
disregardExcludeSettings: typeof options.useDefaultExcludes === 'boolean' ? !options.useDefaultExcludes : false,
506-
disregardSearchExcludeSettings: typeof options.useDefaultSearchExcludes === 'boolean' ? !options.useDefaultSearchExcludes : false,
507-
maxResults: options.maxResults,
508-
excludePattern: excludePattern ? [{ pattern: excludePattern }] : undefined,
509-
shouldGlobSearch: typeof options.fuzzy === 'boolean' ? !options.fuzzy : true,
510-
_reason: 'startFileSearch'
511-
};
512-
const parseInclude = parseSearchExcludeInclude(GlobPattern.from(include ?? filePattern));
513-
const folderToUse: URI | undefined = parseInclude?.folder;
514-
if (include) {
515-
fileQueries.includePattern = parseInclude?.pattern;
516-
} else {
517-
fileQueries.filePattern = parseInclude?.pattern;
518-
}
527+
const filePatternsToUse = include !== undefined ? [include] : filePatterns;
528+
const queryOptions: QueryOptions<IFileQueryBuilderOptions>[] = filePatternsToUse?.map(filePattern => {
519529

520-
return this._proxy.$startFileSearch(
521-
folderToUse ?? null,
522-
fileQueries,
523-
token
524-
)
525-
.then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : []);
530+
const excludePatterns = globsToISearchPatternBuilder(options.exclude);
531+
532+
const fileQueries: IFileQueryBuilderOptions = {
533+
ignoreSymlinks: typeof options.followSymlinks === 'boolean' ? !options.followSymlinks : undefined,
534+
disregardIgnoreFiles: typeof options.useIgnoreFiles?.local === 'boolean' ? !options.useIgnoreFiles.local : undefined,
535+
disregardGlobalIgnoreFiles: typeof options.useIgnoreFiles?.global === 'boolean' ? !options.useIgnoreFiles.global : undefined,
536+
disregardParentIgnoreFiles: typeof options.useIgnoreFiles?.parent === 'boolean' ? !options.useIgnoreFiles.parent : undefined,
537+
disregardExcludeSettings: options.useExcludeSettings !== undefined && options.useExcludeSettings === ExcludeSettingOptions.None,
538+
disregardSearchExcludeSettings: options.useExcludeSettings !== undefined && (options.useExcludeSettings !== ExcludeSettingOptions.SearchAndFilesExclude),
539+
maxResults: options.maxResults,
540+
excludePattern: excludePatterns.length > 0 ? excludePatterns : undefined,
541+
_reason: 'startFileSearch',
542+
shouldGlobSearch: include ? undefined : true,
543+
};
544+
545+
const parseInclude = parseSearchExcludeInclude(GlobPattern.from(filePattern));
546+
const folderToUse = parseInclude?.folder;
547+
if (include) {
548+
fileQueries.includePattern = parseInclude?.pattern;
549+
} else {
550+
fileQueries.filePattern = parseInclude?.pattern;
551+
}
552+
return {
553+
folder: folderToUse,
554+
options: fileQueries
555+
};
556+
}) ?? [];
557+
558+
return this._findFilesBase(queryOptions, token);
559+
}
560+
561+
private async _findFilesBase(
562+
queryOptions: QueryOptions<IFileQueryBuilderOptions>[] | undefined,
563+
token: CancellationToken
564+
): Promise<vscode.Uri[]> {
565+
const result = await Promise.all(queryOptions?.map(option => this._proxy.$startFileSearch(
566+
option.folder ?? null,
567+
option.options,
568+
token).then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : [])
569+
) ?? []);
570+
571+
return result.flat();
526572
}
573+
527574
findTextInFilesNew(query: vscode.TextSearchQueryNew, extensionId: ExtensionIdentifier, options?: vscode.FindTextInFilesOptionsNew, token?: vscode.CancellationToken): vscode.FindTextInFilesResponse {
528575
this._logService.trace(`extHostWorkspace#findTextInFilesNew: textSearch, extension: ${extensionId.value}, entryPoint: findTextInFilesNew`);
529-
const queryOptionsRaw: (QueryOptions | undefined)[] = ((options?.include?.map((include) => {
576+
const queryOptionsRaw: (QueryOptions<ITextQueryBuilderOptions> | undefined)[] = ((options?.include?.map((include) => {
530577
const parsedInclude = parseSearchExcludeInclude(GlobPattern.from(include));
531578

532-
const excludePatterns = (
533-
options.exclude?.map((exclude): ISearchPatternBuilder | undefined => {
534-
if (typeof exclude === 'string') {
535-
return {
536-
pattern: exclude,
537-
uri: undefined
538-
} satisfies ISearchPatternBuilder;
539-
} else {
540-
const parsedExclude = parseSearchExcludeInclude(exclude);
541-
if (!parsedExclude) {
542-
return undefined;
543-
}
544-
return {
545-
pattern: parsedExclude.pattern,
546-
uri: parsedExclude.folder
547-
} satisfies ISearchPatternBuilder;
548-
}
549-
}) ?? []
550-
).filter((e): e is ISearchPatternBuilder => !!e);
579+
const excludePatterns = globsToISearchPatternBuilder(options.exclude);
551580
return {
552581
options: {
553582

@@ -569,10 +598,10 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
569598
excludePattern: excludePatterns
570599
} satisfies ITextQueryBuilderOptions,
571600
folder: parsedInclude?.folder
572-
} satisfies QueryOptions;
601+
} satisfies QueryOptions<ITextQueryBuilderOptions>;
573602
}))) ?? [];
574603

575-
const queryOptions = queryOptionsRaw.filter((queryOps): queryOps is QueryOptions => !!queryOps);
604+
const queryOptions = queryOptionsRaw.filter((queryOps): queryOps is QueryOptions<ITextQueryBuilderOptions> => !!queryOps);
576605

577606
const complete: Promise<undefined | vscode.TextSearchComplete> = Promise.resolve(undefined);
578607

@@ -620,7 +649,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
620649
}
621650

622651

623-
async findTextInFilesBase(query: vscode.TextSearchQuery, queryOptions: QueryOptions[] | undefined, callback: (result: ITextSearchResult<URI>, uri: URI) => void, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete> {
652+
async findTextInFilesBase(query: vscode.TextSearchQuery, queryOptions: QueryOptions<ITextQueryBuilderOptions>[] | undefined, callback: (result: ITextSearchResult<URI>, uri: URI) => void, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete> {
624653
const requestId = this._requestIdProvider.getNext();
625654

626655
const isCanceled = false;
@@ -943,3 +972,27 @@ interface IExtensionListener<E> {
943972
(e: E): any;
944973
}
945974

975+
function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined): ISearchPatternBuilder[] {
976+
return (
977+
excludes?.map((exclude): ISearchPatternBuilder | undefined => {
978+
if (typeof exclude === 'string') {
979+
if (exclude === '') {
980+
return undefined;
981+
}
982+
return {
983+
pattern: exclude,
984+
uri: undefined
985+
} satisfies ISearchPatternBuilder;
986+
} else {
987+
const parsedExclude = parseSearchExcludeInclude(exclude);
988+
if (!parsedExclude) {
989+
return undefined;
990+
}
991+
return {
992+
pattern: parsedExclude.pattern,
993+
uri: parsedExclude.folder
994+
} satisfies ISearchPatternBuilder;
995+
}
996+
}) ?? []
997+
).filter((e): e is ISearchPatternBuilder => !!e);
998+
}

0 commit comments

Comments
 (0)