@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.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();
@@ -938,9 +731,10 @@ function sortOptions(active, state) {
938
731
  let result = [], prev = null;
939
732
  let compare = state.facet(completionConfig).compareCompletions;
940
733
  for (let opt of options.sort((a, b) => (b.score - a.score) || compare(a.completion, b.completion))) {
941
- if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail ||
942
- (prev.type != null && opt.completion.type != null && prev.type != opt.completion.type) ||
943
- prev.apply != opt.completion.apply)
734
+ let cur = opt.completion;
735
+ if (!prev || prev.label != cur.label || prev.detail != cur.detail ||
736
+ (prev.type != null && cur.type != null && prev.type != cur.type) ||
737
+ prev.apply != cur.apply || prev.boost != cur.boost)
944
738
  result.push(opt);
945
739
  else if (score(opt.completion) > score(prev))
946
740
  result[result.length - 1] = opt;
@@ -964,7 +758,7 @@ class CompletionDialog {
964
758
  static build(active, state, id, prev, conf) {
965
759
  let options = sortOptions(active, state);
966
760
  if (!options.length) {
967
- return prev && active.some(a => a.state == 1 /* State.Pending */) ?
761
+ return prev && active.some(a => a.state == 1 /* Pending */) ?
968
762
  new CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null;
969
763
  }
970
764
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
@@ -978,7 +772,7 @@ class CompletionDialog {
978
772
  }
979
773
  return new CompletionDialog(options, makeAttrs(id, selected), {
980
774
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
981
- create: completionTooltip(completionState),
775
+ create: completionTooltip(completionState, applyCompletion),
982
776
  above: conf.aboveCursor,
983
777
  }, prev ? prev.timestamp : Date.now(), selected, false);
984
778
  }
@@ -1001,7 +795,7 @@ class CompletionState {
1001
795
  state.languageDataAt("autocomplete", cur(state)).map(asSource);
1002
796
  let active = sources.map(source => {
1003
797
  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 */);
798
+ new ActiveSource(source, this.active.some(a => a.state != 0 /* Inactive */) ? 1 /* Pending */ : 0 /* Inactive */);
1005
799
  return value.update(tr, conf);
1006
800
  });
1007
801
  if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
@@ -1012,10 +806,10 @@ class CompletionState {
1012
806
  if (tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
1013
807
  !sameResults(active, this.active))
1014
808
  open = CompletionDialog.build(active, state, this.id, open, conf);
1015
- else if (open && open.disabled && !active.some(a => a.state == 1 /* State.Pending */))
809
+ else if (open && open.disabled && !active.some(a => a.state == 1 /* Pending */))
1016
810
  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);
811
+ if (!open && active.every(a => a.state != 1 /* Pending */) && active.some(a => a.hasResult()))
812
+ active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* Inactive */) : a);
1019
813
  for (let effect of tr.effects)
1020
814
  if (effect.is(setSelectedEffect))
1021
815
  open = open && open.setSelected(effect.value, this.id);
@@ -1069,13 +863,13 @@ class ActiveSource {
1069
863
  value = value.handleUserEvent(tr, event, conf);
1070
864
  else if (tr.docChanged)
1071
865
  value = value.handleChange(tr);
1072
- else if (tr.selection && value.state != 0 /* State.Inactive */)
1073
- value = new ActiveSource(value.source, 0 /* State.Inactive */);
866
+ else if (tr.selection && value.state != 0 /* Inactive */)
867
+ value = new ActiveSource(value.source, 0 /* Inactive */);
1074
868
  for (let effect of tr.effects) {
1075
869
  if (effect.is(startCompletionEffect))
1076
- value = new ActiveSource(value.source, 1 /* State.Pending */, effect.value ? cur(tr.state) : -1);
870
+ value = new ActiveSource(value.source, 1 /* Pending */, effect.value ? cur(tr.state) : -1);
1077
871
  else if (effect.is(closeCompletionEffect))
1078
- value = new ActiveSource(value.source, 0 /* State.Inactive */);
872
+ value = new ActiveSource(value.source, 0 /* Inactive */);
1079
873
  else if (effect.is(setActiveEffect))
1080
874
  for (let active of effect.value)
1081
875
  if (active.source == value.source)
@@ -1084,10 +878,10 @@ class ActiveSource {
1084
878
  return value;
1085
879
  }
1086
880
  handleUserEvent(tr, type, conf) {
1087
- return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* State.Pending */);
881
+ return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* Pending */);
1088
882
  }
1089
883
  handleChange(tr) {
1090
- return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
884
+ return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
1091
885
  }
1092
886
  map(changes) {
1093
887
  return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos));
@@ -1095,7 +889,7 @@ class ActiveSource {
1095
889
  }
