@codemirror/language 0.19.6 → 0.19.9

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 CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.19.9 (2022-03-30)
2
+
3
+ ### Bug fixes
4
+
5
+ Make sure nodes that end at the end of a partial parse aren't treated as valid fold targets.
6
+
7
+ Fix an issue where the parser sometimes wouldn't reuse parsing work done in the background on transactions.
8
+
9
+ ## 0.19.8 (2022-03-03)
10
+
11
+ ### Bug fixes
12
+
13
+ Fix an issue that could cause indentation logic to use the wrong line content when indenting multiple lines at once.
14
+
15
+ ## 0.19.7 (2021-12-02)
16
+
17
+ ### Bug fixes
18
+
19
+ Fix an issue where the parse worker could incorrectly stop working when the parse tree has skipped gaps in it.
20
+
1
21
  ## 0.19.6 (2021-11-26)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -7,6 +7,7 @@ var state = require('@codemirror/state');
7
7
  var view = require('@codemirror/view');
8
8
  var text = require('@codemirror/text');
9
9
 
10
+ var _a;
10
11
  /**
11
12
  Node prop stored in a grammar's top syntax node to provide the
12
13
  facet that stores language data for that language.
@@ -179,7 +180,7 @@ up to that point if the tree isn't already available.
179
180
  function ensureSyntaxTree(state, upto, timeout = 50) {
180
181
  var _a;
181
182
  let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
182
- return !parse ? null : parse.treeLen >= upto || parse.work(timeout, upto) ? parse.tree : null;
183
+ return !parse ? null : parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null;
183
184
  }
184
185
  /**
185
186
  Queries whether there is a full syntax tree available up to the
@@ -292,7 +293,7 @@ class ParseContext {
292
293
  /**
293
294
  @internal
294
295
  */
295
- work(time, upto) {
296
+ work(until, upto) {
296
297
  if (upto != null && upto >= this.state.doc.length)
297
298
  upto = undefined;
298
299
  if (this.tree != common.Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) {
@@ -301,7 +302,10 @@ class ParseContext {
301
302
  }
302
303
  return this.withContext(() => {
303
304
  var _a;
304
- let endTime = Date.now() + time;
305
+ if (typeof until == "number") {
306
+ let endTime = Date.now() + until;
307
+ until = () => Date.now() > endTime;
308
+ }
305
309
  if (!this.parse)
306
310
  this.parse = this.startParse();
307
311
  if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) &&
@@ -319,7 +323,7 @@ class ParseContext {
319
323
  else
320
324
  return true;
321
325
  }
322
- if (Date.now() > endTime)
326
+ if (until())
323
327
  return false;
324
328
  }
325
329
  });
@@ -452,6 +456,7 @@ class ParseContext {
452
456
  @internal
453
457
  */
454
458
  isDone(upto) {
459
+ upto = Math.min(upto, this.state.doc.length);
455
460
  let frags = this.fragments;
456
461
  return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
457
462
  }
@@ -473,7 +478,7 @@ class LanguageState {
473
478
  this.tree = context.tree;
474
479
  }
475
480
  apply(tr) {
476
- if (!tr.docChanged)
481
+ if (!tr.docChanged && this.tree == this.context.tree)
477
482
  return this;
478
483
  let newCx = this.context.changes(tr.changes, tr.state);
479
484
  // If the previous parse wasn't done, go forward only up to its
@@ -515,6 +520,8 @@ if (typeof requestIdleCallback != "undefined")
515
520
  }, 100 /* MinPause */);
516
521
  return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
517
522
  };
523
+ const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
524
+ ? () => navigator.scheduling.isInputPending() : null;
518
525
  const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
