Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/codelens/browser/codelens.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 { CancellationToken } from '../../../../base/common/cancellation.js';
7
import { illegalArgument, onUnexpectedExternalError } from '../../../../base/common/errors.js';
8
import { DisposableStore, isDisposable } from '../../../../base/common/lifecycle.js';
9
import { assertType } from '../../../../base/common/types.js';
10
import { URI } from '../../../../base/common/uri.js';
11
import { ITextModel } from '../../../common/model.js';
12
import { CodeLens, CodeLensList, CodeLensProvider } from '../../../common/languages.js';
13
import { IModelService } from '../../../common/services/model.js';
14
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
15
import { LanguageFeatureRegistry } from '../../../common/languageFeatureRegistry.js';
16
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
17
18
export interface CodeLensItem {
19
readonly symbol: CodeLens;
20
readonly provider: CodeLensProvider;
21
}
22
23
export class CodeLensModel {
24
25
static readonly Empty = new CodeLensModel();
26
27
lenses: CodeLensItem[] = [];
28
29
private _store: DisposableStore | undefined;
30
31
dispose(): void {
32
this._store?.dispose();
33
}
34
35
get isDisposed(): boolean {
36
return this._store?.isDisposed ?? false;
37
}
38
39
add(list: CodeLensList, provider: CodeLensProvider): void {
40
if (isDisposable(list)) {
41
this._store ??= new DisposableStore();
42
this._store.add(list);
43
}
44
for (const symbol of list.lenses) {
45
this.lenses.push({ symbol, provider });
46
}
47
}
48
}
49
50
export async function getCodeLensModel(registry: LanguageFeatureRegistry<CodeLensProvider>, model: ITextModel, token: CancellationToken): Promise<CodeLensModel> {
51
52
const provider = registry.ordered(model);
53
const providerRanks = new Map<CodeLensProvider, number>();
54
const result = new CodeLensModel();
55
56
const promises = provider.map(async (provider, i) => {
57
58
providerRanks.set(provider, i);
59
60
try {
61
const list = await Promise.resolve(provider.provideCodeLenses(model, token));
62
if (list) {
63
result.add(list, provider);
64
}
65
} catch (err) {
66
onUnexpectedExternalError(err);
67
}
68
});
69
70
await Promise.all(promises);
71
72
if (token.isCancellationRequested) {
73
result.dispose();
74
return CodeLensModel.Empty;
75
}
76
77
result.lenses = result.lenses.sort((a, b) => {
78
// sort by lineNumber, provider-rank, and column
79
if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) {
80
return -1;
81
} else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) {
82
return 1;
83
} else if ((providerRanks.get(a.provider)!) < (providerRanks.get(b.provider)!)) {
84
return -1;
85
} else if ((providerRanks.get(a.provider)!) > (providerRanks.get(b.provider)!)) {
86
return 1;
87
} else if (a.symbol.range.startColumn < b.symbol.range.startColumn) {
88
return -1;
89
} else if (a.symbol.range.startColumn > b.symbol.range.startColumn) {
90
return 1;
91
} else {
92
return 0;
93
}
94
});
95
return result;
96
}
97
98
CommandsRegistry.registerCommand('_executeCodeLensProvider', function (accessor, ...args: [URI, number | undefined | null]) {
99
let [uri, itemResolveCount] = args;
100
assertType(URI.isUri(uri));
101
assertType(typeof itemResolveCount === 'number' || !itemResolveCount);
102
103
const { codeLensProvider } = accessor.get(ILanguageFeaturesService);
104
105
const model = accessor.get(IModelService).getModel(uri);
106
if (!model) {
107
throw illegalArgument();
108
}
109
110
const result: CodeLens[] = [];
111
const disposables = new DisposableStore();
112
return getCodeLensModel(codeLensProvider, model, CancellationToken.None).then(value => {
113
114
disposables.add(value);
115
const resolve: Promise<unknown>[] = [];
116
117
for (const item of value.lenses) {
118
if (itemResolveCount === undefined || itemResolveCount === null || Boolean(item.symbol.command)) {
119
result.push(item.symbol);
120
} else if (itemResolveCount-- > 0 && item.provider.resolveCodeLens) {
121
resolve.push(Promise.resolve(item.provider.resolveCodeLens(model, item.symbol, CancellationToken.None)).then(symbol => result.push(symbol || item.symbol)));
122
}
123
}
124
125
return Promise.all(resolve);
126
127
}).then(() => {
128
return result;
129
}).finally(() => {
130
// make sure to return results, then (on next tick)
131
// dispose the results
132
setTimeout(() => disposables.dispose(), 100);
133
});
134
});
135
136