@codemirror/autocomplete 6.11.1 → 6.13.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 +20 -0
- package/dist/index.cjs +26 -4
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +27 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 6.13.0 (2024-02-29)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
Completions may now provide 'commit characters' that, when typed, commit the completion before inserting the character.
|
|
6
|
+
|
|
7
|
+
## 6.12.0 (2024-01-12)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Make sure snippet completions also set `userEvent` to `input.complete`.
|
|
12
|
+
|
|
13
|
+
Fix a crash when the editor lost focus during an update and autocompletion was active.
|
|
14
|
+
|
|
15
|
+
Fix a crash when using a snippet that has only one field, but multiple instances of that field.
|
|
16
|
+
|
|
17
|
+
### New features
|
|
18
|
+
|
|
19
|
+
The new `activateOnTypingDelay` option allows control over the debounce time before the completions are queried when the user types.
|
|
20
|
+
|
|
1
21
|
## 6.11.1 (2023-11-27)
|
|
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(),
|
|
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() {
|
|
@@ -1173,6 +1179,21 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
|
|
|
1173
1179
|
}
|
|
1174
1180
|
}
|
|
1175
1181
|
});
|
|
1182
|
+
const windows = typeof navigator == "object" && /Win/.test(navigator.platform);
|
|
1183
|
+
const commitCharacters = state.Prec.highest(view.EditorView.domEventHandlers({
|
|
1184
|
+
keydown(event, view) {
|
|
1185
|
+
let field = view.state.field(completionState, false);
|
|
1186
|
+
if (!field || !field.open || field.open.disabled || field.open.selected < 0 ||
|
|
1187
|
+
event.key.length > 1 || event.ctrlKey && !(windows && event.altKey) || event.metaKey)
|
|
1188
|
+
return false;
|
|
1189
|
+
let option = field.open.options[field.open.selected];
|
|
1190
|
+
let result = field.active.find(a => a.source == option.source);
|
|
1191
|
+
let commitChars = option.completion.commitCharacters || result.result.commitCharacters;
|
|
1192
|
+
if (commitChars && commitChars.indexOf(event.key) > -1)
|
|
1193
|
+
applyCompletion(view, option);
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
}));
|
|
1176
1197
|
|
|
1177
1198
|
const baseTheme = view.EditorView.baseTheme({
|
|
1178
1199
|
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
@@ -1465,11 +1486,11 @@ function snippet(template) {
|
|
|
1465
1486
|
let spec = {
|
|
1466
1487
|
changes: { from, to, insert: state.Text.of(text) },
|
|
1467
1488
|
scrollIntoView: true,
|
|
1468
|
-
annotations: completion ? pickedCompletion.of(completion) : undefined
|
|
1489
|
+
annotations: completion ? [pickedCompletion.of(completion), state.Transaction.userEvent.of("input.complete")] : undefined
|
|
1469
1490
|
};
|
|
1470
1491
|
if (ranges.length)
|
|
1471
1492
|
spec.selection = fieldSelection(ranges, 0);
|
|
1472
|
-
if (ranges.
|
|
1493
|
+
if (ranges.some(r => r.field > 0)) {
|
|
1473
1494
|
let active = new ActiveSnippet(ranges, 0);
|
|
1474
1495
|
let effects = spec.effects = [setActive.of(active)];
|
|
1475
1496
|
if (editor.state.field(snippetState, false) === undefined)
|
|
@@ -1894,6 +1915,7 @@ Returns an extension that enables autocompletion.
|
|
|
1894
1915
|
*/
|
|
1895
1916
|
function autocompletion(config = {}) {
|
|
1896
1917
|
return [
|
|
1918
|
+
commitCharacters,
|
|
1897
1919
|
completionState,
|
|
1898
1920
|
completionConfig.of(config),
|
|
1899
1921
|
completionPlugin,
|
package/dist/index.d.cts
CHANGED
|
@@ -54,6 +54,11 @@ interface Completion {
|
|
|
54
54
|
*/
|
|
55
55
|
type?: string;
|
|
56
56
|
/**
|
|
57
|
+
When this option is selected, and one of these characters is
|
|
58
|
+
typed, insert the completion before typing the character.
|
|
59
|
+
*/
|
|
60
|
+
commitCharacters?: readonly string[];
|
|
61
|
+
/**
|
|
57
62
|
When given, should be a number from -99 to 99 that adjusts how
|
|
58
63
|
this completion is ranked compared to other completions that
|
|
59
64
|
match the input as well as this one. A negative number moves it
|
|
@@ -255,6 +260,12 @@ interface CompletionResult {
|
|
|
255
260
|
completion still applies in the new state.
|
|
256
261
|
*/
|
|
257
262
|
update?: (current: CompletionResult, from: number, to: number, context: CompletionContext) => CompletionResult | null;
|
|
263
|
+
/**
|
|
264
|
+
Set a default set of [commit
|
|
265
|
+
characters](https://codemirror.net/6/docs/ref/#autocomplete.Completion.commitCharacters) for all
|
|
266
|
+
options in this result.
|
|
267
|
+
*/
|
|
268
|
+
commitCharacters?: readonly string[];
|
|
258
269
|
}
|
|
259
270
|
/**
|
|
260
271
|
This annotation is added to transactions that are produced by
|
|
@@ -275,6 +286,14 @@ interface CompletionConfig {
|
|
|
275
286
|
*/
|
|
276
287
|
activateOnTyping?: boolean;
|
|
277
288
|
/**
|
|
289
|
+
The amount of time to wait for further typing before querying
|
|
290
|
+
completion sources via
|
|
291
|
+
[`activateOnTyping`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.activateOnTyping).
|
|
292
|
+
Defaults to 100, which should be fine unless your completion
|
|
293
|
+
source is very slow and/or doesn't use `validFor`.
|
|
294
|
+
*/
|
|
295
|
+
activateOnTypingDelay?: number;
|
|
296
|
+
/**
|
|
278
297
|
By default, when completion opens, the first option is selected
|
|
279
298
|
and can be confirmed with
|
|
280
299
|
[`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion). When this
|
|
@@ -571,4 +590,4 @@ the currently selected completion.
|
|
|
571
590
|
*/
|
|
572
591
|
declare function setSelectedCompletion(index: number): StateEffect<unknown>;
|
|
573
592
|
|
|
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 };
|
|
593
|
+
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
|
@@ -54,6 +54,11 @@ interface Completion {
|
|
|
54
54
|
*/
|
|
55
55
|
type?: string;
|
|
56
56
|
/**
|
|
57
|
+
When this option is selected, and one of these characters is
|
|
58
|
+
typed, insert the completion before typing the character.
|
|
59
|
+
*/
|
|
60
|
+
commitCharacters?: readonly string[];
|
|
61
|
+
/**
|
|
57
62
|
When given, should be a number from -99 to 99 that adjusts how
|
|
58
63
|
this completion is ranked compared to other completions that
|
|
59
64
|
match the input as well as this one. A negative number moves it
|
|
@@ -255,6 +260,12 @@ interface CompletionResult {
|
|
|
255
260
|
completion still applies in the new state.
|
|
256
261
|
*/
|
|
257
262
|
update?: (current: CompletionResult, from: number, to: number, context: CompletionContext) => CompletionResult | null;
|
|
263
|
+
/**
|
|
264
|
+
Set a default set of [commit
|
|
265
|
+
characters](https://codemirror.net/6/docs/ref/#autocomplete.Completion.commitCharacters) for all
|
|
266
|
+
options in this result.
|
|
267
|
+
*/
|
|
268
|
+
commitCharacters?: readonly string[];
|
|
258
269
|
}
|
|
259
270
|
/**
|
|
260
271
|
This annotation is added to transactions that are produced by
|
|
@@ -275,6 +286,14 @@ interface CompletionConfig {
|
|
|
275
286
|
*/
|
|
276
287
|
activateOnTyping?: boolean;
|
|
277
288
|
/**
|
|
289
|
+
The amount of time to wait for further typing before querying
|
|
290
|
+
completion sources via
|
|
291
|
+
[`activateOnTyping`](https://codemirror.net/6/docs/ref/#autocomplete.autocompletion^config.activateOnTyping).
|
|
292
|
+
Defaults to 100, which should be fine unless your completion
|
|
293
|
+
source is very slow and/or doesn't use `validFor`.
|
|
294
|
+
*/
|
|
295
|
+
activateOnTypingDelay?: number;
|
|
296
|
+
/**
|
|
278
297
|
By default, when completion opens, the first option is selected
|
|
279
298
|
and can be confirmed with
|
|
280
299
|
[`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion). When this
|
|
@@ -571,4 +590,4 @@ the currently selected completion.
|
|
|
571
590
|
*/
|
|
572
591
|
declare function setSelectedCompletion(index: number): StateEffect<unknown>;
|
|
573
592
|
|
|
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 };
|
|
593
|
+
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(),
|
|
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() {
|
|
@@ -1171,6 +1177,21 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
1171
1177
|
}
|
|
1172
1178
|
}
|
|
1173
1179
|
});
|
|
1180
|
+
const windows = typeof navigator == "object" && /*@__PURE__*//Win/.test(navigator.platform);
|
|
1181
|
+
const commitCharacters = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.domEventHandlers({
|
|
1182
|
+
keydown(event, view) {
|
|
1183
|
+
let field = view.state.field(completionState, false);
|
|
1184
|
+
if (!field || !field.open || field.open.disabled || field.open.selected < 0 ||
|
|
1185
|
+
event.key.length > 1 || event.ctrlKey && !(windows && event.altKey) || event.metaKey)
|
|
1186
|
+
return false;
|
|
1187
|
+
let option = field.open.options[field.open.selected];
|
|
1188
|
+
let result = field.active.find(a => a.source == option.source);
|
|
1189
|
+
let commitChars = option.completion.commitCharacters || result.result.commitCharacters;
|
|
1190
|
+
if (commitChars && commitChars.indexOf(event.key) > -1)
|
|
1191
|
+
applyCompletion(view, option);
|
|
1192
|
+
return false;
|
|
1193
|
+
}
|
|
1194
|
+
}));
|
|
1174
1195
|
|
|
1175
1196
|
const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
1176
1197
|
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
@@ -1463,11 +1484,11 @@ function snippet(template) {
|
|
|
1463
1484
|
let spec = {
|
|
1464
1485
|
changes: { from, to, insert: Text.of(text) },
|
|
1465
1486
|
scrollIntoView: true,
|
|
1466
|
-
annotations: completion ? pickedCompletion.of(completion) : undefined
|
|
1487
|
+
annotations: completion ? [pickedCompletion.of(completion), Transaction.userEvent.of("input.complete")] : undefined
|
|
1467
1488
|
};
|
|
1468
1489
|
if (ranges.length)
|
|
1469
1490
|
spec.selection = fieldSelection(ranges, 0);
|
|
1470
|
-
if (ranges.
|
|
1491
|
+
if (ranges.some(r => r.field > 0)) {
|
|
1471
1492
|
let active = new ActiveSnippet(ranges, 0);
|
|
1472
1493
|
let effects = spec.effects = [setActive.of(active)];
|
|
1473
1494
|
if (editor.state.field(snippetState, false) === undefined)
|
|
@@ -1892,6 +1913,7 @@ Returns an extension that enables autocompletion.
|
|
|
1892
1913
|
*/
|
|
1893
1914
|
function autocompletion(config = {}) {
|
|
1894
1915
|
return [
|
|
1916
|
+
commitCharacters,
|
|
1895
1917
|
completionState,
|
|
1896
1918
|
completionConfig.of(config),
|
|
1897
1919
|
completionPlugin,
|