diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index e86aa2e27e3..59e116b11d4 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -774,7 +774,7 @@ export class QuickOpenController extends Component implements IQuickOpenService } // Get results - return resolvedHandler.getResults(value).then(result => { + const handleResult = (result) => { if (this.currentResultToken === currentResultToken) { // now is the time to show the input if we did not have set it before @@ -787,7 +787,8 @@ export class QuickOpenController extends Component implements IQuickOpenService const handlerResults = (result && result.entries) || []; this.mergeResults(quickOpenModel, handlerResults, resolvedHandler.getGroupLabel()); } - }); + }; + return resolvedHandler.getResults(value).then(handleResult, undefined, handleResult); }); } diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index ebb31e7a833..551ffbd9808 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -5,7 +5,7 @@ 'use strict'; import nls = require('vs/nls'); -import { TPromise } from 'vs/base/common/winjs.base'; +import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import * as objects from 'vs/base/common/objects'; import filters = require('vs/base/common/filters'); import arrays = require('vs/base/common/arrays'); @@ -34,7 +34,7 @@ export class QuickOpenHandler { * As such, returning the same model instance across multiple searches will yield best * results in terms of performance when many items are shown. */ - public getResults(searchValue: string): TPromise> { + public getResults(searchValue: string): PPromise, IModel> { return TPromise.as(null); } diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index cc77586caa2..7ac06c931f6 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -7,7 +7,7 @@ import * as arrays from 'vs/base/common/arrays'; import * as objects from 'vs/base/common/objects'; -import { TPromise } from 'vs/base/common/winjs.base'; +import { PPromise, TPromise } from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import { ThrottledDelayer } from 'vs/base/common/async'; import types = require('vs/base/common/types'); @@ -91,7 +91,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { private openSymbolHandler: OpenSymbolHandler; private openFileHandler: OpenFileHandler; private searchDelayer: ThrottledDelayer; - private pendingSearch: TPromise; + private pendingSearch: PPromise; private isClosed: boolean; private scorerCache: { [key: string]: number }; private includeSymbols: boolean; @@ -135,7 +135,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { }); } - public getResults(searchValue: string): TPromise { + public getResults(searchValue: string): PPromise { const startTime = Date.now(); this.cancelPendingSearch(); @@ -166,21 +166,21 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Symbol Results (unless disabled or a range or absolute path is specified) if (this.includeSymbols && !searchWithRange) { resultPromises.push(this.openSymbolHandler.getResults(searchValue)); - } else { - resultPromises.push(TPromise.as(new QuickOpenModel())); // We need this empty promise because we are using the throttler below! } // Join and sort unified - this.pendingSearch = TPromise.join(resultPromises).then(results => { + const handleResults = (results: (QuickOpenModel | FileQuickOpenModel)[]) => { this.pendingSearch = null; // If the quick open widget has been closed meanwhile, ignore the result if (this.isClosed) { - return TPromise.as(new QuickOpenModel()); + return new QuickOpenModel(); } // Combine file results and symbol results (if any) - const mergedResults = [...results[0].entries, ...results[1].entries]; + const mergedResults: QuickOpenEntry[] = results.reduce((entries: QuickOpenEntry[], model: QuickOpenModel) => { + return entries.concat(model.entries); + }, []); // Sort const unsortedResultTime = Date.now(); @@ -200,10 +200,11 @@ export class OpenAnythingHandler extends QuickOpenHandler { }); let fileSearchStats: ISearchStats; - if (results[0] instanceof FileQuickOpenModel) { - fileSearchStats = (results[0]).stats; - } else if (results[1] instanceof FileQuickOpenModel) { - fileSearchStats = (results[1]).stats; + for (const result of results) { + if (result instanceof FileQuickOpenModel) { + fileSearchStats = (result).stats; + break; + } } const duration = new Date().getTime() - startTime; @@ -218,10 +219,24 @@ export class OpenAnythingHandler extends QuickOpenHandler { this.telemetryService.publicLog('openAnything', objects.assign(data, { duration })); - return TPromise.as(new QuickOpenModel(viewResults)); - }, (error: Error) => { - this.pendingSearch = null; - this.messageService.show(Severity.Error, error); + return new QuickOpenModel(viewResults); + }; + + this.pendingSearch = new PPromise((complete, error, progress) => { + // When any of the result promises return, forward the result as progress. + resultPromises.map(resultPromise => { + resultPromise.then(result => { + progress(handleResults([result])); + }); + }); + // Complete the promise when all promises have completed. + TPromise.join(resultPromises).then(() => { + // We already sent the results via progress. + complete(new QuickOpenModel()); + }, error => { + this.pendingSearch = null; + this.messageService.show(Severity.Error, error); + }); }); return this.pendingSearch;