mirror of
https://github.com/Microsoft/vscode
synced 2024-10-02 17:32:41 +00:00
introduce findFiles2 API (#203844)
* introduce first version of FindFiles2 API
This commit is contained in:
parent
6c7362fe4f
commit
20d18171b3
|
@ -22,6 +22,7 @@
|
|||
"extensionsAny",
|
||||
"externalUriOpener",
|
||||
"fileSearchProvider",
|
||||
"findFiles2",
|
||||
"findTextInFiles",
|
||||
"fsChunks",
|
||||
"interactive",
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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';
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
@ -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>;
|
||||
|
|
|
@ -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';
|
||||
|
@ -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)) : []);
|
||||
|
|
|
@ -18,7 +18,7 @@ import { mock } from 'vs/base/test/common/mock';
|
|||
import { TestRPCProtocol } from 'vs/workbench/api/test/common/testRPCProtocol';
|
||||
import { ExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
|
||||
import { IFileQueryBuilderOptions, ITextQueryBuilderOptions } from 'vs/workbench/services/search/common/queryBuilder';
|
||||
import { IPatternInfo } from 'vs/workbench/services/search/common/search';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
|
||||
|
@ -583,12 +583,13 @@ suite('ExtHostWorkspace', function () {
|
|||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(includePattern, 'foo');
|
||||
assert.strictEqual(options.includePattern, 'foo');
|
||||
assert.strictEqual(_includeFolder, null);
|
||||
assert.strictEqual(excludePatternOrDisregardExcludes, null);
|
||||
assert.strictEqual(maxResults, 10);
|
||||
assert.strictEqual(options.excludePattern, '');
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
assert.strictEqual(options.maxResults, 10);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
@ -605,11 +606,12 @@ suite('ExtHostWorkspace', function () {
|
|||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(includePattern, 'glob/**');
|
||||
assert.strictEqual(options.includePattern, 'glob/**');
|
||||
assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());
|
||||
assert.strictEqual(excludePatternOrDisregardExcludes, null);
|
||||
assert.strictEqual(options.excludePattern, '');
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
@ -634,11 +636,12 @@ suite('ExtHostWorkspace', function () {
|
|||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(includePattern, 'glob/**');
|
||||
assert.strictEqual(options.includePattern, 'glob/**');
|
||||
assert.deepStrictEqual(URI.revive(_includeFolder!).toString(), URI.file('/other/folder').toString());
|
||||
assert.strictEqual(excludePatternOrDisregardExcludes, false);
|
||||
assert.strictEqual(options.excludePattern, '');
|
||||
assert.strictEqual(options.disregardExcludeSettings, true);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
@ -655,7 +658,7 @@ suite('ExtHostWorkspace', function () {
|
|||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
@ -675,9 +678,10 @@ suite('ExtHostWorkspace', function () {
|
|||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
assert.strictEqual(options.excludePattern, 'glob/**'); // Note that the base portion is ignored, see #52651
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
@ -687,6 +691,163 @@ suite('ExtHostWorkspace', function () {
|
|||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
test('findFiles2 - string include', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(options.filePattern, 'foo');
|
||||
assert.strictEqual(options.includePattern, undefined);
|
||||
assert.strictEqual(_includeFolder, null);
|
||||
assert.strictEqual(options.excludePattern, undefined);
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
assert.strictEqual(options.maxResults, 10);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles2('foo', { maxResults: 10, useDefaultExcludes: true }, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
function testFindFiles2Include(pattern: RelativePattern) {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(options.filePattern, 'glob/**');
|
||||
assert.strictEqual(options.includePattern, undefined);
|
||||
assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());
|
||||
assert.strictEqual(options.excludePattern, undefined);
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles2(pattern, { maxResults: 10 }, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
}
|
||||
|
||||
test('findFiles2 - RelativePattern include (string)', () => {
|
||||
return testFindFiles2Include(new RelativePattern('/other/folder', 'glob/**'));
|
||||
});
|
||||
|
||||
test('findFiles2 - RelativePattern include (URI)', () => {
|
||||
return testFindFiles2Include(new RelativePattern(URI.file('/other/folder'), 'glob/**'));
|
||||
});
|
||||
|
||||
test('findFiles2 - no excludes', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(options.filePattern, 'glob/**');
|
||||
assert.strictEqual(options.includePattern, undefined);
|
||||
assert.deepStrictEqual(URI.revive(_includeFolder!).toString(), URI.file('/other/folder').toString());
|
||||
assert.strictEqual(options.excludePattern, undefined);
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles2(new RelativePattern('/other/folder', 'glob/**'), {}, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findFiles2 - with cancelled token', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
|
||||
const token = CancellationToken.Cancelled;
|
||||
return ws.findFiles2(new RelativePattern('/other/folder', 'glob/**'), {}, new ExtensionIdentifier('test'), token).then(() => {
|
||||
assert(!mainThreadCalled, '!mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findFiles2 - RelativePattern exclude', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
assert.strictEqual(options.excludePattern, 'glob/**'); // Note that the base portion is ignored, see #52651
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles2('', { exclude: new RelativePattern(root, 'glob/**') }, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
test('findFiles2 - useIgnoreFiles', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(options.disregardExcludeSettings, false);
|
||||
assert.strictEqual(options.disregardIgnoreFiles, false);
|
||||
assert.strictEqual(options.disregardGlobalIgnoreFiles, false);
|
||||
assert.strictEqual(options.disregardParentIgnoreFiles, false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles2('', { useIgnoreFiles: true, useParentIgnoreFiles: true, useGlobalIgnoreFiles: true }, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findFiles2 - use symlinks', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(options.ignoreSymlinks, false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles2('', { followSymlinks: true }, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findTextInFiles - no include', async () => {
|
||||
const root = '/project/foo';
|
||||
|
|
|
@ -41,7 +41,7 @@ suite('MainThreadWorkspace', () => {
|
|||
});
|
||||
|
||||
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
|
||||
return mtw.$startFileSearch('foo', null, null, 10, new CancellationTokenSource().token);
|
||||
return mtw.$startFileSearch(null, { maxResults: 10, includePattern: 'foo', disregardSearchExcludeSettings: true }, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('exclude defaults', () => {
|
||||
|
@ -63,7 +63,7 @@ suite('MainThreadWorkspace', () => {
|
|||
});
|
||||
|
||||
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
|
||||
return mtw.$startFileSearch('', null, null, 10, new CancellationTokenSource().token);
|
||||
return mtw.$startFileSearch(null, { maxResults: 10, includePattern: '', disregardSearchExcludeSettings: true }, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('disregard excludes', () => {
|
||||
|
@ -76,7 +76,7 @@ suite('MainThreadWorkspace', () => {
|
|||
|
||||
instantiationService.stub(ISearchService, {
|
||||
fileSearch(query: IFileQuery) {
|
||||
assert.strictEqual(query.folderQueries[0].excludePattern, undefined);
|
||||
assert.deepStrictEqual(query.folderQueries[0].excludePattern, undefined);
|
||||
assert.deepStrictEqual(query.excludePattern, undefined);
|
||||
|
||||
return Promise.resolve({ results: [], messages: [] });
|
||||
|
@ -84,7 +84,29 @@ suite('MainThreadWorkspace', () => {
|
|||
});
|
||||
|
||||
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
|
||||
return mtw.$startFileSearch('', null, false, 10, new CancellationTokenSource().token);
|
||||
return mtw.$startFileSearch(null, { maxResults: 10, includePattern: '', disregardSearchExcludeSettings: true, disregardExcludeSettings: true }, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('do not disregard anything if disregardExcludeSettings is true', () => {
|
||||
configService.setUserConfiguration('search', {
|
||||
'exclude': { 'searchExclude': true }
|
||||
});
|
||||
configService.setUserConfiguration('files', {
|
||||
'exclude': { 'filesExclude': true }
|
||||
});
|
||||
|
||||
instantiationService.stub(ISearchService, {
|
||||
fileSearch(query: IFileQuery) {
|
||||
assert.strictEqual(query.folderQueries.length, 1);
|
||||
assert.strictEqual(query.folderQueries[0].disregardIgnoreFiles, true);
|
||||
assert.deepStrictEqual(query.folderQueries[0].excludePattern, undefined);
|
||||
|
||||
return Promise.resolve({ results: [], messages: [] });
|
||||
}
|
||||
});
|
||||
|
||||
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
|
||||
return mtw.$startFileSearch(null, { maxResults: 10, includePattern: '', disregardExcludeSettings: true, disregardSearchExcludeSettings: false }, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('exclude string', () => {
|
||||
|
@ -98,6 +120,6 @@ suite('MainThreadWorkspace', () => {
|
|||
});
|
||||
|
||||
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
|
||||
return mtw.$startFileSearch('', null, 'exclude/**', 10, new CancellationTokenSource().token);
|
||||
return mtw.$startFileSearch(null, { maxResults: 10, includePattern: '', excludePattern: 'exclude/**', disregardSearchExcludeSettings: true }, new CancellationTokenSource().token);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -58,6 +58,7 @@ export const allApiProposals = Object.freeze({
|
|||
externalUriOpener: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.externalUriOpener.d.ts',
|
||||
fileComments: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fileComments.d.ts',
|
||||
fileSearchProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fileSearchProvider.d.ts',
|
||||
findFiles2: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findFiles2.d.ts',
|
||||
findTextInFiles: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles.d.ts',
|
||||
fsChunks: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fsChunks.d.ts',
|
||||
handleIssueUri: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.handleIssueUri.d.ts',
|
||||
|
|
81
src/vscode-dts/vscode.proposed.findFiles2.d.ts
vendored
Normal file
81
src/vscode-dts/vscode.proposed.findFiles2.d.ts
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
export interface FindFiles2Options {
|
||||
// note: this is just FindTextInFilesOptions without select properties (include, previewOptions, beforeContext, afterContext)
|
||||
|
||||
/**
|
||||
* A {@link GlobPattern glob pattern} that defines files and folders to exclude. The glob pattern
|
||||
* will be matched against the file paths of resulting matches relative to their workspace. When `undefined`, default excludes will
|
||||
* apply.
|
||||
*/
|
||||
exclude?: GlobPattern;
|
||||
|
||||
/**
|
||||
* Whether to use the values for files.exclude. Defaults to true.
|
||||
*/
|
||||
useDefaultExcludes?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to use the values for search.exclude. Defaults to true. Will not be followed if `useDefaultExcludes` is set to `false`.
|
||||
*/
|
||||
useDefaultSearchExcludes?: boolean;
|
||||
|
||||
/**
|
||||
* The maximum number of results to search for
|
||||
*/
|
||||
maxResults?: number;
|
||||
|
||||
/**
|
||||
* Whether external files that exclude files, like .gitignore, should be respected.
|
||||
* See the vscode setting `"search.useIgnoreFiles"`.
|
||||
*/
|
||||
useIgnoreFiles?: boolean;
|
||||
|
||||
/**
|
||||
* Whether global files that exclude files, like .gitignore, should be respected.
|
||||
* Must set `useIgnoreFiles` to `true` to use this.
|
||||
* See the vscode setting `"search.useGlobalIgnoreFiles"`.
|
||||
*/
|
||||
useGlobalIgnoreFiles?: boolean;
|
||||
|
||||
/**
|
||||
* Whether files in parent directories that exclude files, like .gitignore, should be respected.
|
||||
* Must set `useIgnoreFiles` to `true` to use this.
|
||||
* See the vscode setting `"search.useParentIgnoreFiles"`.
|
||||
*/
|
||||
useParentIgnoreFiles?: boolean;
|
||||
|
||||
/**
|
||||
* Whether symlinks should be followed while searching.
|
||||
* See the vscode setting `"search.followSymlinks"`.
|
||||
*/
|
||||
followSymlinks?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a session of a currently logged in user.
|
||||
*/
|
||||
export namespace workspace {
|
||||
/**
|
||||
* Find files across all {@link workspace.workspaceFolders workspace folders} in the workspace.
|
||||
*
|
||||
* @example
|
||||
* findFiles('**/*.js', {exclude: '**/out/**', useIgnoreFiles: true}, 10)
|
||||
*
|
||||
* @param filePattern A {@link GlobPattern glob pattern} that defines the files to search for. The glob pattern
|
||||
* will be matched against the file paths of resulting matches relative to their workspace. Use a {@link RelativePattern relative pattern}
|
||||
* to restrict the search results to a {@link WorkspaceFolder workspace folder}.
|
||||
* @param options A set of {@link FindFiles2Options FindFiles2Options} that defines where and how to search (e.g. exclude settings).
|
||||
* If enabled, any ignore files will take prescendence over any files found in the `filePattern` parameter.
|
||||
* @param token A token that can be used to signal cancellation to the underlying search engine.
|
||||
* @returns A thenable that resolves to an array of resource identifiers. Will return no results if no
|
||||
* {@link workspace.workspaceFolders workspace folders} are opened.
|
||||
*/
|
||||
export function findFiles2(filePattern: GlobPattern, options?: FindFiles2Options, token?: CancellationToken): Thenable<Uri[]>;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue