@codemirror/autocomplete 0.19.1 → 0.19.5
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 +42 -0
- package/dist/index.cjs +285 -186
- package/dist/index.d.ts +41 -4
- package/dist/index.js +286 -189
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Facet, combineConfig, StateEffect, StateField,
|
|
2
|
-
import {
|
|
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';
|
|
3
3
|
import { showTooltip } from '@codemirror/tooltip';
|
|
4
4
|
import { syntaxTree, indentUnit } from '@codemirror/language';
|
|
5
5
|
import { codePointAt, codePointSize, fromCodePoint } from '@codemirror/text';
|
|
@@ -146,6 +146,11 @@ function ensureAnchor(expr, start) {
|
|
|
146
146
|
return expr;
|
|
147
147
|
return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : (expr.ignoreCase ? "i" : ""));
|
|
148
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
This annotation is added to transactions that are produced by
|
|
151
|
+
picking a completion.
|
|
152
|
+
*/
|
|
153
|
+
const pickedCompletion = /*@__PURE__*/Annotation.define();
|
|
149
154
|
function applyCompletion(view, option) {
|
|
150
155
|
let apply = option.completion.apply || option.completion.label;
|
|
151
156
|
let result = option.source;
|
|
@@ -153,7 +158,8 @@ function applyCompletion(view, option) {
|
|
|
153
158
|
view.dispatch({
|
|
154
159
|
changes: { from: result.from, to: result.to, insert: apply },
|
|
155
160
|
selection: { anchor: result.from + apply.length },
|
|
156
|
-
userEvent: "input.complete"
|
|
161
|
+
userEvent: "input.complete",
|
|
162
|
+
annotations: pickedCompletion.of(option.completion)
|
|
157
163
|
});
|
|
158
164
|
}
|
|
159
165
|
else {
|
|
@@ -247,7 +253,7 @@ class FuzzyMatcher {
|
|
|
247
253
|
if (next == chars[adjacentTo] || next == folded[adjacentTo]) {
|
|
248
254
|
if (adjacentTo == 0)
|
|
249
255
|
adjacentStart = i;
|
|
250
|
-
adjacentEnd = i;
|
|
256
|
+
adjacentEnd = i + 1;
|
|
251
257
|
adjacentTo++;
|
|
252
258
|
}
|
|
253
259
|
else {
|
|
@@ -297,152 +303,67 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|
|
297
303
|
activateOnTyping: true,
|
|
298
304
|
override: null,
|
|
299
305
|
maxRenderedOptions: 100,
|
|
300
|
-
defaultKeymap: true
|
|
306
|
+
defaultKeymap: true,
|
|
307
|
+
optionClass: () => "",
|
|
308
|
+
icons: true,
|
|
309
|
+
addToOptions: []
|
|
301
310
|
}, {
|
|
302
|
-
defaultKeymap: (a, b) => a && b
|
|
311
|
+
defaultKeymap: (a, b) => a && b,
|
|
312
|
+
icons: (a, b) => a && b,
|
|
313
|
+
optionClass: (a, b) => c => joinClass(a(c), b(c)),
|
|
314
|
+
addToOptions: (a, b) => a.concat(b)
|
|
303
315
|
});
|
|
304
316
|
}
|
|
305
317
|
});
|
|
318
|
+
function joinClass(a, b) {
|
|
319
|
+
return a ? b ? a + " " + b : a : b;
|
|
320
|
+
}
|
|
306
321
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
margin: 0,
|
|
319
|
-
padding: 0,
|
|
320
|
-
"& > li": {
|
|
321
|
-
cursor: "pointer",
|
|
322
|
-
padding: "1px 1em 1px 3px",
|
|
323
|
-
lineHeight: 1.2
|
|
322
|
+
function optionContent(config) {
|
|
323
|
+
let content = config.addToOptions.slice();
|
|
324
|
+
if (config.icons)
|
|
325
|
+
content.push({
|
|
326
|
+
render(completion) {
|
|
327
|
+
let icon = document.createElement("div");
|
|
328
|
+
icon.classList.add("cm-completionIcon");
|
|
329
|
+
if (completion.type)
|
|
330
|
+
icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls));
|
|
331
|
+
icon.setAttribute("aria-hidden", "true");
|
|
332
|
+
return icon;
|
|
324
333
|
},
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
334
|
+
position: 20
|
|
335
|
+
});
|
|
336
|
+
content.push({
|
|
337
|
+
render(completion, _s, match) {
|
|
338
|
+
let labelElt = document.createElement("span");
|
|
339
|
+
labelElt.className = "cm-completionLabel";
|
|
340
|
+
let { label } = completion, off = 0;
|
|
341
|
+
for (let j = 1; j < match.length;) {
|
|
342
|
+
let from = match[j++], to = match[j++];
|
|
343
|
+
if (from > off)
|
|
344
|
+
labelElt.appendChild(document.createTextNode(label.slice(off, from)));
|
|
345
|
+
let span = labelElt.appendChild(document.createElement("span"));
|
|
346
|
+
span.appendChild(document.createTextNode(label.slice(from, to)));
|
|
347
|
+
span.className = "cm-completionMatchedText";
|
|
348
|
+
off = to;
|
|
330
349
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
padding: "3px 9px",
|
|
342
|
-
width: "max-content",
|
|
343
|
-
maxWidth: MaxInfoWidth + "px",
|
|
344
|
-
},
|
|
345
|
-
".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
|
|
346
|
-
".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
|
|
347
|
-
"&light .cm-snippetField": { backgroundColor: "#00000022" },
|
|
348
|
-
"&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
|
|
349
|
-
".cm-snippetFieldPosition": {
|
|
350
|
-
verticalAlign: "text-top",
|
|
351
|
-
width: 0,
|
|
352
|
-
height: "1.15em",
|
|
353
|
-
margin: "0 -0.7px -.7em",
|
|
354
|
-
borderLeft: "1.4px dotted #888"
|
|
355
|
-
},
|
|
356
|
-
".cm-completionMatchedText": {
|
|
357
|
-
textDecoration: "underline"
|
|
358
|
-
},
|
|
359
|
-
".cm-completionDetail": {
|
|
360
|
-
marginLeft: "0.5em",
|
|
361
|
-
fontStyle: "italic"
|
|
362
|
-
},
|
|
363
|
-
".cm-completionIcon": {
|
|
364
|
-
fontSize: "90%",
|
|
365
|
-
width: ".8em",
|
|
366
|
-
display: "inline-block",
|
|
367
|
-
textAlign: "center",
|
|
368
|
-
paddingRight: ".6em",
|
|
369
|
-
opacity: "0.6"
|
|
370
|
-
},
|
|
371
|
-
".cm-completionIcon-function, .cm-completionIcon-method": {
|
|
372
|
-
"&:after": { content: "'ƒ'" }
|
|
373
|
-
},
|
|
374
|
-
".cm-completionIcon-class": {
|
|
375
|
-
"&:after": { content: "'○'" }
|
|
376
|
-
},
|
|
377
|
-
".cm-completionIcon-interface": {
|
|
378
|
-
"&:after": { content: "'◌'" }
|
|
379
|
-
},
|
|
380
|
-
".cm-completionIcon-variable": {
|
|
381
|
-
"&:after": { content: "'𝑥'" }
|
|
382
|
-
},
|
|
383
|
-
".cm-completionIcon-constant": {
|
|
384
|
-
"&:after": { content: "'𝐶'" }
|
|
385
|
-
},
|
|
386
|
-
".cm-completionIcon-type": {
|
|
387
|
-
"&:after": { content: "'𝑡'" }
|
|
388
|
-
},
|
|
389
|
-
".cm-completionIcon-enum": {
|
|
390
|
-
"&:after": { content: "'∪'" }
|
|
391
|
-
},
|
|
392
|
-
".cm-completionIcon-property": {
|
|
393
|
-
"&:after": { content: "'□'" }
|
|
394
|
-
},
|
|
395
|
-
".cm-completionIcon-keyword": {
|
|
396
|
-
"&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering
|
|
397
|
-
},
|
|
398
|
-
".cm-completionIcon-namespace": {
|
|
399
|
-
"&:after": { content: "'▢'" }
|
|
400
|
-
},
|
|
401
|
-
".cm-completionIcon-text": {
|
|
402
|
-
"&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" }
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
function createListBox(options, id, range) {
|
|
407
|
-
const ul = document.createElement("ul");
|
|
408
|
-
ul.id = id;
|
|
409
|
-
ul.setAttribute("role", "listbox");
|
|
410
|
-
ul.setAttribute("aria-expanded", "true");
|
|
411
|
-
for (let i = range.from; i < range.to; i++) {
|
|
412
|
-
let { completion, match } = options[i];
|
|
413
|
-
const li = ul.appendChild(document.createElement("li"));
|
|
414
|
-
li.id = id + "-" + i;
|
|
415
|
-
let icon = li.appendChild(document.createElement("div"));
|
|
416
|
-
icon.classList.add("cm-completionIcon");
|
|
417
|
-
if (completion.type)
|
|
418
|
-
icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls));
|
|
419
|
-
icon.setAttribute("aria-hidden", "true");
|
|
420
|
-
let labelElt = li.appendChild(document.createElement("span"));
|
|
421
|
-
labelElt.className = "cm-completionLabel";
|
|
422
|
-
let { label, detail } = completion, off = 0;
|
|
423
|
-
for (let j = 1; j < match.length;) {
|
|
424
|
-
let from = match[j++], to = match[j++];
|
|
425
|
-
if (from > off)
|
|
426
|
-
labelElt.appendChild(document.createTextNode(label.slice(off, from)));
|
|
427
|
-
let span = labelElt.appendChild(document.createElement("span"));
|
|
428
|
-
span.appendChild(document.createTextNode(label.slice(from, to)));
|
|
429
|
-
span.className = "cm-completionMatchedText";
|
|
430
|
-
off = to;
|
|
431
|
-
}
|
|
432
|
-
if (off < label.length)
|
|
433
|
-
labelElt.appendChild(document.createTextNode(label.slice(off)));
|
|
434
|
-
if (detail) {
|
|
435
|
-
let detailElt = li.appendChild(document.createElement("span"));
|
|
350
|
+
if (off < label.length)
|
|
351
|
+
labelElt.appendChild(document.createTextNode(label.slice(off)));
|
|
352
|
+
return labelElt;
|
|
353
|
+
},
|
|
354
|
+
position: 50
|
|
355
|
+
}, {
|
|
356
|
+
render(completion) {
|
|
357
|
+
if (!completion.detail)
|
|
358
|
+
return null;
|
|
359
|
+
let detailElt = document.createElement("span");
|
|
436
360
|
detailElt.className = "cm-completionDetail";
|
|
437
|
-
detailElt.textContent = detail;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (range.to < options.length)
|
|
444
|
-
ul.classList.add("cm-completionListIncompleteBottom");
|
|
445
|
-
return ul;
|
|
361
|
+
detailElt.textContent = completion.detail;
|
|
362
|
+
return detailElt;
|
|
363
|
+
},
|
|
364
|
+
position: 80
|
|
365
|
+
});
|
|
366
|
+
return content.sort((a, b) => a.position - b.position).map(a => a.render);
|
|
446
367
|
}
|
|
447
368
|
function createInfoDialog(option, view) {
|
|
448
369
|
let dom = document.createElement("div");
|
|
@@ -483,6 +404,8 @@ class CompletionTooltip {
|
|
|
483
404
|
let cState = view.state.field(stateField);
|
|
484
405
|
let { options, selected } = cState.open;
|
|
485
406
|
let config = view.state.facet(completionConfig);
|
|
407
|
+
this.optionContent = optionContent(config);
|
|
408
|
+
this.optionClass = config.optionClass;
|
|
486
409
|
this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions);
|
|
487
410
|
this.dom = document.createElement("div");
|
|
488
411
|
this.dom.className = "cm-tooltip-autocomplete";
|
|
@@ -495,7 +418,7 @@ class CompletionTooltip {
|
|
|
495
418
|
}
|
|
496
419
|
}
|
|
497
420
|
});
|
|
498
|
-
this.list = this.dom.appendChild(createListBox(options, cState.id, this.range));
|
|
421
|
+
this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range));
|
|
499
422
|
this.list.addEventListener("scroll", () => {
|
|
500
423
|
if (this.info)
|
|
501
424
|
this.view.requestMeasure(this.placeInfo);
|
|
@@ -515,7 +438,7 @@ class CompletionTooltip {
|
|
|
515
438
|
if (open.selected < this.range.from || open.selected >= this.range.to) {
|
|
516
439
|
this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
|
|
517
440
|
this.list.remove();
|
|
518
|
-
this.list = this.dom.appendChild(createListBox(open.options, cState.id, this.range));
|
|
441
|
+
this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range));
|
|
519
442
|
this.list.addEventListener("scroll", () => {
|
|
520
443
|
if (this.info)
|
|
521
444
|
this.view.requestMeasure(this.placeInfo);
|
|
@@ -553,17 +476,17 @@ class CompletionTooltip {
|
|
|
553
476
|
}
|
|
554
477
|
measureInfo() {
|
|
555
478
|
let sel = this.dom.querySelector("[aria-selected]");
|
|
556
|
-
if (!sel)
|
|
479
|
+
if (!sel || !this.info)
|
|
557
480
|
return null;
|
|
558
|
-
let rect = this.dom.getBoundingClientRect();
|
|
559
|
-
let top = sel.getBoundingClientRect().top - rect.top;
|
|
481
|
+
let rect = this.dom.getBoundingClientRect(), infoRect = this.info.getBoundingClientRect();
|
|
482
|
+
let top = Math.min(sel.getBoundingClientRect().top, innerHeight - infoRect.height) - rect.top;
|
|
560
483
|
if (top < 0 || top > this.list.clientHeight - 10)
|
|
561
484
|
return null;
|
|
562
485
|
let left = this.view.textDirection == Direction.RTL;
|
|
563
486
|
let spaceLeft = rect.left, spaceRight = innerWidth - rect.right;
|
|
564
|
-
if (left && spaceLeft < Math.min(
|
|
487
|
+
if (left && spaceLeft < Math.min(infoRect.width, spaceRight))
|
|
565
488
|
left = false;
|
|
566
|
-
else if (!left && spaceRight < Math.min(
|
|
489
|
+
else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft))
|
|
567
490
|
left = true;
|
|
568
491
|
return { top, left };
|
|
569
492
|
}
|
|
@@ -574,6 +497,30 @@ class CompletionTooltip {
|
|
|
574
497
|
this.info.classList.toggle("cm-completionInfo-right", !pos.left);
|
|
575
498
|
}
|
|
576
499
|
}
|
|
500
|
+
createListBox(options, id, range) {
|
|
501
|
+
const ul = document.createElement("ul");
|
|
502
|
+
ul.id = id;
|
|
503
|
+
ul.setAttribute("role", "listbox");
|
|
504
|
+
for (let i = range.from; i < range.to; i++) {
|
|
505
|
+
let { completion, match } = options[i];
|
|
506
|
+
const li = ul.appendChild(document.createElement("li"));
|
|
507
|
+
li.id = id + "-" + i;
|
|
508
|
+
li.setAttribute("role", "option");
|
|
509
|
+
let cls = this.optionClass(completion);
|
|
510
|
+
if (cls)
|
|
511
|
+
li.className = cls;
|
|
512
|
+
for (let source of this.optionContent) {
|
|
513
|
+
let node = source(completion, this.view.state, match);
|
|
514
|
+
if (node)
|
|
515
|
+
li.appendChild(node);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (range.from)
|
|
519
|
+
ul.classList.add("cm-completionListIncompleteTop");
|
|
520
|
+
if (range.to < options.length)
|
|
521
|
+
ul.classList.add("cm-completionListIncompleteBottom");
|
|
522
|
+
return ul;
|
|
523
|
+
}
|
|
577
524
|
}
|
|
578
525
|
// We allocate a new function instance every time the completion
|
|
579
526
|
// changes to force redrawing/repositioning of the tooltip
|
|
@@ -708,20 +655,24 @@ function sameResults(a, b) {
|
|
|
708
655
|
return false;
|
|
709
656
|
}
|
|
710
657
|
}
|
|
658
|
+
const baseAttrs = {
|
|
659
|
+
"aria-autocomplete": "list",
|
|
660
|
+
"aria-expanded": "false"
|
|
661
|
+
};
|
|
711
662
|
function makeAttrs(id, selected) {
|
|
712
663
|
return {
|
|
713
664
|
"aria-autocomplete": "list",
|
|
665
|
+
"aria-expanded": "true",
|
|
714
666
|
"aria-activedescendant": id + "-" + selected,
|
|
715
|
-
"aria-
|
|
667
|
+
"aria-controls": id
|
|
716
668
|
};
|
|
717
669
|
}
|
|
718
|
-
const
|
|
670
|
+
const none = [];
|
|
719
671
|
function cmpOption(a, b) {
|
|
720
672
|
let dScore = b.match[0] - a.match[0];
|
|
721
673
|
if (dScore)
|
|
722
674
|
return dScore;
|
|
723
|
-
|
|
724
|
-
return lA < lB ? -1 : lA == lB ? 0 : 1;
|
|
675
|
+
return a.completion.label.localeCompare(b.completion.label);
|
|
725
676
|
}
|
|
726
677
|
function getUserEvent(tr) {
|
|
727
678
|
return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null;
|
|
@@ -832,7 +783,7 @@ Accept the current completion.
|
|
|
832
783
|
*/
|
|
833
784
|
const acceptCompletion = (view) => {
|
|
834
785
|
let cState = view.state.field(completionState, false);
|
|
835
|
-
if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
|
|
786
|
+
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
|
|
836
787
|
return false;
|
|
837
788
|
applyCompletion(view, cState.open.options[cState.open.selected]);
|
|
838
789
|
return true;
|
|
@@ -1008,6 +959,106 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
1008
959
|
}
|
|
1009
960
|
});
|
|
1010
961
|
|
|
962
|
+
const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
963
|
+
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
964
|
+
"& > ul": {
|
|
965
|
+
fontFamily: "monospace",
|
|
966
|
+
whiteSpace: "nowrap",
|
|
967
|
+
overflow: "auto",
|
|
968
|
+
maxWidth_fallback: "700px",
|
|
969
|
+
maxWidth: "min(700px, 95vw)",
|
|
970
|
+
maxHeight: "10em",
|
|
971
|
+
listStyle: "none",
|
|
972
|
+
margin: 0,
|
|
973
|
+
padding: 0,
|
|
974
|
+
"& > li": {
|
|
975
|
+
cursor: "pointer",
|
|
976
|
+
padding: "1px 1em 1px 3px",
|
|
977
|
+
lineHeight: 1.2
|
|
978
|
+
},
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
"&light .cm-tooltip-autocomplete ul li[aria-selected]": {
|
|
982
|
+
background: "#39e",
|
|
983
|
+
color: "white",
|
|
984
|
+
},
|
|
985
|
+
"&dark .cm-tooltip-autocomplete ul li[aria-selected]": {
|
|
986
|
+
background: "#347",
|
|
987
|
+
color: "white",
|
|
988
|
+
},
|
|
989
|
+
".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": {
|
|
990
|
+
content: '"···"',
|
|
991
|
+
opacity: 0.5,
|
|
992
|
+
display: "block",
|
|
993
|
+
textAlign: "center"
|
|
994
|
+
},
|
|
995
|
+
".cm-tooltip.cm-completionInfo": {
|
|
996
|
+
position: "absolute",
|
|
997
|
+
padding: "3px 9px",
|
|
998
|
+
width: "max-content",
|
|
999
|
+
maxWidth: "300px",
|
|
1000
|
+
},
|
|
1001
|
+
".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
|
|
1002
|
+
".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
|
|
1003
|
+
"&light .cm-snippetField": { backgroundColor: "#00000022" },
|
|
1004
|
+
"&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
|
|
1005
|
+
".cm-snippetFieldPosition": {
|
|
1006
|
+
verticalAlign: "text-top",
|
|
1007
|
+
width: 0,
|
|
1008
|
+
height: "1.15em",
|
|
1009
|
+
margin: "0 -0.7px -.7em",
|
|
1010
|
+
borderLeft: "1.4px dotted #888"
|
|
1011
|
+
},
|
|
1012
|
+
".cm-completionMatchedText": {
|
|
1013
|
+
textDecoration: "underline"
|
|
1014
|
+
},
|
|
1015
|
+
".cm-completionDetail": {
|
|
1016
|
+
marginLeft: "0.5em",
|
|
1017
|
+
fontStyle: "italic"
|
|
1018
|
+
},
|
|
1019
|
+
".cm-completionIcon": {
|
|
1020
|
+
fontSize: "90%",
|
|
1021
|
+
width: ".8em",
|
|
1022
|
+
display: "inline-block",
|
|
1023
|
+
textAlign: "center",
|
|
1024
|
+
paddingRight: ".6em",
|
|
1025
|
+
opacity: "0.6"
|
|
1026
|
+
},
|
|
1027
|
+
".cm-completionIcon-function, .cm-completionIcon-method": {
|
|
1028
|
+
"&:after": { content: "'ƒ'" }
|
|
1029
|
+
},
|
|
1030
|
+
".cm-completionIcon-class": {
|
|
1031
|
+
"&:after": { content: "'○'" }
|
|
1032
|
+
},
|
|
1033
|
+
".cm-completionIcon-interface": {
|
|
1034
|
+
"&:after": { content: "'◌'" }
|
|
1035
|
+
},
|
|
1036
|
+
".cm-completionIcon-variable": {
|
|
1037
|
+
"&:after": { content: "'𝑥'" }
|
|
1038
|
+
},
|
|
1039
|
+
".cm-completionIcon-constant": {
|
|
1040
|
+
"&:after": { content: "'𝐶'" }
|
|
1041
|
+
},
|
|
1042
|
+
".cm-completionIcon-type": {
|
|
1043
|
+
"&:after": { content: "'𝑡'" }
|
|
1044
|
+
},
|
|
1045
|
+
".cm-completionIcon-enum": {
|
|
1046
|
+
"&:after": { content: "'∪'" }
|
|
1047
|
+
},
|
|
1048
|
+
".cm-completionIcon-property": {
|
|
1049
|
+
"&:after": { content: "'□'" }
|
|
1050
|
+
},
|
|
1051
|
+
".cm-completionIcon-keyword": {
|
|
1052
|
+
"&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering
|
|
1053
|
+
},
|
|
1054
|
+
".cm-completionIcon-namespace": {
|
|
1055
|
+
"&:after": { content: "'▢'" }
|
|
1056
|
+
},
|
|
1057
|
+
".cm-completionIcon-text": {
|
|
1058
|
+
"&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" }
|
|
1059
|
+
}
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1011
1062
|
class FieldPos {
|
|
1012
1063
|
constructor(field, line, from, to) {
|
|
1013
1064
|
this.field = field;
|
|
@@ -1158,8 +1209,7 @@ function snippet(template) {
|
|
|
1158
1209
|
let active = new ActiveSnippet(ranges, 0);
|
|
1159
1210
|
let effects = spec.effects = [setActive.of(active)];
|
|
1160
1211
|
if (editor.state.field(snippetState, false) === undefined)
|
|
1161
|
-
effects.push(StateEffect.appendConfig.of([snippetState
|
|
1162
|
-
snippetPointerHandler, baseTheme]));
|
|
1212
|
+
effects.push(StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme]));
|
|
1163
1213
|
}
|
|
1164
1214
|
editor.dispatch(editor.state.update(spec));
|
|
1165
1215
|
};
|
|
@@ -1209,7 +1259,7 @@ to [`clearSnippet`](https://codemirror.net/6/docs/ref/#autocomplete.clearSnippet
|
|
|
1209
1259
|
const snippetKeymap = /*@__PURE__*/Facet.define({
|
|
1210
1260
|
combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; }
|
|
1211
1261
|
});
|
|
1212
|
-
const addSnippetKeymap = /*@__PURE__*/Prec.
|
|
1262
|
+
const addSnippetKeymap = /*@__PURE__*/Prec.highest(/*@__PURE__*/keymap.compute([snippetKeymap], state => state.facet(snippetKeymap)));
|
|
1213
1263
|
/**
|
|
1214
1264
|
Create a completion from a snippet. Returns an object with the
|
|
1215
1265
|
properties from `completion`, plus an `apply` function that
|
|
@@ -1234,42 +1284,81 @@ const snippetPointerHandler = /*@__PURE__*/EditorView.domEventHandlers({
|
|
|
1234
1284
|
}
|
|
1235
1285
|
});
|
|
1236
1286
|
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
return
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1287
|
+
function wordRE(wordChars) {
|
|
1288
|
+
let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&");
|
|
1289
|
+
try {
|
|
1290
|
+
return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug");
|
|
1291
|
+
}
|
|
1292
|
+
catch (_a) {
|
|
1293
|
+
return new RegExp(`[\w${escaped}]`, "g");
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function mapRE(re, f) {
|
|
1297
|
+
return new RegExp(f(re.source), re.unicode ? "u" : "");
|
|
1298
|
+
}
|
|
1299
|
+
const wordCaches = /*@__PURE__*/Object.create(null);
|
|
1300
|
+
function wordCache(wordChars) {
|
|
1301
|
+
return wordCaches[wordChars] || (wordCaches[wordChars] = new WeakMap);
|
|
1302
|
+
}
|
|
1303
|
+
function storeWords(doc, wordRE, result, seen, ignoreAt) {
|
|
1304
|
+
for (let lines = doc.iterLines(), pos = 0; !lines.next().done;) {
|
|
1305
|
+
let { value } = lines, m;
|
|
1306
|
+
wordRE.lastIndex = 0;
|
|
1307
|
+
while (m = wordRE.exec(value)) {
|
|
1308
|
+
if (!seen[m[0]] && pos + m.index != ignoreAt) {
|
|
1309
|
+
result.push({ type: "text", label: m[0] });
|
|
1310
|
+
seen[m[0]] = true;
|
|
1311
|
+
if (result.length >= 2000 /* MaxList */)
|
|
1312
|
+
return;
|
|
1253
1313
|
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1314
|
+
}
|
|
1315
|
+
pos += value.length + 1;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
function collectWords(doc, cache, wordRE, to, ignoreAt) {
|
|
1319
|
+
let big = doc.length >= 1000 /* MinCacheLen */;
|
|
1320
|
+
let cached = big && cache.get(doc);
|
|
1321
|
+
if (cached)
|
|
1322
|
+
return cached;
|
|
1323
|
+
let result = [], seen = Object.create(null);
|
|
1324
|
+
if (doc.children) {
|
|
1325
|
+
let pos = 0;
|
|
1326
|
+
for (let ch of doc.children) {
|
|
1327
|
+
if (ch.length >= 1000 /* MinCacheLen */) {
|
|
1328
|
+
for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) {
|
|
1329
|
+
if (!seen[c.label]) {
|
|
1330
|
+
seen[c.label] = true;
|
|
1331
|
+
result.push(c);
|
|
1263
1332
|
}
|
|
1264
1333
|
}
|
|
1265
|
-
start = -1;
|
|
1266
1334
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1335
|
+
else {
|
|
1336
|
+
storeWords(ch, wordRE, result, seen, ignoreAt - pos);
|
|
1337
|
+
}
|
|
1338
|
+
pos += ch.length + 1;
|
|
1269
1339
|
}
|
|
1270
|
-
pos += value.length;
|
|
1271
1340
|
}
|
|
1272
|
-
|
|
1341
|
+
else {
|
|
1342
|
+
storeWords(doc, wordRE, result, seen, ignoreAt);
|
|
1343
|
+
}
|
|
1344
|
+
if (big && result.length < 2000 /* MaxList */)
|
|
1345
|
+
cache.set(doc, result);
|
|
1346
|
+
return result;
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
A completion source that will scan the document for words (using a
|
|
1350
|
+
[character categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer)), and
|
|
1351
|
+
return those as completions.
|
|
1352
|
+
*/
|
|
1353
|
+
const completeAnyWord = context => {
|
|
1354
|
+
let wordChars = context.state.languageDataAt("wordChars", context.pos).join("");
|
|
1355
|
+
let re = wordRE(wordChars);
|
|
1356
|
+
let token = context.matchBefore(mapRE(re, s => s + "$"));
|
|
1357
|
+
if (!token && !context.explicit)
|
|
1358
|
+
return null;
|
|
1359
|
+
let from = token ? token.from : context.pos;
|
|
1360
|
+
let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from);
|
|
1361
|
+
return { from, options, span: mapRE(re, s => "^" + s) };
|
|
1273
1362
|
};
|
|
1274
1363
|
|
|
1275
1364
|
/**
|
|
@@ -1304,7 +1393,7 @@ const completionKeymap = [
|
|
|
1304
1393
|
{ key: "PageUp", run: /*@__PURE__*/moveCompletionSelection(false, "page") },
|
|
1305
1394
|
{ key: "Enter", run: acceptCompletion }
|
|
1306
1395
|
];
|
|
1307
|
-
const completionKeymapExt = /*@__PURE__*/Prec.
|
|
1396
|
+
const completionKeymapExt = /*@__PURE__*/Prec.highest(/*@__PURE__*/keymap.computeN([completionConfig], state => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : []));
|
|
1308
1397
|
/**
|
|
1309
1398
|
Get the current completion status. When completions are available,
|
|
1310
1399
|
this will return `"active"`. When completions are pending (in the
|
|
@@ -1324,5 +1413,13 @@ function currentCompletions(state) {
|
|
|
1324
1413
|
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1325
1414
|
return open ? open.options.map(o => o.completion) : [];
|
|
1326
1415
|
}
|
|
1416
|
+
/**
|
|
1417
|
+
Return the currently selected completion, if any.
|
|
1418
|
+
*/
|
|
1419
|
+
function selectedCompletion(state) {
|
|
1420
|
+
var _a;
|
|
1421
|
+
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1422
|
+
return open ? open.options[open.selected].completion : null;
|
|
1423
|
+
}
|
|
1327
1424
|
|
|
1328
|
-
export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, prevSnippetField, snippet, snippetCompletion, snippetKeymap, startCompletion };
|
|
1425
|
+
export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/autocomplete",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.5",
|
|
4
4
|
"description": "Autocompletion for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@codemirror/language": "^0.19.0",
|
|
30
|
-
"@codemirror/state": "^0.19.
|
|
31
|
-
"@codemirror/text": "^0.19.
|
|
30
|
+
"@codemirror/state": "^0.19.4",
|
|
31
|
+
"@codemirror/text": "^0.19.2",
|
|
32
32
|
"@codemirror/tooltip": "^0.19.0",
|
|
33
33
|
"@codemirror/view": "^0.19.0",
|
|
34
34
|
"@lezer/common": "^0.15.0"
|