Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens.ts
3296 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 { CancelablePromise, createCancelablePromise, RunOnceScheduler } from '../../../../base/common/async.js';
7
import { Disposable } from '../../../../base/common/lifecycle.js';
8
import { ICodeEditor } from '../../../browser/editorBrowser.js';
9
import { EditorContributionInstantiation, registerEditorContribution } from '../../../browser/editorExtensions.js';
10
import { Range } from '../../../common/core/range.js';
11
import { IEditorContribution } from '../../../common/editorCommon.js';
12
import { ITextModel } from '../../../common/model.js';
13
import { getDocumentRangeSemanticTokens, hasDocumentRangeSemanticTokensProvider } from '../common/getSemanticTokens.js';
14
import { isSemanticColoringEnabled, SEMANTIC_HIGHLIGHTING_SETTING_ID } from '../common/semanticTokensConfig.js';
15
import { toMultilineTokens2 } from '../../../common/services/semanticTokensProviderStyling.js';
16
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
17
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
18
import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from '../../../common/services/languageFeatureDebounce.js';
19
import { StopWatch } from '../../../../base/common/stopwatch.js';
20
import { LanguageFeatureRegistry } from '../../../common/languageFeatureRegistry.js';
21
import { DocumentRangeSemanticTokensProvider } from '../../../common/languages.js';
22
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
23
import { ISemanticTokensStylingService } from '../../../common/services/semanticTokensStyling.js';
24
25
export class ViewportSemanticTokensContribution extends Disposable implements IEditorContribution {
26
27
public static readonly ID = 'editor.contrib.viewportSemanticTokens';
28
29
public static get(editor: ICodeEditor): ViewportSemanticTokensContribution | null {
30
return editor.getContribution<ViewportSemanticTokensContribution>(ViewportSemanticTokensContribution.ID);
31
}
32
33
private readonly _editor: ICodeEditor;
34
private readonly _provider: LanguageFeatureRegistry<DocumentRangeSemanticTokensProvider>;
35
private readonly _debounceInformation: IFeatureDebounceInformation;
36
private readonly _tokenizeViewport: RunOnceScheduler;
37
private _outstandingRequests: CancelablePromise<any>[];
38
39
constructor(
40
editor: ICodeEditor,
41
@ISemanticTokensStylingService private readonly _semanticTokensStylingService: ISemanticTokensStylingService,
42
@IThemeService private readonly _themeService: IThemeService,
43
@IConfigurationService private readonly _configurationService: IConfigurationService,
44
@ILanguageFeatureDebounceService languageFeatureDebounceService: ILanguageFeatureDebounceService,
45
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
46
) {
47
super();
48
this._editor = editor;
49
this._provider = languageFeaturesService.documentRangeSemanticTokensProvider;
50
this._debounceInformation = languageFeatureDebounceService.for(this._provider, 'DocumentRangeSemanticTokens', { min: 100, max: 500 });
51
this._tokenizeViewport = this._register(new RunOnceScheduler(() => this._tokenizeViewportNow(), 100));
52
this._outstandingRequests = [];
53
const scheduleTokenizeViewport = () => {
54
if (this._editor.hasModel()) {
55
this._tokenizeViewport.schedule(this._debounceInformation.get(this._editor.getModel()));
56
}
57
};
58
this._register(this._editor.onDidScrollChange(() => {
59
scheduleTokenizeViewport();
60
}));
61
this._register(this._editor.onDidChangeModel(() => {
62
this._cancelAll();
63
scheduleTokenizeViewport();
64
}));
65
this._register(this._editor.onDidChangeModelContent((e) => {
66
this._cancelAll();
67
scheduleTokenizeViewport();
68
}));
69
this._register(this._provider.onDidChange(() => {
70
this._cancelAll();
71
scheduleTokenizeViewport();
72
}));
73
this._register(this._configurationService.onDidChangeConfiguration(e => {
74
if (e.affectsConfiguration(SEMANTIC_HIGHLIGHTING_SETTING_ID)) {
75
this._cancelAll();
76
scheduleTokenizeViewport();
77
}
78
}));
79
this._register(this._themeService.onDidColorThemeChange(() => {
80
this._cancelAll();
81
scheduleTokenizeViewport();
82
}));
83
scheduleTokenizeViewport();
84
}
85
86
private _cancelAll(): void {
87
for (const request of this._outstandingRequests) {
88
request.cancel();
89
}
90
this._outstandingRequests = [];
91
}
92
93
private _removeOutstandingRequest(req: CancelablePromise<any>): void {
94
for (let i = 0, len = this._outstandingRequests.length; i < len; i++) {
95
if (this._outstandingRequests[i] === req) {
96
this._outstandingRequests.splice(i, 1);
97
return;
98
}
99
}
100
}
101
102
private _tokenizeViewportNow(): void {
103
if (!this._editor.hasModel()) {
104
return;
105
}
106
const model = this._editor.getModel();
107
if (model.tokenization.hasCompleteSemanticTokens()) {
108
return;
109
}
110
if (!isSemanticColoringEnabled(model, this._themeService, this._configurationService)) {
111
if (model.tokenization.hasSomeSemanticTokens()) {
112
model.tokenization.setSemanticTokens(null, false);
113
}
114
return;
115
}
116
if (!hasDocumentRangeSemanticTokensProvider(this._provider, model)) {
117
if (model.tokenization.hasSomeSemanticTokens()) {
118
model.tokenization.setSemanticTokens(null, false);
119
}
120
return;
121
}
122
const visibleRanges = this._editor.getVisibleRangesPlusViewportAboveBelow();
123
124
this._outstandingRequests = this._outstandingRequests.concat(visibleRanges.map(range => this._requestRange(model, range)));
125
}
126
127
private _requestRange(model: ITextModel, range: Range): CancelablePromise<any> {
128
const requestVersionId = model.getVersionId();
129
const request = createCancelablePromise(token => Promise.resolve(getDocumentRangeSemanticTokens(this._provider, model, range, token)));
130
const sw = new StopWatch(false);
131
request.then((r) => {
132
this._debounceInformation.update(model, sw.elapsed());
133
if (!r || !r.tokens || model.isDisposed() || model.getVersionId() !== requestVersionId) {
134
return;
135
}
136
const { provider, tokens: result } = r;
137
const styling = this._semanticTokensStylingService.getStyling(provider);
138
model.tokenization.setPartialSemanticTokens(range, toMultilineTokens2(result, styling, model.getLanguageId()));
139
}).then(() => this._removeOutstandingRequest(request), () => this._removeOutstandingRequest(request));
140
return request;
141
}
142
}
143
144
registerEditorContribution(ViewportSemanticTokensContribution.ID, ViewportSemanticTokensContribution, EditorContributionInstantiation.AfterFirstRender);
145
146