@codemirror/language 0.19.5 → 0.19.6
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 +8 -0
- package/dist/index.cjs +31 -26
- package/dist/index.d.ts +1 -1
- package/dist/index.js +31 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.19.6 (2021-11-26)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fixes an issue where the background parse work would be scheduled too aggressively, degrading responsiveness on a newly-created editor with a large document.
|
|
6
|
+
|
|
7
|
+
Improve initial highlight for mixed-language editors and limit the amount of parsing done on state creation for faster startup.
|
|
8
|
+
|
|
1
9
|
## 0.19.5 (2021-11-17)
|
|
2
10
|
|
|
3
11
|
### New features
|
package/dist/index.cjs
CHANGED
|
@@ -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,12 +451,6 @@ 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) {
|
|
460
455
|
let frags = this.fragments;
|
|
461
456
|
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
|
|
@@ -486,13 +481,14 @@ class LanguageState {
|
|
|
486
481
|
// state updates with parse work beyond the viewport.
|
|
487
482
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
488
483
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
489
|
-
if (!newCx.work(
|
|
484
|
+
if (!newCx.work(20 /* Apply */, upto))
|
|
490
485
|
newCx.takeTree();
|
|
491
486
|
return new LanguageState(newCx);
|
|
492
487
|
}
|
|
493
488
|
static init(state) {
|
|
494
|
-
let
|
|
495
|
-
|
|
489
|
+
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
490
|
+
let parseState = new ParseContext(state.facet(language).parser, state, [], common.Tree.empty, 0, { from: 0, to: vpTo }, [], null);
|
|
491
|
+
if (!parseState.work(20 /* Apply */, vpTo))
|
|
496
492
|
parseState.takeTree();
|
|
497
493
|
return new LanguageState(parseState);
|
|
498
494
|
}
|
|
@@ -508,13 +504,21 @@ Language.state = state.StateField.define({
|
|
|
508
504
|
return value.apply(tr);
|
|
509
505
|
}
|
|
510
506
|
});
|
|
511
|
-
let requestIdle =
|
|
512
|
-
|
|
513
|
-
|
|
507
|
+
let requestIdle = (callback) => {
|
|
508
|
+
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
509
|
+
return () => clearTimeout(timeout);
|
|
510
|
+
};
|
|
511
|
+
if (typeof requestIdleCallback != "undefined")
|
|
512
|
+
requestIdle = (callback) => {
|
|
513
|
+
let idle = -1, timeout = setTimeout(() => {
|
|
514
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
515
|
+
}, 100 /* MinPause */);
|
|
516
|
+
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
517
|
+
};
|
|
514
518
|
const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
515
519
|
constructor(view) {
|
|
516
520
|
this.view = view;
|
|
517
|
-
this.working =
|
|
521
|
+
this.working = null;
|
|
518
522
|
this.workScheduled = 0;
|
|
519
523
|
// End of the current time chunk
|
|
520
524
|
this.chunkEnd = -1;
|
|
@@ -535,14 +539,14 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
535
539
|
this.checkAsyncSchedule(cx);
|
|
536
540
|
}
|
|
537
541
|
scheduleWork() {
|
|
538
|
-
if (this.working
|
|
542
|
+
if (this.working)
|
|
539
543
|
return;
|
|
540
544
|
let { state } = this.view, field = state.field(Language.state);
|
|
541
545
|
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
|
|
542
|
-
this.working = requestIdle(this.work
|
|
546
|
+
this.working = requestIdle(this.work);
|
|
543
547
|
}
|
|
544
548
|
work(deadline) {
|
|
545
|
-
this.working =
|
|
549
|
+
this.working = null;
|
|
546
550
|
let now = Date.now();
|
|
547
551
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
548
552
|
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
@@ -551,16 +555,17 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
551
555
|
if (this.chunkBudget <= 0)
|
|
552
556
|
return; // No more budget
|
|
553
557
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
554
|
-
if (field.tree == field.context.tree && field.context.treeLen >= vpTo +
|
|
558
|
+
if (field.tree == field.context.tree && field.context.treeLen >= vpTo + 100000 /* MaxParseAhead */)
|
|
555
559
|
return;
|
|
556
|
-
let time = Math.min(this.chunkBudget, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining()) :
|
|
557
|
-
let
|
|
560
|
+
let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
561
|
+
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
562
|
+
let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
558
563
|
this.chunkBudget -= Date.now() - now;
|
|
559
|
-
if (done || this.chunkBudget <= 0
|
|
564
|
+
if (done || this.chunkBudget <= 0) {
|
|
560
565
|
field.context.takeTree();
|
|
561
566
|
this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) });
|
|
562
567
|
}
|
|
563
|
-
if (
|
|
568
|
+
if (this.chunkBudget > 0 && !(done && !viewportFirst))
|
|
564
569
|
this.scheduleWork();
|
|
565
570
|
this.checkAsyncSchedule(field.context);
|
|
566
571
|
}
|
|
@@ -575,11 +580,11 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
|
|
|
575
580
|
}
|
|
576
581
|
}
|
|
577
582
|
destroy() {
|
|
578
|
-
if (this.working
|
|
579
|
-
|
|
583
|
+
if (this.working)
|
|
584
|
+
this.working();
|
|
580
585
|
}
|
|
581
586
|
isWorking() {
|
|
582
|
-
return this.working
|
|
587
|
+
return this.working || this.workScheduled > 0;
|
|
583
588
|
}
|
|
584
589
|
}, {
|
|
585
590
|
eventHandlers: { focus() { this.scheduleWork(); } }
|
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
|
@@ -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,12 +447,6 @@ 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) {
|
|
456
451
|
let frags = this.fragments;
|
|
457
452
|
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
|
|
@@ -482,13 +477,14 @@ class LanguageState {
|
|
|
482
477
|
// state updates with parse work beyond the viewport.
|
|
483
478
|
let upto = this.context.treeLen == tr.startState.doc.length ? undefined
|
|
484
479
|
: Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to);
|
|
485
|
-
if (!newCx.work(
|
|
480
|
+
if (!newCx.work(20 /* Apply */, upto))
|
|
486
481
|
newCx.takeTree();
|
|
487
482
|
return new LanguageState(newCx);
|
|
488
483
|
}
|
|
489
484
|
static init(state) {
|
|
490
|
-
let
|
|
491
|
-
|
|
485
|
+
let vpTo = Math.min(3000 /* InitViewport */, state.doc.length);
|
|
486
|
+
let parseState = new ParseContext(state.facet(language).parser, state, [], Tree.empty, 0, { from: 0, to: vpTo }, [], null);
|
|
487
|
+
if (!parseState.work(20 /* Apply */, vpTo))
|
|
492
488
|
parseState.takeTree();
|
|
493
489
|
return new LanguageState(parseState);
|
|
494
490
|
}
|
|
@@ -504,13 +500,21 @@ Language.state = /*@__PURE__*/StateField.define({
|
|
|
504
500
|
return value.apply(tr);
|
|
505
501
|
}
|
|
506
502
|
});
|
|
507
|
-
let requestIdle =
|
|
508
|
-
|
|
509
|
-
|
|
503
|
+
let requestIdle = (callback) => {
|
|
504
|
+
let timeout = setTimeout(() => callback(), 500 /* MaxPause */);
|
|
505
|
+
return () => clearTimeout(timeout);
|
|
506
|
+
};
|
|
507
|
+
if (typeof requestIdleCallback != "undefined")
|
|
508
|
+
requestIdle = (callback) => {
|
|
509
|
+
let idle = -1, timeout = setTimeout(() => {
|
|
510
|
+
idle = requestIdleCallback(callback, { timeout: 500 /* MaxPause */ - 100 /* MinPause */ });
|
|
511
|
+
}, 100 /* MinPause */);
|
|
512
|
+
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
|
|
513
|
+
};
|
|
510
514
|
const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
511
515
|
constructor(view) {
|
|
512
516
|
this.view = view;
|
|
513
|
-
this.working =
|
|
517
|
+
this.working = null;
|
|
514
518
|
this.workScheduled = 0;
|
|
515
519
|
// End of the current time chunk
|
|
516
520
|
this.chunkEnd = -1;
|
|
@@ -531,14 +535,14 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
531
535
|
this.checkAsyncSchedule(cx);
|
|
532
536
|
}
|
|
533
537
|
scheduleWork() {
|
|
534
|
-
if (this.working
|
|
538
|
+
if (this.working)
|
|
535
539
|
return;
|
|
536
540
|
let { state } = this.view, field = state.field(Language.state);
|
|
537
541
|
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length))
|
|
538
|
-
this.working = requestIdle(this.work
|
|
542
|
+
this.working = requestIdle(this.work);
|
|
539
543
|
}
|
|
540
544
|
work(deadline) {
|
|
541
|
-
this.working =
|
|
545
|
+
this.working = null;
|
|
542
546
|
let now = Date.now();
|
|
543
547
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { // Start a new chunk
|
|
544
548
|
this.chunkEnd = now + 30000 /* ChunkTime */;
|
|
@@ -547,16 +551,17 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
547
551
|
if (this.chunkBudget <= 0)
|
|
548
552
|
return; // No more budget
|
|
549
553
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
|
|
550
|
-
if (field.tree == field.context.tree && field.context.treeLen >= vpTo +
|
|
554
|
+
if (field.tree == field.context.tree && field.context.treeLen >= vpTo + 100000 /* MaxParseAhead */)
|
|
551
555
|
return;
|
|
552
|
-
let time = Math.min(this.chunkBudget, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining()) :
|
|
553
|
-
let
|
|
556
|
+
let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
|
|
557
|
+
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
|
|
558
|
+
let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
|
|
554
559
|
this.chunkBudget -= Date.now() - now;
|
|
555
|
-
if (done || this.chunkBudget <= 0
|
|
560
|
+
if (done || this.chunkBudget <= 0) {
|
|
556
561
|
field.context.takeTree();
|
|
557
562
|
this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) });
|
|
558
563
|
}
|
|
559
|
-
if (
|
|
564
|
+
if (this.chunkBudget > 0 && !(done && !viewportFirst))
|
|
560
565
|
this.scheduleWork();
|
|
561
566
|
this.checkAsyncSchedule(field.context);
|
|
562
567
|
}
|
|
@@ -571,11 +576,11 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
|
|
|
571
576
|
}
|
|
572
577
|
}
|
|
573
578
|
destroy() {
|
|
574
|
-
if (this.working
|
|
575
|
-
|
|
579
|
+
if (this.working)
|
|
580
|
+
this.working();
|
|
576
581
|
}
|
|
577
582
|
isWorking() {
|
|
578
|
-
return this.working
|
|
583
|
+
return this.working || this.workScheduled > 0;
|
|
579
584
|
}
|
|
580
585
|
}, {
|
|
581
586
|
eventHandlers: { focus() { this.scheduleWork(); } }
|