@codemirror/autocomplete 6.7.1 → 6.8.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Annotation, StateEffect, EditorSelection, codePointAt, codePointSize, fromCodePoint, Facet, combineConfig, StateField, Prec, Text, MapMode, RangeValue, RangeSet, CharCategory } from '@codemirror/state';
2
- import { Direction, ViewPlugin, logException, getTooltip, showTooltip, EditorView, Decoration, WidgetType, keymap } from '@codemirror/view';
2
+ import { Direction, logException, showTooltip, EditorView, ViewPlugin, getTooltip, Decoration, WidgetType, keymap } from '@codemirror/view';
3
3
  import { syntaxTree, indentUnit } from '@codemirror/language';
4
4
 
5
5
  /**
@@ -216,7 +216,7 @@ class FuzzyMatcher {
216
216
  // is. See `Penalty` above.
217
217
  match(word) {
218
218
  if (this.pattern.length == 0)
219
- return [-100 /* Penalty.NotFull */];
219
+ return [-100 /* NotFull */];
220
220
  if (word.length < this.pattern.length)
221
221
  return null;
222
222
  let { chars, folded, any, precise, byWord } = this;
@@ -224,17 +224,17 @@ class FuzzyMatcher {
224
224
  // at the start
225
225
  if (chars.length == 1) {
226
226
  let first = codePointAt(word, 0), firstSize = codePointSize(first);
227
- let score = firstSize == word.length ? 0 : -100 /* Penalty.NotFull */;
227
+ let score = firstSize == word.length ? 0 : -100 /* NotFull */;
228
228
  if (first == chars[0]) ;
229
229
  else if (first == folded[0])
230
- score += -200 /* Penalty.CaseFold */;
230
+ score += -200 /* CaseFold */;
231
231
  else
232
232
  return null;
233
233
  return [score, 0, firstSize];
234
234
  }
235
235
  let direct = word.indexOf(this.pattern);
236
236
  if (direct == 0)
237
- return [word.length == this.pattern.length ? 0 : -100 /* Penalty.NotFull */, 0, this.pattern.length];
237
+ return [word.length == this.pattern.length ? 0 : -100 /* NotFull */, 0, this.pattern.length];
238
238
  let len = chars.length, anyTo = 0;
239
239
  if (direct < 0) {
240
240
  for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) {
@@ -258,7 +258,7 @@ class FuzzyMatcher {
258
258
  let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1;
259
259
  let hasLower = /[a-z]/.test(word), wordAdjacent = true;
260
260
  // Go over the option's text, scanning for the various kinds of matches
261
- for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* Tp.NonWord */; i < e && byWordTo < len;) {
261
+ for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* NonWord */; i < e && byWordTo < len;) {
262
262
  let next = codePointAt(word, i);
263
263
  if (direct < 0) {
264
264
  if (preciseTo < len && next == chars[preciseTo])
@@ -276,9 +276,9 @@ class FuzzyMatcher {
276
276
  }
277
277
  }
278
278
  let ch, type = next < 0xff
279
- ? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Tp.Lower */ : next >= 65 && next <= 90 ? 1 /* Tp.Upper */ : 0 /* Tp.NonWord */)
280
- : ((ch = fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Tp.Upper */ : ch != ch.toUpperCase() ? 2 /* Tp.Lower */ : 0 /* Tp.NonWord */);
281
- if (!i || type == 1 /* Tp.Upper */ && hasLower || prevType == 0 /* Tp.NonWord */ && type != 0 /* Tp.NonWord */) {
279
+ ? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Lower */ : next >= 65 && next <= 90 ? 1 /* Upper */ : 0 /* NonWord */)
280
+ : ((ch = fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Upper */ : ch != ch.toUpperCase() ? 2 /* Lower */ : 0 /* NonWord */);
281
+ if (!i || type == 1 /* Upper */ && hasLower || prevType == 0 /* NonWord */ && type != 0 /* NonWord */) {
282
282
  if (chars[byWordTo] == next || (folded[byWordTo] == next && (byWordFolded = true)))
283
283
  byWord[byWordTo++] = i;
284
284
  else if (byWord.length)
@@ -288,17 +288,17 @@ class FuzzyMatcher {
288
288
  i += codePointSize(next);
289
289
  }
290
290
  if (byWordTo == len && byWord[0] == 0 && wordAdjacent)
291
- return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word);
291
+ return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0), byWord, word);
292
292
  if (adjacentTo == len && adjacentStart == 0)
293
- return [-200 /* Penalty.CaseFold */ - word.length + (adjacentEnd == word.length ? 0 : -100 /* Penalty.NotFull */), 0, adjacentEnd];
293
+ return [-200 /* CaseFold */ - word.length + (adjacentEnd == word.length ? 0 : -100 /* NotFull */), 0, adjacentEnd];
294
294
  if (direct > -1)
295
- return [-700 /* Penalty.NotStart */ - word.length, direct, direct + this.pattern.length];
295
+ return [-700 /* NotStart */ - word.length, direct, direct + this.pattern.length];
296
296
  if (adjacentTo == len)
297
- return [-200 /* Penalty.CaseFold */ + -700 /* Penalty.NotStart */ - word.length, adjacentStart, adjacentEnd];
297
+ return [-200 /* CaseFold */ + -700 /* NotStart */ - word.length, adjacentStart, adjacentEnd];
298
298
  if (byWordTo == len)
299
- return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0) + -700 /* Penalty.NotStart */ +
300
- (wordAdjacent ? 0 : -1100 /* Penalty.Gap */), byWord, word);
301
- return chars.length == 2 ? null : this.result((any[0] ? -700 /* Penalty.NotStart */ : 0) + -200 /* Penalty.CaseFold */ + -1100 /* Penalty.Gap */, any, word);
299
+ return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0) + -700 /* NotStart */ +
300
+ (wordAdjacent ? 0 : -1100 /* Gap */), byWord, word);
301
+ return chars.length == 2 ? null : this.result((any[0] ? -700 /* NotStart */ : 0) + -200 /* CaseFold */ + -1100 /* Gap */, any, word);
302
302
  }
