Skip to content

Commit cd7a106

Browse files
committed
1 parent 1ddbe37 commit cd7a106

3 files changed

Lines changed: 74 additions & 19 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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 { ITextModel } from 'vs/editor/common/model';
7+
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
8+
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
9+
import { ICodeLensData } from 'vs/editor/contrib/codelens/codelens';
10+
import { LRUCache } from 'vs/base/common/map';
11+
import { ICodeLensSymbol, CodeLensProvider } from 'vs/editor/common/modes';
12+
13+
export const ICodeLensCache = createDecorator<ICodeLensCache>('ICodeLensCache');
14+
15+
export interface ICodeLensCache {
16+
_serviceBrand: any;
17+
put(model: ITextModel, data: ICodeLensData[]): void;
18+
get(model: ITextModel): ICodeLensData[] | undefined;
19+
}
20+
21+
22+
registerSingleton(ICodeLensCache, class implements ICodeLensCache {
23+
24+
_serviceBrand: any;
25+
26+
private readonly _cache = new LRUCache<string, ICodeLensData[]>(15, 0.75);
27+
28+
private readonly _fakeProvider = new class implements CodeLensProvider {
29+
provideCodeLenses(): ICodeLensSymbol[] {
30+
throw new Error('not supported');
31+
}
32+
};
33+
34+
put(model: ITextModel, data: ICodeLensData[]): void {
35+
this._cache.set(this._makeKey(model), data.map(item => {
36+
return {
37+
symbol: item.symbol,
38+
provider: this._fakeProvider
39+
};
40+
}));
41+
}
42+
43+
get(model: ITextModel) {
44+
return this._cache.get(this._makeKey(model));
45+
}
46+
47+
private _makeKey(model: ITextModel): string {
48+
return model.id + model.getVersionId;
49+
}
50+
}, true);

src/vs/editor/contrib/codelens/codelensController.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { ICodeLensData, getCodeLensData } from 'vs/editor/contrib/codelens/codel
1717
import { CodeLens, CodeLensHelper } from 'vs/editor/contrib/codelens/codelensWidget';
1818
import { ICommandService } from 'vs/platform/commands/common/commands';
1919
import { INotificationService } from 'vs/platform/notification/common/notification';
20+
import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache';
2021

2122
export class CodeLensContribution implements editorCommon.IEditorContribution {
2223

@@ -35,7 +36,8 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
3536
constructor(
3637
private readonly _editor: editorBrowser.ICodeEditor,
3738
@ICommandService private readonly _commandService: ICommandService,
38-
@INotificationService private readonly _notificationService: INotificationService
39+
@INotificationService private readonly _notificationService: INotificationService,
40+
@ICodeLensCache private readonly _codeLensCache: ICodeLensCache
3941
) {
4042
this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens;
4143

@@ -104,6 +106,11 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
104106
}
105107
}
106108

