@codemirror/autocomplete 6.9.1 → 6.10.0

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,15 @@
1
+ ## 6.10.0 (2023-10-11)
2
+
3
+ ### New features
4
+
5
+ The new autocompletion configuration option `updateSyncTime` allows control over how long fast sources are held back waiting for slower completion sources.
6
+
7
+ ## 6.9.2 (2023-10-06)
8
+
9
+ ### Bug fixes
10
+
11
+ Fix a bug in `completeAnyWord` that could cause it to generate invalid regular expressions and crash.
12
+
1
13
  ## 6.9.1 (2023-09-14)
2
14
 
3
15
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -341,7 +341,8 @@ const completionConfig = state.Facet.define({
341
341
  addToOptions: [],
342
342
  positionInfo: defaultPositionInfo,
343
343
  compareCompletions: (a, b) => a.label.localeCompare(b.label),
344
- interactionDelay: 75
344
+ interactionDelay: 75,
345
+ updateSyncTime: 100
345
346
  }, {
346
347
  defaultKeymap: (a, b) => a && b,
347
348
  closeOnBlur: (a, b) => a && b,
@@ -485,22 +486,32 @@ class CompletionTooltip {
485
486
  e.relatedTarget != view.contentDOM)
486
487
  view.dispatch({ effects: closeCompletionEffect.of(null) });
487
488
  });
488
- this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range));
489
+ this.showOptions(options, cState.id);
490
+ }
491
+ mount() { this.updateSel(); }
492
+ showOptions(options, id) {
493
+ if (this.list)
494
+ this.list.remove();
495
+ this.list = this.dom.appendChild(this.createListBox(options, id, this.range));
489
496
  this.list.addEventListener("scroll", () => {
490
497
  if (this.info)
491
498
  this.view.requestMeasure(this.placeInfoReq);
492
499
  });
493
500
  }
494
- mount() { this.updateSel(); }
495
501
  update(update) {
496
- var _a, _b, _c;
502
+ var _a;
497
503
  let cState = update.state.field(this.stateField);
498
504
  let prevState = update.startState.field(this.stateField);
499
505
  this.updateTooltipClass(update.state);
500
506
  if (cState != prevState) {
507
+ let { options, selected, disabled } = cState.open;
508
+ if (!prevState.open || prevState.open.options != options) {
509
+ this.range = rangeAroundSelected(options.length, selected, update.state.facet(completionConfig).maxRenderedOptions);
510
+ this.showOptions(options, cState.id);
511
+ }
501
512
  this.updateSel();
502
- if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled))
503
- this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled));
513
+ if (disabled != ((_a = prevState.open) === null || _a === void 0 ? void 0 : _a.disabled))
514
+ this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!disabled);
504
515
  }
505
516
  }
506
517
  updateTooltipClass(state) {
@@ -524,12 +535,7 @@ class CompletionTooltip {
524
535
  let cState = this.view.state.field(this.stateField), open = cState.open;
525
536
  if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) {
526
537
  this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
527
- this.list.remove();
528
- this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range));
529
- this.list.addEventListener("scroll", () => {
530
- if (this.info)
531
- this.view.requestMeasure(this.placeInfoReq);
532
- });
538
+ this.showOptions(open.options, cState.id);
533
539
  }
534
540
  if (this.updateSelectedOption(open.selected)) {
535
541
  this.destroyInfo();
@@ -669,8 +675,6 @@ class CompletionTooltip {
669
675
  this.destroyInfo();
670
676
  }
671
677
  }
672
- // We allocate a new function instance every time the completion
673
- // changes to force redrawing/repositioning of the tooltip
674
678
  function completionTooltip(stateField, applyCompletion) {
675
679
  return (view) => new CompletionTooltip(view, stateField, applyCompletion);
676
680
  }
@@ -778,7 +782,7 @@ class CompletionDialog {
778
782
  }
779
783
  return new CompletionDialog(options, makeAttrs(id, selected), {
780
784
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
781
- create: completionTooltip(completionState, applyCompletion),
785
+ create: createTooltip,
782
786
  above: conf.aboveCursor,
783
787
  }, prev ? prev.timestamp : Date.now(), selected, false);
784
788
  }
@@ -954,6 +958,7 @@ function applyCompletion(view, option) {
954
958
  apply(view, option.completion, result.from, result.to);
955
959
  return true;
956
960
  }
961
+ const createTooltip = completionTooltip(completionState, applyCompletion);
957
962
 
