diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index 7fe2dfed86f..e4586fd76cf 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -379,7 +379,12 @@ class FileSearchEngine { public search(): PPromise<{ isLimitHit: boolean }, IInternalFileMatch> { const folderQueries = this.config.folderQueries; - return new PPromise<{ isLimitHit: boolean }, IInternalFileMatch>((resolve, reject, onResult) => { + return new PPromise<{ isLimitHit: boolean }, IInternalFileMatch>((resolve, reject, _onResult) => { + const onResult = (match: IInternalFileMatch) => { + this.resultCount++; + _onResult(match); + }; + // Support that the file pattern is a full path to a file that exists this.checkFilePatternAbsoluteMatch().then(({ exists, size }) => { if (this.isCanceled) { @@ -388,7 +393,6 @@ class FileSearchEngine { // Report result from file pattern if matching if (exists) { - this.resultCount++; onResult({ relativePath: this.filePattern, basename: path.basename(this.filePattern), @@ -487,7 +491,6 @@ class FileSearchEngine { // If the limit was hit, check whether filePattern is an exact relative match because it must be included return this.checkFilePatternRelativeMatch(folderStr).then(({ exists, size }) => { if (exists) { - this.resultCount++; onResult({ base: folderStr, relativePath: this.filePattern, @@ -655,10 +658,9 @@ class FileSearchEngine { private matchFile(onResult: (result: IInternalFileMatch) => void, candidate: IInternalFileMatch): void { if (this.isFilePatternMatch(candidate.relativePath) && (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename))) { - this.resultCount++; - - if (this.exists || (this.maxResults && this.resultCount > this.maxResults)) { + if (this.exists || (this.maxResults && this.resultCount >= this.maxResults)) { this.isLimitHit = true; + this.cancel(); } if (!this.isLimitHit) { @@ -1020,14 +1022,14 @@ class FileSearchManager { private doSearch(engine: FileSearchEngine, provider: vscode.SearchProvider, batchSize?: number): PPromise> { return new PPromise>((c, e, p) => { let batch: IInternalFileMatch[] = []; - engine.search().then(() => { + engine.search().then(result => { if (batch.length) { p(batch); } c({ - limitHit: false, - stats: engine.getStats() + limitHit: result.isLimitHit, + stats: engine.getStats() // TODO@roblou }); }, error => { if (batch.length) { diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index f67d958d741..8db360af79e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -444,6 +444,78 @@ suite('ExtHostSearch', () => { ]); }); + test('max results = 1', async () => { + const reportedResults = [ + makeAbsoluteURI(rootFolderA, 'file1.ts'), + makeAbsoluteURI(rootFolderA, 'file2.ts'), + makeAbsoluteURI(rootFolderA, 'file3.ts'), + ]; + + let wasCanceled = false; + await registerTestSearchProvider({ + provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress, token: vscode.CancellationToken): Thenable { + reportedResults.forEach(r => progress.report(r)); + token.onCancellationRequested(() => wasCanceled = true); + + return TPromise.wrap(null); + } + }); + + const query: ISearchQuery = { + type: QueryType.File, + + filePattern: '', + maxResults: 1, + + folderQueries: [ + { + folder: rootFolderA + } + ] + }; + + const results = await runFileSearch(query); + assert.equal(results.length, 1); + assert(wasCanceled, 'Expected to be canceled when hitting limit'); + compareURIs(results, reportedResults.slice(0, 1)); + }); + + test('max results = 2', async () => { + const reportedResults = [ + makeAbsoluteURI(rootFolderA, 'file1.ts'), + makeAbsoluteURI(rootFolderA, 'file2.ts'), + makeAbsoluteURI(rootFolderA, 'file3.ts'), + ]; + + let wasCanceled = false; + await registerTestSearchProvider({ + provideFileSearchResults(options: vscode.FileSearchOptions, progress: vscode.Progress, token: vscode.CancellationToken): Thenable { + reportedResults.forEach(r => progress.report(r)); + token.onCancellationRequested(() => wasCanceled = true); + + return TPromise.wrap(null); + } + }); + + const query: ISearchQuery = { + type: QueryType.File, + + filePattern: '', + maxResults: 2, + + folderQueries: [ + { + folder: rootFolderA + } + ] + }; + + const results = await runFileSearch(query); + assert.equal(results.length, 2); + assert(wasCanceled, 'Expected to be canceled when hitting limit'); + compareURIs(results, reportedResults.slice(0, 2)); + }); + // Mock fs? // test('Returns result for absolute path', async () => { // const queriedFile = makeFileResult(rootFolderA, 'file2.ts');