Skip to content

Commit

Permalink
introduce findFiles2 API (#203844)
Browse files Browse the repository at this point in the history
* introduce first version of FindFiles2 API
  • Loading branch information
andreamah authored Feb 7, 2024
1 parent 6c7362f commit 20d1817
Show file tree
Hide file tree
Showing 10 changed files with 391 additions and 44 deletions.
1 change: 1 addition & 0 deletions extensions/vscode-api-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"extensionsAny",
"externalUriOpener",
"fileSearchProvider",
"findFiles2",
"findTextInFiles",
"fsChunks",
"interactive",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,45 @@ suite('vscode API - workspace', () => {
});
});

test('`findFiles2`', () => {
return vscode.workspace.findFiles2('*image.png').then((res) => {
assert.strictEqual(res.length, 4);
// TODO: see why this is fuzzy matching
});
});

test('findFiles2 - null exclude', async () => {
await vscode.workspace.findFiles2('**/file.txt', { useDefaultExcludes: true, useDefaultSearchExcludes: false }).then((res) => {
// file.exclude folder is still searched, search.exclude folder is not
assert.strictEqual(res.length, 1);
assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt');
});

await vscode.workspace.findFiles2('**/file.txt', { useDefaultExcludes: false, useDefaultSearchExcludes: false }).then((res) => {
// search.exclude and files.exclude folders are both searched
assert.strictEqual(res.length, 2);
assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt');
});
});

test('findFiles2, exclude', () => {
return vscode.workspace.findFiles2('*image.png', { exclude: '**/sub/**' }).then((res) => {
assert.strictEqual(res.length, 3);
// TODO: see why this is fuzzy matching
});
});

test('findFiles2, cancellation', () => {

const source = new vscode.CancellationTokenSource();
const token = source.token; // just to get an instance first
source.cancel();

return vscode.workspace.findFiles2('*.js', {}, token).then((res) => {
assert.deepStrictEqual(res, []);
});
});

