@codemirror/autocomplete 6.0.2 → 6.1.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 +27 -17
- package/dist/index.d.ts +15 -0
- package/dist/index.js +27 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 6.1.0 (2022-07-19)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
You can now provide a `compareCompletions` option to autocompletion to influence the way completions with the same match score are sorted.
|
|
6
|
+
|
|
7
|
+
The `selectOnOpen` option to autocompletion can be used to require explicitly selecting a completion option before `acceptCompletion` does anything.
|
|
8
|
+
|
|
9
|
+
## 6.0.4 (2022-07-07)
|
|
10
|
+
|
|
11
|
+
### Bug fixes
|
|
12
|
+
|
|
13
|
+
Remove a leftover `console.log` in bracket closing code.
|
|
14
|
+
|
|
15
|
+
## 6.0.3 (2022-07-04)
|
|
16
|
+
|
|
17
|
+
### Bug fixes
|
|
18
|
+
|
|
19
|
+
Fix a bug that caused `closeBrackets` to not close quotes when at the end of a syntactic construct that starts with a similar quote.
|
|
20
|
+
|
|
1
21
|
## 6.0.2 (2022-06-15)
|
|
2
22
|
|
|
3
23
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -322,6 +322,7 @@ const completionConfig = state.Facet.define({
|
|
|
322
322
|
combine(configs) {
|
|
323
323
|
return state.combineConfig(configs, {
|
|
324
324
|
activateOnTyping: true,
|
|
325
|
+
selectOnOpen: true,
|
|
325
326
|
override: null,
|
|
326
327
|
closeOnBlur: true,
|
|
327
328
|
maxRenderedOptions: 100,
|
|
@@ -329,7 +330,8 @@ const completionConfig = state.Facet.define({
|
|
|
329
330
|
optionClass: () => "",
|
|
330
331
|
aboveCursor: false,
|
|
331
332
|
icons: true,
|
|
332
|
-
addToOptions: []
|
|
333
|
+
addToOptions: [],
|
|
334
|
+
compareCompletions: (a, b) => a.label.localeCompare(b.label)
|
|
333
335
|
}, {
|
|
334
336
|
defaultKeymap: (a, b) => a && b,
|
|
335
337
|
closeOnBlur: (a, b) => a && b,
|
|
@@ -392,6 +394,8 @@ function optionContent(config) {
|
|
|
392
394
|
function rangeAroundSelected(total, selected, max) {
|
|
393
395
|
if (total <= max)
|
|
394
396
|
return { from: 0, to: total };
|
|
397
|
+
if (selected < 0)
|
|
398
|
+
selected = 0;
|
|
395
399
|
if (selected <= (total >> 1)) {
|
|
396
400
|
let off = Math.floor(selected / max);
|
|
397
401
|
return { from: off * max, to: (off + 1) * max };
|
|
@@ -599,7 +603,8 @@ function sortOptions(active, state) {
|
|
|
599
603
|
}
|
|
600
604
|
}
|
|
601
605
|
let result = [], prev = null;
|
|
602
|
-
|
|
606
|
+
let compare = state.facet(completionConfig).compareCompletions;
|
|
607
|
+
for (let opt of options.sort((a, b) => (b.match[0] - a.match[0]) || compare(a.completion, b.completion))) {
|
|
603
608
|
if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail ||
|
|
604
609
|
(prev.type != null && opt.completion.type != null && prev.type != opt.completion.type) ||
|
|
605
610
|
prev.apply != opt.completion.apply)
|
|
@@ -626,8 +631,8 @@ class CompletionDialog {
|
|
|
626
631
|
let options = sortOptions(active, state);
|
|
627
632
|
if (!options.length)
|
|
628
633
|
return null;
|
|
629
|
-
let selected = 0;
|
|
630
|
-
if (prev && prev.selected) {
|
|
634
|
+
let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
|
|
635
|
+
if (prev && prev.selected != selected && prev.selected != -1) {
|
|
631
636
|
let selectedValue = prev.options[prev.selected].completion;
|
|
632
637
|
for (let i = 0; i < options.length; i++)
|
|
633
638
|
if (options[i].completion == selectedValue) {
|
|
@@ -697,20 +702,16 @@ const baseAttrs = {
|
|
|
697
702
|
"aria-autocomplete": "list"
|
|
698
703
|
};
|
|
699
704
|
function makeAttrs(id, selected) {
|
|
700
|
-
|
|
705
|
+
let result = {
|
|
701
706
|
"aria-autocomplete": "list",
|
|
702
707
|
"aria-haspopup": "listbox",
|
|
703
|
-
"aria-activedescendant": id + "-" + selected,
|
|
704
708
|
"aria-controls": id
|
|
705
709
|
};
|
|
710
|
+
if (selected > -1)
|
|
711
|
+
result["aria-activedescendant"] = id + "-" + selected;
|
|
712
|
+
return result;
|
|
706
713
|
}
|
|
707
714
|
const none = [];
|
|
708
|
-
function cmpOption(a, b) {
|
|
709
|
-
let dScore = b.match[0] - a.match[0];
|
|
710
|
-
if (dScore)
|
|
711
|
-
return dScore;
|
|
712
|
-
return a.completion.label.localeCompare(b.completion.label);
|
|
713
|
-
}
|
|
714
715
|
function getUserEvent(tr) {
|
|
715
716
|
return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null;
|
|
716
717
|
}
|
|
@@ -818,7 +819,8 @@ function moveCompletionSelection(forward, by = "option") {
|
|
|
818
819
|
if (by == "page" && (tooltip = view.getTooltip(view$1, cState.open.tooltip)))
|
|
819
820
|
step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
|
|
820
821
|
tooltip.dom.querySelector("li").offsetHeight) - 1);
|
|
821
|
-
let
|
|
822
|
+
let { length } = cState.open.options;
|
|
823
|
+
let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
|
|
822
824
|
if (selected < 0)
|
|
823
825
|
selected = by == "page" ? 0 : length - 1;
|
|
824
826
|
else if (selected >= length)
|
|
@@ -832,7 +834,8 @@ Accept the current completion.
|
|
|
832
834
|
*/
|
|
833
835
|
const acceptCompletion = (view) => {
|
|
834
836
|
let cState = view.state.field(completionState, false);
|
|
835
|
-
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin
|
|
837
|
+
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin ||
|
|
838
|
+
cState.open.selected < 0)
|
|
836
839
|
return false;
|
|
837
840
|
applyCompletion(view, cState.open.options[cState.open.selected]);
|
|
838
841
|
return true;
|
|
@@ -1664,8 +1667,15 @@ function nodeStart(state, pos) {
|
|
|
1664
1667
|
function probablyInString(state, pos, quoteToken) {
|
|
1665
1668
|
let node = language.syntaxTree(state).resolveInner(pos, -1);
|
|
1666
1669
|
for (let i = 0; i < 5; i++) {
|
|
1667
|
-
if (state.sliceDoc(node.from, node.from + quoteToken.length) == quoteToken)
|
|
1670
|
+
if (state.sliceDoc(node.from, node.from + quoteToken.length) == quoteToken) {
|
|
1671
|
+
let first = node.firstChild;
|
|
1672
|
+
while (first && first.from == node.from && first.to - first.from > quoteToken.length) {
|
|
1673
|
+
if (state.sliceDoc(first.to - quoteToken.length, first.to) == quoteToken)
|
|
1674
|
+
return false;
|
|
1675
|
+
first = first.firstChild;
|
|
1676
|
+
}
|
|
1668
1677
|
return true;
|
|
1678
|
+
}
|
|
1669
1679
|
let parent = node.to == pos && node.parent;
|
|
1670
1680
|
if (!parent)
|
|
1671
1681
|
break;
|
|
@@ -1738,7 +1748,7 @@ Return the currently selected completion, if any.
|
|
|
1738
1748
|
function selectedCompletion(state) {
|
|
1739
1749
|
var _a;
|
|
1740
1750
|
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1741
|
-
return open ? open.options[open.selected].completion : null;
|
|
1751
|
+
return open && open.selected >= 0 ? open.options[open.selected].completion : null;
|
|
1742
1752
|
}
|
|
1743
1753
|
/**
|
|
1744
1754
|
Returns the currently selected position in the active completion
|
|
@@ -1747,7 +1757,7 @@ list, or null if no completions are active.
|
|
|
1747
1757
|
function selectedCompletionIndex(state) {
|
|
1748
1758
|
var _a;
|
|
1749
1759
|
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1750
|
-
return open ? open.selected : null;
|
|
1760
|
+
return open && open.selected >= 0 ? open.selected : null;
|
|
1751
1761
|
}
|
|
1752
1762
|
/**
|
|
1753
1763
|
Create an effect that can be attached to a transaction to change
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ interface CompletionConfig {
|
|
|
10
10
|
*/
|
|
11
11
|
activateOnTyping?: boolean;
|
|
12
12
|
/**
|
|
13
|
+
By default, when completion opens, the first option is selected
|
|
14
|
+
and can be confirmed with
|
|
15
|
+
[`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion). When this
|
|
16
|
+
is set to false, the completion widget starts with no completion
|
|
17
|
+
selected, and the user has to explicitly move to a completion
|
|
18
|
+
before you can confirm one.
|
|
19
|
+
*/
|
|
20
|
+
selectOnOpen?: boolean;
|
|
21
|
+
/**
|
|
13
22
|
Override the completion sources used. By default, they will be
|
|
14
23
|
taken from the `"autocomplete"` [language
|
|
15
24
|
data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) (which should hold
|
|
@@ -63,6 +72,12 @@ interface CompletionConfig {
|
|
|
63
72
|
render: (completion: Completion, state: EditorState) => Node | null;
|
|
64
73
|
position: number;
|
|
65
74
|
}[];
|
|
75
|
+
/**
|
|
76
|
+
The comparison function to use when sorting completions with the same
|
|
77
|
+
match score. Defaults to using
|
|
78
|
+
[`localeCompare`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare).
|
|
79
|
+
*/
|
|
80
|
+
compareCompletions?: (a: Completion, b: Completion) => number;
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
/**
|
package/dist/index.js
CHANGED
|
@@ -318,6 +318,7 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|
|
318
318
|
combine(configs) {
|
|
319
319
|
return combineConfig(configs, {
|
|
320
320
|
activateOnTyping: true,
|
|
321
|
+
selectOnOpen: true,
|
|
321
322
|
override: null,
|
|
322
323
|
closeOnBlur: true,
|
|
323
324
|
maxRenderedOptions: 100,
|
|
@@ -325,7 +326,8 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|
|
325
326
|
optionClass: () => "",
|
|
326
327
|
aboveCursor: false,
|
|
327
328
|
icons: true,
|
|
328
|
-
addToOptions: []
|
|
329
|
+
addToOptions: [],
|
|
330
|
+
compareCompletions: (a, b) => a.label.localeCompare(b.label)
|
|
329
331
|
}, {
|
|
330
332
|
defaultKeymap: (a, b) => a && b,
|
|
331
333
|
closeOnBlur: (a, b) => a && b,
|
|
@@ -388,6 +390,8 @@ function optionContent(config) {
|
|
|
388
390
|
function rangeAroundSelected(total, selected, max) {
|
|
389
391
|
if (total <= max)
|
|
390
392
|
return { from: 0, to: total };
|
|
393
|
+
if (selected < 0)
|
|
394
|
+
selected = 0;
|
|
391
395
|
if (selected <= (total >> 1)) {
|
|
392
396
|
let off = Math.floor(selected / max);
|
|
393
397
|
return { from: off * max, to: (off + 1) * max };
|
|
@@ -595,7 +599,8 @@ function sortOptions(active, state) {
|
|
|
595
599
|
}
|
|
596
600
|
}
|
|
597
601
|
let result = [], prev = null;
|
|
598
|
-
|
|
602
|
+
let compare = state.facet(completionConfig).compareCompletions;
|
|
603
|
+
for (let opt of options.sort((a, b) => (b.match[0] - a.match[0]) || compare(a.completion, b.completion))) {
|
|
599
604
|
if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail ||
|
|
600
605
|
(prev.type != null && opt.completion.type != null && prev.type != opt.completion.type) ||
|
|
601
606
|
prev.apply != opt.completion.apply)
|
|
@@ -622,8 +627,8 @@ class CompletionDialog {
|
|
|
622
627
|
let options = sortOptions(active, state);
|
|
623
628
|
if (!options.length)
|
|
624
629
|
return null;
|
|
625
|
-
let selected = 0;
|
|
626
|
-
if (prev && prev.selected) {
|
|
630
|
+
let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
|
|
631
|
+
if (prev && prev.selected != selected && prev.selected != -1) {
|
|
627
632
|
let selectedValue = prev.options[prev.selected].completion;
|
|
628
633
|
for (let i = 0; i < options.length; i++)
|
|
629
634
|
if (options[i].completion == selectedValue) {
|
|
@@ -693,20 +698,16 @@ const baseAttrs = {
|
|
|
693
698
|
"aria-autocomplete": "list"
|
|
694
699
|
};
|
|
695
700
|
function makeAttrs(id, selected) {
|
|
696
|
-
|
|
701
|
+
let result = {
|
|
697
702
|
"aria-autocomplete": "list",
|
|
698
703
|
"aria-haspopup": "listbox",
|
|
699
|
-
"aria-activedescendant": id + "-" + selected,
|
|
700
704
|
"aria-controls": id
|
|
701
705
|
};
|
|
706
|
+
if (selected > -1)
|
|
707
|
+
result["aria-activedescendant"] = id + "-" + selected;
|
|
708
|
+
return result;
|
|
702
709
|
}
|
|
703
710
|
const none = [];
|
|
704
|
-
function cmpOption(a, b) {
|
|
705
|
-
let dScore = b.match[0] - a.match[0];
|
|
706
|
-
if (dScore)
|
|
707
|
-
return dScore;
|
|
708
|
-
return a.completion.label.localeCompare(b.completion.label);
|
|
709
|
-
}
|
|
710
711
|
function getUserEvent(tr) {
|
|
711
712
|
return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null;
|
|
712
713
|
}
|
|
@@ -814,7 +815,8 @@ function moveCompletionSelection(forward, by = "option") {
|
|
|
814
815
|
if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip)))
|
|
815
816
|
step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
|
|
816
817
|
tooltip.dom.querySelector("li").offsetHeight) - 1);
|
|
817
|
-
let
|
|
818
|
+
let { length } = cState.open.options;
|
|
819
|
+
let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
|
|
818
820
|
if (selected < 0)
|
|
819
821
|
selected = by == "page" ? 0 : length - 1;
|
|
820
822
|
else if (selected >= length)
|
|
@@ -828,7 +830,8 @@ Accept the current completion.
|
|
|
828
830
|
*/
|
|
829
831
|
const acceptCompletion = (view) => {
|
|
830
832
|
let cState = view.state.field(completionState, false);
|
|
831
|
-
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin
|
|
833
|
+
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin ||
|
|
834
|
+
cState.open.selected < 0)
|
|
832
835
|
return false;
|
|
833
836
|
applyCompletion(view, cState.open.options[cState.open.selected]);
|
|
834
837
|
return true;
|
|
@@ -1660,8 +1663,15 @@ function nodeStart(state, pos) {
|
|
|
1660
1663
|
function probablyInString(state, pos, quoteToken) {
|
|
1661
1664
|
let node = syntaxTree(state).resolveInner(pos, -1);
|
|
1662
1665
|
for (let i = 0; i < 5; i++) {
|
|
1663
|
-
if (state.sliceDoc(node.from, node.from + quoteToken.length) == quoteToken)
|
|
1666
|
+
if (state.sliceDoc(node.from, node.from + quoteToken.length) == quoteToken) {
|
|
1667
|
+
let first = node.firstChild;
|
|
1668
|
+
while (first && first.from == node.from && first.to - first.from > quoteToken.length) {
|
|
1669
|
+
if (state.sliceDoc(first.to - quoteToken.length, first.to) == quoteToken)
|
|
1670
|
+
return false;
|
|
1671
|
+
first = first.firstChild;
|
|
1672
|
+
}
|
|
1664
1673
|
return true;
|
|
1674
|
+
}
|
|
1665
1675
|
let parent = node.to == pos && node.parent;
|
|
1666
1676
|
if (!parent)
|
|
1667
1677
|
break;
|
|
@@ -1734,7 +1744,7 @@ Return the currently selected completion, if any.
|
|
|
1734
1744
|
function selectedCompletion(state) {
|
|
1735
1745
|
var _a;
|
|
1736
1746
|
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1737
|
-
return open ? open.options[open.selected].completion : null;
|
|
1747
|
+
return open && open.selected >= 0 ? open.options[open.selected].completion : null;
|
|
1738
1748
|
}
|
|
1739
1749
|
/**
|
|
1740
1750
|
Returns the currently selected position in the active completion
|
|
@@ -1743,7 +1753,7 @@ list, or null if no completions are active.
|
|
|
1743
1753
|
function selectedCompletionIndex(state) {
|
|
1744
1754
|
var _a;
|
|
1745
1755
|
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1746
|
-
return open ? open.selected : null;
|
|
1756
|
+
return open && open.selected >= 0 ? open.selected : null;
|
|
1747
1757
|
}
|
|
1748
1758
|
/**
|
|
1749
1759
|
Create an effect that can be attached to a transaction to change
|