Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/codelens/browser/codeLensCache.ts
4779 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Event } from '../../../../base/common/event.js';
7
import { LRUCache } from '../../../../base/common/map.js';
8
import { Range } from '../../../common/core/range.js';
9
import { ITextModel } from '../../../common/model.js';
10
import { CodeLens, CodeLensList, CodeLensProvider } from '../../../common/languages.js';
11
import { CodeLensModel } from './codelens.js';
12
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
13
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
14
import { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from '../../../../platform/storage/common/storage.js';
15
import { mainWindow } from '../../../../base/browser/window.js';
16
import { runWhenWindowIdle } from '../../../../base/browser/dom.js';
17
18
export const ICodeLensCache = createDecorator<ICodeLensCache>('ICodeLensCache');
19
20
export interface ICodeLensCache {
21
readonly _serviceBrand: undefined;
22
put(model: ITextModel, data: CodeLensModel): void;
23
get(model: ITextModel): CodeLensModel | undefined;
24
delete(model: ITextModel): void;
25
}
26
27
interface ISerializedCacheData {
28
lineCount: number;
29
lines: number[];
30
}
31
32
class CacheItem {
33
34
constructor(
35
readonly lineCount: number,
36
readonly data: CodeLensModel
37
) { }
38
}
39
40
export class CodeLensCache implements ICodeLensCache {
41
42
declare readonly _serviceBrand: undefined;
43
44
private readonly _fakeProvider = new class implements CodeLensProvider {
45
provideCodeLenses(): CodeLensList {
46
throw new Error('not supported');
47
}
48
};
49
50
private readonly _cache = new LRUCache<string, CacheItem>(20, 0.75);
51
52
constructor(@IStorageService storageService: IStorageService) {
53
54
// remove old data
55
const oldkey = 'codelens/cache';
56
runWhenWindowIdle(mainWindow, () => storageService.remove(oldkey, StorageScope.WORKSPACE));
57
58
// restore lens data on start
59
const key = 'codelens/cache2';
60
const raw = storageService.get(key, StorageScope.WORKSPACE, '{}');
61
this._deserialize(raw);
62
63
// store lens data on shutdown
64
const onWillSaveStateBecauseOfShutdown = Event.filter(storageService.onWillSaveState, e => e.reason === WillSaveStateReason.SHUTDOWN);
65
Event.once(onWillSaveStateBecauseOfShutdown)(e => {
66
storageService.store(key, this._serialize(), StorageScope.WORKSPACE, StorageTarget.MACHINE);
67
});
68
}
69
70
put(model: ITextModel, data: CodeLensModel): void {
71
// create a copy of the model that is without command-ids
72
// but with comand-labels
73
const copyItems = data.lenses.map((item): CodeLens => {
74
return {
75
range: item.symbol.range,
76
command: item.symbol.command && { id: '', title: item.symbol.command?.title },
77
};
78
});
79
const copyModel = new CodeLensModel();
80
copyModel.add({ lenses: copyItems }, this._fakeProvider);
81
82
const item = new CacheItem(model.getLineCount(), copyModel);
83
this._cache.set(model.uri.toString(), item);
84
}
85
86
get(model: ITextModel) {
87
const item = this._cache.get(model.uri.toString());
88
return item && item.lineCount === model.getLineCount() ? item.data : undefined;
89
}
90
91
delete(model: ITextModel): void {
92
this._cache.delete(model.uri.toString());
93
}
94
95
// --- persistence
96
97
private _serialize(): string {
98
const data: Record<string, ISerializedCacheData> = Object.create(null);
99
for (const [key, value] of this._cache) {
100
const lines = new Set<number>();
101
for (const d of value.data.lenses) {
102
lines.add(d.symbol.range.startLineNumber);
103
}
104
data[key] = {
105
lineCount: value.lineCount,
106
lines: [...lines.values()]
107
};
108
}
109
return JSON.stringify(data);
110
}
111
112
private _deserialize(raw: string): void {
113
try {
114
const data: Record<string, ISerializedCacheData> = JSON.parse(raw);
115
for (const key in data) {
116
const element = data[key];
117
const lenses: CodeLens[] = [];
118
for (const line of element.lines) {
119
lenses.push({ range: new Range(line, 1, line, 11) });
120
}
121
122
const model = new CodeLensModel();
123
model.add({ lenses }, this._fakeProvider);
124
this._cache.set(key, new CacheItem(element.lineCount, model));
125
}
126
} catch {
127
// ignore...
128
}
129
}
130
}
131
132
registerSingleton(ICodeLensCache, CodeLensCache, InstantiationType.Delayed);
133
134