Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/model/tokens/abstractSyntaxTokenBackend.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 { equals } from '../../../../base/common/arrays.js';
7
import { RunOnceScheduler } from '../../../../base/common/async.js';
8
import { Emitter, Event } from '../../../../base/common/event.js';
9
import { Disposable } from '../../../../base/common/lifecycle.js';
10
import { LineRange } from '../../core/ranges/lineRange.js';
11
import { StandardTokenType } from '../../encodedTokenAttributes.js';
12
import { ILanguageIdCodec } from '../../languages.js';
13
import { IAttachedView } from '../../model.js';
14
import { TextModel } from '../textModel.js';
15
import { IModelContentChangedEvent, IModelTokensChangedEvent } from '../../textModelEvents.js';
16
import { BackgroundTokenizationState } from '../../tokenizationTextModelPart.js';
17
import { LineTokens } from '../../tokens/lineTokens.js';
18
import { derivedOpts, IObservable, ISettableObservable, observableSignal, observableValueOpts } from '../../../../base/common/observable.js';
19
import { equalsIfDefined, itemEquals, itemsEquals } from '../../../../base/common/equals.js';
20
21
/**
22
* @internal
23
*/
24
export class AttachedViews {
25
private readonly _onDidChangeVisibleRanges = new Emitter<{ view: IAttachedView; state: AttachedViewState | undefined }>();
26
public readonly onDidChangeVisibleRanges = this._onDidChangeVisibleRanges.event;
27
28
private readonly _views = new Set<AttachedViewImpl>();
29
private readonly _viewsChanged = observableSignal(this);
30
31
public readonly visibleLineRanges: IObservable<readonly LineRange[]>;
32
33
constructor() {
34
this.visibleLineRanges = derivedOpts({
35
owner: this,
36
equalsFn: itemsEquals(itemEquals())
37
}, reader => {
38
this._viewsChanged.read(reader);
39
const ranges = LineRange.joinMany(
40
[...this._views].map(view => view.state.read(reader)?.visibleLineRanges ?? [])
41
);
42
return ranges;
43
});
44
}
45
46
public attachView(): IAttachedView {
47
const view = new AttachedViewImpl((state) => {
48
this._onDidChangeVisibleRanges.fire({ view, state });
49
});
50
this._views.add(view);
51
this._viewsChanged.trigger(undefined);
52
return view;
53
}
54
55
public detachView(view: IAttachedView): void {
56
this._views.delete(view as AttachedViewImpl);
57
this._onDidChangeVisibleRanges.fire({ view, state: undefined });
58
this._viewsChanged.trigger(undefined);
59
}
60
}
61
62
/**
63
* @internal
64
*/
65
export class AttachedViewState {
66
constructor(
67
readonly visibleLineRanges: readonly LineRange[],
68
readonly stabilized: boolean,
69
) { }
70
71
public equals(other: AttachedViewState): boolean {
72
if (this === other) {
73
return true;
74
}
75
if (!equals(this.visibleLineRanges, other.visibleLineRanges, (a, b) => a.equals(b))) {
76
return false;
77
}
78
if (this.stabilized !== other.stabilized) {
79
return false;
80
}
81
return true;
82
}
83
}
84
85
class AttachedViewImpl implements IAttachedView {
86
private readonly _state: ISettableObservable<AttachedViewState | undefined>;
87
public get state(): IObservable<AttachedViewState | undefined> { return this._state; }
88
89
constructor(
90
private readonly handleStateChange: (state: AttachedViewState) => void
91
) {
92
this._state = observableValueOpts<AttachedViewState | undefined>({ owner: this, equalsFn: equalsIfDefined((a, b) => a.equals(b)) }, undefined);
93
}
94
95
setVisibleLines(visibleLines: { startLineNumber: number; endLineNumber: number }[], stabilized: boolean): void {
96
const visibleLineRanges = visibleLines.map((line) => new LineRange(line.startLineNumber, line.endLineNumber + 1));
97
const state = new AttachedViewState(visibleLineRanges, stabilized);
98
this._state.set(state, undefined, undefined);
99
this.handleStateChange(state);
100
}
101
}
102
103
104
export class AttachedViewHandler extends Disposable {
105
private readonly runner = this._register(new RunOnceScheduler(() => this.update(), 50));
106
107
private _computedLineRanges: readonly LineRange[] = [];
108
private _lineRanges: readonly LineRange[] = [];
109
public get lineRanges(): readonly LineRange[] { return this._lineRanges; }
110
111
constructor(private readonly _refreshTokens: () => void) {
112
super();
113
}
114
115
private update(): void {
116
if (equals(this._computedLineRanges, this._lineRanges, (a, b) => a.equals(b))) {
117
return;
118
}
119
this._computedLineRanges = this._lineRanges;
120
this._refreshTokens();
121
}
122
123
public handleStateChange(state: AttachedViewState): void {
124
this._lineRanges = state.visibleLineRanges;
125
if (state.stabilized) {
126
this.runner.cancel();
127
this.update();
128
} else {
129
this.runner.schedule();
130
}
131
}
132
}
133
134
export abstract class AbstractSyntaxTokenBackend extends Disposable {
135
protected abstract _backgroundTokenizationState: BackgroundTokenizationState;
136
public get backgroundTokenizationState(): BackgroundTokenizationState {
137
return this._backgroundTokenizationState;
138
}
139
140
protected abstract readonly _onDidChangeBackgroundTokenizationState: Emitter<void>;
141
/** @internal, should not be exposed by the text model! */
142
public abstract readonly onDidChangeBackgroundTokenizationState: Event<void>;
143
144
protected readonly _onDidChangeTokens = this._register(new Emitter<IModelTokensChangedEvent>());
145
/** @internal, should not be exposed by the text model! */
146
public readonly onDidChangeTokens: Event<IModelTokensChangedEvent> = this._onDidChangeTokens.event;
147
148
constructor(
149
protected readonly _languageIdCodec: ILanguageIdCodec,
150
protected readonly _textModel: TextModel,
151
) {
152
super();
153
}
154
155
public abstract todo_resetTokenization(fireTokenChangeEvent?: boolean): void;
156
157
public abstract handleDidChangeAttached(): void;
158
159
public abstract handleDidChangeContent(e: IModelContentChangedEvent): void;
160
161
public abstract forceTokenization(lineNumber: number): void;
162
163
public abstract hasAccurateTokensForLine(lineNumber: number): boolean;
164
165
public abstract isCheapToTokenize(lineNumber: number): boolean;
166
167
public tokenizeIfCheap(lineNumber: number): void {
168
if (this.isCheapToTokenize(lineNumber)) {
169
this.forceTokenization(lineNumber);
170
}
171
}
172
173
public abstract getLineTokens(lineNumber: number): LineTokens;
174
175
public abstract getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType;
176
177
public abstract tokenizeLinesAt(lineNumber: number, lines: string[]): LineTokens[] | null;
178
179
public abstract get hasTokens(): boolean;
180
}
181
182