Skip to content

Commit 76a5716

Browse files
committed
Refactors async tokenization. Fixes microsoft#188351
1 parent e8f9d75 commit 76a5716

File tree

11 files changed

+268
-283
lines changed

11 files changed

+268
-283
lines changed

src/vs/base/common/objects.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,9 @@ export function filter(obj: obj, predicate: (key: string, value: any) => boolean
230230

231231
export function getAllPropertyNames(obj: object): string[] {
232232
let res: string[] = [];
233-
let proto = Object.getPrototypeOf(obj);
234-
while (Object.prototype !== proto) {
235-
res = res.concat(Object.getOwnPropertyNames(proto));
236-
proto = Object.getPrototypeOf(proto);
233+
while (Object.prototype !== obj) {
234+
res = res.concat(Object.getOwnPropertyNames(obj));
235+
obj = Object.getPrototypeOf(obj);
237236
}
238237
return res;
239238
}

src/vs/editor/common/languages.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,6 @@ export class EncodedTokenizationResult {
8080
}
8181
}
8282

83-
/**
84-
* @internal
85-
*/
86-
export interface IBackgroundTokenizer extends IDisposable {
87-
/**
88-
* Instructs the background tokenizer to set the tokens for the given range again.
89-
*
90-
* This might be necessary if the renderer overwrote those tokens with heuristically computed ones for some viewport,
91-
* when the change does not even propagate to that viewport.
92-
*/
93-
requestTokens(startLineNumber: number, endLineNumberExclusive: number): void;
94-
95-
reportMismatchingTokens?(lineNumber: number): void;
96-
}
97-
98-
9983
/**
10084
* @internal
10185
*/
@@ -118,6 +102,21 @@ export interface ITokenizationSupport {
118102
createBackgroundTokenizer?(textModel: model.ITextModel, store: IBackgroundTokenizationStore): IBackgroundTokenizer | undefined;
119103
}
120104

105+
/**
106+
* @internal
107+
*/
108+
export interface IBackgroundTokenizer extends IDisposable {
109+
/**
110+
* Instructs the background tokenizer to set the tokens for the given range again.
111+
*
112+
* This might be necessary if the renderer overwrote those tokens with heuristically computed ones for some viewport,
113+
* when the change does not even propagate to that viewport.
114+
*/
115+
requestTokens(startLineNumber: number, endLineNumberExclusive: number): void;
116+
117+
reportMismatchingTokens?(lineNumber: number): void;
118+
}
119+
121120
/**
122121
* @internal
123122
*/

src/vs/editor/common/tokenizationRegistry.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ export class TokenizationRegistry implements ITokenizationRegistry {
7878
return this.get(languageId);
7979
}
8080

81-
82-
8381
public isResolved(languageId: string): boolean {
8482
const tokenizationSupport = this.get(languageId);
8583
if (tokenizationSupport) {

src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget {
236236
}
237237

238238
private _beginCompute(position: Position): void {
239-
const grammar = this._textMateService.createGrammar(this._model.getLanguageId());
239+
const grammar = this._textMateService.createTokenizer(this._model.getLanguageId());
240240
const semanticTokens = this._computeSemanticTokens(position);
241241

242242
dom.clearNode(this._domNode);

src/vs/workbench/contrib/themes/browser/themes.test.contribution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class Snapper {
219219

220220
public captureSyntaxTokens(fileName: string, content: string): Promise<IToken[]> {
221221
const languageId = this.languageService.guessLanguageIdByFilepathOrFirstLine(URI.file(fileName));
222-
return this.textMateService.createGrammar(languageId!).then((grammar) => {
222+
return this.textMateService.createTokenizer(languageId!).then((grammar) => {
223223
if (!grammar) {
224224
return [];
225225
}

src/vs/workbench/services/textMate/browser/workerHost/textMateWorkerTokenizerController.ts renamed to src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ import { IModelContentChange, IModelContentChangedEvent } from 'vs/editor/common
1616
import { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder';
1717
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1818
import { ArrayEdit, MonotonousIndexTransformer, SingleArrayEdit } from 'vs/workbench/services/textMate/browser/arrayOperation';
19-
import { TextMateTokenizationWorker } from 'vs/workbench/services/textMate/browser/worker/textMate.worker';
20-
import type { StateDeltas } from 'vs/workbench/services/textMate/browser/workerHost/textMateWorkerHost';
19+
import type { StateDeltas, TextMateTokenizationWorker } from 'vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker';
2120
import type { applyStateStackDiff, StateStack } from 'vscode-textmate';
2221

2322
export class TextMateWorkerTokenizerController extends Disposable {
24-
private _pendingChanges: IModelContentChangedEvent[] = [];
23+
private static _id = 0;
24+
25+
public readonly controllerId = TextMateWorkerTokenizerController._id++;
26+
private readonly _pendingChanges: IModelContentChangedEvent[] = [];
2527

2628
/**
2729
* These states will eventually equal the worker states.
@@ -47,13 +49,13 @@ export class TextMateWorkerTokenizerController extends Disposable {
4749
this._register(keepAlive(this._loggingEnabled));
4850

4951
this._register(this._model.onDidChangeContent((e) => {
50-
if (this.shouldLog) {
52+
if (this._shouldLog) {
5153
console.log('model change', {
5254
fileName: this._model.uri.fsPath.split('\\').pop(),
5355
changes: changesToString(e.changes),
5456
});
5557
}
56-
this._worker.acceptModelChanged(this._model.uri.toString(), e);
58+
this._worker.acceptModelChanged(this.controllerId, e);
5759
this._pendingChanges.push(e);
5860
}));
5961

@@ -62,7 +64,7 @@ export class TextMateWorkerTokenizerController extends Disposable {
6264
const encodedLanguageId =
6365
this._languageIdCodec.encodeLanguageId(languageId);
6466
this._worker.acceptModelLanguageChanged(
65-
this._model.uri.toString(),
67+
this.controllerId,
6668
languageId,
6769
encodedLanguageId
6870
);
@@ -78,27 +80,33 @@ export class TextMateWorkerTokenizerController extends Disposable {
7880
languageId,
7981
encodedLanguageId,
8082
maxTokenizationLineLength: this._maxTokenizationLineLength.get(),
83+
controllerId: this.controllerId,
8184
});
8285

8386
this._register(autorun('update maxTokenizationLineLength', reader => {
8487
const maxTokenizationLineLength = this._maxTokenizationLineLength.read(reader);
85-
this._worker.acceptMaxTokenizationLineLength(this._model.uri.toString(), maxTokenizationLineLength);
88+
this._worker.acceptMaxTokenizationLineLength(this.controllerId, maxTokenizationLineLength);
8689
}));
8790
}
8891

89-
get shouldLog() {
90-
return this._loggingEnabled.get();
91-
}
92-
9392
public override dispose(): void {
9493
super.dispose();
95-
this._worker.acceptRemovedModel(this._model.uri.toString());
94+
this._worker.acceptRemovedModel(this.controllerId);
95+
}
96+
97+
public requestTokens(startLineNumber: number, endLineNumberExclusive: number): void {
98+
this._worker.retokenize(this.controllerId, startLineNumber, endLineNumberExclusive);
9699
}
97100

98101
/**
99102
* This method is called from the worker through the worker host.
100103
*/
101-
public async setTokensAndStates(versionId: number, rawTokens: ArrayBuffer, stateDeltas: StateDeltas[]): Promise<void> {
104+
public async setTokensAndStates(controllerId: number, versionId: number, rawTokens: ArrayBuffer, stateDeltas: StateDeltas[]): Promise<void> {
105+
if (this.controllerId !== controllerId) {
106+
// This event is for an outdated controller (the worker didn't receive the delete/create messages yet), ignore the event.
107+
return;
108+
}
109+
102110
// _states state, change{k}, ..., change{versionId}, state delta base & rawTokens, change{j}, ..., change{m}, current renderer state
103111
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
104112
// | past changes | future states
@@ -107,15 +115,15 @@ export class TextMateWorkerTokenizerController extends Disposable {
107115
new Uint8Array(rawTokens)
108116
);
109117

110-
if (this.shouldLog) {
118+
if (this._shouldLog) {
111119
console.log('received background tokenization result', {
112120
fileName: this._model.uri.fsPath.split('\\').pop(),
113121
updatedTokenLines: tokens.map((t) => t.getLineRange()).join(' & '),
114122
updatedStateLines: stateDeltas.map((s) => new LineRange(s.startLineNumber, s.startLineNumber + s.stateDeltas.length).toString()).join(' & '),
115123
});
116124
}
117125

118-
if (this.shouldLog) {
126+
if (this._shouldLog) {
119127
const changes = this._pendingChanges.filter(c => c.versionId <= versionId).map(c => c.changes).map(c => changesToString(c)).join(' then ');
120128
console.log('Applying changes to local states', changes);
121129
}
@@ -130,7 +138,7 @@ export class TextMateWorkerTokenizerController extends Disposable {
130138
}
131139

132140
if (this._pendingChanges.length > 0) {
133-
if (this.shouldLog) {
141+
if (this._shouldLog) {
134142
const changes = this._pendingChanges.map(c => c.changes).map(c => changesToString(c)).join(' then ');
135143
console.log('Considering non-processed changes', changes);
136144
}
@@ -205,6 +213,9 @@ export class TextMateWorkerTokenizerController extends Disposable {
205213
// First set states, then tokens, so that events fired from set tokens don't read invalid states
206214
this._backgroundTokenizationStore.setTokens(tokens);
207215
}
216+
217+
private get _shouldLog() { return this._loggingEnabled.get(); }
218+
208219
}
209220

210221
function fullLineArrayEditFromModelContentChange(c: IModelContentChange[]): ArrayEdit {

0 commit comments

Comments
 (0)