@codemirror/language 0.19.7 → 0.19.10

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.10 (2022-03-31)
2
+
3
+ ### Bug fixes
4
+
5
+ Autocompletion may now also trigger automatic indentation on input.
6
+
7
+ ## 0.19.9 (2022-03-30)
8
+
9
+ ### Bug fixes
10
+
11
+ Make sure nodes that end at the end of a partial parse aren't treated as valid fold targets.
12
+
13
+ Fix an issue where the parser sometimes wouldn't reuse parsing work done in the background on transactions.
14
+
15
+ ## 0.19.8 (2022-03-03)
16
+
17
+ ### Bug fixes
18
+
19
+ Fix an issue that could cause indentation logic to use the wrong line content when indenting multiple lines at once.
20
+
1
21
  ## 0.19.7 (2021-12-02)
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.
@@ -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(); } }
@@ -822,9 +830,11 @@ class IndentContext {
822
830
  */
823
831
  lineAt(pos, bias = 1) {
824
832
  let line = this.state.doc.lineAt(pos);
825
- let { simulateBreak } = this.options;
833
+ let { simulateBreak, simulateDoubleBreak } = this.options;
826
834
  if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
827
- 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)
828
838
  return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak };
829
839
  else
830
840
  return { text: line.text.slice(0, simulateBreak - line.from), from: line.from };
@@ -1057,7 +1067,7 @@ added at the start of a line.
1057
1067
  */
1058
1068
  function indentOnInput() {
1059
1069
  return state.EditorState.transactionFilter.of(tr => {
1060
- if (!tr.docChanged || !tr.isUserEvent("input.type"))
1070
+ if (!tr.docChanged || !tr.isUserEvent("input.type") && !tr.isUserEvent("input.complete"))
1061
1071
  return tr;
1062
1072
  let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head);
1063
1073
  if (!rules.length)
@@ -1121,7 +1131,7 @@ function syntaxFolding(state, start, end) {
1121
1131
  if (found && cur.from < start)
1122
1132
  break;
1123
1133
  let prop = cur.type.prop(foldNodeProp);
1124
- if (prop) {
1134
+ if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) {
1125
1135
  let value = prop(cur, state);
1126
1136
  if (value && value.from <= end && value.from >= start && value.to > end)
1127
1137
  found = value;
@@ -1129,6 +1139,10 @@ function syntaxFolding(state, start, end) {
1129
1139
  }
1130
1140
  return found;
1131
1141
  }
1142
+ function isUnfinished(node) {
1143
+ let ch = node.lastChild;
1144
+ return ch && ch.to == node.to && ch.type.isError;
1145
+ }
1132
1146
  /**
1133
1147
  Check whether the given line is foldable. First asks any fold
1134
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(); } }
@@ -818,9 +826,11 @@ class IndentContext {
818
826
  */
819
827
  lineAt(pos, bias = 1) {
820
828
  let line = this.state.doc.lineAt(pos);
821
- let { simulateBreak } = this.options;
829
+ let { simulateBreak, simulateDoubleBreak } = this.options;
822
830
  if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) {
823
- 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)
824
834
  return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak };
825
835
  else
826
836
  return { text: line.text.slice(0, simulateBreak - line.from), from: line.from };
@@ -1053,7 +1063,7 @@ added at the start of a line.
1053
1063
  */
1054
1064
  function indentOnInput() {
1055
1065
  return EditorState.transactionFilter.of(tr => {
1056
- if (!tr.docChanged || !tr.isUserEvent("input.type"))
1066
+ if (!tr.docChanged || !tr.isUserEvent("input.type") && !tr.isUserEvent("input.complete"))
1057
1067
  return tr;
1058
1068
  let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head);
1059
1069
  if (!rules.length)
@@ -1117,7 +1127,7 @@ function syntaxFolding(state, start, end) {
1117
1127
  if (found && cur.from < start)
1118
1128
  break;
1119
1129
  let prop = cur.type.prop(foldNodeProp);
1120
- if (prop) {
1130
+ if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) {
1121
1131
  let value = prop(cur, state);
1122
1132
  if (value && value.from <= end && value.from >= start && value.to > end)
1123
1133
  found = value;
@@ -1125,6 +1135,10 @@ function syntaxFolding(state, start, end) {
1125
1135
  }
1126
1136
  return found;
1127
1137
  }
1138
+ function isUnfinished(node) {
1139
+ let ch = node.lastChild;
1140
+ return ch && ch.to == node.to && ch.type.isError;
1141
+ }
1128
1142
  /**
1129
1143
  Check whether the given line is foldable. First asks any fold
1130
1144
  services registered through
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/language",
3
- "version": "0.19.7",
3
+ "version": "0.19.10",
4
4
  "description": "Language support infrastructure for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",