@codemirror/autocomplete 0.19.14 → 0.19.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.19.15 (2022-03-23)
2
+
3
+ ### New features
4
+
5
+ The `selectedCompletionIndex` function tells you the position of the currently selected completion.
6
+
7
+ The new `setSelectionCompletion` function creates a state effect that moves the selected completion to a given index.
8
+
9
+ A completion's `info` method may now return null to indicate that no further info is available.
10
+
1
11
  ## 0.19.14 (2022-03-10)
2
12
 
3
13
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -374,22 +374,6 @@ function optionContent(config) {
374
374
  });
375
375
  return content.sort((a, b) => a.position - b.position).map(a => a.render);
376
376
  }
377
- function createInfoDialog(option, view$1) {
378
- let dom = document.createElement("div");
379
- dom.className = "cm-tooltip cm-completionInfo";
380
- let { info } = option.completion;
381
- if (typeof info == "string") {
382
- dom.textContent = info;
383
- }
384
- else {
385
- let content = info(option.completion);
386
- if (content.then)
387
- content.then(node => dom.appendChild(node), e => view.logException(view$1.state, e, "completion info"));
388
- else
389
- dom.appendChild(content);
390
- }
391
- return dom;
392
- }
393
377
  function rangeAroundSelected(total, selected, max) {
394
378
  if (total <= max)
395
379
  return { from: 0, to: total };
@@ -458,13 +442,31 @@ class CompletionTooltip {
458
442
  this.info.remove();
459
443
  this.info = null;
460
444
  }
461
- let option = open.options[open.selected];
462
- if (option.completion.info) {
463
- this.info = this.dom.appendChild(createInfoDialog(option, this.view));
464
- this.view.requestMeasure(this.placeInfo);
445
+ let { completion } = open.options[open.selected];
446
+ let { info } = completion;
447
+ if (!info)
448
+ return;
449
+ let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion);
450
+ if (!infoResult)
451
+ return;
452
+ if ('then' in infoResult) {
453
+ infoResult.then(node => {
454
+ if (node && this.view.state.field(this.stateField, false) == cState)
455
+ this.addInfoPane(node);
456
+ }).catch(e => view.logException(this.view.state, e, "completion info"));
457
+ }
458
+ else {
459
+ this.addInfoPane(infoResult);
465
460
  }
466
461
  }
467
462
  }
