@codemirror/language 0.19.1 → 0.19.5
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/CHANGELOG.md +30 -0
- package/dist/index.cjs +71 -41
- package/dist/index.d.ts +29 -4
- package/dist/index.js +72 -44
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## 0.19.5 (2021-11-17)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
The new function `syntaxTreeAvailable` can be used to check if a fully-parsed syntax tree is available up to a given document position.
|
|
6
|
+
|
|
7
|
+
The module now exports `syntaxParserRunning`, which tells you whether the background parser is still planning to do more work for a given editor view.
|
|
8
|
+
|
|
9
|
+
## 0.19.4 (2021-11-13)
|
|
10
|
+
|
|
11
|
+
### New features
|
|
12
|
+
|
|
13
|
+
`LanguageDescription.of` now takes an optional already-loaded extension.
|
|
14
|
+
|
|
15
|
+
## 0.19.3 (2021-09-13)
|
|
16
|
+
|
|
17
|
+
### Bug fixes
|
|
18
|
+
|
|
19
|
+
Fix an issue where a parse that skipped content with `skipUntilInView` would in some cases not be restarted when the range came into view.
|
|
20
|
+
|
|
21
|
+
## 0.19.2 (2021-08-11)
|
|
22
|
+
|
|
23
|
+
### Bug fixes
|
|
24
|
+
|
|
25
|
+
Fix a bug that caused `indentOnInput` to fire for the wrong kinds of transactions.
|
|
26
|
+
|
|
27
|
+
Fix a bug that could cause `indentOnInput` to apply its changes incorrectly.
|
|
28
|
+
|
|
1
29
|
## 0.19.1 (2021-08-11)
|
|
2
30
|
|
|
3
31
|
### Bug fixes
|
|
@@ -16,6 +44,8 @@ CodeMirror now uses lezer 0.15, which means different package names (scoped with
|
|
|
16
44
|
|
|
17
45
|
`LezerLanguage` was renamed to `LRLanguage` (because all languages must emit Lezer-style trees, the name was misleading).
|
|
18
46
|
|
|
47
|
+
`Language.parseString` no longer exists. You can just call `.parser.parse(...)` instead.
|
|
48
|
+
|
|
19
49
|
### New features
|
|
20
50
|
|
|
21
51
|
New `IndentContext.lineAt` method to access lines in a way that is aware of simulated line breaks.
|
package/dist/index.cjs
CHANGED
|
@@ -181,6 +181,30 @@ function ensureSyntaxTree(state, upto, timeout = 50) {
|
|
|
181
181
|
let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
|
|
182
182
|
return !parse ? null : parse.treeLen >= upto || parse.work(timeout, upto) ? parse.tree : null;
|
|
183
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
Queries whether there is a full syntax tree available up to the
|
|
186
|
+
given document position. If there isn't, the background parse
|
|
187
|
+
process _might_ still be working and update the tree further, but
|
|
188
|
+
there is no guarantee of that—the parser will [stop
|
|
189
|
+
working](https://codemirror.net/6/docs/ref/#language.syntaxParserStopped) when it has spent a
|
|
190
|
+
certain amount of time or has moved beyond the visible viewport.
|
|
191
|
+
Always returns false if no language has been enabled.
|
|
192
|
+
*/
|
|
193
|
+
function syntaxTreeAvailable(state, upto = state.doc.length) {
|
|
194
|
+
var _a;
|
|
195
|
+
return ((_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context.isDone(upto)) || false;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
Tells you whether the language parser is planning to do more
|
|
199
|
+
parsing work (in a `requestIdleCallback` pseudo-thread) or has
|
|
200
|
+
stopped running, either because it parsed the entire document,
|
|
201
|
+
because it spent too much time and was cut off, or because there
|
|
202
|
+
is no language parser enabled.
|
|
203
|
+
*/
|
|
204
|
+
function syntaxParserRunning(view) {
|
|
205
|
+
var _a;
|
|
206
|
+
return ((_a = view.plugin(parseWorker)) === null || _a === void 0 ? void 0 : _a.isWorking()) || false;
|
|
207
|
+
}
|
|
184
208
|
// Lezer-style Input object for a Text document.
|
|
185
209
|
class DocInput {
|
|
186
210
|
constructor(doc, length = doc.length) {
|
|
@@ -233,7 +257,7 @@ class ParseContext {
|
|
|
233
257
|
The current editor viewport (or some overapproximation
|
|
234
258
|
thereof). Intended to be used for opportunistically avoiding
|
|
235
259
|
work (in which case
|
|
236
|
-
[`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.
|
|
260
|
+
[`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView)
|
|
237
261
|
should be called to make sure the parser is restarted when the
|
|
238
262
|
skipped region becomes visible).
|
|
239
263
|
*/
|
|
@@ -271,7 +295,7 @@ class ParseContext {
|
|
|
271
295
|
work(time, upto) {
|
|
272
296
|
if (upto != null && upto >= this.state.doc.length)
|
|
273
297
|
upto = undefined;
|
|
274
|
-
if (this.tree != common.Tree.empty && (upto
|
|
298
|
+
if (this.tree != common.Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) {
|
|
275
299
|
this.takeTree();
|
|
276
300
|
return true;
|
|
277
301
|
}
|
|
@@ -357,6 +381,8 @@ class ParseContext {
|
|
|
357
381
|
@internal
|
|
358
382
|
*/
|
|
359
383
|
updateViewport(viewport) {
|
|
384
|
+
if (this.viewport.from == viewport.from && this.viewport.to == viewport.to)
|
|
385
|
+
return false;
|
|
360
386
|
this.viewport = viewport;
|
|
361
387
|
let startLen = this.skipped.length;
|
|
362
388
|
for (let i = 0; i < this.skipped.length; i++) {
|
|
@@ -366,7 +392,10 @@ class ParseContext {
|
|
|
366
392
|
this.skipped.splice(i--, 1);
|
|
367
393
|
}
|
|
368
394
|
}
|
|
369
|
-
|
|
395
|
+
if (this.skipped.length >= startLen)
|
|
396
|
+
return false;
|
|
397
|
+
this.reset();
|
|
398
|
+
return true;
|
|
370
399
|
}
|
|
371
400
|
/**
|
|
372
401
|
@internal
|
|
@@ -425,6 +454,13 @@ class ParseContext {
|
|
|
425
454
|
return this.treeLen < pos && this.parse && this.parse.parsedPos >= pos;
|
|
426
455
|
}
|
|
427
456
|
/**
|
|
457
|
+
@internal
|
|
458
|
+
*/
|
|
459
|
+
isDone(upto) {
|
|
460
|
+
let frags = this.fragments;
|
|
461
|
+
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
428
464
|
Get the context for the current parse, or `null` if no editor
|
|
429
465
|
parse is in progress.
|
|
430
466
|
*/
|
|
@@ -479,6 +515,7 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
479
515
|
constructor(view) {
|
|
480
516
|
this.view = view;
|
|
481
517
|
this.working = -1;
|
|
518
|
+
this.workScheduled = 0;
|
|
482
519
|
// End of the current time chunk
|
|
483
520
|
this.chunkEnd = -1;
|
|
484
521
|
// Milliseconds of budget left for this chunk
|
|
@@ -488,12 +525,8 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
488
525
|
}
|
|
489
526
|
update(update) {
|
|
490
527
|
let cx = this.view.state.field(Language.state).context;
|
|
491
|
-
if (update.
|
|
492
|
-
|
|
493
|
-
cx.reset();
|
|
494
|
-
if (this.view.viewport.to > cx.treeLen)
|
|
495
|
-
this.scheduleWork();
|
|
496
|
-
}
|
|
528
|
+
if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen)
|
|
529
|
+
this.scheduleWork();
|
|
497
530
|
if (update.docChanged) {
|
|
498
531
|
if (this.view.hasFocus)
|
|
499
532
|
this.chunkBudget += 50 /* ChangeBonus */;
|
|
@@ -504,11 +537,9 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
504
537
|
scheduleWork() {
|
|
505
538
|
if (this.working > -1)
|
|
506
539
|
return;
|
|
507
|
-
let { state } = this.view, field = state.field(Language.state)
|
|
508
|
-
if (field.tree
|
|
509
|
-
|
|
510
|
-
return;
|
|
511
|
-
this.working = requestIdle(this.work, { timeout: 500 /* Pause */ });
|
|
540
|
+
let { state } = this.view, field = state.field(Language.state);
|
|
541
|
+
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
|
|
542
|
+
this.working = requestIdle(this.work, { timeout: 500 /* Pause */ });
|
|
512
543
|
}
|
|
513
544
|
work(deadline) {
|
|
514
545
|
this.working = -1;
|
|
@@ -535,7 +566,11 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
535
566
|
}
|
|
536
567
|
checkAsyncSchedule(cx) {
|
|
537
568
|
if (cx.scheduleOn) {
|
|
538
|
-
|
|
569
|
+
this.workScheduled++;
|
|
570
|
+
cx.scheduleOn
|
|
571
|
+
.then(() => this.scheduleWork())
|
|
572
|
+
.catch(err => view.logException(this.view.state, err))
|
|
573
|
+
.then(() => this.workScheduled--);
|
|
539
574
|
cx.scheduleOn = null;
|
|
540
575
|
}
|
|
541
576
|
}
|
|
@@ -543,6 +578,9 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
543
578
|
if (this.working >= 0)
|
|
544
579
|
cancelIdle(this.working);
|
|
545
580
|
}
|
|
581
|
+
isWorking() {
|
|
582
|
+
return this.working >= 0 || this.workScheduled > 0;
|
|
583
|
+
}
|
|
546
584
|
}, {
|
|
547
585
|
eventHandlers: { focus() { this.scheduleWork(); } }
|
|
548
586
|
});
|
|
@@ -605,16 +643,17 @@ class LanguageDescription {
|
|
|
605
643
|
Optional filename pattern that should be associated with this
|
|
606
644
|
language.
|
|
607
645
|
*/
|
|
608
|
-
filename, loadFunc
|
|
646
|
+
filename, loadFunc,
|
|
647
|
+
/**
|
|
648
|
+
If the language has been loaded, this will hold its value.
|
|
649
|
+
*/
|
|
650
|
+
support = undefined) {
|
|
609
651
|
this.name = name;
|
|
610
652
|
this.alias = alias;
|
|
611
653
|
this.extensions = extensions;
|
|
612
654
|
this.filename = filename;
|
|
613
655
|
this.loadFunc = loadFunc;
|
|
614
|
-
|
|
615
|
-
If the language has been loaded, this will hold its value.
|
|
616
|
-
*/
|
|
617
|
-
this.support = undefined;
|
|
656
|
+
this.support = support;
|
|
618
657
|
this.loading = null;
|
|
619
658
|
}
|
|
620
659
|
/**
|
|
@@ -629,7 +668,13 @@ class LanguageDescription {
|
|
|
629
668
|
Create a language description.
|
|
630
669
|
*/
|
|
631
670
|
static of(spec) {
|
|
632
|
-
|
|
671
|
+
let { load, support } = spec;
|
|
672
|
+
if (!load) {
|
|
673
|
+
if (!support)
|
|
674
|
+
throw new RangeError("Must pass either 'load' or 'support' to LanguageDescription.of");
|
|
675
|
+
load = () => Promise.resolve(support);
|
|
676
|
+
}
|
|
677
|
+
return new LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map(s => s.toLowerCase()), spec.extensions || [], spec.filename, load, support);
|
|
633
678
|
}
|
|
634
679
|
/**
|
|
635
680
|
Look for a language in the given array of descriptions that
|
|
@@ -839,24 +884,7 @@ definitive indentation can be determined.
|
|
|
839
884
|
const indentNodeProp = new common.NodeProp();
|
|
840
885
|
// Compute the indentation for a given position from the syntax tree.
|
|
841
886
|
function syntaxIndentation(cx, ast, pos) {
|
|
842
|
-
|
|
843
|
-
// Enter previous nodes that end in empty error terms, which means
|
|
844
|
-
// they were broken off by error recovery, so that indentation
|
|
845
|
-
// works even if the constructs haven't been finished.
|
|
846
|
-
for (let scan = tree, scanPos = pos;;) {
|
|
847
|
-
let last = scan.childBefore(scanPos);
|
|
848
|
-
if (!last)
|
|
849
|
-
break;
|
|
850
|
-
if (last.type.isError && last.from == last.to) {
|
|
851
|
-
tree = scan;
|
|
852
|
-
scanPos = last.from;
|
|
853
|
-
}
|
|
854
|
-
else {
|
|
855
|
-
scan = last;
|
|
856
|
-
scanPos = scan.to + 1;
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
return indentFrom(tree, pos, cx);
|
|
887
|
+
return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx);
|
|
860
888
|
}
|
|
861
889
|
function ignoreClosed(cx) {
|
|
862
890
|
return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak;
|
|
@@ -1023,7 +1051,7 @@ added at the start of a line.
|
|
|
1023
1051
|
*/
|
|
1024
1052
|
function indentOnInput() {
|
|
1025
1053
|
return state.EditorState.transactionFilter.of(tr => {
|
|
1026
|
-
if (!tr.docChanged || tr.isUserEvent("input.type"))
|
|
1054
|
+
if (!tr.docChanged || !tr.isUserEvent("input.type"))
|
|
1027
1055
|
return tr;
|
|
1028
1056
|
let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head);
|
|
1029
1057
|
if (!rules.length)
|
|
@@ -1048,7 +1076,7 @@ function indentOnInput() {
|
|
|
1048
1076
|
if (cur != norm)
|
|
1049
1077
|
changes.push({ from: line.from, to: line.from + cur.length, insert: norm });
|
|
1050
1078
|
}
|
|
1051
|
-
return changes.length ? [tr, { changes }] : tr;
|
|
1079
|
+
return changes.length ? [tr, { changes, sequential: true }] : tr;
|
|
1052
1080
|
});
|
|
1053
1081
|
}
|
|
1054
1082
|
|
|
@@ -1137,4 +1165,6 @@ exports.indentString = indentString;
|
|
|
1137
1165
|
exports.indentUnit = indentUnit;
|
|
1138
1166
|
exports.language = language;
|
|
1139
1167
|
exports.languageDataProp = languageDataProp;
|
|
1168
|
+
exports.syntaxParserRunning = syntaxParserRunning;
|
|
1140
1169
|
exports.syntaxTree = syntaxTree;
|
|
1170
|
+
exports.syntaxTreeAvailable = syntaxTreeAvailable;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NodeProp, NodeType, Parser, Tree, TreeFragment, Input, PartialParse, SyntaxNode } from '@lezer/common';
|
|
2
2
|
import { LRParser, ParserConfig } from '@lezer/lr';
|
|
3
3
|
import { Facet, Extension, EditorState } from '@codemirror/state';
|
|
4
|
+
import { EditorView } from '@codemirror/view';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
Node prop stored in a grammar's top syntax node to provide the
|
|
@@ -139,6 +140,24 @@ up to that point if the tree isn't already available.
|
|
|
139
140
|
*/
|
|
140
141
|
declare function ensureSyntaxTree(state: EditorState, upto: number, timeout?: number): Tree | null;
|
|
141
142
|
/**
|
|
143
|
+
Queries whether there is a full syntax tree available up to the
|
|
144
|
+
given document position. If there isn't, the background parse
|
|
145
|
+
process _might_ still be working and update the tree further, but
|
|
146
|
+
there is no guarantee of that—the parser will [stop
|
|
147
|
+
working](https://codemirror.net/6/docs/ref/#language.syntaxParserStopped) when it has spent a
|
|
148
|
+
certain amount of time or has moved beyond the visible viewport.
|
|
149
|
+
Always returns false if no language has been enabled.
|
|
150
|
+
*/
|
|
151
|
+
declare function syntaxTreeAvailable(state: EditorState, upto?: number): boolean;
|
|
152
|
+
/**
|
|
153
|
+
Tells you whether the language parser is planning to do more
|
|
154
|
+
parsing work (in a `requestIdleCallback` pseudo-thread) or has
|
|
155
|
+
stopped running, either because it parsed the entire document,
|
|
156
|
+
because it spent too much time and was cut off, or because there
|
|
157
|
+
is no language parser enabled.
|
|
158
|
+
*/
|
|
159
|
+
declare function syntaxParserRunning(view: EditorView): boolean;
|
|
160
|
+
/**
|
|
142
161
|
A parse context provided to parsers working on the editor content.
|
|
143
162
|
*/
|
|
144
163
|
declare class ParseContext {
|
|
@@ -156,7 +175,7 @@ declare class ParseContext {
|
|
|
156
175
|
The current editor viewport (or some overapproximation
|
|
157
176
|
thereof). Intended to be used for opportunistically avoiding
|
|
158
177
|
work (in which case
|
|
159
|
-
[`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.
|
|
178
|
+
[`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView)
|
|
160
179
|
should be called to make sure the parser is restarted when the
|
|
161
180
|
skipped region becomes visible).
|
|
162
181
|
*/
|
|
@@ -298,7 +317,8 @@ declare class LanguageDescription {
|
|
|
298
317
|
*/
|
|
299
318
|
alias?: readonly string[];
|
|
300
319
|
/**
|
|
301
|
-
An optional array of extensions associated with this
|
|
320
|
+
An optional array of filename extensions associated with this
|
|
321
|
+
language.
|
|
302
322
|
*/
|
|
303
323
|
extensions?: readonly string[];
|
|
304
324
|
/**
|
|
@@ -308,7 +328,12 @@ declare class LanguageDescription {
|
|
|
308
328
|
/**
|
|
309
329
|
A function that will asynchronously load the language.
|
|
310
330
|
*/
|
|
311
|
-
load
|
|
331
|
+
load?: () => Promise<LanguageSupport>;
|
|
332
|
+
/**
|
|
333
|
+
Alternatively to `load`, you can provide an already loaded
|
|
334
|
+
support object. Either this or `load` should be provided.
|
|
335
|
+
*/
|
|
336
|
+
support?: LanguageSupport;
|
|
312
337
|
}): LanguageDescription;
|
|
313
338
|
/**
|
|
314
339
|
Look for a language in the given array of descriptions that
|
|
@@ -584,4 +609,4 @@ declare function foldable(state: EditorState, lineStart: number, lineEnd: number
|
|
|
584
609
|
to: number;
|
|
585
610
|
} | null;
|
|
586
611
|
|
|
587
|
-
export { IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, TreeIndentContext, continuedIndent, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldInside, foldNodeProp, foldService, foldable, getIndentUnit, getIndentation, indentNodeProp, indentOnInput, indentService, indentString, indentUnit, language, languageDataProp, syntaxTree };
|
|
612
|
+
export { IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, TreeIndentContext, continuedIndent, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldInside, foldNodeProp, foldService, foldable, getIndentUnit, getIndentation, indentNodeProp, indentOnInput, indentService, indentString, indentUnit, language, languageDataProp, syntaxParserRunning, syntaxTree, syntaxTreeAvailable };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NodeProp, Tree, TreeFragment, Parser, NodeType } from '@lezer/common';
|
|
2
|
-
import {
|
|
3
|
-
import { ViewPlugin } from '@codemirror/view';
|
|
2
|
+
import { StateEffect, StateField, Facet, EditorState } from '@codemirror/state';
|
|
3
|
+
import { ViewPlugin, logException } from '@codemirror/view';
|
|
4
4
|
import { countColumn } from '@codemirror/text';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -177,6 +177,30 @@ function ensureSyntaxTree(state, upto, timeout = 50) {
|
|
|
177
177
|
let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
|
|
178
178
|
return !parse ? null : parse.treeLen >= upto || parse.work(timeout, upto) ? parse.tree : null;
|
|
179
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
Queries whether there is a full syntax tree available up to the
|
|
182
|
+
given document position. If there isn't, the background parse
|
|
183
|
+
process _might_ still be working and update the tree further, but
|
|
184
|
+
there is no guarantee of that—the parser will [stop
|
|
185
|
+
working](https://codemirror.net/6/docs/ref/#language.syntaxParserStopped) when it has spent a
|
|
186
|
+
certain amount of time or has moved beyond the visible viewport.
|
|
187
|
+
Always returns false if no language has been enabled.
|
|
188
|
+
*/
|
|
189
|
+
function syntaxTreeAvailable(state, upto = state.doc.length) {
|
|
190
|
+
var _a;
|
|
191
|
+
return ((_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context.isDone(upto)) || false;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
Tells you whether the language parser is planning to do more
|
|
195
|
+
parsing work (in a `requestIdleCallback` pseudo-thread) or has
|
|
196
|
+
stopped running, either because it parsed the entire document,
|
|
197
|
+
because it spent too much time and was cut off, or because there
|
|
198
|
+
is no language parser enabled.
|
|
199
|
+
*/
|
|
200
|
+
function syntaxParserRunning(view) {
|
|
201
|
+
var _a;
|
|
202
|
+
return ((_a = view.plugin(parseWorker)) === null || _a === void 0 ? void 0 : _a.isWorking()) || false;
|
|
203
|
+
}
|
|
180
204
|
// Lezer-style Input object for a Text document.
|
|
181
205
|
class DocInput {
|
|
182
206
|
constructor(doc, length = doc.length) {
|
|
@@ -229,7 +253,7 @@ class ParseContext {
|
|
|
229
253
|
The current editor viewport (or some overapproximation
|
|
230
254
|
thereof). Intended to be used for opportunistically avoiding
|
|
231
255
|
work (in which case
|
|
232
|
-
[`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.
|
|
256
|
+
[`skipUntilInView`](https://codemirror.net/6/docs/ref/#language.ParseContext.skipUntilInView)
|
|
233
257
|
should be called to make sure the parser is restarted when the
|
|
234
258
|
skipped region becomes visible).
|
|
235
259
|
*/
|
|
@@ -267,7 +291,7 @@ class ParseContext {
|
|
|
267
291
|
work(time, upto) {
|
|
268
292
|
if (upto != null && upto >= this.state.doc.length)
|
|
269
293
|
upto = undefined;
|
|
270
|
-
if (this.tree != Tree.empty && (upto
|
|
294
|
+
if (this.tree != Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) {
|
|
271
295
|
this.takeTree();
|
|
272
296
|
return true;
|
|
273
297
|
}
|
|
@@ -353,6 +377,8 @@ class ParseContext {
|
|
|
353
377
|
@internal
|
|
354
378
|
*/
|
|
355
379
|
updateViewport(viewport) {
|
|
380
|
+
if (this.viewport.from == viewport.from && this.viewport.to == viewport.to)
|
|
381
|
+
return false;
|
|
356
382
|
this.viewport = viewport;
|
|
357
383
|
let startLen = this.skipped.length;
|
|
358
384
|
for (let i = 0; i < this.skipped.length; i++) {
|
|
@@ -362,7 +388,10 @@ class ParseContext {
|
|
|
362
388
|
this.skipped.splice(i--, 1);
|
|
363
389
|
}
|
|
364
390
|
}
|
|
365
|
-
|
|
391
|
+
if (this.skipped.length >= startLen)
|
|
392
|
+
return false;
|
|
393
|
+
this.reset();
|
|
394
|
+
return true;
|
|
366
395
|
}
|
|
367
396
|
/**
|
|
368
397
|
@internal
|
|
@@ -421,6 +450,13 @@ class ParseContext {
|
|
|
421
450
|
return this.treeLen < pos && this.parse && this.parse.parsedPos >= pos;
|
|
422
451
|
}
|
|
423
452
|
/**
|
|
453
|
+
@internal
|
|
454
|
+
*/
|
|
455
|
+
isDone(upto) {
|
|
456
|
+
let frags = this.fragments;
|
|
457
|
+
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
424
460
|
Get the context for the current parse, or `null` if no editor
|
|
425
461
|
parse is in progress.
|
|
426
462
|
*/
|
|
@@ -475,6 +511,7 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
475
511
|
constructor(view) {
|
|
476
512
|
this.view = view;
|
|
477
513
|
this.working = -1;
|
|
514
|
+
this.workScheduled = 0;
|
|
478
515
|
// End of the current time chunk
|
|
479
516
|
this.chunkEnd = -1;
|
|
480
517
|
// Milliseconds of budget left for this chunk
|
|
@@ -484,12 +521,8 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
484
521
|
}
|
|
485
522
|
update(update) {
|
|
486
523
|
let cx = this.view.state.field(Language.state).context;
|
|
487
|
-
if (update.
|
|
488
|
-
|
|
489
|
-
cx.reset();
|
|
490
|
-
if (this.view.viewport.to > cx.treeLen)
|
|
491
|
-
this.scheduleWork();
|
|
492
|
-
}
|
|
524
|
+
if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen)
|
|
525
|
+
this.scheduleWork();
|
|
493
526
|
if (update.docChanged) {
|
|
494
527
|
if (this.view.hasFocus)
|
|
495
528
|
this.chunkBudget += 50 /* ChangeBonus */;
|
|
@@ -500,11 +533,9 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
500
533
|
scheduleWork() {
|
|
501
534
|
if (this.working > -1)
|
|
502
535
|
return;
|
|
503
|
-
let { state } = this.view, field = state.field(Language.state)
|
|
504
|
-
if (field.tree
|
|
505
|
-
|
|
506
|
-
return;
|
|
507
|
-
this.working = requestIdle(this.work, { timeout: 500 /* Pause */ });
|
|
536
|
+
let { state } = this.view, field = state.field(Language.state);
|
|
537
|
+
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
|
|
538
|
+
this.working = requestIdle(this.work, { timeout: 500 /* Pause */ });
|
|
508
539
|
}
|
|
509
540
|
work(deadline) {
|
|
510
541
|
this.working = -1;
|
|
@@ -531,7 +562,11 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
531
562
|
}
|
|
532
563
|
checkAsyncSchedule(cx) {
|
|
533
564
|
if (cx.scheduleOn) {
|
|
534
|
-
|
|
565
|
+
this.workScheduled++;
|
|
566
|
+
cx.scheduleOn
|
|
567
|
+
.then(() => this.scheduleWork())
|
|
568
|
+
.catch(err => logException(this.view.state, err))
|
|
569
|
+
.then(() => this.workScheduled--);
|
|
535
570
|
cx.scheduleOn = null;
|
|
536
571
|
}
|
|
537
572
|
}
|
|
@@ -539,6 +574,9 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
539
574
|
if (this.working >= 0)
|
|
540
575
|
cancelIdle(this.working);
|
|
541
576
|
}
|
|
577
|
+
isWorking() {
|
|
578
|
+
return this.working >= 0 || this.workScheduled > 0;
|
|
579
|
+
}
|
|
542
580
|
}, {
|
|
543
581
|
eventHandlers: { focus() { this.scheduleWork(); } }
|
|
544
582
|
});
|
|
@@ -601,16 +639,17 @@ class LanguageDescription {
|
|
|
601
639
|
Optional filename pattern that should be associated with this
|
|
602
640
|
language.
|
|
603
641
|
*/
|
|
604
|
-
filename, loadFunc
|
|
642
|
+
filename, loadFunc,
|
|
643
|
+
/**
|
|
644
|
+
If the language has been loaded, this will hold its value.
|
|
645
|
+
*/
|
|
646
|
+
support = undefined) {
|
|
605
647
|
this.name = name;
|
|
606
648
|
this.alias = alias;
|
|
607
649
|
this.extensions = extensions;
|
|
608
650
|
this.filename = filename;
|
|
609
651
|
this.loadFunc = loadFunc;
|
|
610
|
-
|
|
611
|
-
If the language has been loaded, this will hold its value.
|
|
612
|
-
*/
|
|
613
|
-
this.support = undefined;
|
|
652
|
+
this.support = support;
|
|
614
653
|
this.loading = null;
|
|
615
654
|
}
|
|
616
655
|
/**
|
|
@@ -625,7 +664,13 @@ class LanguageDescription {
|
|
|
625
664
|
Create a language description.
|
|
626
665
|
*/
|
|
627
666
|
static of(spec) {
|
|
628
|
-
|
|
667
|
+
let { load, support } = spec;
|
|
668
|
+
if (!load) {
|
|
669
|
+
if (!support)
|
|
670
|
+
throw new RangeError("Must pass either 'load' or 'support' to LanguageDescription.of");
|
|
671
|
+
load = () => Promise.resolve(support);
|
|
672
|
+
}
|
|
673
|
+
return new LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map(s => s.toLowerCase()), spec.extensions || [], spec.filename, load, support);
|
|
629
674
|
}
|
|
630
675
|
/**
|
|
631
676
|
Look for a language in the given array of descriptions that
|
|
@@ -835,24 +880,7 @@ definitive indentation can be determined.
|
|
|
835
880
|
const indentNodeProp = /*@__PURE__*/new NodeProp();
|
|
836
881
|
// Compute the indentation for a given position from the syntax tree.
|
|
837
882
|
function syntaxIndentation(cx, ast, pos) {
|
|
838
|
-
|
|
839
|
-
// Enter previous nodes that end in empty error terms, which means
|
|
840
|
-
// they were broken off by error recovery, so that indentation
|
|
841
|
-
// works even if the constructs haven't been finished.
|
|
842
|
-
for (let scan = tree, scanPos = pos;;) {
|
|
843
|
-
let last = scan.childBefore(scanPos);
|
|
844
|
-
if (!last)
|
|
845
|
-
break;
|
|
846
|
-
if (last.type.isError && last.from == last.to) {
|
|
847
|
-
tree = scan;
|
|
848
|
-
scanPos = last.from;
|
|
849
|
-
}
|
|
850
|
-
else {
|
|
851
|
-
scan = last;
|
|
852
|
-
scanPos = scan.to + 1;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
return indentFrom(tree, pos, cx);
|
|
883
|
+
return indentFrom(ast.resolveInner(pos).enterUnfinishedNodesBefore(pos), pos, cx);
|
|
856
884
|
}
|
|
857
885
|
function ignoreClosed(cx) {
|
|
858
886
|
return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak;
|
|
@@ -1019,7 +1047,7 @@ added at the start of a line.
|
|
|
1019
1047
|
*/
|
|
1020
1048
|
function indentOnInput() {
|
|
1021
1049
|
return EditorState.transactionFilter.of(tr => {
|
|
1022
|
-
if (!tr.docChanged || tr.isUserEvent("input.type"))
|
|
1050
|
+
if (!tr.docChanged || !tr.isUserEvent("input.type"))
|
|
1023
1051
|
return tr;
|
|
1024
1052
|
let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head);
|
|
1025
1053
|
if (!rules.length)
|
|
@@ -1044,7 +1072,7 @@ function indentOnInput() {
|
|
|
1044
1072
|
if (cur != norm)
|
|
1045
1073
|
changes.push({ from: line.from, to: line.from + cur.length, insert: norm });
|
|
1046
1074
|
}
|
|
1047
|
-
return changes.length ? [tr, { changes }] : tr;
|
|
1075
|
+
return changes.length ? [tr, { changes, sequential: true }] : tr;
|
|
1048
1076
|
});
|
|
1049
1077
|
}
|
|
1050
1078
|
|
|
@@ -1108,4 +1136,4 @@ function foldable(state, lineStart, lineEnd) {
|
|
|
1108
1136
|
return syntaxFolding(state, lineStart, lineEnd);
|
|
1109
1137
|
}
|
|
1110
1138
|
|
|
1111
|
-
export { IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, TreeIndentContext, continuedIndent, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldInside, foldNodeProp, foldService, foldable, getIndentUnit, getIndentation, indentNodeProp, indentOnInput, indentService, indentString, indentUnit, language, languageDataProp, syntaxTree };
|
|
1139
|
+
export { IndentContext, LRLanguage, Language, LanguageDescription, LanguageSupport, ParseContext, TreeIndentContext, continuedIndent, defineLanguageFacet, delimitedIndent, ensureSyntaxTree, flatIndent, foldInside, foldNodeProp, foldService, foldable, getIndentUnit, getIndentation, indentNodeProp, indentOnInput, indentService, indentString, indentUnit, language, languageDataProp, syntaxParserRunning, syntaxTree, syntaxTreeAvailable };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/language",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.5",
|
|
4
4
|
"description": "Language support infrastructure for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@codemirror/state": "^0.19.0",
|
|
30
30
|
"@codemirror/text": "^0.19.0",
|
|
31
31
|
"@codemirror/view": "^0.19.0",
|
|
32
|
-
"@lezer/common": "^0.15.
|
|
32
|
+
"@lezer/common": "^0.15.5",
|
|
33
33
|
"@lezer/lr": "^0.15.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|