@codemirror/autocomplete 0.19.12 → 0.19.15

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,27 @@
1
+ ## 0.19.15 (2022-03-23)
2
+
3
+ ### New features
4
+
5
+ The `selectedCompletionIndex` function tells you the position of the currently selected completion.
6
+
7
+ The new `setSelectionCompletion` function creates a state effect that moves the selected completion to a given index.
8
+
9
+ A completion's `info` method may now return null to indicate that no further info is available.
10
+
11
+ ## 0.19.14 (2022-03-10)
12
+
13
+ ### Bug fixes
14
+
15
+ Make the ARIA attributes added to the editor during autocompletion spec-compliant.
16
+
17
+ ## 0.19.13 (2022-02-18)
18
+
19
+ ### Bug fixes
20
+
21
+ Fix an issue where the completion tooltip stayed open if it was explicitly opened and the user backspaced past its start.
22
+
23
+ Stop snippet filling when a change happens across one of the snippet fields' boundaries.
24
+
1
25
  ## 0.19.12 (2022-01-11)
2
26
 
3
27
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -374,22 +374,6 @@ function optionContent(config) {
374
374
  });
375
375
  return content.sort((a, b) => a.position - b.position).map(a => a.render);
376
376
  }
377
- function createInfoDialog(option, view$1) {
378
- let dom = document.createElement("div");
379
- dom.className = "cm-tooltip cm-completionInfo";
380
- let { info } = option.completion;
381
- if (typeof info == "string") {
382
- dom.textContent = info;
383
- }
384
- else {
385
- let content = info(option.completion);
386
- if (content.then)
387
- content.then(node => dom.appendChild(node), e => view.logException(view$1.state, e, "completion info"));
388
- else
389
- dom.appendChild(content);
390
- }
391
- return dom;
392
- }
393
377
  function rangeAroundSelected(total, selected, max) {
394
378
  if (total <= max)
395
379
  return { from: 0, to: total };
@@ -458,13 +442,31 @@ class CompletionTooltip {
458
442
  this.info.remove();
459
443
  this.info = null;
460
444
  }
461
- let option = open.options[open.selected];
462
- if (option.completion.info) {
463
- this.info = this.dom.appendChild(createInfoDialog(option, this.view));
464
- this.view.requestMeasure(this.placeInfo);
445
+ let { completion } = open.options[open.selected];
446
+ let { info } = completion;
447
+ if (!info)
448
+ return;
449
+ let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion);
450
+ if (!infoResult)
451
+ return;
452
+ if ('then' in infoResult) {
453
+ infoResult.then(node => {
454
+ if (node && this.view.state.field(this.stateField, false) == cState)
455
+ this.addInfoPane(node);
456
+ }).catch(e => view.logException(this.view.state, e, "completion info"));
457
+ }
458
+ else {
459
+ this.addInfoPane(infoResult);
465
460
  }
466
461
  }
467
462
  }
