Path: blob/main/src/vs/editor/contrib/codelens/browser/codeLensCache.ts
4779 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Event } from '../../../../base/common/event.js';6import { LRUCache } from '../../../../base/common/map.js';7import { Range } from '../../../common/core/range.js';8import { ITextModel } from '../../../common/model.js';9import { CodeLens, CodeLensList, CodeLensProvider } from '../../../common/languages.js';10import { CodeLensModel } from './codelens.js';11import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';12import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';13import { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from '../../../../platform/storage/common/storage.js';14import { mainWindow } from '../../../../base/browser/window.js';15import { runWhenWindowIdle } from '../../../../base/browser/dom.js';1617export const ICodeLensCache = createDecorator<ICodeLensCache>('ICodeLensCache');1819export interface ICodeLensCache {20readonly _serviceBrand: undefined;21put(model: ITextModel, data: CodeLensModel): void;22get(model: ITextModel): CodeLensModel | undefined;23delete(model: ITextModel): void;24}2526interface ISerializedCacheData {27lineCount: number;28lines: number[];29}3031class CacheItem {3233constructor(34readonly lineCount: number,35readonly data: CodeLensModel36) { }37}3839export class CodeLensCache implements ICodeLensCache {4041declare readonly _serviceBrand: undefined;4243private readonly _fakeProvider = new class implements CodeLensProvider {44provideCodeLenses(): CodeLensList {45throw new Error('not supported');46}47};4849private readonly _cache = new LRUCache<string, CacheItem>(20, 0.75);5051constructor(@IStorageService storageService: IStorageService) {5253// remove old data54const oldkey = 'codelens/cache';55runWhenWindowIdle(mainWindow, () => storageService.remove(oldkey, StorageScope.WORKSPACE));5657// restore lens data on start58const key = 'codelens/cache2';59const raw = storageService.get(key, StorageScope.WORKSPACE, '{}');60this._deserialize(raw);6162// store lens data on shutdown63const onWillSaveStateBecauseOfShutdown = Event.filter(storageService.onWillSaveState, e => e.reason === WillSaveStateReason.SHUTDOWN);64Event.once(onWillSaveStateBecauseOfShutdown)(e => {65storageService.store(key, this._serialize(), StorageScope.WORKSPACE, StorageTarget.MACHINE);66});67}6869put(model: ITextModel, data: CodeLensModel): void {70// create a copy of the model that is without command-ids71// but with comand-labels72const copyItems = data.lenses.map((item): CodeLens => {73return {74range: item.symbol.range,75command: item.symbol.command && { id: '', title: item.symbol.command?.title },76};77});78const copyModel = new CodeLensModel();79copyModel.add({ lenses: copyItems }, this._fakeProvider);8081const item = new CacheItem(model.getLineCount(), copyModel);82this._cache.set(model.uri.toString(), item);83}8485get(model: ITextModel) {86const item = this._cache.get(model.uri.toString());87return item && item.lineCount === model.getLineCount() ? item.data : undefined;88}8990delete(model: ITextModel): void {91this._cache.delete(model.uri.toString());92}9394// --- persistence9596private _serialize(): string {97const data: Record<string, ISerializedCacheData> = Object.create(null);98for (const [key, value] of this._cache) {99const lines = new Set<number>();100for (const d of value.data.lenses) {101lines.add(d.symbol.range.startLineNumber);102}103data[key] = {104lineCount: value.lineCount,105lines: [...lines.values()]106};107}108return JSON.stringify(data);109}110111private _deserialize(raw: string): void {112try {113const data: Record<string, ISerializedCacheData> = JSON.parse(raw);114for (const key in data) {115const element = data[key];116const lenses: CodeLens[] = [];117for (const line of element.lines) {118lenses.push({ range: new Range(line, 1, line, 11) });119}120121const model = new CodeLensModel();122model.add({ lenses }, this._fakeProvider);123this._cache.set(key, new CacheItem(element.lineCount, model));124}125} catch {126// ignore...127}128}129}130131registerSingleton(ICodeLensCache, CodeLensCache, InstantiationType.Delayed);132133134