958
963
  /**
959
964
  Returns a command that moves the completion selection forward or
@@ -1020,7 +1025,7 @@ class RunningQuery {
1020
1025
  this.done = undefined;
1021
1026
  }
1022
1027
  }
1023
- const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000;
1028
+ const MaxUpdateCount = 50, MinAbortTime = 1000;
1024
1029
  const completionPlugin = view.ViewPlugin.fromClass(class {
1025
1030
  constructor(view) {
1026
1031
  this.view = view;
@@ -1061,7 +1066,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
1061
1066
  if (this.debounceUpdate > -1)
1062
1067
  clearTimeout(this.debounceUpdate);
1063
1068
  this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
1064
- ? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
1069
+ ? setTimeout(() => this.startUpdate(), update.state.facet(completionConfig).updateSyncTime) : -1;
1065
1070
  if (this.composing != 0 /* CompositionState.None */)
1066
1071
  for (let tr of update.transactions) {
1067
1072
  if (getUserEvent(tr) == "input")
@@ -1097,7 +1102,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
1097
1102
  if (this.running.every(q => q.done !== undefined))
1098
1103
  this.accept();
1099
1104
  else if (this.debounceAccept < 0)
1100
- this.debounceAccept = setTimeout(() => this.accept(), DebounceTime);
1105
+ this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
1101
1106
  }
1102
1107
  // For each finished query in this.running, try to create a result
1103
1108
  // or, if appropriate, restart the query.
@@ -1562,7 +1567,7 @@ const snippetPointerHandler = view.EditorView.domEventHandlers({
1562
1567
  });
1563
1568
 
1564
1569
  function wordRE(wordChars) {
1565
- let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&");
1570
+ let escaped = wordChars.replace(/[\]\-\\]/g, "\\$&");
1566
1571
  try {
1567
1572
  return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug");
1568
1573
  }
package/dist/index.d.cts CHANGED
@@ -369,6 +369,13 @@ interface CompletionConfig {
369
369
  the tooltip. This option can be used to configure that delay.
370
370
  */
371
371
  interactionDelay?: number;
372
+ /**
373
+ When there are multiple asynchronous completion sources, this
374
+ controls how long the extension waits for a slow source before
375
+ displaying results from faster sources. Defaults to 100
376
+ milliseconds.
377
+ */
378
+ updateSyncTime?: number;
372
379
  }
373
380
 
374
381
  /**
package/dist/index.d.ts CHANGED
@@ -369,6 +369,13 @@ interface CompletionConfig {
369
369
  the tooltip. This option can be used to configure that delay.
370
370
  */
371
371
  interactionDelay?: number;
372
+ /**
373
+ When there are multiple asynchronous completion sources, this
374
+ controls how long the extension waits for a slow source before
375
+ displaying results from faster sources. Defaults to 100
376
+ milliseconds.
377
+ */
378
+ updateSyncTime?: number;
372
379
  }
373
380
 
374
381
  /**
package/dist/index.js CHANGED
@@ -339,7 +339,8 @@ const completionConfig = /*@__PURE__*/Facet.define({
339
339
  addToOptions: [],
340
340
  positionInfo: defaultPositionInfo,
341
341
  compareCompletions: (a, b) => a.label.localeCompare(b.label),
342
- interactionDelay: 75
342
+ interactionDelay: 75,
343
+ updateSyncTime: 100
343
344
  }, {
344
345
  defaultKeymap: (a, b) => a && b,
345
346
  closeOnBlur: (a, b) => a && b,
@@ -483,22 +484,32 @@ class CompletionTooltip {
483
484
  e.relatedTarget != view.contentDOM)
484
485
  view.dispatch({ effects: closeCompletionEffect.of(null) });
485
486
  });
486
- this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range));
487
+ this.showOptions(options, cState.id);
488
+ }
489
+ mount() { this.updateSel(); }
490
+ showOptions(options, id) {
491
+ if (this.list)
492
+ this.list.remove();
493
+ this.list = this.dom.appendChild(this.createListBox(options, id, this.range));
487
494
  this.list.addEventListener("scroll", () => {
488
495
  if (this.info)
489
496
  this.view.requestMeasure(this.placeInfoReq);
490
497
  });
491
498
  }