519
526
  constructor(view) {
520
527
  this.view = view;
@@ -555,11 +562,13 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
555
562
  if (this.chunkBudget <= 0)
556
563
  return; // No more budget
557
564
  let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
558
- if (field.tree == field.context.tree && field.context.treeLen >= vpTo + 100000 /* MaxParseAhead */)
565
+ if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
559
566
  return;
560
- let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
567
+ let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
561
568
  let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
562
- let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
569
+ let done = field.context.work(() => {
570
+ return isInputPending && isInputPending() || Date.now() > endTime;
571
+ }, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
563
572
  this.chunkBudget -= Date.now() - now;
564
573
  if (done || this.chunkBudget <= 0) {
565
574
  field.context.takeTree();
@@ -584,7 +593,7 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
584
593
  this.working();
585
594
  }
586
595
  isWorking() {
587
- return this.working || this.workScheduled > 0;
596
+ return !!(this.working || this.workScheduled > 0);
588
597
  }
589
598
  }, {
590
599
  eventHandlers: { focus() { this.scheduleWork(); } }
@@ -821,9 +830,11 @@ class IndentContext {
821
830
  */
822
831
  lineAt(pos, bias = 1) {
823
832
  let line = this.state.doc.lineAt(pos);
824
- let { simulateBreak } = this.options;
833
+ let { simulateBreak, simulateDoubleBreak } = this.options;
825
834
  if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
826
- if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
835
+ if (simulateDoubleBreak && simulateBreak == pos)
836
+ return { text: "", from: pos };
837
+ else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
827
838
  return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak };
828
839
  else
829
840
  return { text: line.text.slice(0, simulateBreak - line.from), from: line.from };
@@ -1120,7 +1131,7 @@ function syntaxFolding(state, start, end) {
1120
1131
  if (found && cur.from < start)
1121
1132
  break;
1122
1133
  let prop = cur.type.prop(foldNodeProp);
1123
- if (prop) {
1134
+ if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) {
1124
1135
  let value = prop(cur, state);
1125
1136
  if (value && value.from <= end && value.from >= start && value.to > end)
1126
1137
  found = value;
@@ -1128,6 +1139,10 @@ function syntaxFolding(state, start, end) {
1128
1139
  }
1129
1140
  return found;
1130
1141
  }
1142
+ function isUnfinished(node) {
1143
+ let ch = node.lastChild;
1144
+ return ch && ch.to == node.to && ch.type.isError;
1145
+ }
1131
1146
  /**
1132
1147
  Check whether the given line is foldable. First asks any fold
1133
1148
  services registered through
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 | (() => void);
159
+ declare function syntaxParserRunning(view: EditorView): boolean;
160
160
  /**
161
161
  A parse context provided to parsers working on the editor content.
162
162
  */
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { StateEffect, StateField, Facet, EditorState } from '@codemirror/state';
3
3
  import { ViewPlugin, logException } from '@codemirror/view';
4
4
  import { countColumn } from '@codemirror/text';
5
5
 
6
+ var _a;
6
7
  /**
7
8
  Node prop stored in a grammar's top syntax node to provide the
8
9
  facet that stores language data for that language.
@@ -175,7 +176,7 @@ up to that point if the tree isn't already available.
175
176
  function ensureSyntaxTree(state, upto, timeout = 50) {
176
177
  var _a;
177
178
  let parse = (_a = state.field(Language.state, false)) === null || _a === void 0 ? void 0 : _a.context;
178
- return !parse ? null : parse.treeLen >= upto || parse.work(timeout, upto) ? parse.tree : null;
179
+ return !parse ? null : parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null;
179
180
  }
180
181
  /**
181
182
  Queries whether there is a full syntax tree available up to the
@@ -288,7 +289,7 @@ class ParseContext {
288
289
  /**
289
290
  @internal
290
291
  */
291
- work(time, upto) {
292
+ work(until, upto) {
292
293
  if (upto != null && upto >= this.state.doc.length)
293
294
  upto = undefined;
294
295
  if (this.tree != Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) {
@@ -297,7 +298,10 @@ class ParseContext {
297
298
  }
298
299
  return this.withContext(() => {
299
300
  var _a;
300
- let endTime = Date.now() + time;
301
+ if (typeof until == "number") {
302
+ let endTime = Date.now() + until;
303
+ until = () => Date.now() > endTime;
304
+ }
301
305
  if (!this.parse)
302
306
  this.parse = this.startParse();
303
307
  if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) &&
@@ -315,7 +319,7 @@ class ParseContext {
315
319
  else
316
320
  return true;
317
321
  }
318
- if (Date.now() > endTime)
322
+ if (until())
319
323
  return false;
320
324
  }
321
325
  });
@@ -448,6 +452,7 @@ class ParseContext {
448
452
  @internal
449
453
  */
450
454
  isDone(upto) {
455
+ upto = Math.min(upto, this.state.doc.length);
451
456
  let frags = this.fragments;
452
457
  return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto;
453
458
  }
@@ -469,7 +474,7 @@ class LanguageState {
469
474
  this.tree = context.tree;
470
475
  }
471
476
  apply(tr) {
472
- if (!tr.docChanged)
477
+ if (!tr.docChanged && this.tree == this.context.tree)
473
478
  return this;
474
479
  let newCx = this.context.changes(tr.changes, tr.state);
475
480
  // If the previous parse wasn't done, go forward only up to its
@@ -511,6 +516,8 @@ if (typeof requestIdleCallback != "undefined")
511
516
  }, 100 /* MinPause */);
512
517
  return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
513
518
  };
519
+ const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
520
+ ? () => navigator.scheduling.isInputPending() : null;
514
521
  const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
515
522
  constructor(view) {
516
523
  this.view = view;
@@ -551,11 +558,13 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
551
558
  if (this.chunkBudget <= 0)
552
559
  return; // No more budget
553
560
  let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
554
- if (field.tree == field.context.tree && field.context.treeLen >= vpTo + 100000 /* MaxParseAhead */)
561
+ if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
555
562
  return;
556
- let time = Math.min(this.chunkBudget, 100 /* Slice */, deadline ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
563
+ let endTime = Date.now() + Math.min(this.chunkBudget, 100 /* Slice */, deadline && !isInputPending ? Math.max(25 /* MinSlice */, deadline.timeRemaining() - 5) : 1e9);
557
564
  let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
558
- let done = field.context.work(time, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
565
+ let done = field.context.work(() => {
566
+ return isInputPending && isInputPending() || Date.now() > endTime;
567
+ }, vpTo + (viewportFirst ? 0 : 100000 /* MaxParseAhead */));
559
568
  this.chunkBudget -= Date.now() - now;
560
569
  if (done || this.chunkBudget <= 0) {
561
570
  field.context.takeTree();
@@ -580,7 +589,7 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
580
589
  this.working();
581
590
  }
582
591
  isWorking() {
583
- return this.working || this.workScheduled > 0;
592
+ return !!(this.working || this.workScheduled > 0);
584
593
  }
585
594
  }, {
586
595
  eventHandlers: { focus() { this.scheduleWork(); } }
@@ -817,9 +826,11 @@ class IndentContext {
817
826
  */
818
827
  lineAt(pos, bias = 1) {
819
828
  let line = this.state.doc.lineAt(pos);
820
- let { simulateBreak } = this.options;
829
+ let { simulateBreak, simulateDoubleBreak } = this.options;
821
830
  if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
822
- if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
831
+ if (simulateDoubleBreak && simulateBreak == pos)
832
+ return { text: "", from: pos };
833
+ else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos)
823
834
  return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak };
824
835
  else
825
836
  return { text: line.text.slice(0, simulateBreak - line.from), from: line.from };
@@ -1116,7 +1127,7 @@ function syntaxFolding(state, start, end) {
1116
1127
  if (found && cur.from < start)
1117
1128
  break;
1118
1129
  let prop = cur.type.prop(foldNodeProp);
1119
- if (prop) {
1130
+ if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) {
1120
1131
  let value = prop(cur, state);
1121
1132
  if (value && value.from <= end && value.from >= start && value.to > end)
1122
1133
  found = value;
@@ -1124,6 +1135,10 @@ function syntaxFolding(state, start, end) {
1124
1135
  }
1125
1136
  return found;
1126
1137
  }
1138
+ function isUnfinished(node) {
1139
+ let ch = node.lastChild;
1140
+ return ch && ch.to == node.to && ch.type.isError;
1141
+ }
1127
1142
  /**
1128
1143
  Check whether the given line is foldable. First asks any fold
1129
1144
  services registered through
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/language",
3
- "version": "0.19.6",
3
+ "version": "0.19.9",
4
4
  "description": "Language support infrastructure for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",