@codemirror/autocomplete 6.11.0 → 6.12.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,23 @@
1
+ ## 6.12.0 (2024-01-12)
2
+
3
+ ### Bug fixes
4
+
5
+ Make sure snippet completions also set `userEvent` to `input.complete`.
6
+
7
+ Fix a crash when the editor lost focus during an update and autocompletion was active.
8
+
9
+ Fix a crash when using a snippet that has only one field, but multiple instances of that field.
10
+
11
+ ### New features
12
+
13
+ The new `activateOnTypingDelay` option allows control over the debounce time before the completions are queried when the user types.
14
+
15
+ ## 6.11.1 (2023-11-27)
16
+
17
+ ### Bug fixes
18
+
19
+ Fix a bug that caused typing over closed brackets after pressing enter to still not work in many situations.
20
+
1
21
  ## 6.11.0 (2023-11-09)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -329,6 +329,7 @@ const completionConfig = state.Facet.define({
329
329
  combine(configs) {
330
330
  return state.combineConfig(configs, {
331
331
  activateOnTyping: true,
332
+ activateOnTypingDelay: 100,
332
333
  selectOnOpen: true,
333
334
  override: null,
334
335
  closeOnBlur: true,
@@ -1033,6 +1034,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
1033
1034
  this.debounceUpdate = -1;
1034
1035
  this.running = [];
1035
1036
  this.debounceAccept = -1;
1037
+ this.pendingStart = false;
1036
1038
  this.composing = 0 /* CompositionState.None */;
1037
1039
  for (let active of view.state.field(completionState).active)
1038
1040
  if (active.state == 1 /* State.Pending */)
@@ -1066,8 +1068,11 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
1066
1068
  }
1067
1069
  if (this.debounceUpdate > -1)
1068
1070
  clearTimeout(this.debounceUpdate);
1071
+ if (update.transactions.some(tr => tr.effects.some(e => e.is(startCompletionEffect))))
1072
+ this.pendingStart = true;
1073
+ let delay = this.pendingStart ? 50 : update.state.facet(completionConfig).activateOnTypingDelay;
1069
1074
  this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
1070
- ? setTimeout(() => this.startUpdate(), 50) : -1;
1075
+ ? setTimeout(() => this.startUpdate(), delay) : -1;
1071
1076
  if (this.composing != 0 /* CompositionState.None */)
1072
1077
  for (let tr of update.transactions) {
1073
1078
  if (getUserEvent(tr) == "input")
@@ -1078,6 +1083,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
1078
1083
  }
1079
1084
  startUpdate() {
1080
1085
  this.debounceUpdate = -1;
1086
+ this.pendingStart = false;
1081
1087
  let { state } = this.view, cState = state.field(completionState);
1082
1088
  for (let active of cState.active) {
1083
1089
  if (active.state == 1 /* State.Pending */ && !this.running.some(r => r.active.source == active.source))
@@ -1157,7 +1163,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
1157
1163
  if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
1158
1164
  let dialog = state.open && view.getTooltip(this.view, state.open.tooltip);
1159
1165
  if (!dialog || !dialog.dom.contains(event.relatedTarget))
1160
- this.view.dispatch({ effects: closeCompletionEffect.of(null) });
1166
+ setTimeout(() => this.view.dispatch({ effects: closeCompletionEffect.of(null) }), 10);
1161
1167
  }
1162
1168
  },
1163
1169
  compositionstart() {
@@ -1465,11 +1471,11 @@ function snippet(template) {
1465
1471
  let spec = {
1466
1472
  changes: { from, to, insert: state.Text.of(text) },
1467
1473
  scrollIntoView: true,
1468
- annotations: completion ? pickedCompletion.of(completion) : undefined
1474
+ annotations: completion ? [pickedCompletion.of(completion), state.Transaction.userEvent.of("input.complete")] : undefined
1469
1475
  };
1470
1476
  if (ranges.length)
1471
1477
  spec.selection = fieldSelection(ranges, 0);
1472
- if (ranges.length > 1) {
1478
+ if (ranges.some(r => r.field > 0)) {
1473
1479
  let active = new ActiveSnippet(ranges, 0);
1474
1480
  let effects = spec.effects = [setActive.of(active)];
1475
1481
  if (editor.state.field(snippetState, false) === undefined)
@@ -1662,11 +1668,11 @@ closedBracket.endSide = -1;
1662
1668
  const bracketState = state.StateField.define({
1663
1669
  create() { return state.RangeSet.empty; },
1664
1670
  update(value, tr) {
1671
+ value = value.map(tr.changes);
1665
1672
  if (tr.selection) {
1666
1673
  let line = tr.state.doc.lineAt(tr.selection.main.head);
1667
1674
  value = value.update({ filter: from => from >= line.from && from <= line.to });
1668
1675
  }
1669
- value = value.map(tr.changes);
1670
1676
  for (let effect of tr.effects)
1671
1677
  if (effect.is(closeBracketEffect))
1672
1678
  value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] });
package/dist/index.d.cts CHANGED
@@ -275,6 +275,14 @@ interface CompletionConfig {
275
275
  */
276
276
  activateOnTyping?: boolean;
277
277
  /**
278
+ The amount of time to wait for further typing before querying
279
+ completion sources via
280
+ [`activateOnTyping`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.activateOnTyping).
281
+ Defaults to 100, which should be fine unless your completion
282
+ source is very slow and/or doesn't use `validFor`.
283
+ */
284
+ activateOnTypingDelay?: number;
285
+ /**
278
286
  By default, when completion opens, the first option is selected
279
287
  and can be confirmed with
280
288
  [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion). When this
@@ -571,4 +579,4 @@ the currently selected completion.
571
579
  */
572
580
  declare function setSelectedCompletion(index: number): StateEffect<unknown>;
573
581
 
574
- export { CloseBracketConfig, Completion, CompletionContext, CompletionInfo, CompletionResult, CompletionSection, CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, deleteBracketPair, hasNextSnippetField, hasPrevSnippetField, ifIn, ifNotIn, insertBracket, insertCompletionText, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
582
+ export { type CloseBracketConfig, type Completion, CompletionContext, type CompletionInfo, type CompletionResult, type CompletionSection, type CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, deleteBracketPair, hasNextSnippetField, hasPrevSnippetField, ifIn, ifNotIn, insertBracket, insertCompletionText, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
package/dist/index.d.ts CHANGED
@@ -275,6 +275,14 @@ interface CompletionConfig {
275
275
  */
276
276
  activateOnTyping?: boolean;
277
277
  /**
278
+ The amount of time to wait for further typing before querying
279
+ completion sources via
280
+ [`activateOnTyping`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.activateOnTyping).
281
+ Defaults to 100, which should be fine unless your completion
282
+ source is very slow and/or doesn't use `validFor`.
283
+ */
284
+ activateOnTypingDelay?: number;
285
+ /**
278
286
  By default, when completion opens, the first option is selected
279
287
  and can be confirmed with
280
288
  [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion). When this
@@ -571,4 +579,4 @@ the currently selected completion.
571
579
  */
572
580
  declare function setSelectedCompletion(index: number): StateEffect<unknown>;
573
581
 
574
- export { CloseBracketConfig, Completion, CompletionContext, CompletionInfo, CompletionResult, CompletionSection, CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, deleteBracketPair, hasNextSnippetField, hasPrevSnippetField, ifIn, ifNotIn, insertBracket, insertCompletionText, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
582
+ export { type CloseBracketConfig, type Completion, CompletionContext, type CompletionInfo, type CompletionResult, type CompletionSection, type CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, deleteBracketPair, hasNextSnippetField, hasPrevSnippetField, ifIn, ifNotIn, insertBracket, insertCompletionText, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Annotation, StateEffect, EditorSelection, codePointAt, codePointSize, fromCodePoint, Facet, combineConfig, StateField, Prec, Text, MapMode, RangeValue, RangeSet, CharCategory } from '@codemirror/state';
1
+ import { Annotation, StateEffect, EditorSelection, codePointAt, codePointSize, fromCodePoint, Facet, combineConfig, StateField, Prec, Text, Transaction, MapMode, RangeValue, RangeSet, CharCategory } from '@codemirror/state';
2
2
  import { Direction, logException, showTooltip, EditorView, ViewPlugin, getTooltip, Decoration, WidgetType, keymap } from '@codemirror/view';
3
3
  import { syntaxTree, indentUnit } from '@codemirror/language';
4
4
 
@@ -327,6 +327,7 @@ const completionConfig = /*@__PURE__*/Facet.define({
327
327
  combine(configs) {
328
328
  return combineConfig(configs, {
329
329
  activateOnTyping: true,
330
+ activateOnTypingDelay: 100,
330
331
  selectOnOpen: true,
331
332
  override: null,
332
333
  closeOnBlur: true,
@@ -1031,6 +1032,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1031
1032
  this.debounceUpdate = -1;
1032
1033
  this.running = [];
1033
1034
  this.debounceAccept = -1;
1035
+ this.pendingStart = false;
1034
1036
  this.composing = 0 /* CompositionState.None */;
1035
1037
  for (let active of view.state.field(completionState).active)
1036
1038
  if (active.state == 1 /* State.Pending */)
@@ -1064,8 +1066,11 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1064
1066
  }
1065
1067
  if (this.debounceUpdate > -1)
1066
1068
  clearTimeout(this.debounceUpdate);
1069
+ if (update.transactions.some(tr => tr.effects.some(e => e.is(startCompletionEffect))))
1070
+ this.pendingStart = true;
1071
+ let delay = this.pendingStart ? 50 : update.state.facet(completionConfig).activateOnTypingDelay;
1067
1072
  this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
1068
- ? setTimeout(() => this.startUpdate(), 50) : -1;
1073
+ ? setTimeout(() => this.startUpdate(), delay) : -1;
1069
1074
  if (this.composing != 0 /* CompositionState.None */)
1070
1075
  for (let tr of update.transactions) {
1071
1076
  if (getUserEvent(tr) == "input")
@@ -1076,6 +1081,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1076
1081
  }
1077
1082
  startUpdate() {
1078
1083
  this.debounceUpdate = -1;
1084
+ this.pendingStart = false;
1079
1085
  let { state } = this.view, cState = state.field(completionState);
1080
1086
  for (let active of cState.active) {
1081
1087
  if (active.state == 1 /* State.Pending */ && !this.running.some(r => r.active.source == active.source))
@@ -1155,7 +1161,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1155
1161
  if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
1156
1162
  let dialog = state.open && getTooltip(this.view, state.open.tooltip);
1157
1163
  if (!dialog || !dialog.dom.contains(event.relatedTarget))
1158
- this.view.dispatch({ effects: closeCompletionEffect.of(null) });
1164
+ setTimeout(() => this.view.dispatch({ effects: closeCompletionEffect.of(null) }), 10);
1159
1165
  }
1160
1166
  },
1161
1167
  compositionstart() {
@@ -1463,11 +1469,11 @@ function snippet(template) {
1463
1469
  let spec = {
1464
1470
  changes: { from, to, insert: Text.of(text) },
1465
1471
  scrollIntoView: true,
1466
- annotations: completion ? pickedCompletion.of(completion) : undefined
1472
+ annotations: completion ? [pickedCompletion.of(completion), Transaction.userEvent.of("input.complete")] : undefined
1467
1473
  };
1468
1474
  if (ranges.length)
1469
1475
  spec.selection = fieldSelection(ranges, 0);
1470
- if (ranges.length > 1) {
1476
+ if (ranges.some(r => r.field > 0)) {
1471
1477
  let active = new ActiveSnippet(ranges, 0);
1472
1478
  let effects = spec.effects = [setActive.of(active)];
1473
1479
  if (editor.state.field(snippetState, false) === undefined)
@@ -1660,11 +1666,11 @@ closedBracket.endSide = -1;
1660
1666
  const bracketState = /*@__PURE__*/StateField.define({
1661
1667
  create() { return RangeSet.empty; },
1662
1668
  update(value, tr) {
1669
+ value = value.map(tr.changes);
1663
1670
  if (tr.selection) {
1664
1671
  let line = tr.state.doc.lineAt(tr.selection.main.head);
1665
1672
  value = value.update({ filter: from => from >= line.from && from <= line.to });
1666
1673
  }
1667
- value = value.map(tr.changes);
1668
1674
  for (let effect of tr.effects)
1669
1675
  if (effect.is(closeBracketEffect))
1670
1676
  value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/autocomplete",
3
- "version": "6.11.0",
3
+ "version": "6.12.0",
4
4
  "description": "Autocompletion for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",