提交 1e25b497 编写于 作者: J Johannes Rieken

debt - use cancellation token for outline

上级 21991b49
......@@ -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<string, { promiseCnt: number, promise: TPromise<any>, model: OutlineModel }>(9, .75);
private static readonly _requests = new LRUCache<string, { promiseCnt: number, source: CancellationTokenSource, promise: Promise<any>, 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<OutlineModel> {
static create(textModel: ITextModel, token: CancellationToken): Promise<OutlineModel> {
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<OutlineModel> {
static _create(textModel: ITextModel, token: CancellationToken): Promise<OutlineModel> {
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) {
......
......@@ -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();
......
......@@ -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<OutlineModel> {
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<void> {
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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册