109+
const cachedLenses = this._codeLensCache.get(model);
110+
if (cachedLenses) {
111+
this._renderCodeLensSymbols(cachedLenses);
112+
}
113+
107114
this._detectVisibleLenses = new RunOnceScheduler(() => {
108115
this._onViewportChanged();
109116
}, 500);
@@ -116,8 +123,9 @@ export class CodeLensContribution implements editorCommon.IEditorContribution {
116123

117124
this._currentFindCodeLensSymbolsPromise = createCancelablePromise(token => getCodeLensData(model, token));
118125

119-
this._currentFindCodeLensSymbolsPromise.then((result) => {
126+
this._currentFindCodeLensSymbolsPromise.then(result => {
120127
if (counterValue === this._modelChangeCounter) { // only the last one wins
128+
this._codeLensCache.put(model, result);
121129
this._renderCodeLensSymbols(result);
122130
this._detectVisibleLenses.schedule();
123131
}

src/vs/editor/contrib/codelens/codelensWidget.ts

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
5858
private readonly _id: string;
5959
private readonly _domNode: HTMLElement;
6060
private readonly _editor: editorBrowser.ICodeEditor;
61+
private readonly _commands = new Map<string, Command>();
6162

6263
private _widgetPosition: editorBrowser.IContentWidgetPosition;
63-
private _commands: { [id: string]: Command } = Object.create(null);
6464

6565
constructor(
6666
editor: editorBrowser.ICodeEditor,
67-
symbolRange: Range
67+
symbolRange: Range,
68+
data: ICodeLensData[]
6869
) {
6970
this._id = 'codeLensWidget' + (++CodeLensContentWidget._idPool);
7071
this._editor = editor;
@@ -74,9 +75,8 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
7475
this._domNode = document.createElement('span');
7576
this._domNode.innerHTML = '&nbsp;';
7677
dom.addClass(this._domNode, 'codelens-decoration');
77-
dom.addClass(this._domNode, 'invisible-cl');
7878
this.updateHeight();
79-
this.updateVisibility();
79+
this.withCommands(data.map(data => data.symbol), false);
8080
}
8181

8282
updateHeight(): void {
@@ -88,15 +88,9 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
8888
this._domNode.innerHTML = '&nbsp;';
8989
}
9090

91-
updateVisibility(): void {
92-
if (this.isVisible()) {
93-
dom.removeClass(this._domNode, 'invisible-cl');
94-
dom.addClass(this._domNode, 'fadein');
95-
}
96-
}
91+
withCommands(inSymbols: Array<ICodeLensSymbol | undefined | null>, animate: boolean): void {
92+
this._commands.clear();
9793

98-
withCommands(inSymbols: Array<ICodeLensSymbol | undefined | null>): void {
99-
this._commands = Object.create(null);
10094
const symbols = coalesce(inSymbols);
10195
if (isFalsyOrEmpty(symbols)) {
10296
this._domNode.innerHTML = '<span>no commands</span>';
@@ -111,21 +105,25 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget {
111105
let part: string;
112106
if (command.id) {
113107
part = `<a id=${i}>${title}</a>`;
114-
this._commands[i] = command;
108+
this._commands.set(String(i), command);
115109
} else {
116110
part = `<span>${title}</span>`;
117111
}
118112
html.push(part);
119113
}
120114
}
121115

116+
const wasEmpty = this._domNode.innerHTML === '' || this._domNode.innerHTML === '&nbsp;';
122117
this._domNode.innerHTML = html.join('<span>&nbsp;|&nbsp;</span>');
123118
this._editor.layoutContentWidget(this);
119+
if (wasEmpty && animate) {
120+
dom.addClass(this._domNode, 'fadein');
121+
}
124122
}
125123

126124
getCommand(link: HTMLLinkElement): Command | undefined {
127125
return link.parentElement === this._domNode
128-
? this._commands[link.id]
126+
? this._commands.get(link.id)
129127
: undefined;
130128
}
131129

@@ -228,7 +226,7 @@ export class CodeLens {
228226
});
229227

230228
if (range) {
231-
this._contentWidget = new CodeLensContentWidget(editor, range);
229+
this._contentWidget = new CodeLensContentWidget(editor, range, this._data);
232230
this._viewZone = new CodeLensViewZone(range.startLineNumber - 1, updateCallback);
233231

234232
this._viewZoneId = viewZoneChangeAccessor.addZone(this._viewZone);
@@ -273,7 +271,6 @@ export class CodeLens {
273271
}
274272

275273
computeIfNecessary(model: ITextModel): ICodeLensData[] | null {
276-
this._contentWidget.updateVisibility(); // trigger the fade in
277274
if (!this._contentWidget.isVisible()) {
278275
return null;
279276
}
@@ -289,7 +286,7 @@ export class CodeLens {
289286
}
290287

291288
updateCommands(symbols: Array<ICodeLensSymbol | undefined | null>): void {
292-
this._contentWidget.withCommands(symbols);
289+
this._contentWidget.withCommands(symbols, true);
293290
for (let i = 0; i < this._data.length; i++) {
294291
const resolved = symbols[i];
295292
if (resolved) {

0 commit comments

Comments
 (0)