@codemirror/language 0.19.5 → 0.19.8
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 +20 -0
- package/dist/index.cjs +37 -29
- package/dist/index.d.ts +1 -1
- package/dist/index.js +37 -29
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 0.19.8 (2022-03-03)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue that could cause indentation logic to use the wrong line content when indenting multiple lines at once.
|
|
6
|
+
|
|
7
|
+
## 0.19.7 (2021-12-02)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Fix an issue where the parse worker could incorrectly stop working when the parse tree has skipped gaps in it.
|
|
12
|
+
|
|
13
|
+
## 0.19.6 (2021-11-26)
|
|
14
|
+
|
|
15
|
+
### Bug fixes
|
|
16
|
+
|
|
17
|
+
Fixes an issue where the background parse work would be scheduled too aggressively, degrading responsiveness on a newly-created editor with a large document.
|
|
18
|
+
|
|
19
|
+
Improve initial highlight for mixed-language editors and limit the amount of parsing done on state creation for faster startup.
|
|
20
|
+
|
|
1
21
|
## 0.19.5 (2021-11-17)
|
|
2
22
|
|
|
3
23
|
### New features
|
package/dist/index.cjs
CHANGED
|
@@ -179,7 +179,7 @@ up to that point if the tree isn't already available.
|
|
|
179
179
|
function ensureSyntaxTree(state, upto, timeout = 50) {
|
|
180
180
|
var _a;
|
|
181
181
|
let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
|
|
182
|
-
return !parse ? null : parse.
|
|
182
|
+
return !parse ? null : parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null;
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
185
|
Queries whether there is a full syntax tree available up to the
|
|
@@ -301,12 +301,12 @@ class ParseContext {
|
|
|
301
301
|
}
|
|
302
302
|
return this.withContext(() => {
|
|
303
303
|
var _a;
|
|
304
|
+
let endTime = Date.now() + time;
|
|
304
305
|
if (!this.parse)
|
|
305
306
|
this.parse = this.startParse();
|
|
306
307
|
if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) &&
|
|
307
308
|
upto < this.state.doc.length)
|
|
308
309
|
this.parse.stopAt(upto);
|
|
309
|
-
let endTime = Date.now() + time;
|
|
310
310
|
for (;;) {
|
|
311
311
|
let done = this.parse.advance();
|
|
312
312
|
if (done) {
|
|
@@ -329,10 +329,11 @@ class ParseContext {
|
|
|
329
329
|
*/
|
|
330
330
|
takeTree() {
|
|
331
331
|
let pos, tree;
|
|
332
|
-
if (this.parse && (pos = this.parse.parsedPos)
|
|
332
|
+
if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) {
|
|
333
333
|
if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos)
|
|
334
334
|
this.parse.stopAt(pos);
|
|
335
335
|
this.withContext(() => { while (!(tree = this.parse.advance())) { } });
|
|
336
|
+
this.treeLen = pos;
|
|
336
337
|
this.tree = tree;
|
|
337
338
|
this.fragments = this.withoutTempSkipped(common.TreeFragment.addTree(this.tree, this.fragments, true));
|
|
338
339
|
this.parse = null;
|
|
@@ -450,13 +451,8 @@ class ParseContext {
|
|
|
450
451
|
/**
|
|
451
452
|
@internal
|
|
452
453
|
*/
|
|
453
|
-
movedPast(pos) {
|
|
454
|
-
return this.treeLen < pos && this.parse && this.parse.parsedPos >= pos;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
@internal
|
|
458
|
-
*/
|
|
459
454
|
isDone(upto) {
|
|
455
|
+
upto = Math.min(upto, this.state.doc.length);
|
|
460
456
|
let frags = this.fragments;
|
|
461
457
|
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
|
|
462
458
|
}
|
|
@@ -486,13 +482,14 @@ class LanguageState {
|
|
|
486
482
|
// state updates with parse work beyond the viewport.
|
|
487
483
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
488
484
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
489
|
-
if (!newCx.work(
|
|
485
|
+
if (!newCx.work(20 /* Apply */, upto))
|
|
490
486
|
newCx.takeTree();
|
|
491
487
|
return new LanguageState(newCx);
|
|
492
488
|
}
|
|
493
489
|
static init(state) {
|
|
494
|
-
let
|
|
495
|
-
|
|
490
|
+
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
491
|
+
let parseState = new ParseContext(state.facet(language).parser, state, [], common.Tree.empty, 0, { from: 0, to: vpTo }, [], null);
|
|
492
|
+
if (!parseState.work(20 /* Apply */, vpTo))
|
|
496
493
|
parseState.takeTree();
|
|
497
494
|
return new LanguageState(parseState);
|
|
498
495
|
}
|
|
@@ -508,13 +505,21 @@ Language.state = state.StateField.define({
|
|
|
508
505
|
return value.apply(tr);
|
|
509
506
|
}
|
|
510
507
|
});
|
|
511
|
-
let requestIdle =
|
|
512
|
-
|
|
513
|
-
|
|
508
|
+
let requestIdle = (callback) => {
|
|
509
|
+
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
510
|
+
return () => clearTimeout(timeout);
|
|
511
|
+
};
|
|
512
|
+
if (typeof requestIdleCallback != "undefined")
|
|
513
|
+
requestIdle = (callback) => {
|
|
514
|
+
let idle = -1, timeout = setTimeout(() => {
|
|
515
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
516
|
+
}, 100 /* MinPause */);
|
|
517
|
+
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
518
|
+
};
|
|
514
519
|
const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
515
520
|
constructor(view) {
|
|
516
521
|
this.view = view;
|
|
517
|
-
this.working =
|
|
522
|
+
this.working = null;
|
|
518
523
|
this.workScheduled = 0;
|
|
519
524
|
// End of the current time chunk
|
|
520
525
|
this.chunkEnd = -1;
|
|
@@ -535,14 +540,14 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
535
540
|
this.checkAsyncSchedule(cx);
|
|
536
541
|
}
|
|
537
542
|
scheduleWork() {
|
|
538
|
-
if (this.working
|
|
543
|
+
if (this.working)
|
|
539
544
|
return;
|
|
540
545
|
let { state } = this.view, field = state.field(Language.state);
|
|
541
546
|
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
|
|
542
|
-
this.working = requestIdle(this.work
|
|
547
|
+
this.working = requestIdle(this.work);
|
|
543
548
|
}
|
|
544
549
|
work(deadline) {
|
|
545
|
-
this.working =
|
|
550
|
+
this.working = null;
|
|
546
551
|
let now = Date.now();
|
|
547
552
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
548
553
|
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
@@ -551,16 +556,17 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
551
556
|
if (this.chunkBudget <= 0)
|
|
552
557
|
return; // No more budget
|
|
553
558
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
554
|
-
if (field.tree == field.context.tree && field.context.
|
|
559
|
+
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
|
|
555
560
|
return;
|
|
556
|
-
let time = Math.min(this.chunkBudget, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining()) :
|
|
557
|
-
let
|
|
561
|
+
let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
562
|
+
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
563
|
+
let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
558
564
|
this.chunkBudget -= Date.now() - now;
|
|
559
|
-
if (done || this.chunkBudget <= 0
|
|
565
|
+
if (done || this.chunkBudget <= 0) {
|
|
560
566
|
field.context.takeTree();
|
|
561
567
|
this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) });
|
|
562
568
|
}
|
|
563
|
-
if (
|
|
569
|
+
if (this.chunkBudget > 0 && !(done && !viewportFirst))
|
|
564
570
|
this.scheduleWork();
|
|
565
571
|
this.checkAsyncSchedule(field.context);
|
|
566
572
|
}
|
|
@@ -575,11 +581,11 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
575
581
|
}
|
|
576
582
|
}
|
|
577
583
|
destroy() {
|
|
578
|
-
if (this.working
|
|
579
|
-
|
|
584
|
+
if (this.working)
|
|
585
|
+
this.working();
|
|
580
586
|
}
|
|
581
587
|
isWorking() {
|
|
582
|
-
return this.working
|
|
588
|
+
return this.working || this.workScheduled > 0;
|
|
583
589
|
}
|
|
584
590
|
}, {
|
|
585
591
|
eventHandlers: { focus() { this.scheduleWork(); } }
|
|
@@ -816,9 +822,11 @@ class IndentContext {
|
|
|
816
822
|
*/
|
|
817
823
|
lineAt(pos, bias = 1) {
|
|
818
824
|
let line = this.state.doc.lineAt(pos);
|
|
819
|
-
let { simulateBreak } = this.options;
|
|
825
|
+
let { simulateBreak, simulateDoubleBreak } = this.options;
|
|
820
826
|
if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
|
|
821
|
-
if (
|
|
827
|
+
if (simulateDoubleBreak && simulateBreak == pos)
|
|
828
|
+
return { text: "", from: pos };
|
|
829
|
+
else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
|
|
822
830
|
return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak };
|
|
823
831
|
else
|
|
824
832
|
return { text: line.text.slice(0, simulateBreak - line.from), from: line.from };
|
package/dist/index.d.ts
CHANGED
|
@@ -156,7 +156,7 @@ stopped running, either because it parsed the entire document,
|
|
|
156
156
|
because it spent too much time and was cut off, or because there
|
|
157
157
|
is no language parser enabled.
|
|
158
158
|
*/
|
|
159
|
-
declare function syntaxParserRunning(view: EditorView): boolean;
|
|
159
|
+
declare function syntaxParserRunning(view: EditorView): boolean | (() => void);
|
|
160
160
|
/**
|
|
161
161
|
A parse context provided to parsers working on the editor content.
|
|
162
162
|
*/
|
package/dist/index.js
CHANGED
|
@@ -175,7 +175,7 @@ up to that point if the tree isn't already available.
|
|
|
175
175
|
function ensureSyntaxTree(state, upto, timeout = 50) {
|
|
176
176
|
var _a;
|
|
177
177
|
let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
|
|
178
|
-
return !parse ? null : parse.
|
|
178
|
+
return !parse ? null : parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null;
|
|
179
179
|
}
|
|
180
180
|
/**
|
|
181
181
|
Queries whether there is a full syntax tree available up to the
|
|
@@ -297,12 +297,12 @@ class ParseContext {
|
|
|
297
297
|
}
|
|
298
298
|
return this.withContext(() => {
|
|
299
299
|
var _a;
|
|
300
|
+
let endTime = Date.now() + time;
|
|
300
301
|
if (!this.parse)
|
|
301
302
|
this.parse = this.startParse();
|
|
302
303
|
if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) &&
|
|
303
304
|
upto < this.state.doc.length)
|
|
304
305
|
this.parse.stopAt(upto);
|
|
305
|
-
let endTime = Date.now() + time;
|
|
306
306
|
for (;;) {
|
|
307
307
|
let done = this.parse.advance();
|
|
308
308
|
if (done) {
|
|
@@ -325,10 +325,11 @@ class ParseContext {
|
|
|
325
325
|
*/
|
|
326
326
|
takeTree() {
|
|
327
327
|
let pos, tree;
|
|
328
|
-
if (this.parse && (pos = this.parse.parsedPos)
|
|
328
|
+
if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) {
|
|
329
329
|
if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos)
|
|
330
330
|
this.parse.stopAt(pos);
|
|
331
331
|
this.withContext(() => { while (!(tree = this.parse.advance())) { } });
|
|
332
|
+
this.treeLen = pos;
|
|
332
333
|
this.tree = tree;
|
|
333
334
|
this.fragments = this.withoutTempSkipped(TreeFragment.addTree(this.tree, this.fragments, true));
|
|
334
335
|
this.parse = null;
|
|
@@ -446,13 +447,8 @@ class ParseContext {
|
|
|
446
447
|
/**
|
|
447
448
|
@internal
|
|
448
449
|
*/
|
|
449
|
-
movedPast(pos) {
|
|
450
|
-
return this.treeLen < pos && this.parse && this.parse.parsedPos >= pos;
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
@internal
|
|
454
|
-
*/
|
|
455
450
|
isDone(upto) {
|
|
451
|
+
upto = Math.min(upto, this.state.doc.length);
|
|
456
452
|
let frags = this.fragments;
|
|
457
453
|
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
|
|
458
454
|
}
|
|
@@ -482,13 +478,14 @@ class LanguageState {
|
|
|
482
478
|
// state updates with parse work beyond the viewport.
|
|
483
479
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
484
480
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
485
|
-
if (!newCx.work(
|
|
481
|
+
if (!newCx.work(20 /* Apply */, upto))
|
|
486
482
|
newCx.takeTree();
|
|
487
483
|
return new LanguageState(newCx);
|
|
488
484
|
}
|
|
489
485
|
static init(state) {
|
|
490
|
-
let
|
|
491
|
-
|
|
486
|
+
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
487
|
+
let parseState = new ParseContext(state.facet(language).parser, state, [], Tree.empty, 0, { from: 0, to: vpTo }, [], null);
|
|
488
|
+
if (!parseState.work(20 /* Apply */, vpTo))
|
|
492
489
|
parseState.takeTree();
|
|
493
490
|
return new LanguageState(parseState);
|
|
494
491
|
}
|
|
@@ -504,13 +501,21 @@ Language.state = /*@__PURE__*/StateField.define({
|
|
|
504
501
|
return value.apply(tr);
|
|
505
502
|
}
|
|
506
503
|
});
|
|
507
|
-
let requestIdle =
|
|
508
|
-
|
|
509
|
-
|
|
504
|
+
let requestIdle = (callback) => {
|
|
505
|
+
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
506
|
+
return () => clearTimeout(timeout);
|
|
507
|
+
};
|
|
508
|
+
if (typeof requestIdleCallback != "undefined")
|
|
509
|
+
requestIdle = (callback) => {
|
|
510
|
+
let idle = -1, timeout = setTimeout(() => {
|
|
511
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
512
|
+
}, 100 /* MinPause */);
|
|
513
|
+
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
514
|
+
};
|
|
510
515
|
const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
511
516
|
constructor(view) {
|
|
512
517
|
this.view = view;
|
|
513
|
-
this.working =
|
|
518
|
+
this.working = null;
|
|
514
519
|
this.workScheduled = 0;
|
|
515
520
|
// End of the current time chunk
|
|
516
521
|
this.chunkEnd = -1;
|
|
@@ -531,14 +536,14 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
531
536
|
this.checkAsyncSchedule(cx);
|
|
532
537
|
}
|
|
533
538
|
scheduleWork() {
|
|
534
|
-
if (this.working
|
|
539
|
+
if (this.working)
|
|
535
540
|
return;
|
|
536
541
|
let { state } = this.view, field = state.field(Language.state);
|
|
537
542
|
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
|
|
538
|
-
this.working = requestIdle(this.work
|
|
543
|
+
this.working = requestIdle(this.work);
|
|
539
544
|
}
|
|
540
545
|
work(deadline) {
|
|
541
|
-
this.working =
|
|
546
|
+
this.working = null;
|
|
542
547
|
let now = Date.now();
|
|
543
548
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
544
549
|
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
@@ -547,16 +552,17 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
547
552
|
if (this.chunkBudget <= 0)
|
|
548
553
|
return; // No more budget
|
|
549
554
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
550
|
-
if (field.tree == field.context.tree && field.context.
|
|
555
|
+
if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
|
|
551
556
|
return;
|
|
552
|
-
let time = Math.min(this.chunkBudget, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining()) :
|
|
553
|
-
let
|
|
557
|
+
let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
558
|
+
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
559
|
+
let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
554
560
|
this.chunkBudget -= Date.now() - now;
|
|
555
|
-
if (done || this.chunkBudget <= 0
|
|
561
|
+
if (done || this.chunkBudget <= 0) {
|
|
556
562
|
field.context.takeTree();
|
|
557
563
|
this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) });
|
|
558
564
|
}
|
|
559
|
-
if (
|
|
565
|
+
if (this.chunkBudget > 0 && !(done && !viewportFirst))
|
|
560
566
|
this.scheduleWork();
|
|
561
567
|
this.checkAsyncSchedule(field.context);
|
|
562
568
|
}
|
|
@@ -571,11 +577,11 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
571
577
|
}
|
|
572
578
|
}
|
|
573
579
|
destroy() {
|
|
574
|
-
if (this.working
|
|
575
|
-
|
|
580
|
+
if (this.working)
|
|
581
|
+
this.working();
|
|
576
582
|
}
|
|
577
583
|
isWorking() {
|
|
578
|
-
return this.working
|
|
584
|
+
return this.working || this.workScheduled > 0;
|
|
579
585
|
}
|
|
580
586
|
}, {
|
|
581
587
|
eventHandlers: { focus() { this.scheduleWork(); } }
|
|
@@ -812,9 +818,11 @@ class IndentContext {
|
|
|
812
818
|
*/
|
|
813
819
|
lineAt(pos, bias = 1) {
|
|
814
820
|
let line = this.state.doc.lineAt(pos);
|
|
815
|
-
let { simulateBreak } = this.options;
|
|
821
|
+
let { simulateBreak, simulateDoubleBreak } = this.options;
|
|
816
822
|
if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
|
|
817
|
-
if (
|
|
823
|
+
if (simulateDoubleBreak && simulateBreak == pos)
|
|
824
|
+
return { text: "", from: pos };
|
|
825
|
+
else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
|
|
818
826
|
return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak };
|
|
819
827
|
else
|
|
820
828
|
return { text: line.text.slice(0, simulateBreak - line.from), from: line.from };
|