463
+ addInfoPane(content) {
464
+ let dom = this.info = document.createElement("div");
465
+ dom.className = "cm-tooltip cm-completionInfo";
466
+ dom.appendChild(content);
467
+ this.dom.appendChild(dom);
468
+ this.view.requestMeasure(this.placeInfo);
469
+ }
468
470
  updateSelectedOption(selected) {
469
471
  let set = null;
470
472
  for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) {
@@ -1435,13 +1437,19 @@ function completionStatus(state) {
1435
1437
  return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
1436
1438
  : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
1437
1439
  }
1440
+ const completionArrayCache = new WeakMap;
1438
1441
  /**
1439
1442
  Returns the available completions as an array.
1440
1443
  */
1441
1444
  function currentCompletions(state) {
1442
1445
  var _a;
1443
1446
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1444
- return open ? open.options.map(o => o.completion) : [];
1447
+ if (!open)
1448
+ return [];
1449
+ let completions = completionArrayCache.get(open.options);
1450
+ if (!completions)
1451
+ completionArrayCache.set(open.options, completions = open.options.map(o => o.completion));
1452
+ return completions;
1445
1453
  }
1446
1454
  /**
1447
1455
  Return the currently selected completion, if any.
@@ -1451,6 +1459,22 @@ function selectedCompletion(state) {
1451
1459
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1452
1460
  return open ? open.options[open.selected].completion : null;
1453
1461
  }
1462
+ /**
1463
+ Returns the currently selected position in the active completion
1464
+ list, or null if no completions are active.
1465
+ */
1466
+ function selectedCompletionIndex(state) {
1467
+ var _a;
1468
+ let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1469
+ return open ? open.selected : null;
1470
+ }
1471
+ /**
1472
+ Create an effect that can be attached to a transaction to change
1473
+ the currently selected completion.
1474
+ */
1475
+ function setSelectedCompletion(index) {
1476
+ return setSelectedEffect.of(index);
1477
+ }
1454
1478
 
1455
1479
  exports.CompletionContext = CompletionContext;
1456
1480
  exports.acceptCompletion = acceptCompletion;
@@ -1469,6 +1493,8 @@ exports.nextSnippetField = nextSnippetField;
1469
1493
  exports.pickedCompletion = pickedCompletion;
1470
1494
  exports.prevSnippetField = prevSnippetField;
1471
1495
  exports.selectedCompletion = selectedCompletion;
1496
+ exports.selectedCompletionIndex = selectedCompletionIndex;
1497
+ exports.setSelectedCompletion = setSelectedCompletion;
1472
1498
  exports.snippet = snippet;
1473
1499
  exports.snippetCompletion = snippetCompletion;
1474
1500
  exports.snippetKeymap = snippetKeymap;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _codemirror_state from '@codemirror/state';
2
- import { EditorState, Transaction, StateCommand, Facet, Extension } from '@codemirror/state';
2
+ import { EditorState, Transaction, StateCommand, Facet, Extension, StateEffect } from '@codemirror/state';
3
3
  import { EditorView, KeyBinding, Command } from '@codemirror/view';
4
4
  import * as _lezer_common from '@lezer/common';
5
5
 
@@ -81,7 +81,7 @@ interface Completion {
81
81
  a plain string or a function that'll render the DOM structure to
82
82
  show when invoked.
83
83
  */
84
- info?: string | ((completion: Completion) => (Node | Promise<Node>));
84
+ info?: string | ((completion: Completion) => (Node | null | Promise<Node | null>));
85
85
  /**
86
86
  How to apply the completion. The default is to replace it with
87
87
  its [label](https://codemirror.net/6/docs/ref/#autocomplete.Completion.label). When this holds a
@@ -362,5 +362,15 @@ declare function currentCompletions(state: EditorState): readonly Completion[];
362
362
  Return the currently selected completion, if any.
363
363
  */
364
364
  declare function selectedCompletion(state: EditorState): Completion | null;
365
+ /**
366
+ Returns the currently selected position in the active completion
367
+ list, or null if no completions are active.
368
+ */
369
+ declare function selectedCompletionIndex(state: EditorState): number | null;
370
+ /**
371
+ Create an effect that can be attached to a transaction to change
372
+ the currently selected completion.
373
+ */
374
+ declare function setSelectedCompletion(index: number): StateEffect<unknown>;
365
375
 
366
- export { Completion, CompletionContext, CompletionResult, CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
376
+ export { Completion, CompletionContext, CompletionResult, CompletionSource, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Annotation, Facet, combineConfig, StateEffect, StateField, Prec, EditorSelection, Text, MapMode } from '@codemirror/state';
2
- import { Direction, logException, EditorView, ViewPlugin, Decoration, WidgetType, keymap } from '@codemirror/view';
2
+ import { logException, Direction, EditorView, ViewPlugin, Decoration, WidgetType, keymap } from '@codemirror/view';
3
3
  import { showTooltip, getTooltip } from '@codemirror/tooltip';
4
4
  import { syntaxTree, indentUnit } from '@codemirror/language';
5
5
  import { codePointAt, codePointSize, fromCodePoint } from '@codemirror/text';
@@ -370,22 +370,6 @@ function optionContent(config) {
370
370
  });
371
371
  return content.sort((a, b) => a.position - b.position).map(a => a.render);
372
372
  }
373
- function createInfoDialog(option, view) {
374
- let dom = document.createElement("div");
375
- dom.className = "cm-tooltip cm-completionInfo";
376
- let { info } = option.completion;
377
- if (typeof info == "string") {
378
- dom.textContent = info;
379
- }
380
- else {
381
- let content = info(option.completion);
382
- if (content.then)
383
- content.then(node => dom.appendChild(node), e => logException(view.state, e, "completion info"));
384
- else
385
- dom.appendChild(content);
386
- }
387
- return dom;
388
- }
389
373
  function rangeAroundSelected(total, selected, max) {
390
374
  if (total <= max)
391
375
  return { from: 0, to: total };
@@ -454,13 +438,31 @@ class CompletionTooltip {
454
438
  this.info.remove();
455
439
  this.info = null;
456
440
  }
457
- let option = open.options[open.selected];
458
- if (option.completion.info) {
459
- this.info = this.dom.appendChild(createInfoDialog(option, this.view));
460
- this.view.requestMeasure(this.placeInfo);
441
+ let { completion } = open.options[open.selected];
442
+ let { info } = completion;
443
+ if (!info)
444
+ return;
445
+ let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion);
446
+ if (!infoResult)
447
+ return;
448
+ if ('then' in infoResult) {
449
+ infoResult.then(node => {
450
+ if (node && this.view.state.field(this.stateField, false) == cState)
451
+ this.addInfoPane(node);
452
+ }).catch(e => logException(this.view.state, e, "completion info"));
453
+ }
454
+ else {
455
+ this.addInfoPane(infoResult);
461
456
  }
462
457
  }
463
458
  }
459
+ addInfoPane(content) {
460
+ let dom = this.info = document.createElement("div");
461
+ dom.className = "cm-tooltip cm-completionInfo";
462
+ dom.appendChild(content);
463
+ this.dom.appendChild(dom);
464
+ this.view.requestMeasure(this.placeInfo);
465
+ }
464
466
  updateSelectedOption(selected) {
465
467
  let set = null;
466
468
  for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) {
@@ -1431,13 +1433,19 @@ function completionStatus(state) {
1431
1433
  return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
1432
1434
  : cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
1433
1435
  }
1436
+ const completionArrayCache = /*@__PURE__*/new WeakMap;
1434
1437
  /**
1435
1438
  Returns the available completions as an array.
1436
1439
  */
1437
1440
  function currentCompletions(state) {
1438
1441
  var _a;
1439
1442
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1440
- return open ? open.options.map(o => o.completion) : [];
1443
+ if (!open)
1444
+ return [];
1445
+ let completions = completionArrayCache.get(open.options);
1446
+ if (!completions)
1447
+ completionArrayCache.set(open.options, completions = open.options.map(o => o.completion));
1448
+ return completions;
1441
1449
  }
1442
1450
  /**
1443
1451
  Return the currently selected completion, if any.
@@ -1447,5 +1455,21 @@ function selectedCompletion(state) {
1447
1455
  let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1448
1456
  return open ? open.options[open.selected].completion : null;
1449
1457
  }
1458
+ /**
1459
+ Returns the currently selected position in the active completion
1460
+ list, or null if no completions are active.
1461
+ */
1462
+ function selectedCompletionIndex(state) {
1463
+ var _a;
1464
+ let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
1465
+ return open ? open.selected : null;
1466
+ }
1467
+ /**
1468
+ Create an effect that can be attached to a transaction to change
1469
+ the currently selected completion.
1470
+ */
1471
+ function setSelectedCompletion(index) {
1472
+ return setSelectedEffect.of(index);
1473
+ }
1450
1474
 
1451
- export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
1475
+ export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, ifIn, ifNotIn, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/autocomplete",
3
- "version": "0.19.14",
3
+ "version": "0.19.15",
4
4
  "description": "Autocompletion for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",