1096
890
  class ActiveResult extends ActiveSource {
1097
891
  constructor(source, explicitPos, result, from, to) {
1098
- super(source, 2 /* State.Result */, explicitPos);
892
+ super(source, 2 /* Result */, explicitPos);
1099
893
  this.result = result;
1100
894
  this.from = from;
1101
895
  this.to = to;
@@ -1108,17 +902,17 @@ class ActiveResult extends ActiveSource {
1108
902
  if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
1109
903
  pos > to ||
1110
904
  type == "delete" && cur(tr.startState) == this.from)
1111
- return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* State.Pending */ : 0 /* State.Inactive */);
905
+ return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
1112
906
  let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos), updated;
1113
907
  if (checkValid(this.result.validFor, tr.state, from, to))
1114
908
  return new ActiveResult(this.source, explicitPos, this.result, from, to);
1115
909
  if (this.result.update &&
1116
910
  (updated = this.result.update(this.result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0))))
1117
911
  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);
912
+ return new ActiveSource(this.source, 1 /* Pending */, explicitPos);
1119
913
  }
1120
914
  handleChange(tr) {
1121
- return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
915
+ return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
1122
916
  }
1123
917
  map(mapping) {
1124
918
  return mapping.empty ? this :
@@ -1143,6 +937,230 @@ const completionState = state.StateField.define({
1143
937
  view.EditorView.contentAttributes.from(f, state => state.attrs)
1144
938
  ]
1145
939
  });
