diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 23162569705..b871093df39 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -598,19 +598,19 @@ suite('vscode API - workspace', () => { }); test('`findFiles2`', () => { - return vscode.workspace.findFiles2('**/image.png').then((res) => { + return vscode.workspace.findFiles2(['**/image.png']).then((res) => { assert.strictEqual(res.length, 2); }); }); test('findFiles2 - null exclude', async () => { - await vscode.workspace.findFiles2('**/file.txt', { useDefaultExcludes: true, useDefaultSearchExcludes: false }).then((res) => { + await vscode.workspace.findFiles2(['**/file.txt'], { useExcludeSettings: vscode.ExcludeSettingOptions.FilesExclude }).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) => { + await vscode.workspace.findFiles2(['**/file.txt'], { useExcludeSettings: vscode.ExcludeSettingOptions.None }).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'); @@ -618,7 +618,7 @@ suite('vscode API - workspace', () => { }); test('findFiles2, exclude', () => { - return vscode.workspace.findFiles2('**/image.png', { exclude: '**/sub/**' }).then((res) => { + return vscode.workspace.findFiles2(['**/image.png'], { exclude: ['**/sub/**'] }).then((res) => { res.forEach(r => console.log(r.toString())); assert.strictEqual(res.length, 1); }); @@ -630,7 +630,7 @@ suite('vscode API - workspace', () => { const token = source.token; // just to get an instance first source.cancel(); - return vscode.workspace.findFiles2('*.js', {}, token).then((res) => { + return vscode.workspace.findFiles2(['*.js'], {}, token).then((res) => { assert.deepStrictEqual(res, []); }); }); diff --git a/src/vs/platform/extensions/common/extensionsApiProposals.ts b/src/vs/platform/extensions/common/extensionsApiProposals.ts index 6ea83f743ad..672a7cf9755 100644 --- a/src/vs/platform/extensions/common/extensionsApiProposals.ts +++ b/src/vs/platform/extensions/common/extensionsApiProposals.ts @@ -14,9 +14,7 @@ const _allApiProposals = { }, aiTextSearchProvider: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.aiTextSearchProvider.d.ts', - }, - aiTextSearchProvider2: { - proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.aiTextSearchProvider2.d.ts', + version: 2 }, attributableCoverage: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.attributableCoverage.d.ts', @@ -205,9 +203,7 @@ const _allApiProposals = { }, findFiles2: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findFiles2.d.ts', - }, - findFiles2New: { - proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findFiles2New.d.ts', + version: 2 }, findTextInFiles: { proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles.d.ts', diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 82b336d4c2b..d45dd274008 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -961,14 +961,10 @@ 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: vscode.GlobPattern, options?: vscode.FindFiles2Options, token?: vscode.CancellationToken): Thenable => { + findFiles2: (filePattern: vscode.GlobPattern[], options?: vscode.FindFiles2Options, token?: vscode.CancellationToken): Thenable => { checkProposedApiEnabled(extension, 'findFiles2'); return extHostWorkspace.findFiles2(filePattern, options, extension.identifier, token); }, - findFiles2New: (filePattern: vscode.GlobPattern[], options?: vscode.FindFiles2OptionsNew, token?: vscode.CancellationToken): Thenable => { - checkProposedApiEnabled(extension, 'findFiles2New'); - return extHostWorkspace.findFiles2New(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; @@ -1136,8 +1132,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerAITextSearchProvider: (scheme: string, provider: vscode.AITextSearchProvider) => { // there are some dependencies on textSearchProvider, so we need to check for both checkProposedApiEnabled(extension, 'aiTextSearchProvider'); - checkProposedApiEnabled(extension, 'textSearchProvider'); - return extHostSearch.registerAITextSearchProviderOld(scheme, provider); + checkProposedApiEnabled(extension, 'textSearchProvider2'); + return extHostSearch.registerAITextSearchProvider(scheme, provider); }, registerFileSearchProvider2: (scheme: string, provider: vscode.FileSearchProvider2) => { checkProposedApiEnabled(extension, 'fileSearchProvider2'); @@ -1147,12 +1143,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension, 'textSearchProvider2'); return extHostSearch.registerTextSearchProvider(scheme, provider); }, - registerAITextSearchProvider2: (scheme: string, provider: vscode.AITextSearchProvider2) => { - // there are some dependencies on textSearchProvider, so we need to check for both - checkProposedApiEnabled(extension, 'aiTextSearchProvider2'); - checkProposedApiEnabled(extension, 'textSearchProvider2'); - return extHostSearch.registerAITextSearchProvider(scheme, provider); - }, registerRemoteAuthorityResolver: (authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver) => { checkProposedApiEnabled(extension, 'resolvers'); return extensionService.registerRemoteAuthorityResolver(authorityPrefix, resolver); diff --git a/src/vs/workbench/api/common/extHostSearch.ts b/src/vs/workbench/api/common/extHostSearch.ts index cac2fb80914..fb92adb1fc9 100644 --- a/src/vs/workbench/api/common/extHostSearch.ts +++ b/src/vs/workbench/api/common/extHostSearch.ts @@ -16,14 +16,13 @@ import { URI, UriComponents } from '../../../base/common/uri.js'; import { TextSearchManager } from '../../services/search/common/textSearchManager.js'; import { CancellationToken } from '../../../base/common/cancellation.js'; import { revive } from '../../../base/common/marshalling.js'; -import { OldAITextSearchProviderConverter, OldFileSearchProviderConverter, OldTextSearchProviderConverter } from '../../services/search/common/searchExtConversionTypes.js'; +import { OldFileSearchProviderConverter, OldTextSearchProviderConverter } from '../../services/search/common/searchExtConversionTypes.js'; export interface IExtHostSearch extends ExtHostSearchShape { registerTextSearchProviderOld(scheme: string, provider: vscode.TextSearchProvider): IDisposable; - registerAITextSearchProviderOld(scheme: string, provider: vscode.AITextSearchProvider): IDisposable; registerFileSearchProviderOld(scheme: string, provider: vscode.FileSearchProvider): IDisposable; registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider2): IDisposable; - registerAITextSearchProvider(scheme: string, provider: vscode.AITextSearchProvider2): IDisposable; + registerAITextSearchProvider(scheme: string, provider: vscode.AITextSearchProvider): IDisposable; registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider2): IDisposable; doInternalFileSearchWithCustomCallback(query: IFileQuery, token: CancellationToken, handleFileMatch: (data: URI[]) => void): Promise; } @@ -38,7 +37,7 @@ export class ExtHostSearch implements IExtHostSearch { private readonly _textSearchProvider = new Map(); private readonly _textSearchUsedSchemes = new Set(); - private readonly _aiTextSearchProvider = new Map(); + private readonly _aiTextSearchProvider = new Map(); private readonly _aiTextSearchUsedSchemes = new Set(); private readonly _fileSearchProvider = new Map(); @@ -88,23 +87,7 @@ export class ExtHostSearch implements IExtHostSearch { }); } - registerAITextSearchProviderOld(scheme: string, provider: vscode.AITextSearchProvider): IDisposable { - if (this._aiTextSearchUsedSchemes.has(scheme)) { - throw new Error(`an AI text search provider for the scheme '${scheme}'is already registered`); - } - - this._aiTextSearchUsedSchemes.add(scheme); - const handle = this._handlePool++; - this._aiTextSearchProvider.set(handle, new OldAITextSearchProviderConverter(provider)); - this._proxy.$registerAITextSearchProvider(handle, this._transformScheme(scheme)); - return toDisposable(() => { - this._aiTextSearchUsedSchemes.delete(scheme); - this._aiTextSearchProvider.delete(handle); - this._proxy.$unregisterProvider(handle); - }); - } - - registerAITextSearchProvider(scheme: string, provider: vscode.AITextSearchProvider2): IDisposable { + registerAITextSearchProvider(scheme: string, provider: vscode.AITextSearchProvider): IDisposable { if (this._aiTextSearchUsedSchemes.has(scheme)) { throw new Error(`an AI text search provider for the scheme '${scheme}'is already registered`); } @@ -215,7 +198,7 @@ export class ExtHostSearch implements IExtHostSearch { }, 'textSearchProvider'); } - protected createAITextSearchManager(query: IAITextQuery, provider: vscode.AITextSearchProvider2): TextSearchManager { + protected createAITextSearchManager(query: IAITextQuery, provider: vscode.AITextSearchProvider): TextSearchManager { return new TextSearchManager({ query, provider }, { readdir: resource => Promise.resolve([]), toCanonicalName: encoding => encoding diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index 2d2305b81f7..2f40bb8a392 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -478,36 +478,11 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac }, token); } - findFiles2(filePattern: vscode.GlobPattern | undefined, + + findFiles2(filePatterns: vscode.GlobPattern[], options: vscode.FindFiles2Options = {}, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { - this._logService.trace(`extHostWorkspace#findFiles2: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles2`); - - - const useDefaultExcludes = options.useDefaultExcludes ?? true; - const useDefaultSearchExcludes = options.useDefaultSearchExcludes ?? true; - const excludeSetting = useDefaultExcludes ? - (useDefaultSearchExcludes ? ExcludeSettingOptions.SearchAndFilesExclude : ExcludeSettingOptions.FilesExclude) : - ExcludeSettingOptions.None; - const newOptions: vscode.FindFiles2OptionsNew = { - exclude: options.exclude ? [options.exclude] : undefined, - useIgnoreFiles: { - local: options.useIgnoreFiles, - global: options.useGlobalIgnoreFiles, - parent: options.useParentIgnoreFiles - }, - useExcludeSettings: excludeSetting, - followSymlinks: options.followSymlinks, - maxResults: options.maxResults, - }; - return this._findFilesImpl(undefined, filePattern !== undefined ? [filePattern] : [], newOptions, token); - } - - findFiles2New(filePatterns: vscode.GlobPattern[], - options: vscode.FindFiles2OptionsNew = {}, - extensionId: ExtensionIdentifier, - token: vscode.CancellationToken = CancellationToken.None): Promise { this._logService.trace(`extHostWorkspace#findFiles2New: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles2New`); return this._findFilesImpl(undefined, filePatterns, options, token); } @@ -517,7 +492,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac // `filePattern` is the proper way to handle this, since it takes less precedence than the ignore files. include: vscode.GlobPattern | undefined, filePatterns: vscode.GlobPattern[] | undefined, - options: vscode.FindFiles2OptionsNew, + options: vscode.FindFiles2Options, token: vscode.CancellationToken = CancellationToken.None): Promise { if (token && token.isCancellationRequested) { return Promise.resolve([]); diff --git a/src/vs/workbench/api/test/browser/extHostWorkspace.test.ts b/src/vs/workbench/api/test/browser/extHostWorkspace.test.ts index 37d95aec3ec..1c0bec661f0 100644 --- a/src/vs/workbench/api/test/browser/extHostWorkspace.test.ts +++ b/src/vs/workbench/api/test/browser/extHostWorkspace.test.ts @@ -716,12 +716,12 @@ suite('ExtHostWorkspace', function () { }); 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(() => { + return ws.findFiles2(['foo'], { maxResults: 10, useExcludeSettings: ExcludeSettingOptions.FilesExclude }, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); - function testFindFiles2Include(pattern: RelativePattern) { + function testFindFiles2Include(pattern: RelativePattern[]) { const root = '/project/foo'; const rpcProtocol = new TestRPCProtocol(); @@ -745,11 +745,11 @@ suite('ExtHostWorkspace', function () { } test('RelativePattern include (string)', () => { - return testFindFiles2Include(new RelativePattern('/other/folder', 'glob/**')); + return testFindFiles2Include([new RelativePattern('/other/folder', 'glob/**')]); }); test('RelativePattern include (URI)', () => { - return testFindFiles2Include(new RelativePattern(URI.file('/other/folder'), 'glob/**')); + return testFindFiles2Include([new RelativePattern(URI.file('/other/folder'), 'glob/**')]); }); test('no excludes', () => { @@ -770,7 +770,7 @@ suite('ExtHostWorkspace', function () { }); 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(() => { + return ws.findFiles2([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -790,7 +790,7 @@ suite('ExtHostWorkspace', function () { 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(() => { + return ws.findFiles2([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test'), token).then(() => { assert(!mainThreadCalled, '!mainThreadCalled'); }); }); @@ -811,7 +811,7 @@ suite('ExtHostWorkspace', function () { }); 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(() => { + return ws.findFiles2([''], { exclude: [new RelativePattern(root, 'glob/**')] }, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -832,7 +832,7 @@ suite('ExtHostWorkspace', function () { }); 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(() => { + return ws.findFiles2([''], { useIgnoreFiles: { local: true, parent: true, global: true } }, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -851,168 +851,7 @@ suite('ExtHostWorkspace', function () { }); 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'); - }); - }); - }); - - suite('findFiles2New -', function () { - test('string include', () => { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - 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.findFiles2New(['foo'], { maxResults: 10, useExcludeSettings: ExcludeSettingOptions.FilesExclude }, new ExtensionIdentifier('test')).then(() => { - assert(mainThreadCalled, 'mainThreadCalled'); - }); - }); - - function testFindFiles2NewInclude(pattern: RelativePattern[]) { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - 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.findFiles2New(pattern, { maxResults: 10 }, new ExtensionIdentifier('test')).then(() => { - assert(mainThreadCalled, 'mainThreadCalled'); - }); - } - - test('RelativePattern include (string)', () => { - return testFindFiles2NewInclude([new RelativePattern('/other/folder', 'glob/**')]); - }); - - test('RelativePattern include (URI)', () => { - return testFindFiles2NewInclude([new RelativePattern(URI.file('/other/folder'), 'glob/**')]); - }); - - test('no excludes', () => { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - 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.findFiles2New([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test')).then(() => { - assert(mainThreadCalled, 'mainThreadCalled'); - }); - }); - - test('with cancelled token', () => { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - 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.findFiles2New([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test'), token).then(() => { - assert(!mainThreadCalled, '!mainThreadCalled'); - }); - }); - - test('RelativePattern exclude', () => { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - mainThreadCalled = true; - assert.strictEqual(options.disregardExcludeSettings, false); - assert.strictEqual(options.excludePattern?.length, 1); - assert.strictEqual(options.excludePattern[0].pattern, '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.findFiles2New([''], { exclude: [new RelativePattern(root, 'glob/**')] }, new ExtensionIdentifier('test')).then(() => { - assert(mainThreadCalled, 'mainThreadCalled'); - }); - }); - test('useIgnoreFiles', () => { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - 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.findFiles2New([''], { useIgnoreFiles: { local: true, parent: true, global: true } }, new ExtensionIdentifier('test')).then(() => { - assert(mainThreadCalled, 'mainThreadCalled'); - }); - }); - - test('use symlinks', () => { - const root = '/project/foo'; - const rpcProtocol = new TestRPCProtocol(); - - let mainThreadCalled = false; - rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise { - 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.findFiles2New([''], { followSymlinks: true }, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles2([''], { followSymlinks: true }, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); diff --git a/src/vs/workbench/services/search/common/searchExtConversionTypes.ts b/src/vs/workbench/services/search/common/searchExtConversionTypes.ts index 96bff831656..5e96fef6d40 100644 --- a/src/vs/workbench/services/search/common/searchExtConversionTypes.ts +++ b/src/vs/workbench/services/search/common/searchExtConversionTypes.ts @@ -13,7 +13,7 @@ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { URI } from '../../../../base/common/uri.js'; import { IProgress } from '../../../../platform/progress/common/progress.js'; import { DEFAULT_TEXT_SEARCH_PREVIEW_OPTIONS } from './search.js'; -import { Range, FileSearchProvider2, FileSearchProviderOptions, ProviderResult, TextSearchComplete2, TextSearchContext2, TextSearchMatch2, TextSearchProvider2, TextSearchProviderOptions, TextSearchQuery2, TextSearchResult2, AITextSearchProvider2, TextSearchCompleteMessage } from './searchExtTypes.js'; +import { Range, FileSearchProvider2, FileSearchProviderOptions, ProviderResult, TextSearchComplete2, TextSearchContext2, TextSearchMatch2, TextSearchProvider2, TextSearchProviderOptions, TextSearchQuery2, TextSearchResult2, TextSearchCompleteMessage } from './searchExtTypes.js'; // old types that are retained for backward compatibility // TODO: delete this when search apis are adopted by all first-party extensions @@ -372,23 +372,6 @@ export interface TextSearchProvider { */ provideTextSearchResults(query: TextSearchQuery, options: TextSearchOptions, progress: IProgress, token: CancellationToken): ProviderResult; } - -export interface AITextSearchProvider { - /** - * The name of the AI searcher. Will be displayed as `{name} Results` in the Search View. - */ - readonly name?: string; - - /** - * Provide results that match the given text pattern. - * @param query The parameter for this query. - * @param options A set of options to consider while searching. - * @param progress A progress callback that must be invoked for all results. - * @param token A cancellation token. - */ - provideAITextSearchResults(query: string, options: AITextSearchOptions, progress: IProgress, token: CancellationToken): ProviderResult; -} - /** * Options that can be set on a findTextInFiles search. */ @@ -561,40 +544,6 @@ export class OldTextSearchProviderConverter implements TextSearchProvider2 { } } -export class OldAITextSearchProviderConverter implements AITextSearchProvider2 { - public readonly name?: string; - - constructor(private provider: AITextSearchProvider) { - this.name = this.provider.name; - } - - provideAITextSearchResults(query: string, options: TextSearchProviderOptions, progress: IProgress, token: CancellationToken): ProviderResult { - const progressShim = (oldResult: TextSearchResult) => { - if (!validateProviderResult(oldResult)) { - return; - } - progress.report(oldToNewTextSearchResult(oldResult)); - }; - - const getResult = async () => { - return coalesce(await Promise.all( - newToOldTextProviderOptions(options).map( - o => this.provider.provideAITextSearchResults(query, o, { report: (e) => progressShim(e) }, token)))) - .reduce( - (prev, cur) => ({ limitHit: prev.limitHit || cur.limitHit }), - { limitHit: false } - ); - }; - const oldResult = getResult(); - return oldResult.then((e) => { - return { - limitHit: e.limitHit, - message: coalesce(asArray(e.message)) - } satisfies TextSearchComplete2; - }); - } -} - function validateProviderResult(result: TextSearchResult): boolean { if (extensionResultIsMatch(result)) { if (Array.isArray(result.ranges)) { diff --git a/src/vs/workbench/services/search/common/searchExtTypes.ts b/src/vs/workbench/services/search/common/searchExtTypes.ts index 7dd13ebc258..fc785ae189b 100644 --- a/src/vs/workbench/services/search/common/searchExtTypes.ts +++ b/src/vs/workbench/services/search/common/searchExtTypes.ts @@ -527,7 +527,7 @@ export interface TextSearchCompleteMessage { /** * An AITextSearchProvider provides additional AI text search results in the workspace. */ -export interface AITextSearchProvider2 { +export interface AITextSearchProvider { /** * The name of the AI searcher. Will be displayed as `{name} Results` in the Search View. diff --git a/src/vs/workbench/services/search/common/textSearchManager.ts b/src/vs/workbench/services/search/common/textSearchManager.ts index 5d8e858833b..59a10ed9024 100644 --- a/src/vs/workbench/services/search/common/textSearchManager.ts +++ b/src/vs/workbench/services/search/common/textSearchManager.ts @@ -12,14 +12,14 @@ import * as resources from '../../../../base/common/resources.js'; import { URI } from '../../../../base/common/uri.js'; import { FolderQuerySearchTree } from './folderQuerySearchTree.js'; import { DEFAULT_MAX_SEARCH_RESULTS, hasSiblingPromiseFn, IAITextQuery, IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, excludeToGlobPattern, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult, ITextSearchStats, QueryGlobTester, QueryType, resolvePatternsForProvider, ISearchRange, DEFAULT_TEXT_SEARCH_PREVIEW_OPTIONS } from './search.js'; -import { AITextSearchProvider2, TextSearchComplete2, TextSearchMatch2, TextSearchProviderFolderOptions, TextSearchProvider2, TextSearchProviderOptions, TextSearchQuery2, TextSearchResult2 } from './searchExtTypes.js'; +import { TextSearchComplete2, TextSearchMatch2, TextSearchProviderFolderOptions, TextSearchProvider2, TextSearchProviderOptions, TextSearchQuery2, TextSearchResult2, AITextSearchProvider } from './searchExtTypes.js'; export interface IFileUtils { readdir: (resource: URI) => Promise; toCanonicalName: (encoding: string) => string; } interface IAITextQueryProviderPair { - query: IAITextQuery; provider: AITextSearchProvider2; + query: IAITextQuery; provider: AITextSearchProvider; } interface ITextQueryProviderPair { diff --git a/src/vscode-dts/vscode.proposed.aiTextSearchProvider.d.ts b/src/vscode-dts/vscode.proposed.aiTextSearchProvider.d.ts index f30b87f6097..46960a0b5b1 100644 --- a/src/vscode-dts/vscode.proposed.aiTextSearchProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.aiTextSearchProvider.d.ts @@ -3,39 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// version: 2 + declare module 'vscode' { - - /** - * Options that apply to AI text search. - */ - export interface AITextSearchOptions extends SearchOptions { - /** - * The maximum number of results to be returned. - */ - maxResults: number; - - /** - * Options to specify the size of the result text preview. - */ - previewOptions?: TextSearchPreviewOptions; - - /** - * Exclude files larger than `maxFileSize` in bytes. - */ - maxFileSize?: number; - - /** - * Number of lines of context to include before each match. - */ - beforeContext?: number; - - /** - * Number of lines of context to include after each match. - */ - afterContext?: number; - } - - /** * An AITextSearchProvider provides additional AI text search results in the workspace. */ @@ -46,14 +16,14 @@ declare module 'vscode' { readonly name?: string; /** + * * Provide results that match the given text pattern. * @param query The parameter for this query. * @param options A set of options to consider while searching. * @param progress A progress callback that must be invoked for all results. * @param token A cancellation token. */ - provideAITextSearchResults(query: string, options: AITextSearchOptions, progress: Progress, token: CancellationToken): ProviderResult; - + provideAITextSearchResults(query: string, options: TextSearchProviderOptions, progress: Progress, token: CancellationToken): ProviderResult; } export namespace workspace { diff --git a/src/vscode-dts/vscode.proposed.aiTextSearchProvider2.d.ts b/src/vscode-dts/vscode.proposed.aiTextSearchProvider2.d.ts deleted file mode 100644 index 05c9c6b0415..00000000000 --- a/src/vscode-dts/vscode.proposed.aiTextSearchProvider2.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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' { - /** - * An AITextSearchProvider provides additional AI text search results in the workspace. - */ - export interface AITextSearchProvider2 { - /** - * The name of the AI searcher. Will be displayed as `{name} Results` in the Search View. - */ - readonly name?: string; - - /** - * WARNING: VERY EXPERIMENTAL. - * - * Provide results that match the given text pattern. - * @param query The parameter for this query. - * @param options A set of options to consider while searching. - * @param progress A progress callback that must be invoked for all results. - * @param token A cancellation token. - */ - provideAITextSearchResults(query: string, options: TextSearchProviderOptions, progress: Progress, token: CancellationToken): ProviderResult; - } - - export namespace workspace { - /** - * Register an AI text search provider. - * - * Only one provider can be registered per scheme. - * - * @param scheme The provider will be invoked for workspace folders that have this file scheme. - * @param provider The provider. - * @return A {@link Disposable} that unregisters this provider when being disposed. - */ - export function registerAITextSearchProvider2(scheme: string, provider: AITextSearchProvider2): Disposable; - } -} diff --git a/src/vscode-dts/vscode.proposed.findFiles2.d.ts b/src/vscode-dts/vscode.proposed.findFiles2.d.ts index 145776110d4..579ba732ac9 100644 --- a/src/vscode-dts/vscode.proposed.findFiles2.d.ts +++ b/src/vscode-dts/vscode.proposed.findFiles2.d.ts @@ -3,87 +3,123 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +// version: 2 + 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. + * An array of {@link GlobPattern GlobPattern} that defines files to exclude. + * The glob patterns will be matched against the file paths of files relative to their workspace or {@link RelativePattern.baseUri} if applicable. + * + * If more than one value is used, the values are combined with a logical AND. + * For example, consider the following code: + * + * ```ts + * const ab = findFiles(['**​/*.js'], {exclude: ['*.ts', '*.js']}); + * const a = findFiles(['**​/*.js'], {exclude: ['*.ts']}); + * const b = findFiles(['**​/*.js'], {exclude: ['*.js']}); + * ``` + * + * In this, `ab` will be the intersection of results from `a` and `b`. */ - exclude?: GlobPattern; + exclude?: GlobPattern[]; /** - * Whether to use the values for files.exclude. Defaults to true. + * Which settings to follow when searching for files. Defaults to {@link ExcludeSettingOptions.searchAndFilesExclude}. */ - useDefaultExcludes?: boolean; + useExcludeSettings?: ExcludeSettingOptions; /** - * 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 + * The maximum number of results to search for. Defaults to 20000 results. */ maxResults?: number; /** - * Whether external files that exclude files, like .gitignore, should be respected. - * Defaults to the value for `search.useIgnoreFiles` in settings. - * For more info, see the setting listed above. + * Which file locations have ignore (`.gitignore` or `.ignore`) files to follow. + * + * When any of these fields are `undefined`, the value will either be assumed (e.g. if only one is valid), + * or it will follow settings based on the corresponding `search.use*IgnoreFiles` setting. + * + * Will log an error if an invalid combination is set. + * + * Although `.ignore` files are uncommon, they can be leveraged if there are patterns + * that should not be known to git, but should be known to the search providers. + * They should be in the same locations where `.gitignore` files are found, and they follow the same format. */ - useIgnoreFiles?: boolean; - - /** - * Whether global files that exclude files, like .gitignore, should be respected. - * Must set `useIgnoreFiles` to `true` to use this. - * Defaults to the value for `search.useGlobalIgnoreFiles` in settings. - * For more info, see the setting listed above. - */ - useGlobalIgnoreFiles?: boolean; - - /** - * Whether files in parent directories that exclude files, like .gitignore, should be respected. - * Must set `useIgnoreFiles` to `true` to use this. - * Defaults to the value for `search.useParentIgnoreFiles` in settings. - * For more info, see the setting listed above. - */ - useParentIgnoreFiles?: boolean; + useIgnoreFiles?: { + /** + * Use ignore files at the current workspace root. + * May default to `search.useIgnoreFiles` setting if not set. + */ + local?: boolean; + /** + * Use ignore files at the parent directory. When set to `true`, {@link FindFiles2Options.useIgnoreFiles.local} must also be `true`. + * May default to `search.useParentIgnoreFiles` setting if not set. + */ + parent?: boolean; + /** + * Use global ignore files. When set to `true`, {@link FindFiles2Options.useIgnoreFiles.local} must also be `true`. + * May default to `search.useGlobalIgnoreFiles` setting if not set. + */ + global?: boolean; + }; /** * Whether symlinks should be followed while searching. * Defaults to the value for `search.followSymlinks` in settings. - * For more info, see the setting listed above. + * For more info, see the setting description for `search.followSymlinks`. */ followSymlinks?: boolean; - - /** - * If set to true, the `filePattern` arg will be fuzzy-searched instead of glob-searched. - * If `filePattern` is a {@link RelativePattern relative pattern}, then the fuzzy search will act on the `pattern` of the {@link RelativePattern RelativePattern} - */ - fuzzy?: boolean; } /** - * Represents a session of a currently logged in user. + * Options for following search.exclude and files.exclude settings. */ + export enum ExcludeSettingOptions { + /** + * Don't use any exclude settings. + */ + None = 1, + /** + * Use the `files.exclude` setting + */ + FilesExclude = 2, + /** + * Use the `files.exclude` and `search.exclude` settings + */ + SearchAndFilesExclude = 3 + } + export namespace workspace { /** + * WARNING: VERY EXPERIMENTAL. + * * Find files across all {@link workspace.workspaceFolders workspace folders} in the workspace. * * @example - * findFiles('**​/*.js', {exclude: '**​/out/**', useIgnoreFiles: true, maxResults: 10}) + * findFiles(['**​/*.js'], {exclude: ['**​/out/**'], useIgnoreFiles: true, maxResults: 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 filePattern An array of {@link GlobPattern GlobPattern} that defines the files to search for. + * The glob patterns will be matched against the file paths of files relative to their workspace or {@link baseUri GlobPattern.baseUri} if applicable. + * Use a {@link RelativePattern RelativePatten} to restrict the search results to a {@link WorkspaceFolder workspace folder}. + * + * If more than one value is used, the values are combined with a logical OR. + * + * For example, consider the following code: + * + * ```ts + * const ab = findFiles(['*.ts', '*.js']); + * const a = findFiles(['**​/*.ts']); + * const b = findFiles(['**​/*.js']); + * ``` + * + * In this, `ab` will be the union of results from `a` and `b`. * @param options A set of {@link FindFiles2Options FindFiles2Options} that defines where and how to search (e.g. exclude settings). * @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; + export function findFiles2(filePattern: GlobPattern[], options?: FindFiles2Options, token?: CancellationToken): Thenable; } } diff --git a/src/vscode-dts/vscode.proposed.findFiles2New.d.ts b/src/vscode-dts/vscode.proposed.findFiles2New.d.ts deleted file mode 100644 index 5ccc4e1bc32..00000000000 --- a/src/vscode-dts/vscode.proposed.findFiles2New.d.ts +++ /dev/null @@ -1,105 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 FindFiles2OptionsNew { - /** - * An array of {@link GlobPattern GlobPattern} that defines files to exclude. - * The glob patterns will be matched against the file paths of files relative to their workspace or {@link RelativePattern.baseUri} if applicable. - * - * If more than one value is used, the values are combined with a logical AND. - * For example, consider the following code: - * - * ```ts - * const ab = findFiles(['**​/*.js'], {exclude: ['*.ts', '*.js']}); - * const a = findFiles(['**​/*.js'], {exclude: ['*.ts']}); - * const b = findFiles(['**​/*.js'], {exclude: ['*.js']}); - * ``` - * - * In this, `ab` will be the intersection of results from `a` and `b`. - */ - exclude?: GlobPattern[]; - - /** - * Which settings to follow when searching for files. Defaults to {@link ExcludeSettingOptions.searchAndFilesExclude}. - */ - useExcludeSettings?: ExcludeSettingOptions; - - /** - * The maximum number of results to search for. Defaults to 20000 results. - */ - maxResults?: number; - - /** - * Which file locations have ignore (`.gitignore` or `.ignore`) files to follow. - * - * When any of these fields are `undefined`, the value will either be assumed (e.g. if only one is valid), - * or it will follow settings based on the corresponding `search.use*IgnoreFiles` setting. - * - * Will log an error if an invalid combination is set. - * - * Although `.ignore` files are uncommon, they can be leveraged if there are patterns - * that should not be known to git, but should be known to the search providers. - * They should be in the same locations where `.gitignore` files are found, and they follow the same format. - */ - useIgnoreFiles?: { - /** - * Use ignore files at the current workspace root. - * May default to `search.useIgnoreFiles` setting if not set. - */ - local?: boolean; - /** - * Use ignore files at the parent directory. When set to `true`, {@link FindFiles2OptionsNew.useIgnoreFiles.local} must also be `true`. - * May default to `search.useParentIgnoreFiles` setting if not set. - */ - parent?: boolean; - /** - * Use global ignore files. When set to `true`, {@link FindFiles2OptionsNew.useIgnoreFiles.local} must also be `true`. - * May default to `search.useGlobalIgnoreFiles` setting if not set. - */ - global?: boolean; - }; - - /** - * Whether symlinks should be followed while searching. - * Defaults to the value for `search.followSymlinks` in settings. - * For more info, see the setting description for `search.followSymlinks`. - */ - followSymlinks?: boolean; - } - - export namespace workspace { - /** - * WARNING: VERY EXPERIMENTAL. - * - * Find files across all {@link workspace.workspaceFolders workspace folders} in the workspace. - * - * @example - * findFiles(['**​/*.js'], {exclude: ['**​/out/**'], useIgnoreFiles: true, maxResults: 10}) - * - * @param filePattern An array of {@link GlobPattern GlobPattern} that defines the files to search for. - * The glob patterns will be matched against the file paths of files relative to their workspace or {@link baseUri GlobPattern.baseUri} if applicable. - * Use a {@link RelativePattern RelativePatten} to restrict the search results to a {@link WorkspaceFolder workspace folder}. - * - * If more than one value is used, the values are combined with a logical OR. - * - * For example, consider the following code: - * - * ```ts - * const ab = findFiles(['*.ts', '*.js']); - * const a = findFiles(['**​/*.ts']); - * const b = findFiles(['**​/*.js']); - * ``` - * - * In this, `ab` will be the union of results from `a` and `b`. - * @param options A set of {@link FindFiles2Options FindFiles2Options} that defines where and how to search (e.g. exclude settings). - * @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 findFiles2New(filePattern: GlobPattern[], options?: FindFiles2OptionsNew, token?: CancellationToken): Thenable; - } -} diff --git a/src/vscode-dts/vscode.proposed.findTextInFiles2.d.ts b/src/vscode-dts/vscode.proposed.findTextInFiles2.d.ts index 6fcec3d0a1e..95a01a850f3 100644 --- a/src/vscode-dts/vscode.proposed.findTextInFiles2.d.ts +++ b/src/vscode-dts/vscode.proposed.findTextInFiles2.d.ts @@ -130,24 +130,6 @@ declare module 'vscode' { complete: Thenable; } - /** - * Options for following search.exclude and files.exclude settings. - */ - export enum ExcludeSettingOptions { - /** - * Don't use any exclude settings. - */ - None = 1, - /** - * Use the `files.exclude` setting - */ - FilesExclude = 2, - /** - * Use the `files.exclude` and `search.exclude` settings - */ - SearchAndFilesExclude = 3 - } - export namespace workspace { /** * WARNING: VERY EXPERIMENTAL.