From 1e25b497f7f451f3839ba4bb12af230471353319 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 3 Jul 2018 16:19:17 +0200 Subject: [PATCH] debt - use cancellation token for outline --- .../contrib/documentSymbols/outlineModel.ts | 35 ++++++++++--------- .../documentSymbols/test/outlineModel.test.ts | 17 +++++---- .../outline/electron-browser/outlinePanel.ts | 18 ++++++++-- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts index f448469a22f..a2a8a2447f8 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineModel.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineModel.ts @@ -6,8 +6,6 @@ import { DocumentSymbolProviderRegistry, DocumentSymbolProvider, DocumentSymbol } from 'vs/editor/common/modes'; import { ITextModel } from 'vs/editor/common/model'; -import { asWinJsPromise } from 'vs/base/common/async'; -import { TPromise } from 'vs/base/common/winjs.base'; import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters'; import { IPosition } from 'vs/editor/common/core/position'; import { Range, IRange } from 'vs/editor/common/core/range'; @@ -17,6 +15,7 @@ import { commonPrefixLength } from 'vs/base/common/strings'; import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { onUnexpectedExternalError } from 'vs/base/common/errors'; import { LRUCache } from 'vs/base/common/map'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; export abstract class TreeElement { abstract id: string; @@ -196,7 +195,7 @@ export class OutlineGroup extends TreeElement { export class OutlineModel extends TreeElement { - private static readonly _requests = new LRUCache, model: OutlineModel }>(9, .75); + private static readonly _requests = new LRUCache, model: OutlineModel }>(9, .75); private static readonly _keys = new class { private _counter = 1; @@ -221,15 +220,17 @@ export class OutlineModel extends TreeElement { }; - static create(textModel: ITextModel): TPromise { + static create(textModel: ITextModel, token: CancellationToken): Promise { let key = this._keys.for(textModel); let data = OutlineModel._requests.get(key); if (!data) { + let source = new CancellationTokenSource(); data = { promiseCnt: 0, - promise: OutlineModel._create(textModel), + source, + promise: OutlineModel._create(textModel, source.token), model: undefined, }; OutlineModel._requests.set(key, data); @@ -237,13 +238,21 @@ export class OutlineModel extends TreeElement { if (data.model) { // resolved -> return data - return TPromise.as(data.model); + return Promise.resolve(data.model); } // increase usage counter data.promiseCnt += 1; - return new TPromise((resolve, reject) => { + token.onCancellationRequested(() => { + // last -> cancel provider request, remove cached promise + if (--data.promiseCnt === 0) { + data.source.cancel(); + OutlineModel._requests.delete(key); + } + }); + + return new Promise((resolve, reject) => { data.promise.then(model => { data.model = model; resolve(model); @@ -251,16 +260,10 @@ export class OutlineModel extends TreeElement { OutlineModel._requests.delete(key); reject(err); }); - }, () => { - // last -> cancel provider request, remove cached promise - if (--data.promiseCnt === 0) { - data.promise.cancel(); - OutlineModel._requests.delete(key); - } }); } - static _create(textModel: ITextModel): TPromise { + static _create(textModel: ITextModel, token: CancellationToken): Promise { let result = new OutlineModel(textModel); let promises = DocumentSymbolProviderRegistry.ordered(textModel).map((provider, index) => { @@ -268,7 +271,7 @@ export class OutlineModel extends TreeElement { let id = TreeElement.findId(`provider_${index}`, result); let group = new OutlineGroup(id, result, provider, index); - return asWinJsPromise(token => provider.provideDocumentSymbols(result.textModel, token)).then(result => { + return Promise.resolve(provider.provideDocumentSymbols(result.textModel, token)).then(result => { if (!isFalsyOrEmpty(result)) { for (const info of result) { OutlineModel._makeOutlineElement(info, group); @@ -283,7 +286,7 @@ export class OutlineModel extends TreeElement { }); }); - return TPromise.join(promises).then(() => { + return Promise.all(promises).then(() => { let count = 0; for (const key in result._groups) { diff --git a/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts b/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts index bd34ffd3550..c07576219f8 100644 --- a/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts +++ b/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts @@ -12,6 +12,7 @@ import { Range } from 'vs/editor/common/core/range'; import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { TextModel } from 'vs/editor/common/model/textModel'; import URI from 'vs/base/common/uri'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; suite('OutlineModel', function () { @@ -26,16 +27,16 @@ suite('OutlineModel', function () { } }); - await OutlineModel.create(model); + await OutlineModel.create(model, CancellationToken.None); assert.equal(count, 1); // cached - await OutlineModel.create(model); + await OutlineModel.create(model, CancellationToken.None); assert.equal(count, 1); // new version model.applyEdits([{ text: 'XXX', range: new Range(1, 1, 1, 1) }]); - await OutlineModel.create(model); + await OutlineModel.create(model, CancellationToken.None); assert.equal(count, 2); reg.dispose(); @@ -58,13 +59,15 @@ suite('OutlineModel', function () { }); assert.equal(isCancelled, false); - let p1 = OutlineModel.create(model); - let p2 = OutlineModel.create(model); + let s1 = new CancellationTokenSource(); + OutlineModel.create(model, s1.token); + let s2 = new CancellationTokenSource(); + OutlineModel.create(model, s2.token); - p1.cancel(); + s1.cancel(); assert.equal(isCancelled, false); - p2.cancel(); + s2.cancel(); assert.equal(isCancelled, true); reg.dispose(); diff --git a/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts b/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts index fa4a2ed4c07..83d1491b256 100644 --- a/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts +++ b/src/vs/workbench/parts/outline/electron-browser/outlinePanel.ts @@ -13,8 +13,8 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { Action, IAction, RadioGroup } from 'vs/base/common/actions'; import { firstIndex } from 'vs/base/common/arrays'; -import { asDisposablePromise, setDisposableTimeout } from 'vs/base/common/async'; -import { onUnexpectedError } from 'vs/base/common/errors'; +import { asDisposablePromise, setDisposableTimeout, createCancelablePromise } from 'vs/base/common/async'; +import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors'; import { Emitter } from 'vs/base/common/event'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -54,6 +54,7 @@ import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron import { OutlineConfigKeys, OutlineViewFiltered, OutlineViewFocused, OutlineViewId } from './outline'; import { OutlineController, OutlineDataSource, OutlineItemComparator, OutlineItemCompareType, OutlineItemFilter, OutlineRenderer, OutlineTreeState } from '../../../../editor/contrib/documentSymbols/outlineTree'; import { IResourceInput } from 'vs/platform/editor/common/editor'; +import { ITextModel } from 'vs/editor/common/model'; class RequestState { @@ -440,6 +441,17 @@ export class OutlinePanel extends ViewletPanel { this._message.innerText = escape(message); } + private static _createOutlineModel(model: ITextModel, disposables: IDisposable[]): Promise { + let promise = createCancelablePromise(token => OutlineModel.create(model, token)); + disposables.push({ dispose() { promise.cancel(); } }); + return promise.catch(err => { + if (!isPromiseCanceledError(err)) { + throw err; + } + return undefined; + }); + } + private async _doUpdate(editor: ICodeEditor, event: IModelContentChangedEvent): Promise { dispose(this._editorDisposables); @@ -464,7 +476,7 @@ export class OutlinePanel extends ViewletPanel { ); } - let model = await asDisposablePromise(OutlineModel.create(textModel), undefined, this._editorDisposables).promise; + let model = await OutlinePanel._createOutlineModel(textModel, this._editorDisposables); dispose(loadingMessage); if (!model) { return; -- GitLab