@codemirror/autocomplete 6.7.1 → 6.8.0

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