@codingame/monaco-vscode-treesitter-service-override 15.0.2 → 16.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 +1 -1
- package/package.json +9 -6
- package/vscode/src/vs/editor/common/languages/highlights/typescript.scm +488 -0
- package/vscode/src/vs/editor/common/model/tokenStore.d.ts +0 -1
- package/vscode/src/vs/editor/common/model/tokenStore.js +14 -8
- package/vscode/src/vs/editor/common/model/treeSitterTokenStoreService.d.ts +3 -0
- package/vscode/src/vs/editor/common/model/treeSitterTokenStoreService.js +33 -27
- package/vscode/src/vs/editor/common/services/treeSitter/cursorUtils.d.ts +6 -0
- package/vscode/src/vs/editor/common/services/treeSitter/cursorUtils.js +76 -0
- package/vscode/src/vs/editor/common/services/treeSitter/textModelTreeSitter.d.ts +88 -0
- package/vscode/src/vs/editor/common/services/treeSitter/textModelTreeSitter.js +675 -0
- package/vscode/src/vs/editor/common/services/treeSitter/treeSitterLanguages.d.ts +30 -0
- package/vscode/src/vs/editor/common/services/treeSitter/treeSitterLanguages.js +102 -0
- package/vscode/src/vs/editor/common/services/treeSitter/treeSitterParserService.d.ts +8 -80
- package/vscode/src/vs/editor/common/services/treeSitter/treeSitterParserService.js +20 -522
- package/vscode/src/vs/editor/common/services/treeSitterParserService.d.ts +16 -3
- package/vscode/src/vs/editor/common/services/treeSitterParserService.js +1 -1
- package/vscode/src/vs/workbench/services/treeSitter/browser/treeSitterCodeEditors.d.ts +7 -2
- package/vscode/src/vs/workbench/services/treeSitter/browser/treeSitterCodeEditors.js +43 -22
- package/vscode/src/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.d.ts +14 -14
- package/vscode/src/vs/workbench/services/treeSitter/browser/treeSitterTokenizationFeature.js +256 -169
- package/assets/typescript.scm +0 -388
|
@@ -1,495 +1,28 @@
|
|
|
1
1
|
|
|
2
2
|
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
|
|
3
|
-
import {
|
|
3
|
+
import { FileAccess } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network';
|
|
4
4
|
import { EDITOR_EXPERIMENTAL_PREFER_TREESITTER, TREESITTER_ALLOWED_SUPPORT } from '../treeSitterParserService.js';
|
|
5
5
|
import { ITreeSitterImporter } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService.service';
|
|
6
6
|
import { IModelService } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/services/model.service';
|
|
7
|
-
import { Disposable,
|
|
7
|
+
import { Disposable, DisposableMap, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
|
|
8
8
|
import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
|
|
9
|
-
import { ITelemetryService } from '@codingame/monaco-vscode-api/vscode/vs/platform/telemetry/common/telemetry.service';
|
|
10
|
-
import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
|
|
11
9
|
import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service';
|
|
12
|
-
import {
|
|
13
|
-
import { Emitter, Event } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
|
|
14
|
-
import { cancelOnDispose } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
|
|
10
|
+
import { Emitter } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
|
|
15
11
|
import { IEnvironmentService } from '@codingame/monaco-vscode-api/vscode/vs/platform/environment/common/environment.service';
|
|
16
|
-
import {
|
|
17
|
-
import '
|
|
18
|
-
import {
|
|
19
|
-
import { Position } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/position';
|
|
20
|
-
import { LimitedQueue } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
|
|
21
|
-
import { TextLength } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/core/textLength';
|
|
22
|
-
import { PromiseResult } from '@codingame/monaco-vscode-168b98e5-dc20-5807-b1f9-798f1f92b37f-common/vscode/vs/base/common/observableInternal/promise';
|
|
12
|
+
import { TextModelTreeSitter } from './textModelTreeSitter.js';
|
|
13
|
+
import { TreeSitterLanguages, getModuleLocation } from './treeSitterLanguages.js';
|
|
14
|
+
import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
|
|
23
15
|
|
|
24
16
|
const EDITOR_TREESITTER_TELEMETRY = 'editor.experimental.treeSitterTelemetry';
|
|
25
|
-
const MODULE_LOCATION_SUBPATH = `@vscode/tree-sitter-wasm/wasm`;
|
|
26
17
|
const FILENAME_TREESITTER_WASM = `tree-sitter.wasm`;
|
|
27
|
-
function getModuleLocation(environmentService) {
|
|
28
|
-
return `${nodeModulesPath}/${MODULE_LOCATION_SUBPATH}`;
|
|
29
|
-
}
|
|
30
|
-
class TextModelTreeSitter extends Disposable {
|
|
31
|
-
get parseResult() { return this._parseResult; }
|
|
32
|
-
constructor(model, _treeSitterLanguages, _treeSitterImporter, _logService, _telemetryService, parseImmediately = true) {
|
|
33
|
-
super();
|
|
34
|
-
this.model = model;
|
|
35
|
-
this._treeSitterLanguages = _treeSitterLanguages;
|
|
36
|
-
this._treeSitterImporter = _treeSitterImporter;
|
|
37
|
-
this._logService = _logService;
|
|
38
|
-
this._telemetryService = _telemetryService;
|
|
39
|
-
this._onDidChangeParseResult = this._register(( new Emitter()));
|
|
40
|
-
this.onDidChangeParseResult = this._onDidChangeParseResult.event;
|
|
41
|
-
this._versionId = 0;
|
|
42
|
-
this._parseSessionDisposables = this._register(( new DisposableStore()));
|
|
43
|
-
if (parseImmediately) {
|
|
44
|
-
this._register(Event.runAndSubscribe(this.model.onDidChangeLanguage, (e => this._onDidChangeLanguage(e ? e.newLanguage : this.model.getLanguageId()))));
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this._register(this.model.onDidChangeLanguage(e => this._onDidChangeLanguage(e ? e.newLanguage : this.model.getLanguageId())));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
async _onDidChangeLanguage(languageId) {
|
|
51
|
-
this.parse(languageId);
|
|
52
|
-
}
|
|
53
|
-
async parse(languageId = this.model.getLanguageId()) {
|
|
54
|
-
this._parseSessionDisposables.clear();
|
|
55
|
-
this._parseResult = undefined;
|
|
56
|
-
const token = cancelOnDispose(this._parseSessionDisposables);
|
|
57
|
-
let language;
|
|
58
|
-
try {
|
|
59
|
-
language = await this._getLanguage(languageId, token);
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
if (isCancellationError(e)) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
throw e;
|
|
66
|
-
}
|
|
67
|
-
const Parser = await this._treeSitterImporter.getParserClass();
|
|
68
|
-
if (token.isCancellationRequested) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const treeSitterTree = this._parseSessionDisposables.add(( new TreeSitterParseResult(( new Parser()), language, this._logService, this._telemetryService)));
|
|
72
|
-
this._parseResult = treeSitterTree;
|
|
73
|
-
this._parseSessionDisposables.add(treeSitterTree.onDidUpdate(e => {
|
|
74
|
-
if (e.ranges && (e.versionId > this._versionId)) {
|
|
75
|
-
this._versionId = e.versionId;
|
|
76
|
-
this._onDidChangeParseResult.fire({ ranges: e.ranges, versionId: e.versionId });
|
|
77
|
-
}
|
|
78
|
-
}));
|
|
79
|
-
this._parseSessionDisposables.add(this.model.onDidChangeContent(e => this._onDidChangeContent(treeSitterTree, e)));
|
|
80
|
-
this._onDidChangeContent(treeSitterTree, undefined);
|
|
81
|
-
if (token.isCancellationRequested) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
return this._parseResult;
|
|
85
|
-
}
|
|
86
|
-
_getLanguage(languageId, token) {
|
|
87
|
-
const language = this._treeSitterLanguages.getOrInitLanguage(languageId);
|
|
88
|
-
if (language) {
|
|
89
|
-
return Promise.resolve(language);
|
|
90
|
-
}
|
|
91
|
-
const disposables = [];
|
|
92
|
-
return ( new Promise((resolve, reject) => {
|
|
93
|
-
disposables.push(this._treeSitterLanguages.onDidAddLanguage(e => {
|
|
94
|
-
if (e.id === languageId) {
|
|
95
|
-
dispose(disposables);
|
|
96
|
-
resolve(e.language);
|
|
97
|
-
}
|
|
98
|
-
}));
|
|
99
|
-
token.onCancellationRequested(() => {
|
|
100
|
-
dispose(disposables);
|
|
101
|
-
reject(( new CancellationError()));
|
|
102
|
-
}, undefined, disposables);
|
|
103
|
-
}));
|
|
104
|
-
}
|
|
105
|
-
_onDidChangeContent(treeSitterTree, change) {
|
|
106
|
-
return treeSitterTree.onDidChangeContent(this.model, change);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
var TelemetryParseType;
|
|
110
|
-
(function (TelemetryParseType) {
|
|
111
|
-
TelemetryParseType["Full"] = "fullParse";
|
|
112
|
-
TelemetryParseType["Incremental"] = "incrementalParse";
|
|
113
|
-
})(TelemetryParseType || (TelemetryParseType = {}));
|
|
114
|
-
class TreeSitterParseResult {
|
|
115
|
-
get versionId() {
|
|
116
|
-
return this._versionId;
|
|
117
|
-
}
|
|
118
|
-
constructor(parser, language, _logService, _telemetryService) {
|
|
119
|
-
this.parser = parser;
|
|
120
|
-
this.language = language;
|
|
121
|
-
this._logService = _logService;
|
|
122
|
-
this._telemetryService = _telemetryService;
|
|
123
|
-
this._onDidUpdate = ( new Emitter());
|
|
124
|
-
this.onDidUpdate = this._onDidUpdate.event;
|
|
125
|
-
this._versionId = 0;
|
|
126
|
-
this._editVersion = 0;
|
|
127
|
-
this._isDisposed = false;
|
|
128
|
-
this._onDidChangeContentQueue = ( new LimitedQueue());
|
|
129
|
-
this._lastYieldTime = 0;
|
|
130
|
-
this.parser.setLanguage(language);
|
|
131
|
-
}
|
|
132
|
-
dispose() {
|
|
133
|
-
this._isDisposed = true;
|
|
134
|
-
this._onDidUpdate.dispose();
|
|
135
|
-
this._tree?.delete();
|
|
136
|
-
this._lastFullyParsed?.delete();
|
|
137
|
-
this._lastFullyParsedWithEdits?.delete();
|
|
138
|
-
this.parser?.delete();
|
|
139
|
-
}
|
|
140
|
-
get tree() { return this._lastFullyParsed; }
|
|
141
|
-
get isDisposed() { return this._isDisposed; }
|
|
142
|
-
findChangedNodes(newTree, oldTree) {
|
|
143
|
-
const newCursor = newTree.walk();
|
|
144
|
-
const oldCursor = oldTree.walk();
|
|
145
|
-
const gotoNextSibling = () => {
|
|
146
|
-
const n = newCursor.gotoNextSibling();
|
|
147
|
-
const o = oldCursor.gotoNextSibling();
|
|
148
|
-
if (n !== o) {
|
|
149
|
-
throw ( new Error('Trees are out of sync'));
|
|
150
|
-
}
|
|
151
|
-
return n && o;
|
|
152
|
-
};
|
|
153
|
-
const gotoParent = () => {
|
|
154
|
-
const n = newCursor.gotoParent();
|
|
155
|
-
const o = oldCursor.gotoParent();
|
|
156
|
-
if (n !== o) {
|
|
157
|
-
throw ( new Error('Trees are out of sync'));
|
|
158
|
-
}
|
|
159
|
-
return n && o;
|
|
160
|
-
};
|
|
161
|
-
const gotoNthChild = (index) => {
|
|
162
|
-
const n = newCursor.gotoFirstChild();
|
|
163
|
-
const o = oldCursor.gotoFirstChild();
|
|
164
|
-
if (n !== o) {
|
|
165
|
-
throw ( new Error('Trees are out of sync'));
|
|
166
|
-
}
|
|
167
|
-
if (index === 0) {
|
|
168
|
-
return n && o;
|
|
169
|
-
}
|
|
170
|
-
for (let i = 1; i <= index; i++) {
|
|
171
|
-
const nn = newCursor.gotoNextSibling();
|
|
172
|
-
const oo = oldCursor.gotoNextSibling();
|
|
173
|
-
if (nn !== oo) {
|
|
174
|
-
throw ( new Error('Trees are out of sync'));
|
|
175
|
-
}
|
|
176
|
-
if (!nn || !oo) {
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return n && o;
|
|
181
|
-
};
|
|
182
|
-
const changedRanges = [];
|
|
183
|
-
let next = true;
|
|
184
|
-
const nextSiblingOrParentSibling = () => {
|
|
185
|
-
do {
|
|
186
|
-
if (newCursor.currentNode.nextSibling) {
|
|
187
|
-
return gotoNextSibling();
|
|
188
|
-
}
|
|
189
|
-
if (newCursor.currentNode.parent) {
|
|
190
|
-
gotoParent();
|
|
191
|
-
}
|
|
192
|
-
} while (newCursor.currentNode.nextSibling || newCursor.currentNode.parent);
|
|
193
|
-
return false;
|
|
194
|
-
};
|
|
195
|
-
const getClosestPreviousNodes = () => {
|
|
196
|
-
const newFindPrev = newTree.walk();
|
|
197
|
-
newFindPrev.resetTo(newCursor);
|
|
198
|
-
const oldFindPrev = oldTree.walk();
|
|
199
|
-
oldFindPrev.resetTo(oldCursor);
|
|
200
|
-
const startingNode = newCursor.currentNode;
|
|
201
|
-
do {
|
|
202
|
-
if (newFindPrev.currentNode.previousSibling && ((newFindPrev.currentNode.endIndex - newFindPrev.currentNode.startIndex) !== 0)) {
|
|
203
|
-
newFindPrev.gotoPreviousSibling();
|
|
204
|
-
oldFindPrev.gotoPreviousSibling();
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
while (!newFindPrev.currentNode.previousSibling && newFindPrev.currentNode.parent) {
|
|
208
|
-
newFindPrev.gotoParent();
|
|
209
|
-
oldFindPrev.gotoParent();
|
|
210
|
-
}
|
|
211
|
-
newFindPrev.gotoPreviousSibling();
|
|
212
|
-
oldFindPrev.gotoPreviousSibling();
|
|
213
|
-
}
|
|
214
|
-
} while ((newFindPrev.currentNode.endIndex > startingNode.startIndex)
|
|
215
|
-
&& (newFindPrev.currentNode.parent || newFindPrev.currentNode.previousSibling)
|
|
216
|
-
&& (newFindPrev.currentNode.id !== startingNode.id));
|
|
217
|
-
if ((newFindPrev.currentNode.id !== startingNode.id) && newFindPrev.currentNode.endIndex <= startingNode.startIndex) {
|
|
218
|
-
return { old: oldFindPrev.currentNode, new: newFindPrev.currentNode };
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
return undefined;
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
do {
|
|
225
|
-
if (newCursor.currentNode.hasChanges) {
|
|
226
|
-
const newChildren = newCursor.currentNode.children;
|
|
227
|
-
const indexChangedChildren = [];
|
|
228
|
-
const changedChildren = newChildren.filter((c, index) => {
|
|
229
|
-
if (c?.hasChanges) {
|
|
230
|
-
indexChangedChildren.push(index);
|
|
231
|
-
}
|
|
232
|
-
return c?.hasChanges;
|
|
233
|
-
});
|
|
234
|
-
if ((changedChildren.length === 0) || oldCursor.currentNode.hasError) {
|
|
235
|
-
while (newCursor.currentNode.parent && !newCursor.currentNode.isNamed && next) {
|
|
236
|
-
next = gotoParent();
|
|
237
|
-
}
|
|
238
|
-
const newNode = newCursor.currentNode;
|
|
239
|
-
const oldNode = oldCursor.currentNode;
|
|
240
|
-
const newEndPosition = ( new Position(newNode.endPosition.row + 1, newNode.endPosition.column + 1));
|
|
241
|
-
const oldEndIndex = oldNode.endIndex;
|
|
242
|
-
const closestPrev = getClosestPreviousNodes();
|
|
243
|
-
const newStartPosition = ( new Position(
|
|
244
|
-
closestPrev ? closestPrev.new.endPosition.row + 1 : newNode.startPosition.row + 1,
|
|
245
|
-
closestPrev ? closestPrev.new.endPosition.column + 1 : newNode.startPosition.column + 1
|
|
246
|
-
));
|
|
247
|
-
const newStartIndex = closestPrev ? closestPrev.new.endIndex : newNode.startIndex;
|
|
248
|
-
const oldStartIndex = closestPrev ? closestPrev.old.endIndex : oldNode.startIndex;
|
|
249
|
-
changedRanges.push({ newStartPosition, newEndPosition, oldStartIndex, oldEndIndex, newNodeId: newNode.id, newStartIndex, newEndIndex: newNode.endIndex });
|
|
250
|
-
next = nextSiblingOrParentSibling();
|
|
251
|
-
}
|
|
252
|
-
else if (changedChildren.length >= 1) {
|
|
253
|
-
next = gotoNthChild(indexChangedChildren[0]);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
next = nextSiblingOrParentSibling();
|
|
258
|
-
}
|
|
259
|
-
} while (next);
|
|
260
|
-
if (changedRanges.length === 0 && newTree.rootNode.hasChanges) {
|
|
261
|
-
return [{ newStartPosition: ( new Position(
|
|
262
|
-
newTree.rootNode.startPosition.row + 1,
|
|
263
|
-
newTree.rootNode.startPosition.column + 1
|
|
264
|
-
)), newEndPosition: ( new Position(
|
|
265
|
-
newTree.rootNode.endPosition.row + 1,
|
|
266
|
-
newTree.rootNode.endPosition.column + 1
|
|
267
|
-
)), oldStartIndex: oldTree.rootNode.startIndex, oldEndIndex: oldTree.rootNode.endIndex, newStartIndex: newTree.rootNode.startIndex, newEndIndex: newTree.rootNode.endIndex, newNodeId: newTree.rootNode.id }];
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
return changedRanges;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
calculateRangeChange(model, changedNodes) {
|
|
274
|
-
if (!changedNodes) {
|
|
275
|
-
return undefined;
|
|
276
|
-
}
|
|
277
|
-
const ranges = [];
|
|
278
|
-
for (let i = 0; i < changedNodes.length; i++) {
|
|
279
|
-
const node = changedNodes[i];
|
|
280
|
-
const prevNode = changedNodes[i - 1];
|
|
281
|
-
if ((i > 0) && prevNode.newEndPosition.equals(node.newStartPosition)) {
|
|
282
|
-
const prevRangeChange = ranges[ranges.length - 1];
|
|
283
|
-
prevRangeChange.newRange = ( new Range(
|
|
284
|
-
prevRangeChange.newRange.startLineNumber,
|
|
285
|
-
prevRangeChange.newRange.startColumn,
|
|
286
|
-
node.newEndPosition.lineNumber,
|
|
287
|
-
node.newEndPosition.column
|
|
288
|
-
));
|
|
289
|
-
prevRangeChange.oldRangeLength = node.oldEndIndex - prevNode.oldStartIndex;
|
|
290
|
-
prevRangeChange.newRangeEndOffset = node.newEndIndex;
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
ranges.push({ newRange: Range.fromPositions(node.newStartPosition, node.newEndPosition), oldRangeLength: node.oldEndIndex - node.oldStartIndex, newRangeStartOffset: node.newStartIndex, newRangeEndOffset: node.newEndIndex });
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
if (ranges.length > 0) {
|
|
297
|
-
const lastRange = ranges[ranges.length - 1];
|
|
298
|
-
const maxLine = model.getLineCount();
|
|
299
|
-
if (lastRange.newRange.endLineNumber > maxLine) {
|
|
300
|
-
lastRange.newRange = ( new Range(
|
|
301
|
-
lastRange.newRange.startLineNumber,
|
|
302
|
-
lastRange.newRange.startColumn,
|
|
303
|
-
maxLine,
|
|
304
|
-
model.getLineMaxColumn(maxLine)
|
|
305
|
-
));
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return ranges;
|
|
309
|
-
}
|
|
310
|
-
onDidChangeContent(model, changes) {
|
|
311
|
-
const version = model.getVersionId();
|
|
312
|
-
if (version === this._editVersion) {
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
this._applyEdits(changes?.changes ?? [], version);
|
|
316
|
-
this._onDidChangeContentQueue.queue(async () => {
|
|
317
|
-
if (this.isDisposed) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
let ranges;
|
|
321
|
-
if (this._lastFullyParsedWithEdits && this._lastFullyParsed) {
|
|
322
|
-
ranges = this.calculateRangeChange(model, this.findChangedNodes(this._lastFullyParsedWithEdits, this._lastFullyParsed));
|
|
323
|
-
}
|
|
324
|
-
const completed = await this._parseAndUpdateTree(model, version);
|
|
325
|
-
if (completed) {
|
|
326
|
-
if (!ranges) {
|
|
327
|
-
ranges = [{ newRange: model.getFullModelRange(), oldRangeLength: model.getValueLength(), newRangeStartOffset: 0, newRangeEndOffset: model.getValueLength() }];
|
|
328
|
-
}
|
|
329
|
-
this._onDidUpdate.fire({ ranges, versionId: version });
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
_applyEdits(changes, version) {
|
|
334
|
-
for (const change of changes) {
|
|
335
|
-
const originalTextLength = TextLength.ofRange(Range.lift(change.range));
|
|
336
|
-
const newTextLength = TextLength.ofText(change.text);
|
|
337
|
-
const summedTextLengths = change.text.length === 0 ? newTextLength : originalTextLength.add(newTextLength);
|
|
338
|
-
const edit = {
|
|
339
|
-
startIndex: change.rangeOffset,
|
|
340
|
-
oldEndIndex: change.rangeOffset + change.rangeLength,
|
|
341
|
-
newEndIndex: change.rangeOffset + change.text.length,
|
|
342
|
-
startPosition: { row: change.range.startLineNumber - 1, column: change.range.startColumn - 1 },
|
|
343
|
-
oldEndPosition: { row: change.range.endLineNumber - 1, column: change.range.endColumn - 1 },
|
|
344
|
-
newEndPosition: { row: change.range.startLineNumber + summedTextLengths.lineCount - 1, column: summedTextLengths.lineCount ? summedTextLengths.columnCount : (change.range.endColumn + summedTextLengths.columnCount) }
|
|
345
|
-
};
|
|
346
|
-
this._tree?.edit(edit);
|
|
347
|
-
this._lastFullyParsedWithEdits?.edit(edit);
|
|
348
|
-
}
|
|
349
|
-
this._editVersion = version;
|
|
350
|
-
}
|
|
351
|
-
async _parseAndUpdateTree(model, version) {
|
|
352
|
-
const tree = await this._parse(model);
|
|
353
|
-
if (tree) {
|
|
354
|
-
this._tree?.delete();
|
|
355
|
-
this._tree = tree;
|
|
356
|
-
this._lastFullyParsed?.delete();
|
|
357
|
-
this._lastFullyParsed = tree.copy();
|
|
358
|
-
this._lastFullyParsedWithEdits?.delete();
|
|
359
|
-
this._lastFullyParsedWithEdits = tree.copy();
|
|
360
|
-
this._versionId = version;
|
|
361
|
-
return tree;
|
|
362
|
-
}
|
|
363
|
-
else if (!this._tree) {
|
|
364
|
-
this.parser.reset();
|
|
365
|
-
}
|
|
366
|
-
return undefined;
|
|
367
|
-
}
|
|
368
|
-
_parse(model) {
|
|
369
|
-
let parseType = TelemetryParseType.Full;
|
|
370
|
-
if (this.tree) {
|
|
371
|
-
parseType = TelemetryParseType.Incremental;
|
|
372
|
-
}
|
|
373
|
-
return this._parseAndYield(model, parseType);
|
|
374
|
-
}
|
|
375
|
-
async _parseAndYield(model, parseType) {
|
|
376
|
-
const language = model.getLanguageId();
|
|
377
|
-
let time = 0;
|
|
378
|
-
let passes = 0;
|
|
379
|
-
const inProgressVersion = this._editVersion;
|
|
380
|
-
let newTree;
|
|
381
|
-
this._lastYieldTime = performance.now();
|
|
382
|
-
do {
|
|
383
|
-
const timer = performance.now();
|
|
384
|
-
try {
|
|
385
|
-
newTree = this.parser.parse((index, position) => this._parseCallback(model, index), this._tree, { progressCallback: this._parseProgressCallback.bind(this) });
|
|
386
|
-
}
|
|
387
|
-
catch (e) {
|
|
388
|
-
}
|
|
389
|
-
finally {
|
|
390
|
-
time += performance.now() - timer;
|
|
391
|
-
passes++;
|
|
392
|
-
}
|
|
393
|
-
await ( new Promise(resolve => setTimeout0(resolve)));
|
|
394
|
-
} while (!model.isDisposed() && !this.isDisposed && !newTree && inProgressVersion === model.getVersionId());
|
|
395
|
-
this.sendParseTimeTelemetry(parseType, language, time, passes);
|
|
396
|
-
return (newTree && (inProgressVersion === model.getVersionId())) ? newTree : undefined;
|
|
397
|
-
}
|
|
398
|
-
_parseProgressCallback(state) {
|
|
399
|
-
const now = performance.now();
|
|
400
|
-
if (now - this._lastYieldTime > 50) {
|
|
401
|
-
this._lastYieldTime = now;
|
|
402
|
-
return true;
|
|
403
|
-
}
|
|
404
|
-
return false;
|
|
405
|
-
}
|
|
406
|
-
_parseCallback(textModel, index) {
|
|
407
|
-
try {
|
|
408
|
-
return textModel.getTextBuffer().getNearestChunk(index);
|
|
409
|
-
}
|
|
410
|
-
catch (e) {
|
|
411
|
-
this._logService.debug('Error getting chunk for tree-sitter parsing', e);
|
|
412
|
-
}
|
|
413
|
-
return undefined;
|
|
414
|
-
}
|
|
415
|
-
sendParseTimeTelemetry(parseType, languageId, time, passes) {
|
|
416
|
-
this._logService.debug(`Tree parsing (${parseType}) took ${time} ms and ${passes} passes.`);
|
|
417
|
-
if (parseType === TelemetryParseType.Full) {
|
|
418
|
-
this._telemetryService.publicLog2(`treeSitter.fullParse`, { languageId, time, passes });
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
this._telemetryService.publicLog2(`treeSitter.incrementalParse`, { languageId, time, passes });
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
class TreeSitterLanguages extends Disposable {
|
|
426
|
-
constructor(_treeSitterImporter, _fileService, _environmentService, _registeredLanguages) {
|
|
427
|
-
super();
|
|
428
|
-
this._treeSitterImporter = _treeSitterImporter;
|
|
429
|
-
this._fileService = _fileService;
|
|
430
|
-
this._environmentService = _environmentService;
|
|
431
|
-
this._registeredLanguages = _registeredLanguages;
|
|
432
|
-
this._languages = ( new AsyncCache());
|
|
433
|
-
this._onDidAddLanguage = this._register(( new Emitter()));
|
|
434
|
-
this.onDidAddLanguage = this._onDidAddLanguage.event;
|
|
435
|
-
}
|
|
436
|
-
getOrInitLanguage(languageId) {
|
|
437
|
-
if (this._languages.isCached(languageId)) {
|
|
438
|
-
return this._languages.getSyncIfCached(languageId);
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
this._addLanguage(languageId);
|
|
442
|
-
return undefined;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
async getLanguage(languageId) {
|
|
446
|
-
if (this._languages.isCached(languageId)) {
|
|
447
|
-
return this._languages.getSyncIfCached(languageId);
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
await this._addLanguage(languageId);
|
|
451
|
-
return this._languages.get(languageId);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
async _addLanguage(languageId) {
|
|
455
|
-
const languagePromise = this._languages.get(languageId);
|
|
456
|
-
if (!languagePromise) {
|
|
457
|
-
this._languages.set(languageId, this._fetchLanguage(languageId));
|
|
458
|
-
const language = await this._languages.get(languageId);
|
|
459
|
-
if (!language) {
|
|
460
|
-
return undefined;
|
|
461
|
-
}
|
|
462
|
-
this._onDidAddLanguage.fire({ id: languageId, language });
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
async _fetchLanguage(languageId) {
|
|
466
|
-
const grammarName = this._registeredLanguages.get(languageId);
|
|
467
|
-
const languageLocation = this._getLanguageLocation(languageId);
|
|
468
|
-
if (!grammarName || !languageLocation) {
|
|
469
|
-
return undefined;
|
|
470
|
-
}
|
|
471
|
-
const wasmPath = `${languageLocation}/${grammarName}.wasm`;
|
|
472
|
-
const languageFile = await (this._fileService.readFile(( FileAccess.asFileUri(wasmPath))));
|
|
473
|
-
const Language = await this._treeSitterImporter.getLanguageClass();
|
|
474
|
-
return Language.load(languageFile.value.buffer);
|
|
475
|
-
}
|
|
476
|
-
_getLanguageLocation(languageId) {
|
|
477
|
-
const grammarName = this._registeredLanguages.get(languageId);
|
|
478
|
-
if (!grammarName) {
|
|
479
|
-
return undefined;
|
|
480
|
-
}
|
|
481
|
-
return getModuleLocation();
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
18
|
let TreeSitterTextModelService = class TreeSitterTextModelService extends Disposable {
|
|
485
|
-
constructor(_modelService, fileService,
|
|
19
|
+
constructor(_modelService, fileService, _configurationService, _environmentService, _treeSitterImporter, _instantiationService) {
|
|
486
20
|
super();
|
|
487
21
|
this._modelService = _modelService;
|
|
488
|
-
this._telemetryService = _telemetryService;
|
|
489
|
-
this._logService = _logService;
|
|
490
22
|
this._configurationService = _configurationService;
|
|
491
23
|
this._environmentService = _environmentService;
|
|
492
24
|
this._treeSitterImporter = _treeSitterImporter;
|
|
25
|
+
this._instantiationService = _instantiationService;
|
|
493
26
|
this._textModelTreeSitters = this._register(( new DisposableMap()));
|
|
494
27
|
this._registeredLanguages = ( new Map());
|
|
495
28
|
this._onDidUpdateTree = this._register(( new Emitter()));
|
|
@@ -515,7 +48,7 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
|
|
|
515
48
|
}
|
|
516
49
|
getParseResult(textModel) {
|
|
517
50
|
const textModelTreeSitter = this._textModelTreeSitters.get(textModel);
|
|
518
|
-
return textModelTreeSitter?.textModelTreeSitter
|
|
51
|
+
return textModelTreeSitter?.textModelTreeSitter;
|
|
519
52
|
}
|
|
520
53
|
async getTree(content, languageId) {
|
|
521
54
|
const language = await this.getLanguage(languageId);
|
|
@@ -608,17 +141,10 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
|
|
|
608
141
|
return this._createTextModelTreeSitter(model, parseImmediately);
|
|
609
142
|
}
|
|
610
143
|
_createTextModelTreeSitter(model, parseImmediately = true) {
|
|
611
|
-
const textModelTreeSitter = (
|
|
612
|
-
model,
|
|
613
|
-
this._treeSitterLanguages,
|
|
614
|
-
this._treeSitterImporter,
|
|
615
|
-
this._logService,
|
|
616
|
-
this._telemetryService,
|
|
617
|
-
parseImmediately
|
|
618
|
-
));
|
|
144
|
+
const textModelTreeSitter = this._instantiationService.createInstance(TextModelTreeSitter, model, this._treeSitterLanguages, parseImmediately);
|
|
619
145
|
const disposables = ( new DisposableStore());
|
|
620
146
|
disposables.add(textModelTreeSitter);
|
|
621
|
-
disposables.add(textModelTreeSitter.onDidChangeParseResult(
|
|
147
|
+
disposables.add(textModelTreeSitter.onDidChangeParseResult((e) => this._handleOnDidChangeParseResult(e, model)));
|
|
622
148
|
this._textModelTreeSitters.set(model, {
|
|
623
149
|
textModelTreeSitter,
|
|
624
150
|
disposables,
|
|
@@ -626,6 +152,9 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
|
|
|
626
152
|
});
|
|
627
153
|
return textModelTreeSitter;
|
|
628
154
|
}
|
|
155
|
+
_handleOnDidChangeParseResult(change, model) {
|
|
156
|
+
this._onDidUpdateTree.fire({ textModel: model, ranges: change.ranges, versionId: change.versionId, tree: change.tree, languageId: change.languageId, hasInjections: change.hasInjections });
|
|
157
|
+
}
|
|
629
158
|
_addGrammar(languageId, grammarName) {
|
|
630
159
|
if (!( this._registeredLanguages.has(languageId))) {
|
|
631
160
|
this._registeredLanguages.set(languageId, grammarName);
|
|
@@ -633,48 +162,17 @@ let TreeSitterTextModelService = class TreeSitterTextModelService extends Dispos
|
|
|
633
162
|
}
|
|
634
163
|
_removeGrammar(languageId) {
|
|
635
164
|
if (( this._registeredLanguages.has(languageId))) {
|
|
636
|
-
this._registeredLanguages.delete(
|
|
165
|
+
this._registeredLanguages.delete(languageId);
|
|
637
166
|
}
|
|
638
167
|
}
|
|
639
168
|
};
|
|
640
169
|
TreeSitterTextModelService = ( __decorate([
|
|
641
170
|
( __param(0, IModelService)),
|
|
642
171
|
( __param(1, IFileService)),
|
|
643
|
-
( __param(2,
|
|
644
|
-
( __param(3,
|
|
645
|
-
( __param(4,
|
|
646
|
-
( __param(5,
|
|
647
|
-
( __param(6, ITreeSitterImporter))
|
|
172
|
+
( __param(2, IConfigurationService)),
|
|
173
|
+
( __param(3, IEnvironmentService)),
|
|
174
|
+
( __param(4, ITreeSitterImporter)),
|
|
175
|
+
( __param(5, IInstantiationService))
|
|
648
176
|
], TreeSitterTextModelService));
|
|
649
|
-
class PromiseWithSyncAccess {
|
|
650
|
-
get result() {
|
|
651
|
-
return this._result;
|
|
652
|
-
}
|
|
653
|
-
constructor(promise) {
|
|
654
|
-
this.promise = promise;
|
|
655
|
-
promise.then(result => {
|
|
656
|
-
this._result = ( new PromiseResult(result, undefined));
|
|
657
|
-
}).catch(e => {
|
|
658
|
-
this._result = ( new PromiseResult(undefined, e));
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
class AsyncCache {
|
|
663
|
-
constructor() {
|
|
664
|
-
this._values = ( new Map());
|
|
665
|
-
}
|
|
666
|
-
set(key, promise) {
|
|
667
|
-
this._values.set(key, ( new PromiseWithSyncAccess(promise)));
|
|
668
|
-
}
|
|
669
|
-
get(key) {
|
|
670
|
-
return this._values.get(key)?.promise;
|
|
671
|
-
}
|
|
672
|
-
getSyncIfCached(key) {
|
|
673
|
-
return this._values.get(key)?.result?.data;
|
|
674
|
-
}
|
|
675
|
-
isCached(key) {
|
|
676
|
-
return this._values.get(key)?.result !== undefined;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
177
|
|
|
680
|
-
export {
|
|
178
|
+
export { TreeSitterTextModelService };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type * as Parser from "@vscode/tree-sitter-wasm";
|
|
2
2
|
import { ITextModel } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/model";
|
|
3
3
|
import { Range } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/core/range";
|
|
4
|
+
import { IModelContentChangedEvent } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/textModelEvents";
|
|
4
5
|
import { ITreeSitterImporter } from "@codingame/monaco-vscode-api/vscode/vs/editor/common/services/treeSitterParserService.service";
|
|
5
6
|
export declare const EDITOR_EXPERIMENTAL_PREFER_TREESITTER = "editor.experimental.preferTreeSitter";
|
|
6
7
|
export declare const TREESITTER_ALLOWED_SUPPORT: string[];
|
|
@@ -11,26 +12,38 @@ export interface RangeWithOffsets {
|
|
|
11
12
|
}
|
|
12
13
|
export interface RangeChange {
|
|
13
14
|
newRange: Range;
|
|
14
|
-
oldRangeLength: number;
|
|
15
15
|
newRangeStartOffset: number;
|
|
16
16
|
newRangeEndOffset: number;
|
|
17
17
|
}
|
|
18
18
|
export interface TreeParseUpdateEvent {
|
|
19
19
|
ranges: RangeChange[] | undefined;
|
|
20
|
+
language: string;
|
|
20
21
|
versionId: number;
|
|
22
|
+
tree: Parser.Tree;
|
|
23
|
+
includedModelChanges: IModelContentChangedEvent[];
|
|
21
24
|
}
|
|
22
|
-
export interface
|
|
23
|
-
textModel: ITextModel;
|
|
25
|
+
export interface ModelTreeUpdateEvent {
|
|
24
26
|
ranges: RangeChange[];
|
|
25
27
|
versionId: number;
|
|
28
|
+
tree: ITextModelTreeSitter;
|
|
29
|
+
languageId: string;
|
|
30
|
+
hasInjections: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface TreeUpdateEvent extends ModelTreeUpdateEvent {
|
|
33
|
+
textModel: ITextModel;
|
|
26
34
|
}
|
|
27
35
|
export interface ITreeSitterParseResult {
|
|
28
36
|
readonly tree: Parser.Tree | undefined;
|
|
29
37
|
readonly language: Parser.Language;
|
|
38
|
+
readonly languageId: string;
|
|
39
|
+
readonly ranges: Parser.Range[] | undefined;
|
|
30
40
|
versionId: number;
|
|
31
41
|
}
|
|
32
42
|
export interface ITextModelTreeSitter {
|
|
33
43
|
parse(languageId?: string): Promise<ITreeSitterParseResult | undefined>;
|
|
44
|
+
textModel: ITextModel;
|
|
45
|
+
parseResult: ITreeSitterParseResult | undefined;
|
|
46
|
+
getInjection(offset: number, parentLanguage: string): ITreeSitterParseResult | undefined;
|
|
34
47
|
dispose(): void;
|
|
35
48
|
}
|
|
36
49
|
export declare class TreeSitterImporter implements ITreeSitterImporter {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
const EDITOR_EXPERIMENTAL_PREFER_TREESITTER = 'editor.experimental.preferTreeSitter';
|
|
4
|
-
const TREESITTER_ALLOWED_SUPPORT = ['typescript', 'ini'];
|
|
4
|
+
const TREESITTER_ALLOWED_SUPPORT = ['css', 'typescript', 'ini', 'regex'];
|
|
5
5
|
class TreeSitterImporter {
|
|
6
6
|
constructor() { }
|
|
7
7
|
async _getTreeSitterImport() {
|
|
@@ -13,15 +13,20 @@ export declare class TreeSitterCodeEditors extends Disposable {
|
|
|
13
13
|
private readonly _languageId;
|
|
14
14
|
private readonly _codeEditorService;
|
|
15
15
|
private readonly _treeSitterParserService;
|
|
16
|
-
private readonly
|
|
16
|
+
private readonly _textModels;
|
|
17
|
+
private readonly _languageEditors;
|
|
18
|
+
private readonly _allEditors;
|
|
17
19
|
private readonly _onDidChangeViewport;
|
|
18
20
|
readonly onDidChangeViewport: Event<IViewPortChangeEvent>;
|
|
19
21
|
constructor(_languageId: string, _codeEditorService: ICodeEditorService, _treeSitterParserService: ITreeSitterParserService);
|
|
20
|
-
get
|
|
22
|
+
get textModels(): ITextModel[];
|
|
23
|
+
getEditorForModel(model: ITextModel): ICodeEditor | undefined;
|
|
21
24
|
getInitialViewPorts(): Promise<IViewPortChangeEvent[]>;
|
|
22
25
|
private _onCodeEditorRemove;
|
|
23
26
|
private getEditorModel;
|
|
24
27
|
private _onCodeEditorAdd;
|
|
28
|
+
private _tryAddEditor;
|
|
29
|
+
private _onDidChangeModel;
|
|
25
30
|
private _onViewportChange;
|
|
26
31
|
private _nonIntersectingViewPortRanges;
|
|
27
32
|
}
|