test('findTextInFiles', async () => {
const options: vscode.FindTextInFilesOptions = {
include: '*.ts',
Expand Down
15 changes: 4 additions & 11 deletions src/vs/workbench/api/browser/mainThreadWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { WorkspaceTrustRequestOptions, IWorkspaceTrustManagementService, IWorksp
import { IWorkspace, IWorkspaceContextService, WorkbenchState, isUntitledWorkspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { checkGlobFileExists } from 'vs/workbench/services/extensions/common/workspaceContains';
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder';
import { IFileQueryBuilderOptions, ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder';
import { IEditorService, ISaveEditorsResult } from 'vs/workbench/services/editor/common/editorService';
import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
Expand Down Expand Up @@ -140,21 +140,14 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {

// --- search ---

$startFileSearch(includePattern: string | null, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise<UriComponents[] | null> {
$startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<UriComponents[] | null> {
const includeFolder = URI.revive(_includeFolder);
const workspace = this._contextService.getWorkspace();

const query = this._queryBuilder.file(
includeFolder ? [includeFolder] : workspace.folders,
{
maxResults: maxResults ?? undefined,
disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined,
disregardSearchExcludeSettings: true,
disregardIgnoreFiles: true,
includePattern: includePattern ?? undefined,
excludePattern: typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined,
_reason: 'startFileSearch'
});
options
);

return this._searchService.fileSearch(query, token).then(result => {
return result.results.map(m => m.resource);
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// Note, undefined/null have different meanings on "exclude"
return extHostWorkspace.findFiles(include, exclude, maxResults, extension.identifier, token);
},
findFiles2: (filePattern, options?, token?) => {
return extHostWorkspace.findFiles2(filePattern, options, extension.identifier, token);
},
findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback: vscode.FindTextInFilesOptions | ((result: vscode.TextSearchResult) => void), callbackOrToken?: vscode.CancellationToken | ((result: vscode.TextSearchResult) => void), token?: vscode.CancellationToken) => {
checkProposedApiEnabled(extension, 'findTextInFiles');
let options: vscode.FindTextInFilesOptions;
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import { Dto, IRPCProtocol, SerializableObjectWithBuffers, createProxyIdentifier
import { ILanguageStatus } from 'vs/workbench/services/languageStatus/common/languageStatusService';
import { OutputChannelUpdateMode } from 'vs/workbench/services/output/common/output';
import { CandidatePort } from 'vs/workbench/services/remote/common/tunnelModel';
import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
import { IFileQueryBuilderOptions, ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
import * as search from 'vs/workbench/services/search/common/search';
import { ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';

Expand Down Expand Up @@ -1341,7 +1341,7 @@ export interface ITextSearchComplete {
}

export interface MainThreadWorkspaceShape extends IDisposable {
$startFileSearch(includePattern: string | null, includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise<UriComponents[] | null>;
$startFileSearch(includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<UriComponents[] | null>;
$startTextSearch(query: search.IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null>;
$checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
$save(uri: UriComponents, options: { saveAs: boolean }): Promise<UriComponents | undefined>;
Expand Down
70 changes: 58 additions & 12 deletions src/vs/workbench/api/common/extHostWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { GlobPattern } from 'vs/workbench/api/common/extHostTypeConverters';
import { Range } from 'vs/workbench/api/common/extHostTypes';
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
import { IFileQueryBuilderOptions, ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
import { IRawFileMatch2, ITextSearchResult, resultIsMatch } from 'vs/workbench/services/search/common/search';
import * as vscode from 'vscode';
import { ExtHostWorkspaceShape, IRelativePatternDto, IWorkspaceData, MainContext, MainThreadMessageOptions, MainThreadMessageServiceShape, MainThreadWorkspaceShape } from './extHost.protocol';
Expand Down Expand Up @@ -446,27 +446,73 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
findFiles(include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | null | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`);

let excludePatternOrDisregardExcludes: string | false | undefined = undefined;
let excludeString: string = '';
let useFileExcludes = true;
if (exclude === null) {
excludePatternOrDisregardExcludes = false;
} else if (exclude) {
useFileExcludes = false;
} else if (exclude !== undefined) {
if (typeof exclude === 'string') {
excludePatternOrDisregardExcludes = exclude;
excludeString = exclude;
} else {
excludePatternOrDisregardExcludes = exclude.pattern;
excludeString = exclude.pattern;
}
}

return this._findFilesImpl(include, undefined, {
exclude: excludeString,
maxResults,
useDefaultExcludes: useFileExcludes,
useDefaultSearchExcludes: false,
useIgnoreFiles: true
}, token);
}

findFiles2(filePattern: vscode.GlobPattern | undefined,
options: vscode.FindFiles2Options = {},
extensionId: ExtensionIdentifier,
token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
this._logService.trace(`extHostWorkspace#findFiles2: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles2`);
return this._findFilesImpl(undefined, filePattern, options, token);
}

private async _findFilesImpl(
// the old `findFiles` used `include` to query, but the new `findFiles2` uses `filePattern` to query.
// `filePattern` is the proper way to handle this, since it takes less precedence than the ignore files.
include: vscode.GlobPattern | undefined,
filePattern: vscode.GlobPattern | undefined,
options: vscode.FindFiles2Options,
token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.Uri[]> {
if (token && token.isCancellationRequested) {
return Promise.resolve([]);
}

const { includePattern, folder } = parseSearchInclude(GlobPattern.from(include));
const excludePattern = (typeof options.exclude === 'string') ? options.exclude :
options.exclude ? options.exclude.pattern : undefined;

const fileQueries = <IFileQueryBuilderOptions>{
ignoreSymlinks: typeof options.followSymlinks === 'boolean' ? !options.followSymlinks : undefined,
disregardIgnoreFiles: typeof options.useIgnoreFiles === 'boolean' ? !options.useIgnoreFiles : undefined,
disregardGlobalIgnoreFiles: typeof options.useGlobalIgnoreFiles === 'boolean' ? !options.useGlobalIgnoreFiles : undefined,
disregardParentIgnoreFiles: typeof options.useParentIgnoreFiles === 'boolean' ? !options.useParentIgnoreFiles : undefined,
disregardExcludeSettings: typeof options.useDefaultExcludes === 'boolean' ? !options.useDefaultExcludes : false,
disregardSearchExcludeSettings: typeof options.useDefaultSearchExcludes === 'boolean' ? !options.useDefaultSearchExcludes : false,
maxResults: options.maxResults,
excludePattern: excludePattern,
_reason: 'startFileSearch'
};
let folderToUse: URI | undefined;
if (include) {
const { includePattern, folder } = parseSearchInclude(GlobPattern.from(include));
folderToUse = folder;
fileQueries.includePattern = includePattern;
} else {
const { includePattern, folder } = parseSearchInclude(GlobPattern.from(filePattern));
folderToUse = folder;
fileQueries.filePattern = includePattern;
}

return this._proxy.$startFileSearch(
includePattern ?? null,
folder ?? null,
excludePatternOrDisregardExcludes ?? null,
maxResults ?? null,
folderToUse ?? null,
fileQueries,
token
)
.then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : []);
Expand Down
Loading

0 comments on commit 20d1817

Please sign in to comment.