303
303
  result(score, positions, word) {
304
304
  let result = [score - word.length], i = 1;
@@ -356,11 +356,11 @@ function defaultPositionInfo(view, list, option, info, space) {
356
356
  left = true;
357
357
  if (infoWidth <= (left ? spaceLeft : spaceRight)) {
358
358
  offset = Math.max(space.top, Math.min(option.top, space.bottom - infoHeight)) - list.top;
359
- maxWidth = Math.min(400 /* Info.Width */, left ? spaceLeft : spaceRight);
359
+ maxWidth = Math.min(400 /* Width */, left ? spaceLeft : spaceRight);
360
360
  }
361
361
  else {
362
362
  narrow = true;
363
- maxWidth = Math.min(400 /* Info.Width */, (rtl ? list.right : space.right - list.left) - 30 /* Info.Margin */);
363
+ maxWidth = Math.min(400 /* Width */, (rtl ? list.right : space.right - list.left) - 30 /* Margin */);
364
364
  let spaceBelow = space.bottom - list.bottom;
365
365
  if (spaceBelow >= infoHeight || spaceBelow > list.top) { // Below the completion
366
366
  offset = option.bottom - list.top;
@@ -376,232 +376,6 @@ function defaultPositionInfo(view, list, option, info, space) {
376
376
  };
377
377
  }
378
378
 
379
- /**
380
- Returns a command that moves the completion selection forward or
381
- backward by the given amount.
382
- */
383
- function moveCompletionSelection(forward, by = "option") {
384
- return (view) => {
385
- let cState = view.state.field(completionState, false);
386
- if (!cState || !cState.open || cState.open.disabled ||
387
- Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
388
- return false;
389
- let step = 1, tooltip;
390
- if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip)))
391
- step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
392
- tooltip.dom.querySelector("li").offsetHeight) - 1);
393
- let { length } = cState.open.options;
394
- let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
395
- if (selected < 0)
396
- selected = by == "page" ? 0 : length - 1;
397
- else if (selected >= length)
398
- selected = by == "page" ? length - 1 : 0;
399
- view.dispatch({ effects: setSelectedEffect.of(selected) });
400
- return true;
401
- };
402
- }
403
- /**
404
- Accept the current completion.
405
- */
406
- const acceptCompletion = (view) => {
407
- let cState = view.state.field(completionState, false);
408
- if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 ||
409
- Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
410
- return false;
411
- if (!cState.open.disabled)
412
- return applyCompletion(view, cState.open.options[cState.open.selected]);
413
- return true;
414
- };
415
- /**
416
- Explicitly start autocompletion.
417
- */
418
- const startCompletion = (view) => {
419
- let cState = view.state.field(completionState, false);
420
- if (!cState)
421
- return false;
422
- view.dispatch({ effects: startCompletionEffect.of(true) });
423
- return true;
424
- };
425
- /**
426
- Close the currently active completion.
427
- */
428
- const closeCompletion = (view) => {
429
- let cState = view.state.field(completionState, false);
430
- if (!cState || !cState.active.some(a => a.state != 0 /* State.Inactive */))
431
- return false;
432
- view.dispatch({ effects: closeCompletionEffect.of(null) });
433
- return true;
434
- };
435
- class RunningQuery {
436
- constructor(active, context) {
437
- this.active = active;
438
- this.context = context;
439
- this.time = Date.now();
440
- this.updates = [];
441
- // Note that 'undefined' means 'not done yet', whereas 'null' means
442
- // 'query returned null'.
443
- this.done = undefined;
444
- }
445
- }
446
- const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000;
447
- const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
448
- constructor(view) {
449
- this.view = view;
450
- this.debounceUpdate = -1;
451
- this.running = [];
452
- this.debounceAccept = -1;
453
- this.composing = 0 /* CompositionState.None */;
454
- for (let active of view.state.field(completionState).active)
455
- if (active.state == 1 /* State.Pending */)
456
- this.startQuery(active);
457
- }
458
- update(update) {
459
- let cState = update.state.field(completionState);
460
- if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState)
461
- return;
462
- let doesReset = update.transactions.some(tr => {
463
- return (tr.selection || tr.docChanged) && !getUserEvent(tr);
464
- });
465
- for (let i = 0; i < this.running.length; i++) {
466
- let query = this.running[i];
467
- if (doesReset ||
468
- query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
469
- for (let handler of query.context.abortListeners) {
470
- try {
471
- handler();
472
- }
473
- catch (e) {
474
- logException(this.view.state, e);
475
- }
476
- }
477
- query.context.abortListeners = null;
478
- this.running.splice(i--, 1);
479
- }
480
- else {
481
- query.updates.push(...update.transactions);
482
- }
483
- }
484
- if (this.debounceUpdate > -1)
485
- clearTimeout(this.debounceUpdate);
486
- this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
487
- ? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
488
- if (this.composing != 0 /* CompositionState.None */)
489
- for (let tr of update.transactions) {
490
- if (getUserEvent(tr) == "input")
491
- this.composing = 2 /* CompositionState.Changed */;
492
- else if (this.composing == 2 /* CompositionState.Changed */ && tr.selection)
493
- this.composing = 3 /* CompositionState.ChangedAndMoved */;
494
- }
495
- }
496
- startUpdate() {
497
- this.debounceUpdate = -1;
498
- let { state } = this.view, cState = state.field(completionState);
499
- for (let active of cState.active) {
500
- if (active.state == 1 /* State.Pending */ && !this.running.some(r => r.active.source == active.source))
501
- this.startQuery(active);
502
- }
503
- }
504
- startQuery(active) {
505
- let { state } = this.view, pos = cur(state);
506
- let context = new CompletionContext(state, pos, active.explicitPos == pos);
507
- let pending = new RunningQuery(active, context);
508
- this.running.push(pending);
509
- Promise.resolve(active.source(context)).then(result => {
510
- if (!pending.context.aborted) {
511
- pending.done = result || null;
512
- this.scheduleAccept();
513
- }
514
- }, err => {
515
- this.view.dispatch({ effects: closeCompletionEffect.of(null) });
516
- logException(this.view.state, err);
517
- });
518
- }
519
- scheduleAccept() {
520
- if (this.running.every(q => q.done !== undefined))
521
- this.accept();
522
- else if (this.debounceAccept < 0)
523
- this.debounceAccept = setTimeout(() => this.accept(), DebounceTime);
524
- }
525
- // For each finished query in this.running, try to create a result
526
- // or, if appropriate, restart the query.
527
- accept() {
528
- var _a;
529
- if (this.debounceAccept > -1)
530
- clearTimeout(this.debounceAccept);
531
- this.debounceAccept = -1;
532
- let updated = [];
533
- let conf = this.view.state.facet(completionConfig);
534
- for (let i = 0; i < this.running.length; i++) {
535
- let query = this.running[i];
536
- if (query.done === undefined)
537
- continue;
538
- this.running.splice(i--, 1);
539
- if (query.done) {
540
- let active = new ActiveResult(query.active.source, query.active.explicitPos, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : cur(query.updates.length ? query.updates[0].startState : this.view.state));
541
- // Replay the transactions that happened since the start of
542
- // the request and see if that preserves the result
543
- for (let tr of query.updates)
544
- active = active.update(tr, conf);
545
- if (active.hasResult()) {
546
- updated.push(active);
547
- continue;
548
- }
549
- }
550
- let current = this.view.state.field(completionState).active.find(a => a.source == query.active.source);
551
- if (current && current.state == 1 /* State.Pending */) {
552
- if (query.done == null) {
553
- // Explicitly failed. Should clear the pending status if it
554
- // hasn't been re-set in the meantime.
555
- let active = new ActiveSource(query.active.source, 0 /* State.Inactive */);
556
- for (let tr of query.updates)
557
- active = active.update(tr, conf);
558
- if (active.state != 1 /* State.Pending */)
559
- updated.push(active);
560
- }
561
- else {
562
- // Cleared by subsequent transactions. Restart.
563
- this.startQuery(current);
564
- }
565
- }
566
- }
567
- if (updated.length)
568
- this.view.dispatch({ effects: setActiveEffect.of(updated) });
569
- }
570
- }, {
571
- eventHandlers: {
572
- blur(event) {
573
- let state = this.view.state.field(completionState, false);
574
- if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
575
- let dialog = state.open && getTooltip(this.view, state.open.tooltip);
576
- if (!dialog || !dialog.dom.contains(event.relatedTarget))
577
- this.view.dispatch({ effects: closeCompletionEffect.of(null) });
578
- }
579
- },
580
- compositionstart() {
581
- this.composing = 1 /* CompositionState.Started */;
582
- },
583
- compositionend() {
584
- if (this.composing == 3 /* CompositionState.ChangedAndMoved */) {
585
- // Safari fires compositionend events synchronously, possibly
586
- // from inside an update, so dispatch asynchronously to avoid reentrancy
587
- setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20);
588
- }
589
- this.composing = 0 /* CompositionState.None */;
590
- }
591
- }
592
- });
593
- function applyCompletion(view, option) {
594
- const apply = option.completion.apply || option.completion.label;
595
- let result = view.state.field(completionState).active.find(a => a.source == option.source);
596
- if (!(result instanceof ActiveResult))
597
- return false;
598
- if (typeof apply == "string")
599
- view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
600
- else
601
- apply(view, option.completion, result.from, result.to);
602
- return true;
603
- }
604
-
605
379
  function optionContent(config) {
606
380
  let content = config.addToOptions.slice();
607
381
  if (config.icons)
@@ -661,10 +435,12 @@ function rangeAroundSelected(total, selected, max) {
661
435
  return { from: total - (off + 1) * max, to: total - off * max };
662
436
  }
663
437
  class CompletionTooltip {
664
- constructor(view, stateField) {
438
+ constructor(view, stateField, applyCompletion) {
665
439
  this.view = view;
666
440
  this.stateField = stateField;
441
+ this.applyCompletion = applyCompletion;
667
442
  this.info = null;
443
+ this.infoDestroy = null;
668
444
  this.placeInfoReq = {
669
445
  read: () => this.measureInfo(),
670
446
  write: (pos) => this.placeInfo(pos),
@@ -685,7 +461,7 @@ class CompletionTooltip {
685
461
  this.dom.addEventListener("mousedown", (e) => {
686
462
  for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) {
687
463
  if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) {
688
- applyCompletion(view, options[+match[1]]);
464
+ this.applyCompletion(view, options[+match[1]]);
689
465
  e.preventDefault();
690
466
  return;
691
467
  }
@@ -744,33 +520,39 @@ class CompletionTooltip {
744
520
  });
745
521
  }
746
522
  if (this.updateSelectedOption(open.selected)) {
747
- if (this.info) {
748
- this.info.remove();
749
- this.info = null;
750
- }
523
+ this.destroyInfo();
751
524
  let { completion } = open.options[open.selected];
752
525
  let { info } = completion;
753
526
  if (!info)
754
527
  return;
755
- let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion);
528
+ let infoResult = typeof info === "string" ? document.createTextNode(info) : info(completion);
756
529
  if (!infoResult)
757
530
  return;
758
- if ('then' in infoResult) {
759
- infoResult.then(node => {
760
- if (node && this.view.state.field(this.stateField, false) == cState)
761
- this.addInfoPane(node);
531
+ if ("then" in infoResult) {
532
+ infoResult.then(obj => {
533
+ if (obj && this.view.state.field(this.stateField, false) == cState)
534
+ this.addInfoPane(obj, completion);
762
535
  }).catch(e => logException(this.view.state, e, "completion info"));
763
536
  }
764
537
  else {
765
- this.addInfoPane(infoResult);
538
+ this.addInfoPane(infoResult, completion);
766
539
  }
767
540
  }
768
541
  }
769
- addInfoPane(content) {
770
- let dom = this.info = document.createElement("div");
771
- dom.className = "cm-tooltip cm-completionInfo";
772
- dom.appendChild(content);
773
- this.dom.appendChild(dom);
542
+ addInfoPane(content, completion) {
543
+ this.destroyInfo();
544
+ let wrap = this.info = document.createElement("div");
545
+ wrap.className = "cm-tooltip cm-completionInfo";
546
+ if (content.nodeType != null) {
547
+ wrap.appendChild(content);
548
+ this.infoDestroy = null;
549
+ }
550
+ else {
551
+ let { dom, destroy } = content;
552
+ wrap.appendChild(dom);
553
+ this.infoDestroy = destroy || null;
554
+ }
555
+ this.dom.appendChild(wrap);
774
556
  this.view.requestMeasure(this.placeInfoReq);
775
557
  }
776
558
  updateSelectedOption(selected) {
@@ -863,11 +645,22 @@ class CompletionTooltip {
863
645
  ul.classList.add("cm-completionListIncompleteBottom");
864
646
  return ul;
865
647
  }
648
+ destroyInfo() {
649
+ if (this.info) {
650
+ if (this.infoDestroy)
651
+ this.infoDestroy();
652
+ this.info.remove();
653
+ this.info = null;
654
+ }
655
+ }
656
+ destroy() {
657
+ this.destroyInfo();
658
+ }
866
659
  }
867
660
  // We allocate a new function instance every time the completion
868
661
  // changes to force redrawing/repositioning of the tooltip
869
- function completionTooltip(stateField) {
870
- return (view) => new CompletionTooltip(view, stateField);
662
+ function completionTooltip(stateField, applyCompletion) {
663
+ return (view) => new CompletionTooltip(view, stateField, applyCompletion);
871
664
  }
872
665
  function scrollIntoView(container, element) {
873
666
  let parent = container.getBoundingClientRect();
@@ -934,9 +727,10 @@ function sortOptions(active, state) {
934
727
  let result = [], prev = null;
935
728
  let compare = state.facet(completionConfig).compareCompletions;
936
729
  for (let opt of options.sort((a, b) => (b.score - a.score) || compare(a.completion, b.completion))) {
937
- if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail ||
938
- (prev.type != null && opt.completion.type != null && prev.type != opt.completion.type) ||
939
- prev.apply != opt.completion.apply)
730
+ let cur = opt.completion;
731
+ if (!prev || prev.label != cur.label || prev.detail != cur.detail ||
732
+ (prev.type != null && cur.type != null && prev.type != cur.type) ||
733
+ prev.apply != cur.apply || prev.boost != cur.boost)
940
734
  result.push(opt);
941
735
  else if (score(opt.completion) > score(prev))
942
736
  result[result.length - 1] = opt;
@@ -960,7 +754,7 @@ class CompletionDialog {
960
754
  static build(active, state, id, prev, conf) {
961
755
  let options = sortOptions(active, state);
962
756
  if (!options.length) {
963
- return prev && active.some(a => a.state == 1 /* State.Pending */) ?
757
+ return prev && active.some(a => a.state == 1 /* Pending */) ?
964
758
  new CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null;
965
759
  }
966
760
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
@@ -974,7 +768,7 @@ class CompletionDialog {
974
768
  }
975
769
  return new CompletionDialog(options, makeAttrs(id, selected), {
976
770
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
977
- create: completionTooltip(completionState),
771
+ create: completionTooltip(completionState, applyCompletion),
978
772
  above: conf.aboveCursor,
979
773
  }, prev ? prev.timestamp : Date.now(), selected, false);
980
774
  }
@@ -997,7 +791,7 @@ class CompletionState {
997
791
  state.languageDataAt("autocomplete", cur(state)).map(asSource);
998
792
  let active = sources.map(source => {
999
793
  let value = this.active.find(s => s.source == source) ||
1000
- new ActiveSource(source, this.active.some(a => a.state != 0 /* State.Inactive */) ? 1 /* State.Pending */ : 0 /* State.Inactive */);
794
+ new ActiveSource(source, this.active.some(a => a.state != 0 /* Inactive */) ? 1 /* Pending */ : 0 /* Inactive */);
1001
795
  return value.update(tr, conf);
1002
796
  });
1003
797
  if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
@@ -1008,10 +802,10 @@ class CompletionState {
1008
802
  if (tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
1009
803
  !sameResults(active, this.active))
1010
804
  open = CompletionDialog.build(active, state, this.id, open, conf);
1011
- else if (open && open.disabled && !active.some(a => a.state == 1 /* State.Pending */))
805
+ else if (open && open.disabled && !active.some(a => a.state == 1 /* Pending */))
1012
806
  open = null;
1013
- if (!open && active.every(a => a.state != 1 /* State.Pending */) && active.some(a => a.hasResult()))
1014
- active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a);
807
+ if (!open && active.every(a => a.state != 1 /* Pending */) && active.some(a => a.hasResult()))
808
+ active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* Inactive */) : a);
1015
809
  for (let effect of tr.effects)
1016
810
  if (effect.is(setSelectedEffect))
1017
811
  open = open && open.setSelected(effect.value, this.id);
@@ -1065,13 +859,13 @@ class ActiveSource {
1065
859
  value = value.handleUserEvent(tr, event, conf);
1066
860
  else if (tr.docChanged)
1067
861
  value = value.handleChange(tr);
1068
- else if (tr.selection && value.state != 0 /* State.Inactive */)
1069
- value = new ActiveSource(value.source, 0 /* State.Inactive */);
862
+ else if (tr.selection && value.state != 0 /* Inactive */)
863
+ value = new ActiveSource(value.source, 0 /* Inactive */);
1070
864
  for (let effect of tr.effects) {
1071
865
  if (effect.is(startCompletionEffect))
1072
- value = new ActiveSource(value.source, 1 /* State.Pending */, effect.value ? cur(tr.state) : -1);
866
+ value = new ActiveSource(value.source, 1 /* Pending */, effect.value ? cur(tr.state) : -1);
1073
867
  else if (effect.is(closeCompletionEffect))
1074
- value = new ActiveSource(value.source, 0 /* State.Inactive */);
868
+ value = new ActiveSource(value.source, 0 /* Inactive */);
1075
869
  else if (effect.is(setActiveEffect))
1076
870
  for (let active of effect.value)
1077
871
  if (active.source == value.source)
@@ -1080,10 +874,10 @@ class ActiveSource {
1080
874
  return value;
1081
875
  }
1082
876
  handleUserEvent(tr, type, conf) {
1083
- return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* State.Pending */);
877
+ return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* Pending */);
1084
878
  }
1085
879
  handleChange(tr) {
1086
- return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
880
+ return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
1087
881
  }
1088
882
  map(changes) {
1089
883
  return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos));
@@ -1091,7 +885,7 @@ class ActiveSource {
1091
885
  }
1092
886
  class ActiveResult extends ActiveSource {
1093
887
  constructor(source, explicitPos, result, from, to) {
1094
- super(source, 2 /* State.Result */, explicitPos);
888
+ super(source, 2 /* Result */, explicitPos);
1095
889
  this.result = result;
1096
890
  this.from = from;
1097
891
  this.to = to;
@@ -1104,17 +898,17 @@ class ActiveResult extends ActiveSource {
1104
898
  if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
1105
899
  pos > to ||
1106
900
  type == "delete" && cur(tr.startState) == this.from)
1107
- return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* State.Pending */ : 0 /* State.Inactive */);
901
+ return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
1108
902
  let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos), updated;
1109
903
  if (checkValid(this.result.validFor, tr.state, from, to))
1110
904
  return new ActiveResult(this.source, explicitPos, this.result, from, to);
1111
905
  if (this.result.update &&
1112
906
  (updated = this.result.update(this.result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0))))
1113
907
  return new ActiveResult(this.source, explicitPos, updated, updated.from, (_a = updated.to) !== null && _a !== void 0 ? _a : cur(tr.state));
1114
- return new ActiveSource(this.source, 1 /* State.Pending */, explicitPos);
908
+ return new ActiveSource(this.source, 1 /* Pending */, explicitPos);
1115
909
  }
1116
910
  handleChange(tr) {
1117
- return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
911
+ return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
1118
912
  }
1119
913
  map(mapping) {
1120
914
  return mapping.empty ? this :
@@ -1139,6 +933,230 @@ const completionState = /*@__PURE__*/StateField.define({
1139
933
  EditorView.contentAttributes.from(f, state => state.attrs)
1140
934
  ]
1141
935
  });
936
+ function applyCompletion(view, option) {
937
+ const apply = option.completion.apply || option.completion.label;
938
+ let result = view.state.field(completionState).active.find(a => a.source == option.source);
939
+ if (!(result instanceof ActiveResult))
940
+ return false;
941
+ if (typeof apply == "string")
942
+ view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
943
+ else
944
+ apply(view, option.completion, result.from, result.to);
945
+ return true;
946
+ }
947
+
948
+ /**
949
+ Returns a command that moves the completion selection forward or
950
+ backward by the given amount.
951
+ */
952
+ function moveCompletionSelection(forward, by = "option") {
953
+ return (view) => {
954
+ let cState = view.state.field(completionState, false);
955
+ if (!cState || !cState.open || cState.open.disabled ||
956
+ Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
957
+ return false;
958
+ let step = 1, tooltip;
959
+ if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip)))
960
+ step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
961
+ tooltip.dom.querySelector("li").offsetHeight) - 1);
962
+ let { length } = cState.open.options;
963
+ let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
964
+ if (selected < 0)
965
+ selected = by == "page" ? 0 : length - 1;
966
+ else if (selected >= length)
967
+ selected = by == "page" ? length - 1 : 0;
968
+ view.dispatch({ effects: setSelectedEffect.of(selected) });
969
+ return true;
970
+ };
971
+ }
972
+ /**
973
+ Accept the current completion.
974
+ */
975
+ const acceptCompletion = (view) => {
976
+ let cState = view.state.field(completionState, false);
977
+ if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 || cState.open.disabled ||
978
+ Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
979
+ return false;
980
+ return applyCompletion(view, cState.open.options[cState.open.selected]);
981
+ };
982
+ /**
983
+ Explicitly start autocompletion.
984
+ */
985
+ const startCompletion = (view) => {
986
+ let cState = view.state.field(completionState, false);
987
+ if (!cState)
988
+ return false;
989
+ view.dispatch({ effects: startCompletionEffect.of(true) });
990
+ return true;
991
+ };
992
+ /**
993
+ Close the currently active completion.
994
+ */
995
+ const closeCompletion = (view) => {
996
+ let cState = view.state.field(completionState, false);
997
+ if (!cState || !cState.active.some(a => a.state != 0 /* Inactive */))
998
+ return false;
999
+ view.dispatch({ effects: closeCompletionEffect.of(null) });
1000
+ return true;
1001
+ };
1002
+ class RunningQuery {
1003
+ constructor(active, context) {
1004
+ this.active = active;
1005
+ this.context = context;
1006
+ this.time = Date.now();
1007
+ this.updates = [];
1008
+ // Note that 'undefined' means 'not done yet', whereas 'null' means
1009
+ // 'query returned null'.
1010
+ this.done = undefined;
1011
+ }
1012
+ }
1013
+ const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000;
1014
+ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
1015
+ constructor(view) {
1016
+ this.view = view;
1017
+ this.debounceUpdate = -1;
1018
+ this.running = [];
1019
+ this.debounceAccept = -1;
1020
+ this.composing = 0 /* None */;
1021
+ for (let active of view.state.field(completionState).active)
1022
+ if (active.state == 1 /* Pending */)
1023
+ this.startQuery(active);
1024
+ }
1025
+ update(update) {
1026
+ let cState = update.state.field(completionState);
1027
+ if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState)
1028
+ return;
1029
+ let doesReset = update.transactions.some(tr => {
1030
+ return (tr.selection || tr.docChanged) && !getUserEvent(tr);
1031
+ });
1032
+ for (let i = 0; i < this.running.length; i++) {
1033
+ let query = this.running[i];
1034
+ if (doesReset ||
1035
+ query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
1036
+ for (let handler of query.context.abortListeners) {
1037
+ try {
1038
+ handler();
1039
+ }
1040
+ catch (e) {
1041
+ logException(this.view.state, e);
1042
+ }
1043
+ }
1044
+ query.context.abortListeners = null;
1045
+ this.running.splice(i--, 1);
1046
+ }
1047
+ else {
1048
+ query.updates.push(...update.transactions);
1049
+ }
1050
+ }
1051
+ if (this.debounceUpdate > -1)
1052
+ clearTimeout(this.debounceUpdate);
1053
+ this.debounceUpdate = cState.active.some(a => a.state == 1 /* Pending */ && !this.running.some(q => q.active.source == a.source))
1054
+ ? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
1055
+ if (this.composing != 0 /* None */)
1056
+ for (let tr of update.transactions) {
1057
+ if (getUserEvent(tr) == "input")
1058
+ this.composing = 2 /* Changed */;
1059
+ else if (this.composing == 2 /* Changed */ && tr.selection)
1060
+ this.composing = 3 /* ChangedAndMoved */;
1061
+ }
1062
+ }
1063
+ startUpdate() {
1064
+ this.debounceUpdate = -1;
1065
+ let { state } = this.view, cState = state.field(completionState);
1066
+ for (let active of cState.active) {
1067
+ if (active.state == 1 /* Pending */ && !this.running.some(r => r.active.source == active.source))
1068
+ this.startQuery(active);
1069
+ }
1070
+ }
1071
+ startQuery(active) {
1072
+ let { state } = this.view, pos = cur(state);
1073
+ let context = new CompletionContext(state, pos, active.explicitPos == pos);
1074
+ let pending = new RunningQuery(active, context);
1075
+ this.running.push(pending);
1076
+ Promise.resolve(active.source(context)).then(result => {
1077
+ if (!pending.context.aborted) {
1078
+ pending.done = result || null;
1079
+ this.scheduleAccept();
1080
+ }
1081
+ }, err => {
1082
+ this.view.dispatch({ effects: closeCompletionEffect.of(null) });
1083
+ logException(this.view.state, err);
1084
+ });
1085
+ }
1086
+ scheduleAccept() {
1087
+ if (this.running.every(q => q.done !== undefined))
1088
+ this.accept();
1089
+ else if (this.debounceAccept < 0)
1090
+ this.debounceAccept = setTimeout(() => this.accept(), DebounceTime);
1091
+ }
1092
+ // For each finished query in this.running, try to create a result
1093
+ // or, if appropriate, restart the query.
1094
+ accept() {
1095
+ var _a;
1096
+ if (this.debounceAccept > -1)
1097
+ clearTimeout(this.debounceAccept);
1098
+ this.debounceAccept = -1;
1099
+ let updated = [];
1100
+ let conf = this.view.state.facet(completionConfig);
1101
+ for (let i = 0; i < this.running.length; i++) {
1102
+ let query = this.running[i];
1103
+ if (query.done === undefined)
1104
+ continue;
1105
+ this.running.splice(i--, 1);
1106
+ if (query.done) {
1107
+ let active = new ActiveResult(query.active.source, query.active.explicitPos, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : cur(query.updates.length ? query.updates[0].startState : this.view.state));
1108
+ // Replay the transactions that happened since the start of
1109
+ // the request and see if that preserves the result
1110
+ for (let tr of query.updates)
1111
+ active = active.update(tr, conf);
1112
+ if (active.hasResult()) {
1113
+ updated.push(active);
1114
+ continue;
1115
+ }
1116
+ }
1117
+ let current = this.view.state.field(completionState).active.find(a => a.source == query.active.source);
1118
+ if (current && current.state == 1 /* Pending */) {
1119
+ if (query.done == null) {
1120
+ // Explicitly failed. Should clear the pending status if it
1121
+ // hasn't been re-set in the meantime.
1122
+ let active = new ActiveSource(query.active.source, 0 /* Inactive */);
1123
+ for (let tr of query.updates)
1124
+ active = active.update(tr, conf);
1125
+ if (active.state != 1 /* Pending */)
1126
+ updated.push(active);
1127
+ }
1128
+ else {
1129
+ // Cleared by subsequent transactions. Restart.
1130
+ this.startQuery(current);
1131
+ }
1132
+ }
1133
+ }
1134
+ if (updated.length)
1135
+ this.view.dispatch({ effects: setActiveEffect.of(updated) });
1136
+ }
1137
+ }, {
1138
+ eventHandlers: {
1139
+ blur(event) {
1140
+ let state = this.view.state.field(completionState, false);
1141
+ if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
1142
+ let dialog = state.open && getTooltip(this.view, state.open.tooltip);
1143
+ if (!dialog || !dialog.dom.contains(event.relatedTarget))
1144
+ this.view.dispatch({ effects: closeCompletionEffect.of(null) });
1145
+ }
1146
+ },
1147
+ compositionstart() {
1148
+ this.composing = 1 /* Started */;
1149
+ },
1150
+ compositionend() {
1151
+ if (this.composing == 3 /* ChangedAndMoved */) {
1152
+ // Safari fires compositionend events synchronously, possibly
1153
+ // from inside an update, so dispatch asynchronously to avoid reentrancy
1154
+ setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20);
1155
+ }
1156
+ this.composing = 0 /* None */;
1157
+ }
1158
+ }
1159
+ });
1142
1160
 
