diff --git a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts index 861859a7f4f..29a81a2b32d 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts @@ -24,7 +24,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape } from '../node/extHost.protocol'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -113,7 +113,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- search --- - $startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable { + $startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Thenable { const workspace = this._contextService.getWorkspace(); if (!workspace.folders.length) { return undefined; @@ -158,8 +158,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { this._searchService.extendQuery(query); - const tokenSource = new CancellationTokenSource(); - const search = this._searchService.search(query, tokenSource.token).then(result => { + return this._searchService.search(query, token).then(result => { return result.results.map(m => m.resource); }, err => { if (!isPromiseCanceledError(err)) { @@ -167,18 +166,9 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } return undefined; }); - - this._activeCancelTokens[requestId] = tokenSource; - const onDone = () => { - tokenSource.dispose(); - delete this._activeCancelTokens[requestId]; - }; - search.then(onDone, onDone); - - return search; } - $startTextSearch(pattern: IPatternInfo, options: IQueryOptions, requestId: number): Thenable { + $startTextSearch(pattern: IPatternInfo, options: IQueryOptions, requestId: number, token: CancellationToken): Thenable { const workspace = this._contextService.getWorkspace(); const folders = workspace.folders.map(folder => folder.uri); @@ -191,8 +181,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { } }; - const tokenSource = new CancellationTokenSource(); - const search = this._searchService.search(query, tokenSource.token, onProgress).then( + const search = this._searchService.search(query, token, onProgress).then( () => { return null; }, @@ -204,17 +193,10 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { return undefined; }); - this._activeCancelTokens[requestId] = tokenSource; - const onDone = () => { - tokenSource.dispose(); - delete this._activeCancelTokens[requestId]; - }; - search.then(onDone, onDone); - return search; } - $checkExists(includes: string[], requestId: number): Thenable { + $checkExists(includes: string[], token: CancellationToken): Thenable { const queryBuilder = this._instantiationService.createInstance(QueryBuilder); const folders = this._contextService.getWorkspace().folders.map(folder => folder.uri); const query = queryBuilder.file(folders, { @@ -222,34 +204,17 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { exists: true }); - const tokenSource = new CancellationTokenSource(); - const search = this._searchService.search(query, tokenSource.token).then( + return this._searchService.search(query, token).then( result => { - delete this._activeCancelTokens[requestId]; return result.limitHit; }, err => { - delete this._activeCancelTokens[requestId]; if (!isPromiseCanceledError(err)) { return TPromise.wrapError(err); } return undefined; }); - - this._activeCancelTokens[requestId] = tokenSource; - - return search; - } - - $cancelSearch(requestId: number): Thenable { - const tokenSource = this._activeCancelTokens[requestId]; - if (tokenSource) { - delete this._activeCancelTokens[requestId]; - tokenSource.cancel(); - return TPromise.as(true); - } - return undefined; } // --- save & edit resources --- diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index c9c12d075df..6c935c93b48 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -470,10 +470,9 @@ export interface ExtHostUrlsShape { } export interface MainThreadWorkspaceShape extends IDisposable { - $startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable; - $startTextSearch(query: IPatternInfo, options: IQueryOptions, requestId: number): Thenable; - $checkExists(includes: string[], requestId: number): Thenable; - $cancelSearch(requestId: number): Thenable; + $startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Thenable; + $startTextSearch(query: IPatternInfo, options: IQueryOptions, requestId: number, token: CancellationToken): Thenable; + $checkExists(includes: string[], token: CancellationToken): Thenable; $saveAll(includeUntitled?: boolean): Thenable; $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Thenable; } diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index 2188ae2eb64..76e7c914f66 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -93,7 +93,7 @@ export class ExtHostSearch implements ExtHostSearchShape { }); } else { const indexProvider = this._fileIndexProvider.get(handle); - return this._fileIndexSearchManager.fileSearch(query, indexProvider, batch => { + const searchP = this._fileIndexSearchManager.fileSearch(query, indexProvider, batch => { this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource)); }).then(null, err => { if (!isPromiseCanceledError(err)) { @@ -102,6 +102,10 @@ export class ExtHostSearch implements ExtHostSearchShape { return null; }); + + token.onCancellationRequested(() => searchP.cancel()); + + return searchP; } } diff --git a/src/vs/workbench/api/node/extHostWorkspace.ts b/src/vs/workbench/api/node/extHostWorkspace.ts index 2a8e6fa1e4a..26f0f0bf0bb 100644 --- a/src/vs/workbench/api/node/extHostWorkspace.ts +++ b/src/vs/workbench/api/node/extHostWorkspace.ts @@ -24,6 +24,7 @@ import { Range } from 'vs/workbench/api/node/extHostTypes'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import * as vscode from 'vscode'; import { ExtHostWorkspaceShape, IMainContext, IWorkspaceData, MainContext, MainThreadMessageServiceShape, MainThreadWorkspaceShape } from './extHost.protocol'; +import { CancellationToken } from 'vs/base/common/cancellation'; function isFolderEqual(folderA: URI, folderB: URI): boolean { return isEqual(folderA, folderB, !isLinux); @@ -345,11 +346,9 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { // --- search --- - findFiles(include: vscode.GlobPattern, exclude: vscode.GlobPattern, maxResults: number, extensionId: string, token?: vscode.CancellationToken): Thenable { + findFiles(include: vscode.GlobPattern, exclude: vscode.GlobPattern, maxResults: number, extensionId: string, token: vscode.CancellationToken = CancellationToken.None): Thenable { this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId}, entryPoint: findFiles`); - const requestId = this._requestIdProvider.getNext(); - let includePattern: string; let includeFolder: string; if (include) { @@ -376,14 +375,11 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { return TPromise.wrap([]); } - const result = this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, requestId); - if (token) { - token.onCancellationRequested(() => this._proxy.$cancelSearch(requestId)); - } - return result.then(data => Array.isArray(data) ? data.map(URI.revive) : []); + return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token) + .then(data => Array.isArray(data) ? data.map(URI.revive) : []); } - findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: string, token?: vscode.CancellationToken) { + findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: string, token: vscode.CancellationToken = CancellationToken.None) { this._logService.trace(`extHostWorkspace#findTextInFiles: textSearch, extension: ${extensionId}, entryPoint: findTextInFiles`); if (options.previewOptions && options.previewOptions.totalChars <= options.previewOptions.leadingChars) { @@ -431,18 +427,11 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape { }); }; - if (token) { - if (token.isCancellationRequested) { - return TPromise.wrap(undefined); - } else { - token.onCancellationRequested(() => { - isCanceled = true; - this._proxy.$cancelSearch(requestId); - }); - } + if (token.isCancellationRequested) { + return TPromise.wrap(undefined); } - return this._proxy.$startTextSearch(query, queryOptions, requestId).then( + return this._proxy.$startTextSearch(query, queryOptions, requestId, token).then( () => { delete this._activeSearchCallbacks[requestId]; }, diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index 89d53c520af..8fbb0efc2e2 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -23,6 +23,7 @@ import { URI } from 'vs/base/common/uri'; import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; import { timeout } from 'vs/base/common/async'; import { Counter } from 'vs/base/common/numbers'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; const nativeExit = process.exit.bind(process); function patchProcess(allowExit: boolean) { @@ -264,17 +265,27 @@ export class ExtensionHostMain { return TPromise.as(void 0); } - const requestId = this._searchRequestIdProvider.getNext(); - const searchP = this._mainThreadWorkspace.$checkExists(globPatterns, requestId); + const tokenSource = new CancellationTokenSource(); + const searchP = this._mainThreadWorkspace.$checkExists(globPatterns, tokenSource.token); const timer = setTimeout(async () => { - await this._mainThreadWorkspace.$cancelSearch(requestId); + tokenSource.cancel(); this._extensionService.activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContainsTimeout:${globPatterns.join(',')}`)) .then(null, err => console.error(err)); }, ExtensionHostMain.WORKSPACE_CONTAINS_TIMEOUT); - const exists = await searchP; + let exists: boolean; + try { + exists = await searchP; + } catch (err) { + if (!errors.isPromiseCanceledError(err)) { + console.error(err); + } + } + + tokenSource.dispose(); clearTimeout(timer); + if (exists) { // a file was found matching one of the glob patterns return (