outline - more correct request caching

This commit is contained in:
Johannes Rieken 2018-06-15 15:41:22 +02:00
parent 8a7521f2a9
commit 8cfc11a461
2 changed files with 75 additions and 9 deletions

View file

@ -193,7 +193,7 @@ export class OutlineGroup extends TreeElement {
export class OutlineModel extends TreeElement {
private static readonly _requests = new LRUCache<string, { count: number, promise: TPromise<OutlineModel> }>(9, .75);
private static readonly _requests = new LRUCache<string, { promiseCnt: number, promise: TPromise<any>, model: OutlineModel }>(9, .75);
static create(textModel: ITextModel): TPromise<OutlineModel> {
@ -201,25 +201,35 @@ export class OutlineModel extends TreeElement {
let data = OutlineModel._requests.get(key);
if (!data) {
data = { promise: OutlineModel._create(textModel), count: 0 };
data = {
promiseCnt: 0,
promise: OutlineModel._create(textModel),
model: undefined,
};
OutlineModel._requests.set(key, data);
}
if (data.model) {
// resolved -> return data
return TPromise.as(data.model);
}
// increase usage counter
data.count += 1;
data.promiseCnt += 1;
return new TPromise((resolve, reject) => {
data.promise.then(value => {
OutlineModel._requests.delete(key);
resolve(value);
data.promise.then(model => {
data.model = model;
resolve(model);
}, err => {
OutlineModel._requests.delete(key);
reject(err);
});
}, () => {
// last -> cancel provider request, remove cached promise
if (--data.count === 0) {
if (--data.promiseCnt === 0) {
data.promise.cancel();
OutlineModel._requests.delete(key);
}
});
}

View file

@ -6,13 +6,69 @@
'use strict';
import * as assert from 'assert';
import { OutlineElement, OutlineGroup } from '../outlineModel';
import { SymbolKind, DocumentSymbol } from 'vs/editor/common/modes';
import { OutlineElement, OutlineGroup, OutlineModel } from '../outlineModel';
import { SymbolKind, DocumentSymbol, DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';
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';
suite('OutlineModel', function () {
test('OutlineModel#create, cached', async function () {
let model = TextModel.createFromString('foo', undefined, undefined, URI.file('/fome/path.foo'));
let count = 0;
let reg = DocumentSymbolProviderRegistry.register({ pattern: '**/path.foo' }, {
provideDocumentSymbols() {
count += 1;
return [];
}
});
await OutlineModel.create(model);
assert.equal(count, 1);
// cached
await OutlineModel.create(model);
assert.equal(count, 1);
// new version
model.applyEdits([{ text: 'XXX', range: new Range(1, 1, 1, 1) }]);
await OutlineModel.create(model);
assert.equal(count, 2);
reg.dispose();
});
test('OutlineModel#create, cached/cancel', async function () {
let model = TextModel.createFromString('foo', undefined, undefined, URI.file('/fome/path.foo'));
let isCancelled = false;
let reg = DocumentSymbolProviderRegistry.register({ pattern: '**/path.foo' }, {
provideDocumentSymbols(d, token) {
return new Promise(resolve => {
token.onCancellationRequested(_ => {
isCancelled = true;
resolve(null);
});
});
}
});
assert.equal(isCancelled, false);
let p1 = OutlineModel.create(model);
let p2 = OutlineModel.create(model);
p1.cancel();
assert.equal(isCancelled, false);
p2.cancel();
assert.equal(isCancelled, true);
reg.dispose();
});
function fakeSymbolInformation(range: Range, name: string = 'foo'): DocumentSymbol {
return {