1143
1161
  const baseTheme = /*@__PURE__*/EditorView.baseTheme({
1144
1162
  ".cm-tooltip.cm-tooltip-autocomplete": {
@@ -1195,13 +1213,13 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
1195
1213
  position: "absolute",
1196
1214
  padding: "3px 9px",
1197
1215
  width: "max-content",
1198
- maxWidth: `${400 /* Info.Width */}px`,
1216
+ maxWidth: `${400 /* Width */}px`,
1199
1217
  boxSizing: "border-box"
1200
1218
  },
1201
1219
  ".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
1202
1220
  ".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
1203
- ".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30 /* Info.Margin */}px` },
1204
- ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30 /* Info.Margin */}px` },
1221
+ ".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30 /* Margin */}px` },
1222
+ ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30 /* Margin */}px` },
1205
1223
  "&light .cm-snippetField": { backgroundColor: "#00000022" },
1206
1224
  "&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
1207
1225
  ".cm-snippetFieldPosition": {
@@ -1554,7 +1572,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
1554
1572
  if (!seen[m[0]] && pos + m.index != ignoreAt) {
1555
1573
  result.push({ type: "text", label: m[0] });
1556
1574
  seen[m[0]] = true;
1557
- if (result.length >= 2000 /* C.MaxList */)
1575
+ if (result.length >= 2000 /* MaxList */)
1558
1576
  return;
1559
1577
  }
1560
1578
  }
@@ -1562,7 +1580,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
1562
1580
  }
1563
1581
  }
1564
1582
  function collectWords(doc, cache, wordRE, to, ignoreAt) {
1565
- let big = doc.length >= 1000 /* C.MinCacheLen */;
1583
+ let big = doc.length >= 1000 /* MinCacheLen */;
1566
1584
  let cached = big && cache.get(doc);
1567
1585
  if (cached)
1568
1586
  return cached;
@@ -1570,7 +1588,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
1570
1588
  if (doc.children) {
1571
1589
  let pos = 0;
1572
1590
  for (let ch of doc.children) {
1573
- if (ch.length >= 1000 /* C.MinCacheLen */) {
1591
+ if (ch.length >= 1000 /* MinCacheLen */) {
1574
1592
  for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) {
1575
1593
  if (!seen[c.label]) {
1576
1594
  seen[c.label] = true;
@@ -1587,7 +1605,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
1587
1605
  else {
1588
1606
  storeWords(doc, wordRE, result, seen, ignoreAt);
1589
1607
  }
1590
- if (big && result.length < 2000 /* C.MaxList */)
1608
+ if (big && result.length < 2000 /* MaxList */)
1591
1609
  cache.set(doc, result);
1592
1610
  return result;
1593
1611
  }
@@ -1603,7 +1621,7 @@ const completeAnyWord = context => {
1603
1621
  if (!token && !context.explicit)
1604
1622
  return null;
1605
1623
  let from = token ? token.from : context.pos;
1606
- let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* C.Range */, from);
1624
+ let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from);
1607
1625
  return { from, options, validFor: mapRE(re, s => "^" + s) };
1608
1626
  };
1609
1627
 
@@ -1895,8 +1913,8 @@ returns `null`.
1895
1913
  */
1896
1914
  function completionStatus(state) {
1897
1915
  let cState = state.field(completionState, false);
1898
- return cState && cState.active.some(a => a.state == 1 /* State.Pending */) ? "pending"
1899
- : cState && cState.active.some(a => a.state != 0 /* State.Inactive */) ? "active" : null;
1916
+ return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
1917
+ : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
1900
1918
  }
1901
1919
  const completionArrayCache = /*@__PURE__*/new WeakMap;
1902
1920
  /**