@codingame/monaco-vscode-treesitter-service-override 13.1.6 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
 
2
2
  import { SyncDescriptor } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/descriptors';
3
3
  import { ITreeSitterParserService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService';
4
- import { TreeSitterTextModelService } from './vscode/src/vs/editor/browser/services/treeSitter/treeSitterParserService.js';
4
+ import { TreeSitterTextModelService } from './vscode/src/vs/editor/common/services/treeSitter/treeSitterParserService.js';
5
5
  import { ITreeSitterTokenizationFeature } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.service';
6
6
  import { TreeSitterTokenizationFeature } from './vscode/src/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.js';
7
7
  import { registerAssets } from '@codingame/monaco-vscode-api/assets';
8
+ import { ITreeSitterTokenizationStoreService, TreeSitterTokenizationStoreService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/model/treeSitterTokenStoreService';
8
9
  import './vscode/src/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.contribution.js';
9
10
 
10
11
  registerAssets({
@@ -15,7 +16,8 @@ registerAssets({
15
16
  function getServiceOverride() {
16
17
  return {
17
18
  [ITreeSitterParserService.toString()]: new SyncDescriptor(TreeSitterTextModelService, [], false),
18
- [ITreeSitterTokenizationFeature.toString()]: new SyncDescriptor(TreeSitterTokenizationFeature, [], false)
19
+ [ITreeSitterTokenizationFeature.toString()]: new SyncDescriptor(TreeSitterTokenizationFeature, [], false),
20
+ [ITreeSitterTokenizationStoreService.toString()]: new SyncDescriptor(TreeSitterTokenizationStoreService, [], false)
19
21
  };
20
22
  }
21
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codingame/monaco-vscode-treesitter-service-override",
3
- "version": "13.1.6",
3
+ "version": "14.0.0",
4
4
  "private": false,
5
5
  "description": "VSCode public API plugged on the monaco editor - treesitter service-override",
6
6
  "keywords": [],
@@ -15,9 +15,10 @@
15
15
  },
16
16
  "type": "module",
17
17
  "dependencies": {
18
- "@codingame/monaco-vscode-9d0168a3-519b-57f3-9bcc-89efc41f951a-common": "13.1.6",
19
- "@codingame/monaco-vscode-api": "13.1.6",
20
- "@vscode/tree-sitter-wasm": "0.0.4"
18
+ "@codingame/monaco-vscode-168b98e5-dc20-5807-b1f9-798f1f92b37f-common": "14.0.0",
19
+ "@codingame/monaco-vscode-9d0168a3-519b-57f3-9bcc-89efc41f951a-common": "14.0.0",
20
+ "@codingame/monaco-vscode-api": "14.0.0",
21
+ "@vscode/tree-sitter-wasm": "0.0.5"
21
22
  },
22
23
  "main": "index.js",
23
24
  "module": "index.js",
@@ -1,16 +1,15 @@
1
1
  import type { Parser } from "@vscode/tree-sitter-wasm";
2
- import { ITreeSitterParserService, ITreeSitterParseResult, ITextModelTreeSitter } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService";
2
+ import { ITreeSitterParserService, ITreeSitterParseResult, ITextModelTreeSitter, TreeUpdateEvent, TreeParseUpdateEvent } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService";
3
3
  import { IModelService } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/services/model";
4
4
  import { Disposable, IDisposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle";
5
5
  import { ITextModel } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/model";
6
6
  import { IFileService } from "@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service";
7
- import { IModelContentChange } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/textModelEvents";
7
+ import { IModelContentChangedEvent } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/textModelEvents";
8
8
  import { ITelemetryService } from "@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service";
9
9
  import { ILogService } from "@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service";
10
10
  import { IConfigurationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service";
11
11
  import { Emitter, Event } from "@codingame/monaco-vscode-api/vscode/vs/base/common/event";
12
12
  import { IEnvironmentService } from "@codingame/monaco-vscode-api/vscode/vs/platform/environment/common/environment.service";
13
- import { Range } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/core/range";
14
13
  export declare class TextModelTreeSitter extends Disposable implements ITextModelTreeSitter {
15
14
  readonly model: ITextModel;
16
15
  private readonly _treeSitterLanguages;
@@ -18,11 +17,12 @@ export declare class TextModelTreeSitter extends Disposable implements ITextMode
18
17
  private readonly _logService;
19
18
  private readonly _telemetryService;
20
19
  private _onDidChangeParseResult;
21
- readonly onDidChangeParseResult: Event<Range[]>;
20
+ readonly onDidChangeParseResult: Event<TreeParseUpdateEvent>;
22
21
  private _parseResult;
22
+ private _versionId;
23
23
  get parseResult(): ITreeSitterParseResult | undefined;
24
24
  constructor(model: ITextModel, _treeSitterLanguages: TreeSitterLanguages, _treeSitterImporter: TreeSitterImporter, _logService: ILogService, _telemetryService: ITelemetryService, parseImmediately?: boolean);
25
- private readonly _languageSessionDisposables;
25
+ private readonly _parseSessionDisposables;
26
26
  private _onDidChangeLanguage;
27
27
  parse(languageId?: string): Promise<ITreeSitterParseResult | undefined>;
28
28
  private _getLanguage;
@@ -34,15 +34,22 @@ export declare class TreeSitterParseResult implements IDisposable, ITreeSitterPa
34
34
  private readonly _logService;
35
35
  private readonly _telemetryService;
36
36
  private _tree;
37
+ private _lastFullyParsed;
38
+ private _lastFullyParsedWithEdits;
39
+ private readonly _onDidUpdate;
40
+ readonly onDidUpdate: Event<TreeParseUpdateEvent>;
41
+ private _versionId;
42
+ private _editVersion;
43
+ get versionId(): number;
37
44
  private _isDisposed;
38
45
  constructor(parser: Parser, language: Parser.Language, _logService: ILogService, _telemetryService: ITelemetryService);
39
46
  dispose(): void;
40
47
  get tree(): Parser.Tree | undefined;
41
- private set tree(value);
42
48
  get isDisposed(): boolean;
49
+ private findChangedNodes;
50
+ private calculateRangeChange;
43
51
  private _onDidChangeContentQueue;
44
- onDidChangeContent(model: ITextModel, changes: IModelContentChange[]): Promise<Parser.Range[] | undefined>;
45
- private _newEdits;
52
+ onDidChangeContent(model: ITextModel, changes: IModelContentChangedEvent | undefined): void;
46
53
  private _applyEdits;
47
54
  private _parseAndUpdateTree;
48
55
  private _parse;
@@ -94,21 +101,20 @@ export declare class TreeSitterTextModelService extends Disposable implements IT
94
101
  language: Parser.Language;
95
102
  }>;
96
103
  private _onDidUpdateTree;
97
- readonly onDidUpdateTree: Event<{
98
- textModel: ITextModel;
99
- ranges: Range[];
100
- }>;
104
+ readonly onDidUpdateTree: Event<TreeUpdateEvent>;
105
+ isTest: boolean;
101
106
  constructor(_modelService: IModelService, fileService: IFileService, _telemetryService: ITelemetryService, _logService: ILogService, _configurationService: IConfigurationService, _environmentService: IEnvironmentService);
102
107
  getOrInitLanguage(languageId: string): Parser.Language | undefined;
103
108
  getParseResult(textModel: ITextModel): ITreeSitterParseResult | undefined;
104
109
  getTree(content: string, languageId: string): Promise<Parser.Tree | undefined>;
110
+ getLanguage(languageId: string): Promise<Parser.Language | undefined>;
105
111
  private _doInitParser;
106
112
  private _hasInit;
107
113
  private _initParser;
108
114
  private _supportedLanguagesChanged;
109
115
  private _getSetting;
110
116
  private _registerModelServiceListeners;
111
- getTextModelTreeSitter(model: ITextModel): ITextModelTreeSitter;
117
+ getTextModelTreeSitter(model: ITextModel, parseImmediately?: boolean): Promise<ITextModelTreeSitter>;
112
118
  private _createTextModelTreeSitter;
113
119
  private _addGrammar;
114
120
  private _removeGrammar;
@@ -16,9 +16,12 @@ import { isCancellationError, CancellationError } from '@codingame/monaco-vscode
16
16
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/arrays';
17
17
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/autorun';
18
18
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/derived';
19
- import { PromiseResult } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/promise';
19
+ import { PromiseResult } from '@codingame/monaco-vscode-168b98e5-dc20-5807-b1f9-798f1f92b37f-common/vscode/vs/base/common/observableInternal/promise';
20
20
  import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/utils';
21
21
  import { Range } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/range';
22
+ import { Position } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/position';
23
+ import { LimitedQueue } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
24
+ import { TextLength } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/textLength';
22
25
 
23
26
  const EDITOR_TREESITTER_TELEMETRY = 'editor.experimental.treeSitterTelemetry';
24
27
  const MODULE_LOCATION_SUBPATH = `@vscode/tree-sitter-wasm/wasm`;
@@ -37,7 +40,8 @@ class TextModelTreeSitter extends Disposable {
37
40
  this._telemetryService = _telemetryService;
38
41
  this._onDidChangeParseResult = this._register(( new Emitter()));
39
42
  this.onDidChangeParseResult = this._onDidChangeParseResult.event;
40
- this._languageSessionDisposables = this._register(( new DisposableStore()));
43
+ this._versionId = 0;
44
+ this._parseSessionDisposables = this._register(( new DisposableStore()));
41
45
  if (parseImmediately) {
42
46
  this._register(Event.runAndSubscribe(this.model.onDidChangeLanguage, (e => this._onDidChangeLanguage(e ? e.newLanguage : this.model.getLanguageId()))));
43
47
  }
@@ -49,9 +53,9 @@ class TextModelTreeSitter extends Disposable {
49
53
  this.parse(languageId);
50
54
  }
51
55
  async parse(languageId = this.model.getLanguageId()) {
52
- this._languageSessionDisposables.clear();
56
+ this._parseSessionDisposables.clear();
53
57
  this._parseResult = undefined;
54
- const token = cancelOnDispose(this._languageSessionDisposables);
58
+ const token = cancelOnDispose(this._parseSessionDisposables);
55
59
  let language;
56
60
  try {
57
61
  language = await this._getLanguage(languageId, token);
@@ -66,13 +70,19 @@ class TextModelTreeSitter extends Disposable {
66
70
  if (token.isCancellationRequested) {
67
71
  return;
68
72
  }
69
- const treeSitterTree = this._languageSessionDisposables.add(( new TreeSitterParseResult(( new Parser()), language, this._logService, this._telemetryService)));
70
- this._languageSessionDisposables.add(this.model.onDidChangeContent(e => this._onDidChangeContent(treeSitterTree, e.changes)));
71
- await this._onDidChangeContent(treeSitterTree, []);
73
+ const treeSitterTree = this._parseSessionDisposables.add(( new TreeSitterParseResult(( new Parser()), language, this._logService, this._telemetryService)));
74
+ this._parseResult = treeSitterTree;
75
+ this._parseSessionDisposables.add(treeSitterTree.onDidUpdate(e => {
76
+ if (e.ranges && (e.versionId > this._versionId)) {
77
+ this._versionId = e.versionId;
78
+ this._onDidChangeParseResult.fire({ ranges: e.ranges, versionId: e.versionId });
79
+ }
80
+ }));
81
+ this._parseSessionDisposables.add(this.model.onDidChangeContent(e => this._onDidChangeContent(treeSitterTree, e)));
82
+ this._onDidChangeContent(treeSitterTree, undefined);
72
83
  if (token.isCancellationRequested) {
73
84
  return;
74
85
  }
75
- this._parseResult = treeSitterTree;
76
86
  return this._parseResult;
77
87
  }
78
88
  _getLanguage(languageId, token) {
@@ -94,17 +104,8 @@ class TextModelTreeSitter extends Disposable {
94
104
  }, undefined, disposables);
95
105
  }));
96
106
  }
97
- async _onDidChangeContent(treeSitterTree, changes) {
98
- const diff = await treeSitterTree.onDidChangeContent(this.model, changes);
99
- if (!diff || diff.length > 0) {
100
- const ranges = diff ? ( diff.map(r => ( new Range(
101
- r.startPosition.row + 1,
102
- r.startPosition.column + 1,
103
- r.endPosition.row + 1,
104
- r.endPosition.column + 1
105
- )))) : [this.model.getFullModelRange()];
106
- this._onDidChangeParseResult.fire(ranges);
107
- }
107
+ _onDidChangeContent(treeSitterTree, change) {
108
+ return treeSitterTree.onDidChangeContent(this.model, change);
108
109
  }
109
110
  }
110
111
  var TelemetryParseType;
@@ -113,63 +114,246 @@ var TelemetryParseType;
113
114
  TelemetryParseType["Incremental"] = "incrementalParse";
114
115
  })(TelemetryParseType || (TelemetryParseType = {}));
115
116
  class TreeSitterParseResult {
117
+ get versionId() {
118
+ return this._versionId;
119
+ }
116
120
  constructor(parser, language, _logService, _telemetryService) {
117
121
  this.parser = parser;
118
122
  this.language = language;
119
123
  this._logService = _logService;
120
124
  this._telemetryService = _telemetryService;
125
+ this._onDidUpdate = ( new Emitter());
126
+ this.onDidUpdate = this._onDidUpdate.event;
127
+ this._versionId = 0;
128
+ this._editVersion = 0;
121
129
  this._isDisposed = false;
122
- this._onDidChangeContentQueue = Promise.resolve();
123
- this._newEdits = true;
130
+ this._onDidChangeContentQueue = ( new LimitedQueue());
124
131
  this.parser.setTimeoutMicros(50 * 1000);
125
132
  this.parser.setLanguage(language);
126
133
  }
127
134
  dispose() {
128
135
  this._isDisposed = true;
136
+ this._onDidUpdate.dispose();
129
137
  this._tree?.delete();
138
+ this._lastFullyParsed?.delete();
139
+ this._lastFullyParsedWithEdits?.delete();
130
140
  this.parser?.delete();
131
141
  }
132
- get tree() { return this._tree; }
133
- set tree(newTree) {
134
- this._tree?.delete();
135
- this._tree = newTree;
136
- }
142
+ get tree() { return this._lastFullyParsed; }
137
143
  get isDisposed() { return this._isDisposed; }
138
- async onDidChangeContent(model, changes) {
139
- const oldTree = this.tree?.copy();
140
- this._applyEdits(model, changes);
141
- return ( new Promise(resolve => {
142
- this._onDidChangeContentQueue = this._onDidChangeContentQueue.then(async () => {
143
- if (this.isDisposed) {
144
- return;
144
+ findChangedNodes(newTree, oldTree) {
145
+ const newCursor = newTree.walk();
146
+ const oldCursor = oldTree.walk();
147
+ const gotoNextSibling = () => {
148
+ const n = newCursor.gotoNextSibling();
149
+ const o = oldCursor.gotoNextSibling();
150
+ if (n !== o) {
151
+ throw ( new Error('Trees are out of sync'));
152
+ }
153
+ return n && o;
154
+ };
155
+ const gotoParent = () => {
156
+ const n = newCursor.gotoParent();
157
+ const o = oldCursor.gotoParent();
158
+ if (n !== o) {
159
+ throw ( new Error('Trees are out of sync'));
160
+ }
161
+ return n && o;
162
+ };
163
+ const gotoNthChild = (index) => {
164
+ const n = newCursor.gotoFirstChild();
165
+ const o = oldCursor.gotoFirstChild();
166
+ if (n !== o) {
167
+ throw ( new Error('Trees are out of sync'));
168
+ }
169
+ if (index === 0) {
170
+ return n && o;
171
+ }
172
+ for (let i = 1; i <= index; i++) {
173
+ const nn = newCursor.gotoNextSibling();
174
+ const oo = oldCursor.gotoNextSibling();
175
+ if (nn !== oo) {
176
+ throw ( new Error('Trees are out of sync'));
145
177
  }
146
- await this._parseAndUpdateTree(model);
147
- resolve((this.tree && oldTree) ? oldTree.getChangedRanges(this.tree) : undefined);
148
- }).catch((e) => {
149
- this._logService.error('Error parsing tree-sitter tree', e);
150
- });
151
- }));
178
+ if (!nn || !oo) {
179
+ return false;
180
+ }
181
+ }
182
+ return n && o;
183
+ };
184
+ const changedRanges = [];
185
+ let next = true;
186
+ const nextSiblingOrParentSibling = () => {
187
+ do {
188
+ if (newCursor.currentNode.nextSibling) {
189
+ return gotoNextSibling();
190
+ }
191
+ if (newCursor.currentNode.parent) {
192
+ gotoParent();
193
+ }
194
+ } while (newCursor.currentNode.nextSibling || newCursor.currentNode.parent);
195
+ return false;
196
+ };
197
+ const getClosestPreviousNodes = () => {
198
+ const newFindPrev = newTree.walk();
199
+ newFindPrev.resetTo(newCursor);
200
+ const oldFindPrev = oldTree.walk();
201
+ oldFindPrev.resetTo(oldCursor);
202
+ const startingNode = newCursor.currentNode;
203
+ do {
204
+ if (newFindPrev.currentNode.previousSibling && ((newFindPrev.currentNode.endIndex - newFindPrev.currentNode.startIndex) !== 0)) {
205
+ newFindPrev.gotoPreviousSibling();
206
+ oldFindPrev.gotoPreviousSibling();
207
+ }
208
+ else {
209
+ while (!newFindPrev.currentNode.previousSibling && newFindPrev.currentNode.parent) {
210
+ newFindPrev.gotoParent();
211
+ oldFindPrev.gotoParent();
212
+ }
213
+ newFindPrev.gotoPreviousSibling();
214
+ oldFindPrev.gotoPreviousSibling();
215
+ }
216
+ } while ((newFindPrev.currentNode.endIndex > startingNode.startIndex)
217
+ && (newFindPrev.currentNode.parent || newFindPrev.currentNode.previousSibling)
218
+ && (newFindPrev.currentNode.id !== startingNode.id));
219
+ if ((newFindPrev.currentNode.id !== startingNode.id) && newFindPrev.currentNode.endIndex <= startingNode.startIndex) {
220
+ return { old: oldFindPrev.currentNode, new: newFindPrev.currentNode };
221
+ }
222
+ else {
223
+ return undefined;
224
+ }
225
+ };
226
+ do {
227
+ if (newCursor.currentNode.hasChanges) {
228
+ const newChildren = newCursor.currentNode.children;
229
+ const indexChangedChildren = [];
230
+ const changedChildren = newChildren.filter((c, index) => {
231
+ if (c.hasChanges) {
232
+ indexChangedChildren.push(index);
233
+ }
234
+ return c.hasChanges;
235
+ });
236
+ if (changedChildren.length >= 1) {
237
+ next = gotoNthChild(indexChangedChildren[0]);
238
+ }
239
+ else if (changedChildren.length === 0) {
240
+ while (newCursor.currentNode.parent && !newCursor.currentNode.isNamed && next) {
241
+ next = gotoParent();
242
+ }
243
+ const newNode = newCursor.currentNode;
244
+ const oldNode = oldCursor.currentNode;
245
+ const newEndPosition = ( new Position(newNode.endPosition.row + 1, newNode.endPosition.column + 1));
246
+ const oldEndIndex = oldNode.endIndex;
247
+ const closestPrev = getClosestPreviousNodes();
248
+ const newStartPosition = ( new Position(
249
+ closestPrev ? closestPrev.new.endPosition.row + 1 : newNode.startPosition.row + 1,
250
+ closestPrev ? closestPrev.new.endPosition.column + 1 : newNode.startPosition.column + 1
251
+ ));
252
+ const newStartIndex = closestPrev ? closestPrev.new.endIndex : newNode.startIndex;
253
+ const oldStartIndex = closestPrev ? closestPrev.old.endIndex : oldNode.startIndex;
254
+ changedRanges.push({ newStartPosition, newEndPosition, oldStartIndex, oldEndIndex, newNodeId: newNode.id, newStartIndex, newEndIndex: newNode.endIndex });
255
+ next = nextSiblingOrParentSibling();
256
+ }
257
+ }
258
+ else {
259
+ next = nextSiblingOrParentSibling();
260
+ }
261
+ } while (next);
262
+ if (changedRanges.length === 0 && newTree.rootNode.hasChanges) {
263
+ return [{ newStartPosition: ( new Position(
264
+ newTree.rootNode.startPosition.row + 1,
265
+ newTree.rootNode.startPosition.column + 1
266
+ )), newEndPosition: ( new Position(
267
+ newTree.rootNode.endPosition.row + 1,
268
+ newTree.rootNode.endPosition.column + 1
269
+ )), oldStartIndex: oldTree.rootNode.startIndex, oldEndIndex: oldTree.rootNode.endIndex, newStartIndex: newTree.rootNode.startIndex, newEndIndex: newTree.rootNode.endIndex, newNodeId: newTree.rootNode.id }];
270
+ }
271
+ else {
272
+ return changedRanges;
273
+ }
152
274
  }
153
- _applyEdits(model, changes) {
275
+ calculateRangeChange(changedNodes) {
276
+ if (!changedNodes) {
277
+ return undefined;
278
+ }
279
+ const ranges = [];
280
+ for (let i = 0; i < changedNodes.length; i++) {
281
+ const node = changedNodes[i];
282
+ const prevNode = changedNodes[i - 1];
283
+ if ((i > 0) && prevNode.newEndPosition.equals(node.newStartPosition)) {
284
+ const prevRangeChange = ranges[ranges.length - 1];
285
+ prevRangeChange.newRange = ( new Range(
286
+ prevRangeChange.newRange.startLineNumber,
287
+ prevRangeChange.newRange.startColumn,
288
+ node.newEndPosition.lineNumber,
289
+ node.newEndPosition.column
290
+ ));
291
+ prevRangeChange.oldRangeLength = node.oldEndIndex - prevNode.oldStartIndex;
292
+ prevRangeChange.newRangeEndOffset = node.newEndIndex;
293
+ }
294
+ else {
295
+ ranges.push({ newRange: Range.fromPositions(node.newStartPosition, node.newEndPosition), oldRangeLength: node.oldEndIndex - node.oldStartIndex, newRangeStartOffset: node.newStartIndex, newRangeEndOffset: node.newEndIndex });
296
+ }
297
+ }
298
+ return ranges;
299
+ }
300
+ onDidChangeContent(model, changes) {
301
+ const version = model.getVersionId();
302
+ if (version === this._editVersion) {
303
+ return;
304
+ }
305
+ this._applyEdits(changes?.changes ?? [], version);
306
+ this._onDidChangeContentQueue.queue(async () => {
307
+ if (this.isDisposed) {
308
+ return;
309
+ }
310
+ let ranges;
311
+ if (this._lastFullyParsedWithEdits && this._lastFullyParsed) {
312
+ ranges = this.calculateRangeChange(this.findChangedNodes(this._lastFullyParsedWithEdits, this._lastFullyParsed));
313
+ }
314
+ const completed = await this._parseAndUpdateTree(model, version);
315
+ if (completed) {
316
+ if (!ranges) {
317
+ ranges = [{ newRange: model.getFullModelRange(), oldRangeLength: model.getValueLength(), newRangeStartOffset: 0, newRangeEndOffset: model.getValueLength() }];
318
+ }
319
+ this._onDidUpdate.fire({ ranges, versionId: version });
320
+ }
321
+ });
322
+ }
323
+ _applyEdits(changes, version) {
154
324
  for (const change of changes) {
155
- const newEndOffset = change.rangeOffset + change.text.length;
156
- const newEndPosition = model.getPositionAt(newEndOffset);
157
- this.tree?.edit({
325
+ const originalTextLength = TextLength.ofRange(Range.lift(change.range));
326
+ const newTextLength = TextLength.ofText(change.text);
327
+ const summedTextLengths = change.text.length === 0 ? newTextLength : originalTextLength.add(newTextLength);
328
+ const edit = {
158
329
  startIndex: change.rangeOffset,
159
330
  oldEndIndex: change.rangeOffset + change.rangeLength,
160
331
  newEndIndex: change.rangeOffset + change.text.length,
161
332
  startPosition: { row: change.range.startLineNumber - 1, column: change.range.startColumn - 1 },
162
333
  oldEndPosition: { row: change.range.endLineNumber - 1, column: change.range.endColumn - 1 },
163
- newEndPosition: { row: newEndPosition.lineNumber - 1, column: newEndPosition.column - 1 }
164
- });
165
- this._newEdits = true;
334
+ newEndPosition: { row: change.range.startLineNumber + summedTextLengths.lineCount - 1, column: summedTextLengths.lineCount ? summedTextLengths.columnCount : (change.range.endColumn + summedTextLengths.columnCount) }
335
+ };
336
+ this._tree?.edit(edit);
337
+ this._lastFullyParsedWithEdits?.edit(edit);
166
338
  }
339
+ this._editVersion = version;
167
340
  }
168
- async _parseAndUpdateTree(model) {
341
+ async _parseAndUpdateTree(model, version) {
169
342
  const tree = await this._parse(model);
170
- if (!this._newEdits) {
171
- this.tree = tree;
343
+ if (tree) {
344
+ this._tree?.delete();
345
+ this._tree = tree;
346
+ this._lastFullyParsed?.delete();
347
+ this._lastFullyParsed = tree.copy();
348
+ this._lastFullyParsedWithEdits?.delete();
349
+ this._lastFullyParsedWithEdits = tree.copy();
350
+ this._versionId = version;
351
+ return tree;
352
+ }
353
+ else if (!this._tree) {
354
+ this.parser.reset();
172
355
  }
356
+ return undefined;
173
357
  }
174
358
  _parse(model) {
175
359
  let parseType = TelemetryParseType.Full;
@@ -180,14 +364,14 @@ class TreeSitterParseResult {
180
364
  }
181
365
  async _parseAndYield(model, parseType) {
182
366
  const language = model.getLanguageId();
183
- let tree;
184
367
  let time = 0;
185
368
  let passes = 0;
186
- this._newEdits = false;
369
+ const inProgressVersion = this._editVersion;
370
+ let newTree;
187
371
  do {
188
372
  const timer = performance.now();
189
373
  try {
190
- tree = this.parser.parse((index, position) => this._parseCallback(model, index), this.tree);
374
+ newTree = this.parser.parse((index, position) => this._parseCallback(model, index), this._tree);
191
375
  }
192
376
  catch (e) {
193
377
  }
@@ -196,12 +380,9 @@ class TreeSitterParseResult {
196
380
  passes++;
197
381
  }
198
382
  await ( new Promise(resolve => setTimeout0(resolve)));
199
- if (model.isDisposed() || this.isDisposed) {
200
- return;
201
- }
202
- } while (!tree && !this._newEdits);
383
+ } while (!model.isDisposed() && !this.isDisposed && !newTree && inProgressVersion === model.getVersionId());
203
384
  this.sendParseTimeTelemetry(parseType, language, time, passes);
204
- return tree;
385
+ return (newTree && (inProgressVersion === model.getVersionId())) ? newTree : undefined;
205
386
  }
206
387
  _parseCallback(textModel, index) {
207
388
  try {
@@ -308,6 +489,7 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
308
489
  this._treeSitterImporter = ( new TreeSitterImporter());
309
490
  this._onDidUpdateTree = this._register(( new Emitter()));
310
491
  this.onDidUpdateTree = this._onDidUpdateTree.event;
492
+ this.isTest = false;
311
493
  this._hasInit = false;
312
494
  this._treeSitterLanguages = this._register(( new TreeSitterLanguages(
313
495
  this._treeSitterImporter,
@@ -331,8 +513,7 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
331
513
  return textModelTreeSitter?.textModelTreeSitter.parseResult;
332
514
  }
333
515
  async getTree(content, languageId) {
334
- await this._init;
335
- const language = await this._treeSitterLanguages.getLanguage(languageId);
516
+ const language = await this.getLanguage(languageId);
336
517
  const Parser = await this._treeSitterImporter.getParserClass();
337
518
  if (language) {
338
519
  const parser = ( new Parser());
@@ -341,11 +522,22 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
341
522
  }
342
523
  return undefined;
343
524
  }
525
+ async getLanguage(languageId) {
526
+ await this._init;
527
+ return this._treeSitterLanguages.getLanguage(languageId);
528
+ }
344
529
  async _doInitParser() {
345
530
  const Parser = await this._treeSitterImporter.getParserClass();
531
+ const isTest = this.isTest;
346
532
  await Parser.init({
347
533
  locateFile(_file, _folder) {
348
- return ( ( FileAccess.asBrowserUri(`${getModuleLocation()}/${FILENAME_TREESITTER_WASM}`)).toString(true));
534
+ const location = `${getModuleLocation()}/${FILENAME_TREESITTER_WASM}`;
535
+ if (isTest) {
536
+ return ( ( FileAccess.asFileUri(location)).toString(true));
537
+ }
538
+ else {
539
+ return ( ( FileAccess.asBrowserUri(location)).toString(true));
540
+ }
349
541
  }
350
542
  });
351
543
  return true;
@@ -400,32 +592,28 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
400
592
  }));
401
593
  this._modelService.getModels().forEach(model => this._createTextModelTreeSitter(model));
402
594
  }
403
- getTextModelTreeSitter(model) {
404
- return ( new TextModelTreeSitter(
405
- model,
406
- this._treeSitterLanguages,
407
- this._treeSitterImporter,
408
- this._logService,
409
- this._telemetryService,
410
- false
411
- ));
595
+ async getTextModelTreeSitter(model, parseImmediately = false) {
596
+ await this.getLanguage(model.getLanguageId());
597
+ return this._createTextModelTreeSitter(model, parseImmediately);
412
598
  }
413
- _createTextModelTreeSitter(model) {
599
+ _createTextModelTreeSitter(model, parseImmediately = true) {
414
600
  const textModelTreeSitter = ( new TextModelTreeSitter(
415
601
  model,
416
602
  this._treeSitterLanguages,
417
603
  this._treeSitterImporter,
418
604
  this._logService,
419
- this._telemetryService
605
+ this._telemetryService,
606
+ parseImmediately
420
607
  ));
421
608
  const disposables = ( new DisposableStore());
422
609
  disposables.add(textModelTreeSitter);
423
- disposables.add(textModelTreeSitter.onDidChangeParseResult((ranges) => this._onDidUpdateTree.fire({ textModel: model, ranges })));
610
+ disposables.add(textModelTreeSitter.onDidChangeParseResult(change => this._onDidUpdateTree.fire({ textModel: model, ranges: change.ranges ?? [], versionId: change.versionId })));
424
611
  this._textModelTreeSitters.set(model, {
425
612
  textModelTreeSitter,
426
613
  disposables,
427
614
  dispose: disposables.dispose.bind(disposables)
428
615
  });
616
+ return textModelTreeSitter;
429
617
  }
430
618
  _addGrammar(languageId, grammarName) {
431
619
  if (!( this._registeredLanguages.has(languageId))) {
@@ -2,7 +2,7 @@
2
2
  import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
3
  import '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/extensions';
4
4
  import { registerWorkbenchContribution2, WorkbenchPhase } from '@codingame/monaco-vscode-api/vscode/vs/workbench/common/contributions';
5
- import '../../../../editor/browser/services/treeSitter/treeSitterParserService.js';
5
+ import '../../../../editor/common/services/treeSitter/treeSitterParserService.js';
6
6
  import { ITreeSitterParserService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService';
7
7
  import { ITreeSitterTokenizationFeature } from '@codingame/monaco-vscode-api/vscode/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.service';
8
8
  import { CommandsRegistry } from '@codingame/monaco-vscode-api/vscode/vs/platform/commands/common/commands';
@@ -30,7 +30,7 @@ CommandsRegistry.registerCommand('_workbench.colorizeTreeSitterTokens', async (a
30
30
  if (!tokenizer) {
31
31
  throw ( new Error(`Cannot resolve tokenizer for language ${textModel.getLanguageId()}`));
32
32
  }
33
- const textModelTreeSitter = treeSitterParserService.getTextModelTreeSitter(textModel);
33
+ const textModelTreeSitter = await treeSitterParserService.getTextModelTreeSitter(textModel);
34
34
  if (!textModelTreeSitter) {
35
35
  throw ( new Error(
36
36
  `Cannot resolve tree sitter parser for language ${textModel.getLanguageId()}`
@@ -1,9 +1,21 @@
1
+ import type { Parser } from "@vscode/tree-sitter-wasm";
2
+ import { Event } from "@codingame/monaco-vscode-api/vscode/vs/base/common/event";
1
3
  import { Disposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle";
4
+ import { ILanguageIdCodec, ITreeSitterTokenizationSupport, QueryCapture } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/languages";
5
+ import { ITextModel } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/model";
6
+ import { ITreeSitterParserService, ITreeSitterParseResult } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService";
7
+ import { IModelTokensChangedEvent } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/textModelEvents";
2
8
  import { IConfigurationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service";
3
9
  import { IFileService } from "@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service";
4
10
  import { IInstantiationService } from "@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation";
11
+ import { IThemeService } from "@codingame/monaco-vscode-api/vscode/vs/platform/theme/common/themeService.service";
5
12
  import { ILanguageService } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/languages/language";
13
+ import { ITreeSitterTokenizationStoreService } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/model/treeSitterTokenStoreService";
14
+ import { TokenUpdate } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/model/tokenStore";
15
+ import { Range } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/core/range";
16
+ import { ICodeEditorService } from "@codingame/monaco-vscode-api/vscode/vs/editor/browser/services/codeEditorService";
6
17
  import { ITreeSitterTokenizationFeature } from "@codingame/monaco-vscode-api/vscode/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.service";
18
+ type TreeSitterQueries = string;
7
19
  export declare class TreeSitterTokenizationFeature extends Disposable implements ITreeSitterTokenizationFeature {
8
20
  private readonly _languageService;
9
21
  private readonly _configurationService;
@@ -17,3 +29,52 @@ export declare class TreeSitterTokenizationFeature extends Disposable implements
17
29
  private _fetchQueries;
18
30
  private _createTokenizationSupport;
19
31
  }
32
+ export declare class TreeSitterTokenizationSupport extends Disposable implements ITreeSitterTokenizationSupport {
33
+ private readonly _queries;
34
+ private readonly _languageId;
35
+ private readonly _languageIdCodec;
36
+ private readonly _treeSitterService;
37
+ private readonly _themeService;
38
+ private readonly _tokenizationStoreService;
39
+ private readonly _codeEditorService;
40
+ private _query;
41
+ private readonly _onDidChangeTokens;
42
+ readonly onDidChangeTokens: Event<{
43
+ textModel: ITextModel;
44
+ changes: IModelTokensChangedEvent;
45
+ }>;
46
+ private _colorThemeData;
47
+ private _languageAddedListener;
48
+ constructor(_queries: TreeSitterQueries, _languageId: string, _languageIdCodec: ILanguageIdCodec, _treeSitterService: ITreeSitterParserService, _themeService: IThemeService, _tokenizationStoreService: ITreeSitterTokenizationStoreService, _codeEditorService: ICodeEditorService);
49
+ private _createEmptyTokens;
50
+ private _firstTreeUpdate;
51
+ private _setViewPortTokens;
52
+ private _handleTreeUpdate;
53
+ private _updateTreeForRanges;
54
+ private _refreshNeedsRefresh;
55
+ private _rangeTokensAsUpdates;
56
+ getTokensInRange(textModel: ITextModel, range: Range, rangeStartOffset: number, rangeEndOffset: number, captures?: {
57
+ tree: ITreeSitterParseResult | undefined;
58
+ captures: QueryCapture[];
59
+ }): TokenUpdate[] | undefined;
60
+ private _getTree;
61
+ private _ensureQuery;
62
+ private reset;
63
+ captureAtPosition(lineNumber: number, column: number, textModel: ITextModel): QueryCapture[];
64
+ captureAtPositionTree(lineNumber: number, column: number, tree: Parser.Tree): QueryCapture[];
65
+ private _captureAtRange;
66
+ tokenizeEncoded(lineNumber: number, textModel: ITextModel): Uint32Array | undefined;
67
+ tokenizeEncodedInstrumented(lineNumber: number, textModel: ITextModel): {
68
+ result: Uint32Array;
69
+ captureTime: number;
70
+ metadataTime: number;
71
+ } | undefined;
72
+ private _getTreeAndCaptures;
73
+ private _tokenize;
74
+ private _createTokensFromCaptures;
75
+ private _tokenizeCapturesWithMetadata;
76
+ private _emptyToken;
77
+ private _tokenizeEncoded;
78
+ dispose(): void;
79
+ }
80
+ export {};
@@ -5,7 +5,6 @@ import { Disposable, DisposableMap, DisposableStore } from '@codingame/monaco-vs
5
5
  import { FileAccess } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network';
6
6
  import { LazyTokenizationSupport, TreeSitterTokenizationRegistry } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/languages';
7
7
  import { EDITOR_EXPERIMENTAL_PREFER_TREESITTER, ITreeSitterParserService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService';
8
- import { ColumnRange } from '@codingame/monaco-vscode-api/vscode/vs/editor/contrib/inlineCompletions/browser/utils';
9
8
  import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service';
10
9
  import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
11
10
  import '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/extensions';
@@ -14,6 +13,10 @@ import { IThemeService } from '@codingame/monaco-vscode-api/vscode/vs/platform/t
14
13
  import { findMetadata } from '@codingame/monaco-vscode-9d0168a3-519b-57f3-9bcc-89efc41f951a-common/vscode/vs/workbench/services/themes/common/colorThemeData';
15
14
  import { ILanguageService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/languages/language';
16
15
  import { StopWatch } from '@codingame/monaco-vscode-api/vscode/vs/base/common/stopwatch';
16
+ import { ITreeSitterTokenizationStoreService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/model/treeSitterTokenStoreService';
17
+ import { Range } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/range';
18
+ import { ICodeEditorService } from '@codingame/monaco-vscode-api/vscode/vs/editor/browser/services/codeEditorService';
19
+ import { setTimeout0 } from '@codingame/monaco-vscode-api/vscode/vs/base/common/platform';
17
20
 
18
21
  const ALLOWED_SUPPORT = ['typescript'];
19
22
  let TreeSitterTokenizationFeature = class TreeSitterTokenizationFeature extends Disposable {
@@ -23,7 +26,7 @@ let TreeSitterTokenizationFeature = class TreeSitterTokenizationFeature extends
23
26
  this._configurationService = _configurationService;
24
27
  this._instantiationService = _instantiationService;
25
28
  this._fileService = _fileService;
26
- this._tokenizersRegistrations = ( new DisposableMap());
29
+ this._tokenizersRegistrations = this._register(( new DisposableMap()));
27
30
  this._handleGrammarsExtPoint();
28
31
  this._register(this._configurationService.onDidChangeConfiguration(e => {
29
32
  if (e.affectsConfiguration(EDITOR_EXPERIMENTAL_PREFER_TREESITTER)) {
@@ -68,28 +71,183 @@ TreeSitterTokenizationFeature = ( __decorate([
68
71
  ( __param(3, IFileService))
69
72
  ], TreeSitterTokenizationFeature));
70
73
  let TreeSitterTokenizationSupport = class TreeSitterTokenizationSupport extends Disposable {
71
- constructor(_queries, _languageId, _languageIdCodec, _treeSitterService, _themeService) {
74
+ constructor(_queries, _languageId, _languageIdCodec, _treeSitterService, _themeService, _tokenizationStoreService, _codeEditorService) {
72
75
  super();
73
76
  this._queries = _queries;
74
77
  this._languageId = _languageId;
75
78
  this._languageIdCodec = _languageIdCodec;
76
79
  this._treeSitterService = _treeSitterService;
77
80
  this._themeService = _themeService;
81
+ this._tokenizationStoreService = _tokenizationStoreService;
82
+ this._codeEditorService = _codeEditorService;
78
83
  this._onDidChangeTokens = ( new Emitter());
79
84
  this.onDidChangeTokens = this._onDidChangeTokens.event;
80
85
  this._register(Event.runAndSubscribe(this._themeService.onDidColorThemeChange, () => this.reset()));
81
86
  this._register(this._treeSitterService.onDidUpdateTree((e) => {
82
- const maxLine = e.textModel.getLineCount();
87
+ if (this._tokenizationStoreService.hasTokens(e.textModel)) {
88
+ for (const range of e.ranges) {
89
+ this._tokenizationStoreService.markForRefresh(e.textModel, range.newRange);
90
+ }
91
+ }
92
+ if (e.versionId !== e.textModel.getVersionId()) {
93
+ return;
94
+ }
95
+ if (!this._tokenizationStoreService.hasTokens(e.textModel)) {
96
+ this._firstTreeUpdate(e.textModel, e.versionId);
97
+ }
98
+ else {
99
+ this._handleTreeUpdate(e);
100
+ }
101
+ }));
102
+ }
103
+ _createEmptyTokens(textModel) {
104
+ const languageId = this._languageIdCodec.encodeLanguageId(this._languageId);
105
+ const emptyToken = this._emptyToken(languageId);
106
+ const modelEndOffset = textModel.getValueLength();
107
+ const emptyTokens = [{ token: emptyToken, length: modelEndOffset, startOffsetInclusive: 0 }];
108
+ return emptyTokens;
109
+ }
110
+ _firstTreeUpdate(textModel, versionId) {
111
+ const tokens = this._createEmptyTokens(textModel);
112
+ this._tokenizationStoreService.setTokens(textModel, tokens);
113
+ this._setViewPortTokens(textModel, versionId);
114
+ }
115
+ _setViewPortTokens(textModel, versionId) {
116
+ const maxLine = textModel.getLineCount();
117
+ let rangeChanges;
118
+ const editor = this._codeEditorService.listCodeEditors().find(editor => editor.getModel() === textModel);
119
+ if (editor) {
120
+ const viewPort = editor.getVisibleRangesPlusViewportAboveBelow();
121
+ const ranges = ( new Array(viewPort.length));
122
+ rangeChanges = ( new Array(viewPort.length));
123
+ for (let i = 0; i < viewPort.length; i++) {
124
+ const range = viewPort[i];
125
+ ranges[i] = { fromLineNumber: range.startLineNumber, toLineNumber: range.endLineNumber < maxLine ? range.endLineNumber : maxLine };
126
+ const newRangeStartOffset = textModel.getOffsetAt(range.getStartPosition());
127
+ const newRangeEndOffset = textModel.getOffsetAt(range.getEndPosition());
128
+ rangeChanges[i] = {
129
+ newRange: range,
130
+ newRangeStartOffset,
131
+ newRangeEndOffset,
132
+ oldRangeLength: newRangeEndOffset - newRangeStartOffset
133
+ };
134
+ }
135
+ }
136
+ else {
137
+ const valueLength = textModel.getValueLength();
138
+ rangeChanges = [{ newRange: ( new Range(1, 1, maxLine, textModel.getLineMaxColumn(maxLine))), newRangeStartOffset: 0, newRangeEndOffset: valueLength, oldRangeLength: valueLength }];
139
+ }
140
+ this._handleTreeUpdate({ ranges: rangeChanges, textModel, versionId });
141
+ }
142
+ _handleTreeUpdate(e) {
143
+ let rangeChanges = [];
144
+ const chunkSize = 10000;
145
+ for (let i = 0; i < e.ranges.length; i++) {
146
+ const rangeLength = e.ranges[i].newRangeEndOffset - e.ranges[i].newRangeStartOffset;
147
+ if (e.ranges[i].oldRangeLength === rangeLength) {
148
+ if (rangeLength > chunkSize) {
149
+ const fullRangeEndOffset = e.ranges[i].newRangeEndOffset;
150
+ let chunkStart = e.ranges[i].newRangeStartOffset;
151
+ let chunkEnd = chunkStart + chunkSize;
152
+ let chunkStartingPosition = e.ranges[i].newRange.getStartPosition();
153
+ do {
154
+ const chunkEndPosition = e.textModel.getPositionAt(chunkEnd);
155
+ const chunkRange = Range.fromPositions(chunkStartingPosition, chunkEndPosition);
156
+ rangeChanges.push({
157
+ newRange: chunkRange,
158
+ newRangeStartOffset: chunkStart,
159
+ newRangeEndOffset: chunkEnd,
160
+ oldRangeLength: chunkEnd - chunkStart
161
+ });
162
+ chunkStart = chunkEnd;
163
+ if (chunkEnd < fullRangeEndOffset && chunkEnd + chunkSize > fullRangeEndOffset) {
164
+ chunkEnd = fullRangeEndOffset;
165
+ }
166
+ else {
167
+ chunkEnd = chunkEnd + chunkSize;
168
+ }
169
+ chunkStartingPosition = chunkEndPosition;
170
+ } while (chunkEnd <= fullRangeEndOffset);
171
+ }
172
+ else {
173
+ rangeChanges.push(e.ranges[i]);
174
+ }
175
+ }
176
+ else {
177
+ rangeChanges = e.ranges;
178
+ break;
179
+ }
180
+ }
181
+ const captures = ( rangeChanges.map(range => this._getTreeAndCaptures(range.newRange, e.textModel)));
182
+ this._updateTreeForRanges(e.textModel, rangeChanges, e.versionId, captures).then(() => {
183
+ const tree = this._getTree(e.textModel);
184
+ if (!e.textModel.isDisposed() && (tree?.versionId === e.textModel.getVersionId())) {
185
+ this._refreshNeedsRefresh(e.textModel);
186
+ }
187
+ });
188
+ }
189
+ async _updateTreeForRanges(textModel, rangeChanges, versionId, captures) {
190
+ let tokenUpdate;
191
+ for (let i = 0; i < rangeChanges.length; i++) {
192
+ if (versionId !== textModel.getVersionId()) {
193
+ break;
194
+ }
195
+ const capture = captures[i];
196
+ const range = rangeChanges[i];
197
+ const updates = this.getTokensInRange(textModel, range.newRange, range.newRangeStartOffset, range.newRangeEndOffset, capture);
198
+ if (updates) {
199
+ tokenUpdate = { oldRangeLength: range.oldRangeLength, newTokens: updates };
200
+ }
201
+ else {
202
+ tokenUpdate = { oldRangeLength: range.oldRangeLength, newTokens: [] };
203
+ }
204
+ this._tokenizationStoreService.updateTokens(textModel, versionId, [tokenUpdate]);
83
205
  this._onDidChangeTokens.fire({
84
- textModel: e.textModel,
206
+ textModel: textModel,
85
207
  changes: {
86
208
  semanticTokensApplied: false,
87
- ranges: ( e.ranges.map(
88
- range => ({ fromLineNumber: range.startLineNumber, toLineNumber: range.endLineNumber < maxLine ? range.endLineNumber : maxLine })
89
- )),
209
+ ranges: [{ fromLineNumber: range.newRange.getStartPosition().lineNumber, toLineNumber: range.newRange.getEndPosition().lineNumber }]
90
210
  }
91
211
  });
92
- }));
212
+ await ( new Promise(resolve => setTimeout0(resolve)));
213
+ }
214
+ }
215
+ _refreshNeedsRefresh(textModel) {
216
+ const rangesToRefresh = this._tokenizationStoreService.getNeedsRefresh(textModel);
217
+ if (rangesToRefresh.length === 0) {
218
+ return;
219
+ }
220
+ const rangeChanges = ( new Array(rangesToRefresh.length));
221
+ for (let i = 0; i < rangesToRefresh.length; i++) {
222
+ const range = rangesToRefresh[i];
223
+ rangeChanges[i] = {
224
+ newRange: range.range,
225
+ newRangeStartOffset: range.startOffset,
226
+ newRangeEndOffset: range.endOffset,
227
+ oldRangeLength: range.endOffset - range.startOffset
228
+ };
229
+ }
230
+ this._handleTreeUpdate({ ranges: rangeChanges, textModel, versionId: textModel.getVersionId() });
231
+ }
232
+ _rangeTokensAsUpdates(rangeOffset, endOffsetToken) {
233
+ const updates = [];
234
+ let lastEnd = 0;
235
+ for (const token of endOffsetToken) {
236
+ if (token.endOffset <= lastEnd) {
237
+ continue;
238
+ }
239
+ updates.push({ startOffsetInclusive: rangeOffset + lastEnd, length: token.endOffset - lastEnd, token: token.metadata });
240
+ lastEnd = token.endOffset;
241
+ }
242
+ return updates;
243
+ }
244
+ getTokensInRange(textModel, range, rangeStartOffset, rangeEndOffset, captures) {
245
+ const languageId = this._languageIdCodec.encodeLanguageId(this._languageId);
246
+ const tokens = captures ? this._tokenizeCapturesWithMetadata(captures.tree, captures.captures, languageId, rangeStartOffset, rangeEndOffset) : this._tokenize(languageId, range, rangeStartOffset, rangeEndOffset, textModel);
247
+ if (tokens?.endOffsetsAndMetadata) {
248
+ return this._rangeTokensAsUpdates(rangeStartOffset, tokens.endOffsetsAndMetadata);
249
+ }
250
+ return undefined;
93
251
  }
94
252
  _getTree(textModel) {
95
253
  return this._treeSitterService.getParseResult(textModel);
@@ -114,19 +272,26 @@ let TreeSitterTokenizationSupport = class TreeSitterTokenizationSupport extends
114
272
  }
115
273
  captureAtPosition(lineNumber, column, textModel) {
116
274
  const tree = this._getTree(textModel);
117
- const captures = this._captureAtRange(lineNumber, ( new ColumnRange(column, column)), tree?.tree);
275
+ const captures = this._captureAtRange(( new Range(lineNumber, column, lineNumber, column + 1)), tree?.tree);
118
276
  return captures;
119
277
  }
120
278
  captureAtPositionTree(lineNumber, column, tree) {
121
- const captures = this._captureAtRange(lineNumber, ( new ColumnRange(column, column)), tree);
279
+ const captures = this._captureAtRange(( new Range(lineNumber, column, lineNumber, column + 1)), tree);
122
280
  return captures;
123
281
  }
124
- _captureAtRange(lineNumber, columnRange, tree) {
282
+ _captureAtRange(range, tree) {
125
283
  const query = this._ensureQuery();
126
284
  if (!tree || !query) {
127
285
  return [];
128
286
  }
129
- return query.captures(tree.rootNode, { startPosition: { row: lineNumber - 1, column: columnRange.startColumn - 1 }, endPosition: { row: lineNumber - 1, column: columnRange.endColumnExclusive } });
287
+ return ( query.captures(tree.rootNode, { startPosition: { row: range.startLineNumber - 1, column: range.startColumn - 1 }, endPosition: { row: range.endLineNumber - 1, column: range.endColumn - 1 } }).map(capture => ({
288
+ name: capture.name,
289
+ text: capture.node.text,
290
+ node: {
291
+ startIndex: capture.node.startIndex,
292
+ endIndex: capture.node.endIndex
293
+ }
294
+ })));
130
295
  }
131
296
  tokenizeEncoded(lineNumber, textModel) {
132
297
  return this._tokenizeEncoded(lineNumber, textModel)?.result;
@@ -134,34 +299,44 @@ let TreeSitterTokenizationSupport = class TreeSitterTokenizationSupport extends
134
299
  tokenizeEncodedInstrumented(lineNumber, textModel) {
135
300
  return this._tokenizeEncoded(lineNumber, textModel);
136
301
  }
137
- _tokenizeEncoded(lineNumber, textModel) {
138
- const stopwatch = StopWatch.create();
139
- const lineLength = textModel.getLineMaxColumn(lineNumber);
302
+ _getTreeAndCaptures(range, textModel) {
140
303
  const tree = this._getTree(textModel);
141
- const captures = this._captureAtRange(lineNumber, ( new ColumnRange(1, lineLength)), tree?.tree);
304
+ const captures = this._captureAtRange(range, tree?.tree);
305
+ return { tree, captures };
306
+ }
307
+ _tokenize(encodedLanguageId, range, rangeStartOffset, rangeEndOffset, textModel) {
308
+ const { tree, captures } = this._getTreeAndCaptures(range, textModel);
309
+ return this._tokenizeCapturesWithMetadata(tree, captures, encodedLanguageId, rangeStartOffset, rangeEndOffset);
310
+ }
311
+ _createTokensFromCaptures(tree, captures, rangeStartOffset, rangeEndOffset) {
312
+ const stopwatch = StopWatch.create();
313
+ const rangeLength = rangeEndOffset - rangeStartOffset;
142
314
  if (captures.length === 0) {
315
+ if (tree) {
316
+ stopwatch.stop();
317
+ const endOffsetsAndMetadata = [{ endOffset: rangeLength, scopes: [] }];
318
+ return { endOffsets: endOffsetsAndMetadata, captureTime: stopwatch.elapsed() };
319
+ }
143
320
  return undefined;
144
321
  }
145
322
  const endOffsetsAndScopes = Array(captures.length);
146
323
  endOffsetsAndScopes.fill({ endOffset: 0, scopes: [] });
147
324
  let tokenIndex = 0;
148
- const lineStartOffset = textModel.getOffsetAt({ lineNumber: lineNumber, column: 1 });
149
325
  const increaseSizeOfTokensByOneToken = () => {
150
326
  endOffsetsAndScopes.push({ endOffset: 0, scopes: [] });
151
327
  };
152
- const encodedLanguageId = this._languageIdCodec.encodeLanguageId(this._languageId);
153
328
  for (let captureIndex = 0; captureIndex < captures.length; captureIndex++) {
154
329
  const capture = captures[captureIndex];
155
- const tokenEndIndex = capture.node.endIndex < lineStartOffset + lineLength ? capture.node.endIndex : lineStartOffset + lineLength;
156
- const tokenStartIndex = capture.node.startIndex < lineStartOffset ? lineStartOffset : capture.node.startIndex;
157
- const lineRelativeOffset = tokenEndIndex - lineStartOffset;
330
+ const tokenEndIndex = capture.node.endIndex < rangeEndOffset ? ((capture.node.endIndex < rangeStartOffset) ? rangeStartOffset : capture.node.endIndex) : rangeEndOffset;
331
+ const tokenStartIndex = capture.node.startIndex < rangeStartOffset ? rangeStartOffset : ((capture.node.startIndex > tokenEndIndex) ? tokenEndIndex : capture.node.startIndex);
332
+ const lineRelativeOffset = tokenEndIndex - rangeStartOffset;
158
333
  let previousTokenEnd;
159
334
  const currentTokenLength = tokenEndIndex - tokenStartIndex;
160
335
  if (captureIndex > 0) {
161
336
  previousTokenEnd = endOffsetsAndScopes[(tokenIndex - 1)].endOffset;
162
337
  }
163
338
  else {
164
- previousTokenEnd = tokenStartIndex - lineStartOffset - 1;
339
+ previousTokenEnd = tokenStartIndex - rangeStartOffset - 1;
165
340
  }
166
341
  const intermediateTokenOffset = lineRelativeOffset - currentTokenLength;
167
342
  if ((previousTokenEnd >= 0) && (previousTokenEnd < intermediateTokenOffset)) {
@@ -174,42 +349,89 @@ let TreeSitterTokenizationSupport = class TreeSitterTokenizationSupport extends
174
349
  tokenIndex++;
175
350
  };
176
351
  if (previousTokenEnd >= lineRelativeOffset) {
177
- const previousTokenStartOffset = ((tokenIndex >= 2) ? endOffsetsAndScopes[tokenIndex - 2].endOffset : 0);
178
352
  const originalPreviousTokenEndOffset = endOffsetsAndScopes[tokenIndex - 1].endOffset;
179
- if ((previousTokenStartOffset + currentTokenLength) === originalPreviousTokenEndOffset) {
353
+ const previousTokenStartOffset = ((tokenIndex >= 2) ? endOffsetsAndScopes[tokenIndex - 2].endOffset : 0);
354
+ const loopOriginalPreviousTokenEndOffset = endOffsetsAndScopes[tokenIndex - 1].endOffset;
355
+ const previousPreviousTokenEndOffset = (tokenIndex >= 2) ? endOffsetsAndScopes[tokenIndex - 2].endOffset : 0;
356
+ if ((previousTokenStartOffset + currentTokenLength) === loopOriginalPreviousTokenEndOffset) {
180
357
  endOffsetsAndScopes[tokenIndex - 1].scopes[endOffsetsAndScopes[tokenIndex - 1].scopes.length - 1] = capture.name;
181
358
  }
182
- else {
183
- endOffsetsAndScopes[tokenIndex - 1].endOffset = intermediateTokenOffset;
184
- addCurrentTokenToArray();
185
- increaseSizeOfTokensByOneToken();
186
- endOffsetsAndScopes[tokenIndex].endOffset = originalPreviousTokenEndOffset;
187
- endOffsetsAndScopes[tokenIndex].scopes = endOffsetsAndScopes[tokenIndex - 2].scopes;
188
- tokenIndex++;
359
+ else if (previousPreviousTokenEndOffset <= intermediateTokenOffset) {
360
+ let originalPreviousTokenScopes;
361
+ if (previousPreviousTokenEndOffset !== intermediateTokenOffset) {
362
+ endOffsetsAndScopes[tokenIndex - 1] = { endOffset: intermediateTokenOffset, scopes: endOffsetsAndScopes[tokenIndex - 1].scopes };
363
+ addCurrentTokenToArray();
364
+ originalPreviousTokenScopes = [...endOffsetsAndScopes[tokenIndex - 2].scopes];
365
+ }
366
+ else {
367
+ originalPreviousTokenScopes = [...endOffsetsAndScopes[tokenIndex - 1].scopes];
368
+ endOffsetsAndScopes[tokenIndex - 1] = { endOffset: lineRelativeOffset, scopes: [capture.name] };
369
+ }
370
+ if (originalPreviousTokenEndOffset !== lineRelativeOffset) {
371
+ increaseSizeOfTokensByOneToken();
372
+ endOffsetsAndScopes[tokenIndex] = { endOffset: originalPreviousTokenEndOffset, scopes: originalPreviousTokenScopes };
373
+ tokenIndex++;
374
+ }
375
+ else {
376
+ endOffsetsAndScopes[tokenIndex - 1].scopes.unshift(...originalPreviousTokenScopes);
377
+ }
189
378
  }
190
379
  }
191
380
  else {
192
381
  addCurrentTokenToArray();
193
382
  }
194
383
  }
195
- if (captures[captures.length - 1].node.endPosition.column + 1 < lineLength) {
196
- increaseSizeOfTokensByOneToken();
197
- endOffsetsAndScopes[tokenIndex].endOffset = lineLength - 1;
198
- tokenIndex++;
384
+ if ((endOffsetsAndScopes[tokenIndex - 1].endOffset < rangeLength)) {
385
+ if (rangeLength - endOffsetsAndScopes[tokenIndex - 1].endOffset > 0) {
386
+ increaseSizeOfTokensByOneToken();
387
+ endOffsetsAndScopes[tokenIndex] = { endOffset: rangeLength, scopes: endOffsetsAndScopes[tokenIndex].scopes };
388
+ tokenIndex++;
389
+ }
199
390
  }
200
- const captureTime = stopwatch.elapsed();
201
- stopwatch.reset();
202
- const tokens = ( new Uint32Array((tokenIndex) * 2));
203
- for (let i = 0; i < tokenIndex; i++) {
391
+ for (let i = 0; i < endOffsetsAndScopes.length; i++) {
204
392
  const token = endOffsetsAndScopes[i];
205
- if (token.endOffset === 0 && token.scopes.length === 0) {
393
+ if (token.endOffset === 0 && token.scopes.length === 0 && i !== 0) {
394
+ endOffsetsAndScopes.splice(i, endOffsetsAndScopes.length - i);
206
395
  break;
207
396
  }
208
- tokens[i * 2] = token.endOffset;
209
- tokens[i * 2 + 1] = findMetadata(this._colorThemeData, token.scopes, encodedLanguageId);
397
+ }
398
+ const captureTime = stopwatch.elapsed();
399
+ return { endOffsets: endOffsetsAndScopes, captureTime };
400
+ }
401
+ _tokenizeCapturesWithMetadata(tree, captures, encodedLanguageId, rangeStartOffset, rangeEndOffset) {
402
+ const stopwatch = StopWatch.create();
403
+ const emptyTokens = this._createTokensFromCaptures(tree, captures, rangeStartOffset, rangeEndOffset);
404
+ if (!emptyTokens) {
405
+ return undefined;
406
+ }
407
+ const endOffsetsAndScopes = emptyTokens.endOffsets;
408
+ for (let i = 0; i < endOffsetsAndScopes.length; i++) {
409
+ const token = endOffsetsAndScopes[i];
410
+ token.metadata = findMetadata(this._colorThemeData, token.scopes, encodedLanguageId);
210
411
  }
211
412
  const metadataTime = stopwatch.elapsed();
212
- return { result: tokens, captureTime, metadataTime };
413
+ return { endOffsetsAndMetadata: endOffsetsAndScopes, captureTime: emptyTokens.captureTime, metadataTime };
414
+ }
415
+ _emptyToken(encodedLanguageId) {
416
+ return findMetadata(this._colorThemeData, [], encodedLanguageId);
417
+ }
418
+ _tokenizeEncoded(lineNumber, textModel) {
419
+ const encodedLanguageId = this._languageIdCodec.encodeLanguageId(this._languageId);
420
+ const lineOffset = textModel.getOffsetAt({ lineNumber: lineNumber, column: 1 });
421
+ const maxLine = textModel.getLineCount();
422
+ const lineEndOffset = (lineNumber + 1 <= maxLine) ? textModel.getOffsetAt({ lineNumber: lineNumber + 1, column: 1 }) : textModel.getValueLength();
423
+ const lineLength = lineEndOffset - lineOffset;
424
+ const result = this._tokenize(encodedLanguageId, ( new Range(lineNumber, 1, lineNumber, lineLength)), lineOffset, lineEndOffset, textModel);
425
+ if (!result) {
426
+ return undefined;
427
+ }
428
+ const tokens = ( new Uint32Array((result.endOffsetsAndMetadata.length) * 2));
429
+ for (let i = 0; i < result.endOffsetsAndMetadata.length; i++) {
430
+ const token = result.endOffsetsAndMetadata[i];
431
+ tokens[i * 2] = token.endOffset;
432
+ tokens[i * 2 + 1] = token.metadata;
433
+ }
434
+ return { result: tokens, captureTime: result.captureTime, metadataTime: result.metadataTime };
213
435
  }
214
436
  dispose() {
215
437
  super.dispose();
@@ -219,7 +441,9 @@ let TreeSitterTokenizationSupport = class TreeSitterTokenizationSupport extends
219
441
  };
220
442
  TreeSitterTokenizationSupport = ( __decorate([
221
443
  ( __param(3, ITreeSitterParserService)),
222
- ( __param(4, IThemeService))
444
+ ( __param(4, IThemeService)),
445
+ ( __param(5, ITreeSitterTokenizationStoreService)),
446
+ ( __param(6, ICodeEditorService))
223
447
  ], TreeSitterTokenizationSupport));
224
448
 
225
- export { TreeSitterTokenizationFeature };
449
+ export { TreeSitterTokenizationFeature, TreeSitterTokenizationSupport };