@codemirror/autocomplete 6.3.4 → 6.4.1
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 +18 -0
- package/LICENSE +1 -1
- package/dist/index.cjs +39 -10
- package/dist/index.d.ts +5 -0
- package/dist/index.js +39 -10
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## 6.4.1 (2023-02-14)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Don't consider node names in trees that aren't the same language as the one at the completion position in `ifIn` and `ifNotIn`.
|
|
6
|
+
|
|
7
|
+
Make sure completions that exactly match the input get a higher score than those that don't (so that even if the latter has a score boost, it ends up lower in the list).
|
|
8
|
+
|
|
9
|
+
## 6.4.0 (2022-12-14)
|
|
10
|
+
|
|
11
|
+
### Bug fixes
|
|
12
|
+
|
|
13
|
+
Fix an issue where the extension would sometimes try to draw a disabled dialog at an outdated position, leading to plugin crashes.
|
|
14
|
+
|
|
15
|
+
### New features
|
|
16
|
+
|
|
17
|
+
A `tooltipClass` option to autocompletion can now be used to add additional CSS classes to the completion tooltip.
|
|
18
|
+
|
|
1
19
|
## 6.3.4 (2022-11-24)
|
|
2
20
|
|
|
3
21
|
### Bug fixes
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (C) 2018-2021 by Marijn Haverbeke <
|
|
3
|
+
Copyright (C) 2018-2021 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/dist/index.cjs
CHANGED
|
@@ -112,9 +112,12 @@ cursor is in a syntax node with one of the given names.
|
|
|
112
112
|
*/
|
|
113
113
|
function ifIn(nodes, source) {
|
|
114
114
|
return (context) => {
|
|
115
|
-
for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent)
|
|
115
|
+
for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
|
|
116
116
|
if (nodes.indexOf(pos.name) > -1)
|
|
117
117
|
return source(context);
|
|
118
|
+
if (pos.type.isTop)
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
118
121
|
return null;
|
|
119
122
|
};
|
|
120
123
|
}
|
|
@@ -124,9 +127,12 @@ cursor is in a syntax node with one of the given names.
|
|
|
124
127
|
*/
|
|
125
128
|
function ifNotIn(nodes, source) {
|
|
126
129
|
return (context) => {
|
|
127
|
-
for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent)
|
|
130
|
+
for (let pos = language.syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
|
|
128
131
|
if (nodes.indexOf(pos.name) > -1)
|
|
129
132
|
return null;
|
|
133
|
+
if (pos.type.isTop)
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
130
136
|
return source(context);
|
|
131
137
|
};
|
|
132
138
|
}
|
|
@@ -231,13 +237,18 @@ class FuzzyMatcher {
|
|
|
231
237
|
// For single-character queries, only match when they occur right
|
|
232
238
|
// at the start
|
|
233
239
|
if (chars.length == 1) {
|
|
234
|
-
let first = state.codePointAt(word, 0);
|
|
235
|
-
|
|
236
|
-
|
|
240
|
+
let first = state.codePointAt(word, 0), firstSize = state.codePointSize(first);
|
|
241
|
+
let score = firstSize == word.length ? 0 : -100 /* Penalty.NotFull */;
|
|
242
|
+
if (first == chars[0]) ;
|
|
243
|
+
else if (first == folded[0])
|
|
244
|
+
score += -200 /* Penalty.CaseFold */;
|
|
245
|
+
else
|
|
246
|
+
return null;
|
|
247
|
+
return [score, 0, firstSize];
|
|
237
248
|
}
|
|
238
249
|
let direct = word.indexOf(this.pattern);
|
|
239
250
|
if (direct == 0)
|
|
240
|
-
return [0
|
|
251
|
+
return [word.length == this.pattern.length ? 0 : -100 /* Penalty.NotFull */, 0, this.pattern.length];
|
|
241
252
|
let len = chars.length, anyTo = 0;
|
|
242
253
|
if (direct < 0) {
|
|
243
254
|
for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) {
|
|
@@ -293,7 +304,7 @@ class FuzzyMatcher {
|
|
|
293
304
|
if (byWordTo == len && byWord[0] == 0 && wordAdjacent)
|
|
294
305
|
return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word);
|
|
295
306
|
if (adjacentTo == len && adjacentStart == 0)
|
|
296
|
-
return [-200 /* Penalty.CaseFold */ - word.length, 0, adjacentEnd];
|
|
307
|
+
return [-200 /* Penalty.CaseFold */ - word.length + (adjacentEnd == word.length ? 0 : -100 /* Penalty.NotFull */), 0, adjacentEnd];
|
|
297
308
|
if (direct > -1)
|
|
298
309
|
return [-700 /* Penalty.NotStart */ - word.length, direct, direct + this.pattern.length];
|
|
299
310
|
if (adjacentTo == len)
|
|
@@ -327,6 +338,7 @@ const completionConfig = state.Facet.define({
|
|
|
327
338
|
closeOnBlur: true,
|
|
328
339
|
maxRenderedOptions: 100,
|
|
329
340
|
defaultKeymap: true,
|
|
341
|
+
tooltipClass: () => "",
|
|
330
342
|
optionClass: () => "",
|
|
331
343
|
aboveCursor: false,
|
|
332
344
|
icons: true,
|
|
@@ -337,6 +349,7 @@ const completionConfig = state.Facet.define({
|
|
|
337
349
|
defaultKeymap: (a, b) => a && b,
|
|
338
350
|
closeOnBlur: (a, b) => a && b,
|
|
339
351
|
icons: (a, b) => a && b,
|
|
352
|
+
tooltipClass: (a, b) => c => joinClass(a(c), b(c)),
|
|
340
353
|
optionClass: (a, b) => c => joinClass(a(c), b(c)),
|
|
341
354
|
addToOptions: (a, b) => a.concat(b)
|
|
342
355
|
});
|
|
@@ -415,14 +428,17 @@ class CompletionTooltip {
|
|
|
415
428
|
key: this
|
|
416
429
|
};
|
|
417
430
|
this.space = null;
|
|
431
|
+
this.currentClass = "";
|
|
418
432
|
let cState = view.state.field(stateField);
|
|
419
433
|
let { options, selected } = cState.open;
|
|
420
434
|
let config = view.state.facet(completionConfig);
|
|
421
435
|
this.optionContent = optionContent(config);
|
|
422
436
|
this.optionClass = config.optionClass;
|
|
437
|
+
this.tooltipClass = config.tooltipClass;
|
|
423
438
|
this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions);
|
|
424
439
|
this.dom = document.createElement("div");
|
|
425
440
|
this.dom.className = "cm-tooltip-autocomplete";
|
|
441
|
+
this.updateTooltipClass(view.state);
|
|
426
442
|
this.dom.addEventListener("mousedown", (e) => {
|
|
427
443
|
for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) {
|
|
428
444
|
if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) {
|
|
@@ -443,12 +459,25 @@ class CompletionTooltip {
|
|
|
443
459
|
var _a, _b, _c;
|
|
444
460
|
let cState = update.state.field(this.stateField);
|
|
445
461
|
let prevState = update.startState.field(this.stateField);
|
|
462
|
+
this.updateTooltipClass(update.state);
|
|
446
463
|
if (cState != prevState) {
|
|
447
464
|
this.updateSel();
|
|
448
465
|
if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled))
|
|
449
466
|
this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled));
|
|
450
467
|
}
|
|
451
468
|
}
|
|
469
|
+
updateTooltipClass(state) {
|
|
470
|
+
let cls = this.tooltipClass(state);
|
|
471
|
+
if (cls != this.currentClass) {
|
|
472
|
+
for (let c of this.currentClass.split(" "))
|
|
473
|
+
if (c)
|
|
474
|
+
this.dom.classList.remove(c);
|
|
475
|
+
for (let c of cls.split(" "))
|
|
476
|
+
if (c)
|
|
477
|
+
this.dom.classList.add(c);
|
|
478
|
+
this.currentClass = cls;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
452
481
|
positioned(space) {
|
|
453
482
|
this.space = space;
|
|
454
483
|
if (this.info)
|
|
@@ -709,13 +738,13 @@ class CompletionState {
|
|
|
709
738
|
if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
|
|
710
739
|
active = this.active;
|
|
711
740
|
let open = this.open;
|
|
741
|
+
if (open && tr.docChanged)
|
|
742
|
+
open = open.map(tr.changes);
|
|
712
743
|
if (tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
|
|
713
744
|
!sameResults(active, this.active))
|
|
714
|
-
open = CompletionDialog.build(active, state, this.id,
|
|
745
|
+
open = CompletionDialog.build(active, state, this.id, open, conf);
|
|
715
746
|
else if (open && open.disabled && !active.some(a => a.state == 1 /* State.Pending */))
|
|
716
747
|
open = null;
|
|
717
|
-
else if (open && tr.docChanged)
|
|
718
|
-
open = open.map(tr.changes);
|
|
719
748
|
if (!open && active.every(a => a.state != 1 /* State.Pending */) && active.some(a => a.hasResult()))
|
|
720
749
|
active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a);
|
|
721
750
|
for (let effect of tr.effects)
|
package/dist/index.d.ts
CHANGED
|
@@ -50,6 +50,11 @@ interface CompletionConfig {
|
|
|
50
50
|
*/
|
|
51
51
|
aboveCursor?: boolean;
|
|
52
52
|
/**
|
|
53
|
+
When given, this may return an additional CSS class to add to
|
|
54
|
+
the completion dialog element.
|
|
55
|
+
*/
|
|
56
|
+
tooltipClass?: (state: EditorState) => string;
|
|
57
|
+
/**
|
|
53
58
|
This can be used to add additional CSS classes to completion
|
|
54
59
|
options.
|
|
55
60
|
*/
|
package/dist/index.js
CHANGED
|
@@ -108,9 +108,12 @@ cursor is in a syntax node with one of the given names.
|
|
|
108
108
|
*/
|
|
109
109
|
function ifIn(nodes, source) {
|
|
110
110
|
return (context) => {
|
|
111
|
-
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent)
|
|
111
|
+
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
|
|
112
112
|
if (nodes.indexOf(pos.name) > -1)
|
|
113
113
|
return source(context);
|
|
114
|
+
if (pos.type.isTop)
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
114
117
|
return null;
|
|
115
118
|
};
|
|
116
119
|
}
|
|
@@ -120,9 +123,12 @@ cursor is in a syntax node with one of the given names.
|
|
|
120
123
|
*/
|
|
121
124
|
function ifNotIn(nodes, source) {
|
|
122
125
|
return (context) => {
|
|
123
|
-
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent)
|
|
126
|
+
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
|
|
124
127
|
if (nodes.indexOf(pos.name) > -1)
|
|
125
128
|
return null;
|
|
129
|
+
if (pos.type.isTop)
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
126
132
|
return source(context);
|
|
127
133
|
};
|
|
128
134
|
}
|
|
@@ -227,13 +233,18 @@ class FuzzyMatcher {
|
|
|
227
233
|
// For single-character queries, only match when they occur right
|
|
228
234
|
// at the start
|
|
229
235
|
if (chars.length == 1) {
|
|
230
|
-
let first = codePointAt(word, 0);
|
|
231
|
-
|
|
232
|
-
|
|
236
|
+
let first = codePointAt(word, 0), firstSize = codePointSize(first);
|
|
237
|
+
let score = firstSize == word.length ? 0 : -100 /* Penalty.NotFull */;
|
|
238
|
+
if (first == chars[0]) ;
|
|
239
|
+
else if (first == folded[0])
|
|
240
|
+
score += -200 /* Penalty.CaseFold */;
|
|
241
|
+
else
|
|
242
|
+
return null;
|
|
243
|
+
return [score, 0, firstSize];
|
|
233
244
|
}
|
|
234
245
|
let direct = word.indexOf(this.pattern);
|
|
235
246
|
if (direct == 0)
|
|
236
|
-
return [0
|
|
247
|
+
return [word.length == this.pattern.length ? 0 : -100 /* Penalty.NotFull */, 0, this.pattern.length];
|
|
237
248
|
let len = chars.length, anyTo = 0;
|
|
238
249
|
if (direct < 0) {
|
|
239
250
|
for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) {
|
|
@@ -289,7 +300,7 @@ class FuzzyMatcher {
|
|
|
289
300
|
if (byWordTo == len && byWord[0] == 0 && wordAdjacent)
|
|
290
301
|
return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word);
|
|
291
302
|
if (adjacentTo == len && adjacentStart == 0)
|
|
292
|
-
return [-200 /* Penalty.CaseFold */ - word.length, 0, adjacentEnd];
|
|
303
|
+
return [-200 /* Penalty.CaseFold */ - word.length + (adjacentEnd == word.length ? 0 : -100 /* Penalty.NotFull */), 0, adjacentEnd];
|
|
293
304
|
if (direct > -1)
|
|
294
305
|
return [-700 /* Penalty.NotStart */ - word.length, direct, direct + this.pattern.length];
|
|
295
306
|
if (adjacentTo == len)
|
|
@@ -323,6 +334,7 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|
|
323
334
|
closeOnBlur: true,
|
|
324
335
|
maxRenderedOptions: 100,
|
|
325
336
|
defaultKeymap: true,
|
|
337
|
+
tooltipClass: () => "",
|
|
326
338
|
optionClass: () => "",
|
|
327
339
|
aboveCursor: false,
|
|
328
340
|
icons: true,
|
|
@@ -333,6 +345,7 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|
|
333
345
|
defaultKeymap: (a, b) => a && b,
|
|
334
346
|
closeOnBlur: (a, b) => a && b,
|
|
335
347
|
icons: (a, b) => a && b,
|
|
348
|
+
tooltipClass: (a, b) => c => joinClass(a(c), b(c)),
|
|
336
349
|
optionClass: (a, b) => c => joinClass(a(c), b(c)),
|
|
337
350
|
addToOptions: (a, b) => a.concat(b)
|
|
338
351
|
});
|
|
@@ -411,14 +424,17 @@ class CompletionTooltip {
|
|
|
411
424
|
key: this
|
|
412
425
|
};
|
|
413
426
|
this.space = null;
|
|
427
|
+
this.currentClass = "";
|
|
414
428
|
let cState = view.state.field(stateField);
|
|
415
429
|
let { options, selected } = cState.open;
|
|
416
430
|
let config = view.state.facet(completionConfig);
|
|
417
431
|
this.optionContent = optionContent(config);
|
|
418
432
|
this.optionClass = config.optionClass;
|
|
433
|
+
this.tooltipClass = config.tooltipClass;
|
|
419
434
|
this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions);
|
|
420
435
|
this.dom = document.createElement("div");
|
|
421
436
|
this.dom.className = "cm-tooltip-autocomplete";
|
|
437
|
+
this.updateTooltipClass(view.state);
|
|
422
438
|
this.dom.addEventListener("mousedown", (e) => {
|
|
423
439
|
for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) {
|
|
424
440
|
if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) {
|
|
@@ -439,12 +455,25 @@ class CompletionTooltip {
|
|
|
439
455
|
var _a, _b, _c;
|
|
440
456
|
let cState = update.state.field(this.stateField);
|
|
441
457
|
let prevState = update.startState.field(this.stateField);
|
|
458
|
+
this.updateTooltipClass(update.state);
|
|
442
459
|
if (cState != prevState) {
|
|
443
460
|
this.updateSel();
|
|
444
461
|
if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled))
|
|
445
462
|
this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled));
|
|
446
463
|
}
|
|
447
464
|
}
|
|
465
|
+
updateTooltipClass(state) {
|
|
466
|
+
let cls = this.tooltipClass(state);
|
|
467
|
+
if (cls != this.currentClass) {
|
|
468
|
+
for (let c of this.currentClass.split(" "))
|
|
469
|
+
if (c)
|
|
470
|
+
this.dom.classList.remove(c);
|
|
471
|
+
for (let c of cls.split(" "))
|
|
472
|
+
if (c)
|
|
473
|
+
this.dom.classList.add(c);
|
|
474
|
+
this.currentClass = cls;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
448
477
|
positioned(space) {
|
|
449
478
|
this.space = space;
|
|
450
479
|
if (this.info)
|
|
@@ -705,13 +734,13 @@ class CompletionState {
|
|
|
705
734
|
if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
|
|
706
735
|
active = this.active;
|
|
707
736
|
let open = this.open;
|
|
737
|
+
if (open && tr.docChanged)
|
|
738
|
+
open = open.map(tr.changes);
|
|
708
739
|
if (tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
|
|
709
740
|
!sameResults(active, this.active))
|
|
710
|
-
open = CompletionDialog.build(active, state, this.id,
|
|
741
|
+
open = CompletionDialog.build(active, state, this.id, open, conf);
|
|
711
742
|
else if (open && open.disabled && !active.some(a => a.state == 1 /* State.Pending */))
|
|
712
743
|
open = null;
|
|
713
|
-
else if (open && tr.docChanged)
|
|
714
|
-
open = open.map(tr.changes);
|
|
715
744
|
if (!open && active.every(a => a.state != 1 /* State.Pending */) && active.some(a => a.hasResult()))
|
|
716
745
|
active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a);
|
|
717
746
|
for (let effect of tr.effects)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/autocomplete",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.1",
|
|
4
4
|
"description": "Autocompletion for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Marijn Haverbeke",
|
|
15
|
-
"email": "
|
|
15
|
+
"email": "marijn@haverbeke.berlin",
|
|
16
16
|
"url": "http://marijnhaverbeke.nl"
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|