492
- mount() { this.updateSel(); }
493
499
  update(update) {
494
- var _a, _b, _c;
500
+ var _a;
495
501
  let cState = update.state.field(this.stateField);
496
502
  let prevState = update.startState.field(this.stateField);
497
503
  this.updateTooltipClass(update.state);
498
504
  if (cState != prevState) {
505
+ let { options, selected, disabled } = cState.open;
506
+ if (!prevState.open || prevState.open.options != options) {
507
+ this.range = rangeAroundSelected(options.length, selected, update.state.facet(completionConfig).maxRenderedOptions);
508
+ this.showOptions(options, cState.id);
509
+ }
499
510
  this.updateSel();
500
- if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled))
501
- this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled));
511
+ if (disabled != ((_a = prevState.open) === null || _a === void 0 ? void 0 : _a.disabled))
512
+ this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!disabled);
502
513
  }
503
514
  }
504
515
  updateTooltipClass(state) {
@@ -522,12 +533,7 @@ class CompletionTooltip {
522
533
  let cState = this.view.state.field(this.stateField), open = cState.open;
523
534
  if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) {
524
535
  this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
525
- this.list.remove();
526
- this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range));
527
- this.list.addEventListener("scroll", () => {
528
- if (this.info)
529
- this.view.requestMeasure(this.placeInfoReq);
530
- });
536
+ this.showOptions(open.options, cState.id);
531
537
  }
532
538
  if (this.updateSelectedOption(open.selected)) {
533
539
  this.destroyInfo();
@@ -667,8 +673,6 @@ class CompletionTooltip {
667
673
  this.destroyInfo();
668
674
  }
669
675
  }
670
- // We allocate a new function instance every time the completion
671
- // changes to force redrawing/repositioning of the tooltip
672
676
  function completionTooltip(stateField, applyCompletion) {
673
677
  return (view) => new CompletionTooltip(view, stateField, applyCompletion);
674
678
  }
@@ -776,7 +780,7 @@ class CompletionDialog {
776
780
  }
777
781
  return new CompletionDialog(options, makeAttrs(id, selected), {
778
782
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
779
- create: completionTooltip(completionState, applyCompletion),
783
+ create: createTooltip,
780
784
  above: conf.aboveCursor,
781
785
  }, prev ? prev.timestamp : Date.now(), selected, false);
782
786
  }
@@ -952,6 +956,7 @@ function applyCompletion(view, option) {
952
956
  apply(view, option.completion, result.from, result.to);
953
957
  return true;
954
958
  }
959
+ const createTooltip = /*@__PURE__*/completionTooltip(completionState, applyCompletion);
955
960
 
956
961
  /**
957
962
  Returns a command that moves the completion selection forward or
@@ -1018,7 +1023,7 @@ class RunningQuery {
1018
1023
  this.done = undefined;
1019
1024
  }
1020
1025
  }
1021
- const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000;
1026
+ const MaxUpdateCount = 50, MinAbortTime = 1000;
1022
1027
  const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1023
1028
  constructor(view) {
1024
1029
  this.view = view;
@@ -1059,7 +1064,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1059
1064
  if (this.debounceUpdate > -1)
1060
1065
  clearTimeout(this.debounceUpdate);
1061
1066
  this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
1062
- ? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
1067
+ ? setTimeout(() => this.startUpdate(), update.state.facet(completionConfig).updateSyncTime) : -1;
1063
1068
  if (this.composing != 0 /* CompositionState.None */)
1064
1069
  for (let tr of update.transactions) {
1065
1070
  if (getUserEvent(tr) == "input")
@@ -1095,7 +1100,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1095
1100
  if (this.running.every(q => q.done !== undefined))
1096
1101
  this.accept();
1097
1102
  else if (this.debounceAccept < 0)
1098
- this.debounceAccept = setTimeout(() => this.accept(), DebounceTime);
1103
+ this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
1099
1104
  }
1100
1105
  // For each finished query in this.running, try to create a result
1101
1106
  // or, if appropriate, restart the query.
@@ -1560,7 +1565,7 @@ const snippetPointerHandler = /*@__PURE__*/EditorView.domEventHandlers({
1560
1565
  });
1561
1566
 
1562
1567
  function wordRE(wordChars) {
1563
- let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&");
1568
+ let escaped = wordChars.replace(/[\]\-\\]/g, "\\$&");
1564
1569
  try {
1565
1570
  return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug");
1566
1571
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/autocomplete",
3
- "version": "6.9.1",
3
+ "version": "6.10.0",
4
4
  "description": "Autocompletion for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",