940
+ function applyCompletion(view, option) {
941
+ const apply = option.completion.apply || option.completion.label;
942
+ let result = view.state.field(completionState).active.find(a => a.source == option.source);
943
+ if (!(result instanceof ActiveResult))
944
+ return false;
945
+ if (typeof apply == "string")
946
+ view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
947
+ else
948
+ apply(view, option.completion, result.from, result.to);
949
+ return true;
950
+ }
951
+
952
+ /**
953
+ Returns a command that moves the completion selection forward or
954
+ backward by the given amount.
955
+ */
956
+ function moveCompletionSelection(forward, by = "option") {
957
+ return (view$1) => {
958
+ let cState = view$1.state.field(completionState, false);
959
+ if (!cState || !cState.open || cState.open.disabled ||
960
+ Date.now() - cState.open.timestamp < view$1.state.facet(completionConfig).interactionDelay)
961
+ return false;
962
+ let step = 1, tooltip;
963
+ if (by == "page" && (tooltip = view.getTooltip(view$1, cState.open.tooltip)))
964
+ step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
965
+ tooltip.dom.querySelector("li").offsetHeight) - 1);
966
+ let { length } = cState.open.options;
967
+ let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
968
+ if (selected < 0)
969
+ selected = by == "page" ? 0 : length - 1;
970
+ else if (selected >= length)
971
+ selected = by == "page" ? length - 1 : 0;
972
+ view$1.dispatch({ effects: setSelectedEffect.of(selected) });
973
+ return true;
974
+ };
975
+ }
976
+ /**
977
+ Accept the current completion.
978
+ */
979
+ const acceptCompletion = (view) => {
980
+ let cState = view.state.field(completionState, false);
981
+ if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 || cState.open.disabled ||
982
+ Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
983
+ return false;
984
+ return applyCompletion(view, cState.open.options[cState.open.selected]);
985
+ };
986
+ /**
987
+ Explicitly start autocompletion.
988
+ */
989
+ const startCompletion = (view) => {
990
+ let cState = view.state.field(completionState, false);
991
+ if (!cState)
992
+ return false;
993
+ view.dispatch({ effects: startCompletionEffect.of(true) });
994
+ return true;
995
+ };
996
+ /**
997
+ Close the currently active completion.
998
+ */
999
+ const closeCompletion = (view) => {
1000
+ let cState = view.state.field(completionState, false);
1001
+ if (!cState || !cState.active.some(a => a.state != 0 /* Inactive */))
1002
+ return false;
1003
+ view.dispatch({ effects: closeCompletionEffect.of(null) });
1004
+ return true;
1005
+ };
1006
+ class RunningQuery {
1007
+ constructor(active, context) {
1008
+ this.active = active;
1009
+ this.context = context;
1010
+ this.time = Date.now();
1011
+ this.updates = [];
1012
+ // Note that 'undefined' means 'not done yet', whereas 'null' means
1013
+ // 'query returned null'.
1014
+ this.done = undefined;
1015
+ }
1016
+ }
1017
+ const DebounceTime = 50, MaxUpdateCount = 50, MinAbortTime = 1000;
1018
+ const completionPlugin = view.ViewPlugin.fromClass(class {
1019
+ constructor(view) {
1020
+ this.view = view;
1021
+ this.debounceUpdate = -1;
1022
+ this.running = [];
1023
+ this.debounceAccept = -1;
1024
+ this.composing = 0 /* None */;
1025
+ for (let active of view.state.field(completionState).active)
1026
+ if (active.state == 1 /* Pending */)
1027
+ this.startQuery(active);
1028
+ }
1029
+ update(update) {
1030
+ let cState = update.state.field(completionState);
1031
+ if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState)
1032
+ return;
1033
+ let doesReset = update.transactions.some(tr => {
1034
+ return (tr.selection || tr.docChanged) && !getUserEvent(tr);
1035
+ });
1036
+ for (let i = 0; i < this.running.length; i++) {
1037
+ let query = this.running[i];
1038
+ if (doesReset ||
1039
+ query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
1040
+ for (let handler of query.context.abortListeners) {
1041
+ try {
1042
+ handler();
1043
+ }
1044
+ catch (e) {
1045
+ view.logException(this.view.state, e);
1046
+ }
1047
+ }
1048
+ query.context.abortListeners = null;
1049
+ this.running.splice(i--, 1);
1050
+ }
1051
+ else {
1052
+ query.updates.push(...update.transactions);
1053
+ }
1054
+ }
1055
+ if (this.debounceUpdate > -1)
1056
+ clearTimeout(this.debounceUpdate);
1057
+ this.debounceUpdate = cState.active.some(a => a.state == 1 /* Pending */ && !this.running.some(q => q.active.source == a.source))
1058
+ ? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
1059
+ if (this.composing != 0 /* None */)
1060
+ for (let tr of update.transactions) {
1061
+ if (getUserEvent(tr) == "input")
1062
+ this.composing = 2 /* Changed */;
1063
+ else if (this.composing == 2 /* Changed */ && tr.selection)
1064
+ this.composing = 3 /* ChangedAndMoved */;
1065
+ }
1066
+ }
1067
+ startUpdate() {
1068
+ this.debounceUpdate = -1;
1069
+ let { state } = this.view, cState = state.field(completionState);
1070
+ for (let active of cState.active) {
1071
+ if (active.state == 1 /* Pending */ && !this.running.some(r => r.active.source == active.source))
1072
+ this.startQuery(active);
1073
+ }
1074
+ }
1075
+ startQuery(active) {
1076
+ let { state } = this.view, pos = cur(state);
1077
+ let context = new CompletionContext(state, pos, active.explicitPos == pos);
1078
+ let pending = new RunningQuery(active, context);
1079
+ this.running.push(pending);
1080
+ Promise.resolve(active.source(context)).then(result => {
1081
+ if (!pending.context.aborted) {
1082
+ pending.done = result || null;
1083
+ this.scheduleAccept();
1084
+ }
1085
+ }, err => {
1086
+ this.view.dispatch({ effects: closeCompletionEffect.of(null) });
1087
+ view.logException(this.view.state, err);
1088
+ });
1089
+ }
1090
+ scheduleAccept() {
1091
+ if (this.running.every(q => q.done !== undefined))
1092
+ this.accept();
1093
+ else if (this.debounceAccept < 0)
1094
+ this.debounceAccept = setTimeout(() => this.accept(), DebounceTime);
1095
+ }
1096
+ // For each finished query in this.running, try to create a result
1097
+ // or, if appropriate, restart the query.
1098
+ accept() {
1099
+ var _a;
1100
+ if (this.debounceAccept > -1)
1101
+ clearTimeout(this.debounceAccept);
1102
+ this.debounceAccept = -1;
1103
+ let updated = [];
1104
+ let conf = this.view.state.facet(completionConfig);
1105
+ for (let i = 0; i < this.running.length; i++) {
1106
+ let query = this.running[i];
1107
+ if (query.done === undefined)
1108
+ continue;
1109
+ this.running.splice(i--, 1);
1110
+ if (query.done) {
1111
+ 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));
1112
+ // Replay the transactions that happened since the start of
1113
+ // the request and see if that preserves the result
1114
+ for (let tr of query.updates)
1115
+ active = active.update(tr, conf);
1116
+ if (active.hasResult()) {
1117
+ updated.push(active);
1118
+ continue;
1119
+ }
1120
+ }
1121
+ let current = this.view.state.field(completionState).active.find(a => a.source == query.active.source);
1122
+ if (current && current.state == 1 /* Pending */) {
1123
+ if (query.done == null) {
1124
+ // Explicitly failed. Should clear the pending status if it
1125
+ // hasn't been re-set in the meantime.
1126
+ let active = new ActiveSource(query.active.source, 0 /* Inactive */);
1127
+ for (let tr of query.updates)
1128
+ active = active.update(tr, conf);
1129
+ if (active.state != 1 /* Pending */)
1130
+ updated.push(active);
1131
+ }
1132
+ else {
1133
+ // Cleared by subsequent transactions. Restart.
1134
+ this.startQuery(current);
1135
+ }
1136
+ }
1137
+ }
1138
+ if (updated.length)
1139
+ this.view.dispatch({ effects: setActiveEffect.of(updated) });
1140
+ }
1141
+ }, {
1142
+ eventHandlers: {
1143
+ blur(event) {
1144
+ let state = this.view.state.field(completionState, false);
1145
+ if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
1146
+ let dialog = state.open && view.getTooltip(this.view, state.open.tooltip);
1147
+ if (!dialog || !dialog.dom.contains(event.relatedTarget))
1148
+ this.view.dispatch({ effects: closeCompletionEffect.of(null) });
1149
+ }
1150
+ },
1151
+ compositionstart() {
1152
+ this.composing = 1 /* Started */;
1153
+ },
1154
+ compositionend() {
1155
+ if (this.composing == 3 /* ChangedAndMoved */) {
1156
+ // Safari fires compositionend events synchronously, possibly
1157
+ // from inside an update, so dispatch asynchronously to avoid reentrancy
1158
+ setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20);
1159
+ }
1160
+ this.composing = 0 /* None */;
1161
+ }
1162
+ }
1163
+ });
1146
1164
 
