@codemirror/language 0.19.8 → 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,11 @@
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
+
1
9
  ## 0.19.8 (2022-03-03)
2
10
 
3
11
  ### 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.
@@ -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
  });
@@ -474,7 +478,7 @@ class LanguageState {
474
478
  this.tree = context.tree;
475
479
  }
476
480
  apply(tr) {
477
- if (!tr.docChanged)
481
+ if (!tr.docChanged && this.tree == this.context.tree)
478
482
  return this;
479
483
  let newCx = this.context.changes(tr.changes, tr.state);
480
484
  // If the previous parse wasn't done, go forward only up to its
@@ -516,6 +520,8 @@ if (typeof requestIdleCallback != "undefined")
516
520
  }, 100 /* MinPause */);
517
521
  return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
518
522
  };
523
+ const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
524
+ ? () => navigator.scheduling.isInputPending() : null;
519
525
  const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
520
526
  constructor(view) {
521
527
  this.view = view;
@@ -558,9 +564,11 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
558
564
  let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
559
565
  if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
560
566
  return;
561
- 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);
562
568
  let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
563
- 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 */));
564
572
  this.chunkBudget -= Date.now() - now;
565
573
  if (done || this.chunkBudget <= 0) {
566
574
  field.context.takeTree();
@@ -585,7 +593,7 @@ const parseWorker = view.ViewPlugin.fromClass(class ParseWorker {
585
593
  this.working();
586
594
  }
587
595
  isWorking() {
588
- return this.working || this.workScheduled > 0;
596
+ return !!(this.working || this.workScheduled > 0);
589
597
  }
590
598
  }, {
591
599
  eventHandlers: { focus() { this.scheduleWork(); } }
@@ -1123,7 +1131,7 @@ function syntaxFolding(state, start, end) {
1123
1131
  if (found && cur.from < start)
1124
1132
  break;
1125
1133
  let prop = cur.type.prop(foldNodeProp);
1126
- if (prop) {
1134
+ if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) {
1127
1135
  let value = prop(cur, state);
1128
1136
  if (value && value.from <= end && value.from >= start && value.to > end)
1129
1137
  found = value;
@@ -1131,6 +1139,10 @@ function syntaxFolding(state, start, end) {
1131
1139
  }
1132
1140
  return found;
1133
1141
  }
1142
+ function isUnfinished(node) {
1143
+ let ch = node.lastChild;
1144
+ return ch && ch.to == node.to && ch.type.isError;
1145
+ }
1134
1146
  /**
1135
1147
  Check whether the given line is foldable. First asks any fold
1136
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.
@@ -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
  });
@@ -470,7 +474,7 @@ class LanguageState {
470
474
  this.tree = context.tree;
471
475
  }
472
476
  apply(tr) {
473
- if (!tr.docChanged)
477
+ if (!tr.docChanged && this.tree == this.context.tree)
474
478
  return this;
475
479
  let newCx = this.context.changes(tr.changes, tr.state);
476
480
  // If the previous parse wasn't done, go forward only up to its
@@ -512,6 +516,8 @@ if (typeof requestIdleCallback != "undefined")
512
516
  }, 100 /* MinPause */);
513
517
  return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle);
514
518
  };
519
+ const isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending)
520
+ ? () => navigator.scheduling.isInputPending() : null;
515
521
  const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
516
522
  constructor(view) {
517
523
  this.view = view;
@@ -554,9 +560,11 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
554
560
  let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state);
555
561
  if (field.tree == field.context.tree && field.context.isDone(vpTo + 100000 /* MaxParseAhead */))
556
562
  return;
557
- 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);
558
564
  let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1000;
559
- 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 */));
560
568
  this.chunkBudget -= Date.now() - now;
561
569
  if (done || this.chunkBudget <= 0) {
562
570
  field.context.takeTree();
@@ -581,7 +589,7 @@ const parseWorker = /*@__PURE__*/ViewPlugin.fromClass(class ParseWorker {
581
589
  this.working();
582
590
  }
583
591
  isWorking() {
584
- return this.working || this.workScheduled > 0;
592
+ return !!(this.working || this.workScheduled > 0);
585
593
  }
586
594
  }, {
587
595
  eventHandlers: { focus() { this.scheduleWork(); } }
@@ -1119,7 +1127,7 @@ function syntaxFolding(state, start, end) {
1119
1127
  if (found && cur.from < start)
1120
1128
  break;
1121
1129
  let prop = cur.type.prop(foldNodeProp);
1122
- if (prop) {
1130
+ if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) {
1123
1131
  let value = prop(cur, state);
1124
1132
  if (value && value.from <= end && value.from >= start && value.to > end)
1125
1133
  found = value;
@@ -1127,6 +1135,10 @@ function syntaxFolding(state, start, end) {
1127
1135
  }
1128
1136
  return found;
1129
1137
  }
1138
+ function isUnfinished(node) {
1139
+ let ch = node.lastChild;
1140
+ return ch && ch.to == node.to && ch.type.isError;
1141
+ }
1130
1142
  /**
1131
1143
  Check whether the given line is foldable. First asks any fold
1132
1144
  services registered through
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/language",
3
- "version": "0.19.8",
3
+ "version": "0.19.9",
4
4
  "description": "Language support infrastructure for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",