463
+ addInfoPane(content) {
464
+ let dom = this.info = document.createElement("div");
465
+ dom.className = "cm-tooltip cm-completionInfo";
466
+ dom.appendChild(content);
467
+ this.dom.appendChild(dom);
468
+ this.view.requestMeasure(this.placeInfo);
469
+ }
468
470
  updateSelectedOption(selected) {
469
471
  let set = null;
470
472
  for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) {
@@ -514,6 +516,7 @@ class CompletionTooltip {
514
516
  const ul = document.createElement("ul");
515
517
  ul.id = id;
516
518
  ul.setAttribute("role", "listbox");
519
+ ul.setAttribute("aria-expanded", "true");
517
520
  for (let i = range.from; i < range.to; i++) {
518
521
  let { completion, match } = options[i];
519
522
  const li = ul.appendChild(document.createElement("li"));
@@ -574,7 +577,6 @@ function sortOptions(active, state) {
574
577
  }
575
578
  }
576
579
  }
577
- options.sort(cmpOption);
578
580
  let result = [], prev = null;
579
581
  for (let opt of options.sort(cmpOption)) {
580
582
  if (result.length == MaxOptions)
@@ -607,10 +609,11 @@ class CompletionDialog {
607
609
  let selected = 0;
608
610
  if (prev && prev.selected) {
609
611
  let selectedValue = prev.options[prev.selected].completion;
610
- for (let i = 0; i < options.length && !selected; i++) {
611
- if (options[i].completion == selectedValue)
612
+ for (let i = 0; i < options.length; i++)
613
+ if (options[i].completion == selectedValue) {
612
614
  selected = i;
613
- }
615
+ break;
616
+ }
614
617
  }
615
618
  return new CompletionDialog(options, makeAttrs(id, selected), {
616
619
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
@@ -671,13 +674,12 @@ function sameResults(a, b) {
671
674
  }
672
675
  }
673
676
  const baseAttrs = {
674
- "aria-autocomplete": "list",
675
- "aria-expanded": "false"
677
+ "aria-autocomplete": "list"
676
678
  };
677
679
  function makeAttrs(id, selected) {
678
680
  return {
679
681
  "aria-autocomplete": "list",
680
- "aria-expanded": "true",
682
+ "aria-haspopup": "listbox",
681
683
  "aria-activedescendant": id + "-" + selected,
682
684
  "aria-controls": id
683
685
  };
@@ -741,7 +743,9 @@ class ActiveResult extends ActiveSource {
741
743
  handleUserEvent(tr, type, conf) {
742
744
  let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1);
743
745
  let pos = cur(tr.state);
744
- if ((this.explicitPos > -1 ? pos < from : pos <= from) || pos > to)
746
+ if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
747
+ pos > to ||
748
+ type == "delete" && cur(tr.startState) == this.from)
745
749
  return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
746
750
  let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos);
747
751
  if (this.span && (from == to || this.span.test(tr.state.sliceDoc(from, to))))
@@ -857,7 +861,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
857
861
  for (let i = 0; i < this.running.length; i++) {
858
862
  let query = this.running[i];
859
863
  if (doesReset ||
860
- query.updates.length + update.transactions.length > MaxUpdateCount && query.time - Date.now() > MinAbortTime) {
864
+ query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
861
865
  for (let handler of query.context.abortListeners) {
862
866
  try {
863
867
  handler();
@@ -1093,7 +1097,9 @@ class FieldRange {
1093
1097
  this.to = to;
1094
1098
  }
1095
1099
  map(changes) {
1096
- return new FieldRange(this.field, changes.mapPos(this.from, -1), changes.mapPos(this.to, 1));
1100
+ let from = changes.mapPos(this.from, -1, state.MapMode.TrackDel);
1101
+ let to = changes.mapPos(this.to, 1, state.MapMode.TrackDel);
1102
+ return from == null || to == null ? null : new FieldRange(this.field, from, to);
1097
1103
  }
1098
1104
  }
1099
1105
  class Snippet {
@@ -1162,7 +1168,14 @@ class ActiveSnippet {
1162
1168
  this.deco = view.Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to)));
1163
1169
  }
1164
1170
  map(changes) {
1165
- return new ActiveSnippet(this.ranges.map(r => r.map(changes)), this.active);
1171
+ let ranges = [];
1172
+ for (let r of this.ranges) {
1173
+ let mapped = r.map(changes);
1174
+ if (!mapped)
1175
+ return null;
1176
+ ranges.push(mapped);
1177
+ }
1178
+ return new ActiveSnippet(ranges, this.active);
1166
1179
  }
1167
1180
  selectionInsideField(sel) {
1168
1181
  return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to));
@@ -1424,13 +1437,19 @@ function completionStatus(state) {
1424
1437
  return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
1425
1438
  : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
1426
1439
  }
1440
+ const completionArrayCache = new WeakMap;
1427
1441
  /**
1428
1442
  Returns the available completions as an array.
1429
1443
  */
1430
1444
  function currentCompletions(state) {
1431
1445
  var _a;
1432
1446
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1433
- return open ? open.options.map(o => o.completion) : [];
1447
+ if (!open)
1448
+ return [];
1449
+ let completions = completionArrayCache.get(open.options);
1450
+ if (!completions)
1451
+ completionArrayCache.set(open.options, completions = open.options.map(o => o.completion));
1452
+ return completions;
1434
1453
  }
1435
1454
  /**
1436
1455
  Return the currently selected completion, if any.
@@ -1440,6 +1459,22 @@ function selectedCompletion(state) {
1440
1459
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1441
1460
  return open ? open.options[open.selected].completion : null;
1442
1461
  }
1462
+ /**
1463
+ Returns the currently selected position in the active completion
1464
+ list, or null if no completions are active.
1465
+ */
1466
+ function selectedCompletionIndex(state) {
1467
+ var _a;
1468
+ let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1469
+ return open ? open.selected : null;
1470
+ }
1471
+ /**
1472
+ Create an effect that can be attached to a transaction to change
1473
+ the currently selected completion.
1474
+ */
1475
+ function setSelectedCompletion(index) {
1476
+ return setSelectedEffect.of(index);
1477
+ }
1443
1478
 
1444
1479
  exports.CompletionContext = CompletionContext;
1445
1480
  exports.acceptCompletion = acceptCompletion;
@@ -1458,6 +1493,8 @@ exports.nextSnippetField = nextSnippetField;
1458
1493
  exports.pickedCompletion = pickedCompletion;
1459
1494
  exports.prevSnippetField = prevSnippetField;
1460
1495
  exports.selectedCompletion = selectedCompletion;
1496
+ exports.selectedCompletionIndex = selectedCompletionIndex;
1497
+ exports.setSelectedCompletion = setSelectedCompletion;
1461
1498
  exports.snippet = snippet;
1462
1499
  exports.snippetCompletion = snippetCompletion;
1463
1500
  exports.snippetKeymap = snippetKeymap;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _codemirror_state from '@codemirror/state';
2
- import { EditorState, Transaction, StateCommand, Facet, Extension } from '@codemirror/state';
2
+ import { EditorState, Transaction, StateCommand, Facet, Extension, StateEffect } from '@codemirror/state';
3
3
  import { EditorView, KeyBinding, Command } from '@codemirror/view';
4
4
  import * as _lezer_common from '@lezer/common';
5
5
 
@@ -81,7 +81,7 @@ interface Completion {
81
81
  a plain string or a function that'll render the DOM structure to
82
82
  show when invoked.
83
83
  */
84
- info?: string | ((completion: Completion) => (Node | Promise<Node>));
84
+ info?: string | ((completion: Completion) => (Node | null | Promise<Node | null>));
85
85
  /**
86
86
  How to apply the completion. The default is to replace it with
87
87
  its [label](https://codemirror.net/6/docs/ref/#autocomplete.Completion.label). When this holds a
@@ -362,5 +362,15 @@ declare function currentCompletions(state: EditorState): readonly Completion[];
362
362
  Return the currently selected completion, if any.
363
363
  */
364
364
  declare function selectedCompletion(state: EditorState): Completion | null;
365
+ /**
366
+ Returns the currently selected position in the active completion
367
+ list, or null if no completions are active.
368
+ */
369
+ declare function selectedCompletionIndex(state: EditorState): number | null;
370
+ /**
371
+ Create an effect that can be attached to a transaction to change
372
+ the currently selected completion.
373
+ */
374
+ declare function setSelectedCompletion(index: number): StateEffect<unknown>;
365
375
 
366
- export { Completion, CompletionContext, CompletionResult, CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
376
+ export { Completion, CompletionContext, CompletionResult, CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { Annotation, Facet, combineConfig, StateEffect, StateField, Prec, EditorSelection, Text } from '@codemirror/state';
2
- import { Direction, logException, EditorView, ViewPlugin, Decoration, WidgetType, keymap } from '@codemirror/view';
1
+ import { Annotation, Facet, combineConfig, StateEffect, StateField, Prec, EditorSelection, Text, MapMode } from '@codemirror/state';
2
+ import { logException, Direction, EditorView, ViewPlugin, Decoration, WidgetType, keymap } from '@codemirror/view';
3
3
  import { showTooltip, getTooltip } from '@codemirror/tooltip';
4
4
  import { syntaxTree, indentUnit } from '@codemirror/language';
5
5
  import { codePointAt, codePointSize, fromCodePoint } from '@codemirror/text';
@@ -370,22 +370,6 @@ function optionContent(config) {
370
370
  });
371
371
  return content.sort((a, b) => a.position - b.position).map(a => a.render);
372
372
  }
373
- function createInfoDialog(option, view) {
374
- let dom = document.createElement("div");
375
- dom.className = "cm-tooltip cm-completionInfo";
376
- let { info } = option.completion;
377
- if (typeof info == "string") {
378
- dom.textContent = info;
379
- }
380
- else {
381
- let content = info(option.completion);
382
- if (content.then)
383
- content.then(node => dom.appendChild(node), e => logException(view.state, e, "completion info"));
384
- else
385
- dom.appendChild(content);
386
- }
387
- return dom;
388
- }
389
373
  function rangeAroundSelected(total, selected, max) {
390
374
  if (total <= max)
391
375
  return { from: 0, to: total };
@@ -454,13 +438,31 @@ class CompletionTooltip {
454
438
  this.info.remove();
455
439
  this.info = null;
456
440
  }
457
- let option = open.options[open.selected];
458
- if (option.completion.info) {
459
- this.info = this.dom.appendChild(createInfoDialog(option, this.view));
460
- this.view.requestMeasure(this.placeInfo);
441
+ let { completion } = open.options[open.selected];
442
+ let { info } = completion;
443
+ if (!info)
444
+ return;
445
+ let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion);
446
+ if (!infoResult)
447
+ return;
448
+ if ('then' in infoResult) {
449
+ infoResult.then(node => {
450
+ if (node && this.view.state.field(this.stateField, false) == cState)
451
+ this.addInfoPane(node);
452
+ }).catch(e => logException(this.view.state, e, "completion info"));
453
+ }
454
+ else {
455
+ this.addInfoPane(infoResult);
461
456
  }
462
457
  }
463
458
  }
459
+ addInfoPane(content) {
460
+ let dom = this.info = document.createElement("div");
461
+ dom.className = "cm-tooltip cm-completionInfo";
462
+ dom.appendChild(content);
463
+ this.dom.appendChild(dom);
464
+ this.view.requestMeasure(this.placeInfo);
465
+ }
464
466
  updateSelectedOption(selected) {
465
467
  let set = null;
466
468
  for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) {
@@ -510,6 +512,7 @@ class CompletionTooltip {
510
512
  const ul = document.createElement("ul");
511
513
  ul.id = id;
512
514
  ul.setAttribute("role", "listbox");
515
+ ul.setAttribute("aria-expanded", "true");
513
516
  for (let i = range.from; i < range.to; i++) {
514
517
  let { completion, match } = options[i];
515
518
  const li = ul.appendChild(document.createElement("li"));
@@ -570,7 +573,6 @@ function sortOptions(active, state) {
570
573
  }
571
574
  }
572
575
  }
573
- options.sort(cmpOption);
574
576
  let result = [], prev = null;
575
577
  for (let opt of options.sort(cmpOption)) {
576
578
  if (result.length == MaxOptions)
@@ -603,10 +605,11 @@ class CompletionDialog {
603
605
  let selected = 0;
604
606
  if (prev && prev.selected) {
605
607
  let selectedValue = prev.options[prev.selected].completion;
606
- for (let i = 0; i < options.length && !selected; i++) {
607
- if (options[i].completion == selectedValue)
608
+ for (let i = 0; i < options.length; i++)
609
+ if (options[i].completion == selectedValue) {
608
610
  selected = i;
609
- }
611
+ break;
612
+ }
610
613
  }
611
614
  return new CompletionDialog(options, makeAttrs(id, selected), {
612
615
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
@@ -667,13 +670,12 @@ function sameResults(a, b) {
667
670
  }
668
671
  }
669
672
  const baseAttrs = {
670
- "aria-autocomplete": "list",
671
- "aria-expanded": "false"
673
+ "aria-autocomplete": "list"
672
674
  };
673
675
  function makeAttrs(id, selected) {
674
676
  return {
675
677
  "aria-autocomplete": "list",
676
- "aria-expanded": "true",
678
+ "aria-haspopup": "listbox",
677
679
  "aria-activedescendant": id + "-" + selected,
678
680
  "aria-controls": id
679
681
  };
@@ -737,7 +739,9 @@ class ActiveResult extends ActiveSource {
737
739
  handleUserEvent(tr, type, conf) {
738
740
  let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1);
739
741
  let pos = cur(tr.state);
740
- if ((this.explicitPos > -1 ? pos < from : pos <= from) || pos > to)
742
+ if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
743
+ pos > to ||
744
+ type == "delete" && cur(tr.startState) == this.from)
741
745
  return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
742
746
  let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos);
743
747
  if (this.span && (from == to || this.span.test(tr.state.sliceDoc(from, to))))
@@ -853,7 +857,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
853
857
  for (let i = 0; i < this.running.length; i++) {
854
858
  let query = this.running[i];
855
859
  if (doesReset ||
856
- query.updates.length + update.transactions.length > MaxUpdateCount && query.time - Date.now() > MinAbortTime) {
860
+ query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
857
861
  for (let handler of query.context.abortListeners) {
858
862
  try {
859
863
  handler();
@@ -1089,7 +1093,9 @@ class FieldRange {
1089
1093
  this.to = to;
1090
1094
  }
1091
1095
  map(changes) {
1092
- return new FieldRange(this.field, changes.mapPos(this.from, -1), changes.mapPos(this.to, 1));
1096
+ let from = changes.mapPos(this.from, -1, MapMode.TrackDel);
1097
+ let to = changes.mapPos(this.to, 1, MapMode.TrackDel);
1098
+ return from == null || to == null ? null : new FieldRange(this.field, from, to);
1093
1099
  }
1094
1100
  }
1095
1101
  class Snippet {
@@ -1158,7 +1164,14 @@ class ActiveSnippet {
1158
1164
  this.deco = Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to)));
1159
1165
  }
1160
1166
  map(changes) {
1161
- return new ActiveSnippet(this.ranges.map(r => r.map(changes)), this.active);
1167
+ let ranges = [];
1168
+ for (let r of this.ranges) {
1169
+ let mapped = r.map(changes);
1170
+ if (!mapped)
1171
+ return null;
1172
+ ranges.push(mapped);
1173
+ }
1174
+ return new ActiveSnippet(ranges, this.active);
1162
1175
  }
1163
1176
  selectionInsideField(sel) {
1164
1177
  return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to));
@@ -1420,13 +1433,19 @@ function completionStatus(state) {
1420
1433
  return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
1421
1434
  : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
1422
1435
  }
1436
+ const completionArrayCache = /*@__PURE__*/new WeakMap;
1423
1437
  /**
1424
1438
  Returns the available completions as an array.
1425
1439
  */
1426
1440
  function currentCompletions(state) {
1427
1441
  var _a;
1428
1442
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1429
- return open ? open.options.map(o => o.completion) : [];
1443
+ if (!open)
1444
+ return [];
1445
+ let completions = completionArrayCache.get(open.options);
1446
+ if (!completions)
1447
+ completionArrayCache.set(open.options, completions = open.options.map(o => o.completion));
1448
+ return completions;
1430
1449
  }
1431
1450
  /**
1432
1451
  Return the currently selected completion, if any.
@@ -1436,5 +1455,21 @@ function selectedCompletion(state) {
1436
1455
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1437
1456
  return open ? open.options[open.selected].completion : null;
1438
1457
  }
1458
+ /**
1459
+ Returns the currently selected position in the active completion
1460
+ list, or null if no completions are active.
1461
+ */
1462
+ function selectedCompletionIndex(state) {
1463
+ var _a;
1464
+ let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1465
+ return open ? open.selected : null;
1466
+ }
1467
+ /**
1468
+ Create an effect that can be attached to a transaction to change
1469
+ the currently selected completion.
1470
+ */
1471
+ function setSelectedCompletion(index) {
1472
+ return setSelectedEffect.of(index);
1473
+ }
1439
1474
 
1440
- export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
1475
+ export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/autocomplete",
3
- "version": "0.19.12",
3
+ "version": "0.19.15",
4
4
  "description": "Autocompletion for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",