1147
1165
  const baseTheme = view.EditorView.baseTheme({
1148
1166
  ".cm-tooltip.cm-tooltip-autocomplete": {
@@ -1199,13 +1217,13 @@ const baseTheme = view.EditorView.baseTheme({
1199
1217
  position: "absolute",
1200
1218
  padding: "3px 9px",
1201
1219
  width: "max-content",
1202
- maxWidth: `${400 /* Info.Width */}px`,
1220
+ maxWidth: `${400 /* Width */}px`,
1203
1221
  boxSizing: "border-box"
1204
1222
  },
1205
1223
  ".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
1206
1224
  ".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` },
1225
+ ".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30 /* Margin */}px` },
1226
+ ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30 /* Margin */}px` },
1209
1227
  "&light .cm-snippetField": { backgroundColor: "#00000022" },
1210
1228
  "&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
1211
1229
  ".cm-snippetFieldPosition": {
@@ -1558,7 +1576,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
1558
1576
  if (!seen[m[0]] && pos + m.index != ignoreAt) {
1559
1577
  result.push({ type: "text", label: m[0] });
1560
1578
  seen[m[0]] = true;
1561
- if (result.length >= 2000 /* C.MaxList */)
1579
+ if (result.length >= 2000 /* MaxList */)
1562
1580
  return;
1563
1581
  }
1564
1582
  }
@@ -1566,7 +1584,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
1566
1584
  }
1567
1585
  }
1568
1586
  function collectWords(doc, cache, wordRE, to, ignoreAt) {
1569
- let big = doc.length >= 1000 /* C.MinCacheLen */;
1587
+ let big = doc.length >= 1000 /* MinCacheLen */;
1570
1588
  let cached = big && cache.get(doc);
1571
1589
  if (cached)
1572
1590
  return cached;
@@ -1574,7 +1592,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
1574
1592
  if (doc.children) {
1575
1593
  let pos = 0;
1576
1594
  for (let ch of doc.children) {
1577
- if (ch.length >= 1000 /* C.MinCacheLen */) {
1595
+ if (ch.length >= 1000 /* MinCacheLen */) {
1578
1596
  for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) {
1579
1597
  if (!seen[c.label]) {
1580
1598
  seen[c.label] = true;
@@ -1591,7 +1609,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
1591
1609
  else {
1592
1610
  storeWords(doc, wordRE, result, seen, ignoreAt);
1593
1611
  }
1594
- if (big && result.length < 2000 /* C.MaxList */)
1612
+ if (big && result.length < 2000 /* MaxList */)
1595
1613
  cache.set(doc, result);
1596
1614
  return result;
1597
1615
  }
@@ -1607,7 +1625,7 @@ const completeAnyWord = context => {
1607
1625
  if (!token && !context.explicit)
1608
1626
  return null;
1609
1627
  let from = token ? token.from : context.pos;
1610
- let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* C.Range */, from);
1628
+ let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from);
1611
1629
  return { from, options, validFor: mapRE(re, s => "^" + s) };
1612
1630
  };
1613
1631
 
@@ -1899,8 +1917,8 @@ returns `null`.
1899
1917
  */
1900
1918
  function completionStatus(state) {
1901
1919
  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;
1920
+ return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
1921
+ : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
1904
1922
  }
1905
1923
  const completionArrayCache = new WeakMap;
1906
1924
  /**