@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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
## 0.19.5 (2021-11-09)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make sure info tooltips don't stick out of the bottom of the page.
|
|
6
|
+
|
|
7
|
+
### New features
|
|
8
|
+
|
|
9
|
+
The package exports a new function `selectedCompletion`, which can be used to find out which completion is currently selected.
|
|
10
|
+
|
|
11
|
+
Transactions created by picking a completion now have an annotation (`pickedCompletion`) holding the original completion.
|
|
12
|
+
|
|
13
|
+
## 0.19.4 (2021-10-24)
|
|
14
|
+
|
|
15
|
+
### Bug fixes
|
|
16
|
+
|
|
17
|
+
Don't rely on the platform's highlight colors for the active completion, since those are inconsistent and may not be appropriate for the theme.
|
|
18
|
+
|
|
19
|
+
Fix incorrect match underline for some kinds of matched completions.
|
|
20
|
+
|
|
21
|
+
## 0.19.3 (2021-08-31)
|
|
22
|
+
|
|
23
|
+
### Bug fixes
|
|
24
|
+
|
|
25
|
+
Improve the sorting of completions by using `localeCompare`.
|
|
26
|
+
|
|
27
|
+
Fix reading of autocompletions in NVDA screen reader.
|
|
28
|
+
|
|
29
|
+
### New features
|
|
30
|
+
|
|
31
|
+
The new `icons` option can be used to turn off icons in the completion list.
|
|
32
|
+
|
|
33
|
+
The `optionClass` option can now be used to add CSS classes to the options in the completion list.
|
|
34
|
+
|
|
35
|
+
It is now possible to inject additional content into rendered completion options with the `addToOptions` configuration option.
|
|
36
|
+
|
|
37
|
+
## 0.19.2 (2021-08-25)
|
|
38
|
+
|
|
39
|
+
### Bug fixes
|
|
40
|
+
|
|
41
|
+
Fix an issue where `completeAnyWord` would return results when there was no query and `explicit` was false.
|
|
42
|
+
|
|
1
43
|
## 0.19.1 (2021-08-11)
|
|
2
44
|
|
|
3
45
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -150,6 +150,11 @@ function ensureAnchor(expr, start) {
|
|
|
150
150
|
return expr;
|
|
151
151
|
return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : (expr.ignoreCase ? "i" : ""));
|
|
152
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
This annotation is added to transactions that are produced by
|
|
155
|
+
picking a completion.
|
|
156
|
+
*/
|
|
157
|
+
const pickedCompletion = state.Annotation.define();
|
|
153
158
|
function applyCompletion(view, option) {
|
|
154
159
|
let apply = option.completion.apply || option.completion.label;
|
|
155
160
|
let result = option.source;
|
|
@@ -157,7 +162,8 @@ function applyCompletion(view, option) {
|
|
|
157
162
|
view.dispatch({
|
|
158
163
|
changes: { from: result.from, to: result.to, insert: apply },
|
|
159
164
|
selection: { anchor: result.from + apply.length },
|
|
160
|
-
userEvent: "input.complete"
|
|
165
|
+
userEvent: "input.complete",
|
|
166
|
+
annotations: pickedCompletion.of(option.completion)
|
|
161
167
|
});
|
|
162
168
|
}
|
|
163
169
|
else {
|
|
@@ -251,7 +257,7 @@ class FuzzyMatcher {
|
|
|
251
257
|
if (next == chars[adjacentTo] || next == folded[adjacentTo]) {
|
|
252
258
|
if (adjacentTo == 0)
|
|
253
259
|
adjacentStart = i;
|
|
254
|
-
adjacentEnd = i;
|
|
260
|
+
adjacentEnd = i + 1;
|
|
255
261
|
adjacentTo++;
|
|
256
262
|
}
|
|
257
263
|
else {
|
|
@@ -301,152 +307,67 @@ const completionConfig = state.Facet.define({
|
|
|
301
307
|
activateOnTyping: true,
|
|
302
308
|
override: null,
|
|
303
309
|
maxRenderedOptions: 100,
|
|
304
|
-
defaultKeymap: true
|
|
310
|
+
defaultKeymap: true,
|
|
311
|
+
optionClass: () => "",
|
|
312
|
+
icons: true,
|
|
313
|
+
addToOptions: []
|
|
305
314
|
}, {
|
|
306
|
-
defaultKeymap: (a, b) => a && b
|
|
315
|
+
defaultKeymap: (a, b) => a && b,
|
|
316
|
+
icons: (a, b) => a && b,
|
|
317
|
+
optionClass: (a, b) => c => joinClass(a(c), b(c)),
|
|
318
|
+
addToOptions: (a, b) => a.concat(b)
|
|
307
319
|
});
|
|
308
320
|
}
|
|
309
321
|
});
|
|
322
|
+
function joinClass(a, b) {
|
|
323
|
+
return a ? b ? a + " " + b : a : b;
|
|
324
|
+
}
|
|
310
325
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
margin: 0,
|
|
323
|
-
padding: 0,
|
|
324
|
-
"& > li": {
|
|
325
|
-
cursor: "pointer",
|
|
326
|
-
padding: "1px 1em 1px 3px",
|
|
327
|
-
lineHeight: 1.2
|
|
326
|
+
function optionContent(config) {
|
|
327
|
+
let content = config.addToOptions.slice();
|
|
328
|
+
if (config.icons)
|
|
329
|
+
content.push({
|
|
330
|
+
render(completion) {
|
|
331
|
+
let icon = document.createElement("div");
|
|
332
|
+
icon.classList.add("cm-completionIcon");
|
|
333
|
+
if (completion.type)
|
|
334
|
+
icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls));
|
|
335
|
+
icon.setAttribute("aria-hidden", "true");
|
|
336
|
+
return icon;
|
|
328
337
|
},
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
338
|
+
position: 20
|
|
339
|
+
});
|
|
340
|
+
content.push({
|
|
341
|
+
render(completion, _s, match) {
|
|
342
|
+
let labelElt = document.createElement("span");
|
|
343
|
+
labelElt.className = "cm-completionLabel";
|
|
344
|
+
let { label } = completion, off = 0;
|
|
345
|
+
for (let j = 1; j < match.length;) {
|
|
346
|
+
let from = match[j++], to = match[j++];
|
|
347
|
+
if (from > off)
|
|
348
|
+
labelElt.appendChild(document.createTextNode(label.slice(off, from)));
|
|
349
|
+
let span = labelElt.appendChild(document.createElement("span"));
|
|
350
|
+
span.appendChild(document.createTextNode(label.slice(from, to)));
|
|
351
|
+
span.className = "cm-completionMatchedText";
|
|
352
|
+
off = to;
|
|
334
353
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
padding: "3px 9px",
|
|
346
|
-
width: "max-content",
|
|
347
|
-
maxWidth: MaxInfoWidth + "px",
|
|
348
|
-
},
|
|
349
|
-
".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
|
|
350
|
-
".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
|
|
351
|
-
"&light .cm-snippetField": { backgroundColor: "#00000022" },
|
|
352
|
-
"&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
|
|
353
|
-
".cm-snippetFieldPosition": {
|
|
354
|
-
verticalAlign: "text-top",
|
|
355
|
-
width: 0,
|
|
356
|
-
height: "1.15em",
|
|
357
|
-
margin: "0 -0.7px -.7em",
|
|
358
|
-
borderLeft: "1.4px dotted #888"
|
|
359
|
-
},
|
|
360
|
-
".cm-completionMatchedText": {
|
|
361
|
-
textDecoration: "underline"
|
|
362
|
-
},
|
|
363
|
-
".cm-completionDetail": {
|
|
364
|
-
marginLeft: "0.5em",
|
|
365
|
-
fontStyle: "italic"
|
|
366
|
-
},
|
|
367
|
-
".cm-completionIcon": {
|
|
368
|
-
fontSize: "90%",
|
|
369
|
-
width: ".8em",
|
|
370
|
-
display: "inline-block",
|
|
371
|
-
textAlign: "center",
|
|
372
|
-
paddingRight: ".6em",
|
|
373
|
-
opacity: "0.6"
|
|
374
|
-
},
|
|
375
|
-
".cm-completionIcon-function, .cm-completionIcon-method": {
|
|
376
|
-
"&:after": { content: "'ƒ'" }
|
|
377
|
-
},
|
|
378
|
-
".cm-completionIcon-class": {
|
|
379
|
-
"&:after": { content: "'○'" }
|
|
380
|
-
},
|
|
381
|
-
".cm-completionIcon-interface": {
|
|
382
|
-
"&:after": { content: "'◌'" }
|
|
383
|
-
},
|
|
384
|
-
".cm-completionIcon-variable": {
|
|
385
|
-
"&:after": { content: "'𝑥'" }
|
|
386
|
-
},
|
|
387
|
-
".cm-completionIcon-constant": {
|
|
388
|
-
"&:after": { content: "'𝐶'" }
|
|
389
|
-
},
|
|
390
|
-
".cm-completionIcon-type": {
|
|
391
|
-
"&:after": { content: "'𝑡'" }
|
|
392
|
-
},
|
|
393
|
-
".cm-completionIcon-enum": {
|
|
394
|
-
"&:after": { content: "'∪'" }
|
|
395
|
-
},
|
|
396
|
-
".cm-completionIcon-property": {
|
|
397
|
-
"&:after": { content: "'□'" }
|
|
398
|
-
},
|
|
399
|
-
".cm-completionIcon-keyword": {
|
|
400
|
-
"&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering
|
|
401
|
-
},
|
|
402
|
-
".cm-completionIcon-namespace": {
|
|
403
|
-
"&:after": { content: "'▢'" }
|
|
404
|
-
},
|
|
405
|
-
".cm-completionIcon-text": {
|
|
406
|
-
"&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" }
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
function createListBox(options, id, range) {
|
|
411
|
-
const ul = document.createElement("ul");
|
|
412
|
-
ul.id = id;
|
|
413
|
-
ul.setAttribute("role", "listbox");
|
|
414
|
-
ul.setAttribute("aria-expanded", "true");
|
|
415
|
-
for (let i = range.from; i < range.to; i++) {
|
|
416
|
-
let { completion, match } = options[i];
|
|
417
|
-
const li = ul.appendChild(document.createElement("li"));
|
|
418
|
-
li.id = id + "-" + i;
|
|
419
|
-
let icon = li.appendChild(document.createElement("div"));
|
|
420
|
-
icon.classList.add("cm-completionIcon");
|
|
421
|
-
if (completion.type)
|
|
422
|
-
icon.classList.add(...completion.type.split(/\s+/g).map(cls => "cm-completionIcon-" + cls));
|
|
423
|
-
icon.setAttribute("aria-hidden", "true");
|
|
424
|
-
let labelElt = li.appendChild(document.createElement("span"));
|
|
425
|
-
labelElt.className = "cm-completionLabel";
|
|
426
|
-
let { label, detail } = completion, off = 0;
|
|
427
|
-
for (let j = 1; j < match.length;) {
|
|
428
|
-
let from = match[j++], to = match[j++];
|
|
429
|
-
if (from > off)
|
|
430
|
-
labelElt.appendChild(document.createTextNode(label.slice(off, from)));
|
|
431
|
-
let span = labelElt.appendChild(document.createElement("span"));
|
|
432
|
-
span.appendChild(document.createTextNode(label.slice(from, to)));
|
|
433
|
-
span.className = "cm-completionMatchedText";
|
|
434
|
-
off = to;
|
|
435
|
-
}
|
|
436
|
-
if (off < label.length)
|
|
437
|
-
labelElt.appendChild(document.createTextNode(label.slice(off)));
|
|
438
|
-
if (detail) {
|
|
439
|
-
let detailElt = li.appendChild(document.createElement("span"));
|
|
354
|
+
if (off < label.length)
|
|
355
|
+
labelElt.appendChild(document.createTextNode(label.slice(off)));
|
|
356
|
+
return labelElt;
|
|
357
|
+
},
|
|
358
|
+
position: 50
|
|
359
|
+
}, {
|
|
360
|
+
render(completion) {
|
|
361
|
+
if (!completion.detail)
|
|
362
|
+
return null;
|
|
363
|
+
let detailElt = document.createElement("span");
|
|
440
364
|
detailElt.className = "cm-completionDetail";
|
|
441
|
-
detailElt.textContent = detail;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (range.to < options.length)
|
|
448
|
-
ul.classList.add("cm-completionListIncompleteBottom");
|
|
449
|
-
return ul;
|
|
365
|
+
detailElt.textContent = completion.detail;
|
|
366
|
+
return detailElt;
|
|
367
|
+
},
|
|
368
|
+
position: 80
|
|
369
|
+
});
|
|
370
|
+
return content.sort((a, b) => a.position - b.position).map(a => a.render);
|
|
450
371
|
}
|
|
451
372
|
function createInfoDialog(option, view$1) {
|
|
452
373
|
let dom = document.createElement("div");
|
|
@@ -487,6 +408,8 @@ class CompletionTooltip {
|
|
|
487
408
|
let cState = view.state.field(stateField);
|
|
488
409
|
let { options, selected } = cState.open;
|
|
489
410
|
let config = view.state.facet(completionConfig);
|
|
411
|
+
this.optionContent = optionContent(config);
|
|
412
|
+
this.optionClass = config.optionClass;
|
|
490
413
|
this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions);
|
|
491
414
|
this.dom = document.createElement("div");
|
|
492
415
|
this.dom.className = "cm-tooltip-autocomplete";
|
|
@@ -499,7 +422,7 @@ class CompletionTooltip {
|
|
|
499
422
|
}
|
|
500
423
|
}
|
|
501
424
|
});
|
|
502
|
-
this.list = this.dom.appendChild(createListBox(options, cState.id, this.range));
|
|
425
|
+
this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range));
|
|
503
426
|
this.list.addEventListener("scroll", () => {
|
|
504
427
|
if (this.info)
|
|
505
428
|
this.view.requestMeasure(this.placeInfo);
|
|
@@ -519,7 +442,7 @@ class CompletionTooltip {
|
|
|
519
442
|
if (open.selected < this.range.from || open.selected >= this.range.to) {
|
|
520
443
|
this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
|
|
521
444
|
this.list.remove();
|
|
522
|
-
this.list = this.dom.appendChild(createListBox(open.options, cState.id, this.range));
|
|
445
|
+
this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range));
|
|
523
446
|
this.list.addEventListener("scroll", () => {
|
|
524
447
|
if (this.info)
|
|
525
448
|
this.view.requestMeasure(this.placeInfo);
|
|
@@ -557,17 +480,17 @@ class CompletionTooltip {
|
|
|
557
480
|
}
|
|
558
481
|
measureInfo() {
|
|
559
482
|
let sel = this.dom.querySelector("[aria-selected]");
|
|
560
|
-
if (!sel)
|
|
483
|
+
if (!sel || !this.info)
|
|
561
484
|
return null;
|
|
562
|
-
let rect = this.dom.getBoundingClientRect();
|
|
563
|
-
let top = sel.getBoundingClientRect().top - rect.top;
|
|
485
|
+
let rect = this.dom.getBoundingClientRect(), infoRect = this.info.getBoundingClientRect();
|
|
486
|
+
let top = Math.min(sel.getBoundingClientRect().top, innerHeight - infoRect.height) - rect.top;
|
|
564
487
|
if (top < 0 || top > this.list.clientHeight - 10)
|
|
565
488
|
return null;
|
|
566
489
|
let left = this.view.textDirection == view.Direction.RTL;
|
|
567
490
|
let spaceLeft = rect.left, spaceRight = innerWidth - rect.right;
|
|
568
|
-
if (left && spaceLeft < Math.min(
|
|
491
|
+
if (left && spaceLeft < Math.min(infoRect.width, spaceRight))
|
|
569
492
|
left = false;
|
|
570
|
-
else if (!left && spaceRight < Math.min(
|
|
493
|
+
else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft))
|
|
571
494
|
left = true;
|
|
572
495
|
return { top, left };
|
|
573
496
|
}
|
|
@@ -578,6 +501,30 @@ class CompletionTooltip {
|
|
|
578
501
|
this.info.classList.toggle("cm-completionInfo-right", !pos.left);
|
|
579
502
|
}
|
|
580
503
|
}
|
|
504
|
+
createListBox(options, id, range) {
|
|
505
|
+
const ul = document.createElement("ul");
|
|
506
|
+
ul.id = id;
|
|
507
|
+
ul.setAttribute("role", "listbox");
|
|
508
|
+
for (let i = range.from; i < range.to; i++) {
|
|
509
|
+
let { completion, match } = options[i];
|
|
510
|
+
const li = ul.appendChild(document.createElement("li"));
|
|
511
|
+
li.id = id + "-" + i;
|
|
512
|
+
li.setAttribute("role", "option");
|
|
513
|
+
let cls = this.optionClass(completion);
|
|
514
|
+
if (cls)
|
|
515
|
+
li.className = cls;
|
|
516
|
+
for (let source of this.optionContent) {
|
|
517
|
+
let node = source(completion, this.view.state, match);
|
|
518
|
+
if (node)
|
|
519
|
+
li.appendChild(node);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (range.from)
|
|
523
|
+
ul.classList.add("cm-completionListIncompleteTop");
|
|
524
|
+
if (range.to < options.length)
|
|
525
|
+
ul.classList.add("cm-completionListIncompleteBottom");
|
|
526
|
+
return ul;
|
|
527
|
+
}
|
|
581
528
|
}
|
|
582
529
|
// We allocate a new function instance every time the completion
|
|
583
530
|
// changes to force redrawing/repositioning of the tooltip
|
|
@@ -712,20 +659,24 @@ function sameResults(a, b) {
|
|
|
712
659
|
return false;
|
|
713
660
|
}
|
|
714
661
|
}
|
|
662
|
+
const baseAttrs = {
|
|
663
|
+
"aria-autocomplete": "list",
|
|
664
|
+
"aria-expanded": "false"
|
|
665
|
+
};
|
|
715
666
|
function makeAttrs(id, selected) {
|
|
716
667
|
return {
|
|
717
668
|
"aria-autocomplete": "list",
|
|
669
|
+
"aria-expanded": "true",
|
|
718
670
|
"aria-activedescendant": id + "-" + selected,
|
|
719
|
-
"aria-
|
|
671
|
+
"aria-controls": id
|
|
720
672
|
};
|
|
721
673
|
}
|
|
722
|
-
const
|
|
674
|
+
const none = [];
|
|
723
675
|
function cmpOption(a, b) {
|
|
724
676
|
let dScore = b.match[0] - a.match[0];
|
|
725
677
|
if (dScore)
|
|
726
678
|
return dScore;
|
|
727
|
-
|
|
728
|
-
return lA < lB ? -1 : lA == lB ? 0 : 1;
|
|
679
|
+
return a.completion.label.localeCompare(b.completion.label);
|
|
729
680
|
}
|
|
730
681
|
function getUserEvent(tr) {
|
|
731
682
|
return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null;
|
|
@@ -836,7 +787,7 @@ Accept the current completion.
|
|
|
836
787
|
*/
|
|
837
788
|
const acceptCompletion = (view) => {
|
|
838
789
|
let cState = view.state.field(completionState, false);
|
|
839
|
-
if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
|
|
790
|
+
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
|
|
840
791
|
return false;
|
|
841
792
|
applyCompletion(view, cState.open.options[cState.open.selected]);
|
|
842
793
|
return true;
|
|
@@ -1012,6 +963,106 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
|
|
|
1012
963
|
}
|
|
1013
964
|
});
|
|
1014
965
|
|
|
966
|
+
const baseTheme = view.EditorView.baseTheme({
|
|
967
|
+
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
968
|
+
"& > ul": {
|
|
969
|
+
fontFamily: "monospace",
|
|
970
|
+
whiteSpace: "nowrap",
|
|
971
|
+
overflow: "auto",
|
|
972
|
+
maxWidth_fallback: "700px",
|
|
973
|
+
maxWidth: "min(700px, 95vw)",
|
|
974
|
+
maxHeight: "10em",
|
|
975
|
+
listStyle: "none",
|
|
976
|
+
margin: 0,
|
|
977
|
+
padding: 0,
|
|
978
|
+
"& > li": {
|
|
979
|
+
cursor: "pointer",
|
|
980
|
+
padding: "1px 1em 1px 3px",
|
|
981
|
+
lineHeight: 1.2
|
|
982
|
+
},
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
"&light .cm-tooltip-autocomplete ul li[aria-selected]": {
|
|
986
|
+
background: "#39e",
|
|
987
|
+
color: "white",
|
|
988
|
+
},
|
|
989
|
+
"&dark .cm-tooltip-autocomplete ul li[aria-selected]": {
|
|
990
|
+
background: "#347",
|
|
991
|
+
color: "white",
|
|
992
|
+
},
|
|
993
|
+
".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": {
|
|
994
|
+
content: '"···"',
|
|
995
|
+
opacity: 0.5,
|
|
996
|
+
display: "block",
|
|
997
|
+
textAlign: "center"
|
|
998
|
+
},
|
|
999
|
+
".cm-tooltip.cm-completionInfo": {
|
|
1000
|
+
position: "absolute",
|
|
1001
|
+
padding: "3px 9px",
|
|
1002
|
+
width: "max-content",
|
|
1003
|
+
maxWidth: "300px",
|
|
1004
|
+
},
|
|
1005
|
+
".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
|
|
1006
|
+
".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
|
|
1007
|
+
"&light .cm-snippetField": { backgroundColor: "#00000022" },
|
|
1008
|
+
"&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
|
|
1009
|
+
".cm-snippetFieldPosition": {
|
|
1010
|
+
verticalAlign: "text-top",
|
|
1011
|
+
width: 0,
|
|
1012
|
+
height: "1.15em",
|
|
1013
|
+
margin: "0 -0.7px -.7em",
|
|
1014
|
+
borderLeft: "1.4px dotted #888"
|
|
1015
|
+
},
|
|
1016
|
+
".cm-completionMatchedText": {
|
|
1017
|
+
textDecoration: "underline"
|
|
1018
|
+
},
|
|
1019
|
+
".cm-completionDetail": {
|
|
1020
|
+
marginLeft: "0.5em",
|
|
1021
|
+
fontStyle: "italic"
|
|
1022
|
+
},
|
|
1023
|
+
".cm-completionIcon": {
|
|
1024
|
+
fontSize: "90%",
|
|
1025
|
+
width: ".8em",
|
|
1026
|
+
display: "inline-block",
|
|
1027
|
+
textAlign: "center",
|
|
1028
|
+
paddingRight: ".6em",
|
|
1029
|
+
opacity: "0.6"
|
|
1030
|
+
},
|
|
1031
|
+
".cm-completionIcon-function, .cm-completionIcon-method": {
|
|
1032
|
+
"&:after": { content: "'ƒ'" }
|
|
1033
|
+
},
|
|
1034
|
+
".cm-completionIcon-class": {
|
|
1035
|
+
"&:after": { content: "'○'" }
|
|
1036
|
+
},
|
|
1037
|
+
".cm-completionIcon-interface": {
|
|
1038
|
+
"&:after": { content: "'◌'" }
|
|
1039
|
+
},
|
|
1040
|
+
".cm-completionIcon-variable": {
|
|
1041
|
+
"&:after": { content: "'𝑥'" }
|
|
1042
|
+
},
|
|
1043
|
+
".cm-completionIcon-constant": {
|
|
1044
|
+
"&:after": { content: "'𝐶'" }
|
|
1045
|
+
},
|
|
1046
|
+
".cm-completionIcon-type": {
|
|
1047
|
+
"&:after": { content: "'𝑡'" }
|
|
1048
|
+
},
|
|
1049
|
+
".cm-completionIcon-enum": {
|
|
1050
|
+
"&:after": { content: "'∪'" }
|
|
1051
|
+
},
|
|
1052
|
+
".cm-completionIcon-property": {
|
|
1053
|
+
"&:after": { content: "'□'" }
|
|
1054
|
+
},
|
|
1055
|
+
".cm-completionIcon-keyword": {
|
|
1056
|
+
"&:after": { content: "'🔑\uFE0E'" } // Disable emoji rendering
|
|
1057
|
+
},
|
|
1058
|
+
".cm-completionIcon-namespace": {
|
|
1059
|
+
"&:after": { content: "'▢'" }
|
|
1060
|
+
},
|
|
1061
|
+
".cm-completionIcon-text": {
|
|
1062
|
+
"&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" }
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1015
1066
|
class FieldPos {
|
|
1016
1067
|
constructor(field, line, from, to) {
|
|
1017
1068
|
this.field = field;
|
|
@@ -1162,8 +1213,7 @@ function snippet(template) {
|
|
|
1162
1213
|
let active = new ActiveSnippet(ranges, 0);
|
|
1163
1214
|
let effects = spec.effects = [setActive.of(active)];
|
|
1164
1215
|
if (editor.state.field(snippetState, false) === undefined)
|
|
1165
|
-
effects.push(state.StateEffect.appendConfig.of([snippetState
|
|
1166
|
-
snippetPointerHandler, baseTheme]));
|
|
1216
|
+
effects.push(state.StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme]));
|
|
1167
1217
|
}
|
|
1168
1218
|
editor.dispatch(editor.state.update(spec));
|
|
1169
1219
|
};
|
|
@@ -1213,7 +1263,7 @@ to [`clearSnippet`](https://codemirror.net/6/docs/ref/#autocomplete.clearSnippet
|
|
|
1213
1263
|
const snippetKeymap = state.Facet.define({
|
|
1214
1264
|
combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; }
|
|
1215
1265
|
});
|
|
1216
|
-
const addSnippetKeymap = state.Prec.
|
|
1266
|
+
const addSnippetKeymap = state.Prec.highest(view.keymap.compute([snippetKeymap], state => state.facet(snippetKeymap)));
|
|
1217
1267
|
/**
|
|
1218
1268
|
Create a completion from a snippet. Returns an object with the
|
|
1219
1269
|
properties from `completion`, plus an `apply` function that
|
|
@@ -1238,42 +1288,81 @@ const snippetPointerHandler = view.EditorView.domEventHandlers({
|
|
|
1238
1288
|
}
|
|
1239
1289
|
});
|
|
1240
1290
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
return
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1291
|
+
function wordRE(wordChars) {
|
|
1292
|
+
let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&");
|
|
1293
|
+
try {
|
|
1294
|
+
return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug");
|
|
1295
|
+
}
|
|
1296
|
+
catch (_a) {
|
|
1297
|
+
return new RegExp(`[\w${escaped}]`, "g");
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
function mapRE(re, f) {
|
|
1301
|
+
return new RegExp(f(re.source), re.unicode ? "u" : "");
|
|
1302
|
+
}
|
|
1303
|
+
const wordCaches = Object.create(null);
|
|
1304
|
+
function wordCache(wordChars) {
|
|
1305
|
+
return wordCaches[wordChars] || (wordCaches[wordChars] = new WeakMap);
|
|
1306
|
+
}
|
|
1307
|
+
function storeWords(doc, wordRE, result, seen, ignoreAt) {
|
|
1308
|
+
for (let lines = doc.iterLines(), pos = 0; !lines.next().done;) {
|
|
1309
|
+
let { value } = lines, m;
|
|
1310
|
+
wordRE.lastIndex = 0;
|
|
1311
|
+
while (m = wordRE.exec(value)) {
|
|
1312
|
+
if (!seen[m[0]] && pos + m.index != ignoreAt) {
|
|
1313
|
+
result.push({ type: "text", label: m[0] });
|
|
1314
|
+
seen[m[0]] = true;
|
|
1315
|
+
if (result.length >= 2000 /* MaxList */)
|
|
1316
|
+
return;
|
|
1257
1317
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1318
|
+
}
|
|
1319
|
+
pos += value.length + 1;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
function collectWords(doc, cache, wordRE, to, ignoreAt) {
|
|
1323
|
+
let big = doc.length >= 1000 /* MinCacheLen */;
|
|
1324
|
+
let cached = big && cache.get(doc);
|
|
1325
|
+
if (cached)
|
|
1326
|
+
return cached;
|
|
1327
|
+
let result = [], seen = Object.create(null);
|
|
1328
|
+
if (doc.children) {
|
|
1329
|
+
let pos = 0;
|
|
1330
|
+
for (let ch of doc.children) {
|
|
1331
|
+
if (ch.length >= 1000 /* MinCacheLen */) {
|
|
1332
|
+
for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) {
|
|
1333
|
+
if (!seen[c.label]) {
|
|
1334
|
+
seen[c.label] = true;
|
|
1335
|
+
result.push(c);
|
|
1267
1336
|
}
|
|
1268
1337
|
}
|
|
1269
|
-
start = -1;
|
|
1270
1338
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1339
|
+
else {
|
|
1340
|
+
storeWords(ch, wordRE, result, seen, ignoreAt - pos);
|
|
1341
|
+
}
|
|
1342
|
+
pos += ch.length + 1;
|
|
1273
1343
|
}
|
|
1274
|
-
pos += value.length;
|
|
1275
1344
|
}
|
|
1276
|
-
|
|
1345
|
+
else {
|
|
1346
|
+
storeWords(doc, wordRE, result, seen, ignoreAt);
|
|
1347
|
+
}
|
|
1348
|
+
if (big && result.length < 2000 /* MaxList */)
|
|
1349
|
+
cache.set(doc, result);
|
|
1350
|
+
return result;
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
A completion source that will scan the document for words (using a
|
|
1354
|
+
[character categorizer](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer)), and
|
|
1355
|
+
return those as completions.
|
|
1356
|
+
*/
|
|
1357
|
+
const completeAnyWord = context => {
|
|
1358
|
+
let wordChars = context.state.languageDataAt("wordChars", context.pos).join("");
|
|
1359
|
+
let re = wordRE(wordChars);
|
|
1360
|
+
let token = context.matchBefore(mapRE(re, s => s + "$"));
|
|
1361
|
+
if (!token && !context.explicit)
|
|
1362
|
+
return null;
|
|
1363
|
+
let from = token ? token.from : context.pos;
|
|
1364
|
+
let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from);
|
|
1365
|
+
return { from, options, span: mapRE(re, s => "^" + s) };
|
|
1277
1366
|
};
|
|
1278
1367
|
|
|
1279
1368
|
/**
|
|
@@ -1308,7 +1397,7 @@ const completionKeymap = [
|
|
|
1308
1397
|
{ key: "PageUp", run: moveCompletionSelection(false, "page") },
|
|
1309
1398
|
{ key: "Enter", run: acceptCompletion }
|
|
1310
1399
|
];
|
|
1311
|
-
const completionKeymapExt = state.Prec.
|
|
1400
|
+
const completionKeymapExt = state.Prec.highest(view.keymap.computeN([completionConfig], state => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : []));
|
|
1312
1401
|
/**
|
|
1313
1402
|
Get the current completion status. When completions are available,
|
|
1314
1403
|
this will return `"active"`. When completions are pending (in the
|
|
@@ -1328,6 +1417,14 @@ function currentCompletions(state) {
|
|
|
1328
1417
|
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1329
1418
|
return open ? open.options.map(o => o.completion) : [];
|
|
1330
1419
|
}
|
|
1420
|
+
/**
|
|
1421
|
+
Return the currently selected completion, if any.
|
|
1422
|
+
*/
|
|
1423
|
+
function selectedCompletion(state) {
|
|
1424
|
+
var _a;
|
|
1425
|
+
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
|
|
1426
|
+
return open ? open.options[open.selected].completion : null;
|
|
1427
|
+
}
|
|
1331
1428
|
|
|
1332
1429
|
exports.CompletionContext = CompletionContext;
|
|
1333
1430
|
exports.acceptCompletion = acceptCompletion;
|
|
@@ -1343,7 +1440,9 @@ exports.ifIn = ifIn;
|
|
|
1343
1440
|
exports.ifNotIn = ifNotIn;
|
|
1344
1441
|
exports.moveCompletionSelection = moveCompletionSelection;
|
|
1345
1442
|
exports.nextSnippetField = nextSnippetField;
|
|
1443
|
+
exports.pickedCompletion = pickedCompletion;
|
|
1346
1444
|
exports.prevSnippetField = prevSnippetField;
|
|
1445
|
+
exports.selectedCompletion = selectedCompletion;
|
|
1347
1446
|
exports.snippet = snippet;
|
|
1348
1447
|
exports.snippetCompletion = snippetCompletion;
|
|
1349
1448
|
exports.snippetKeymap = snippetKeymap;
|