mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-05 02:39:46 +02:00
npm update
This commit is contained in:
parent
0cdd3e9fee
commit
4696ba952f
1437 changed files with 32727 additions and 1248226 deletions
499
node_modules/@codemirror/autocomplete/dist/index.js
generated
vendored
499
node_modules/@codemirror/autocomplete/dist/index.js
generated
vendored
|
@ -1,5 +1,5 @@
|
|||
import { Annotation, EditorSelection, codePointAt, codePointSize, fromCodePoint, Facet, combineConfig, StateEffect, StateField, Prec, Text, MapMode, RangeValue, RangeSet, CharCategory } from '@codemirror/state';
|
||||
import { logException, Direction, showTooltip, EditorView, ViewPlugin, getTooltip, Decoration, WidgetType, keymap } from '@codemirror/view';
|
||||
import { Annotation, StateEffect, EditorSelection, codePointAt, codePointSize, fromCodePoint, Facet, combineConfig, StateField, Prec, Text, MapMode, RangeValue, RangeSet, CharCategory } from '@codemirror/state';
|
||||
import { Direction, logException, showTooltip, EditorView, ViewPlugin, getTooltip, Decoration, WidgetType, keymap } from '@codemirror/view';
|
||||
import { syntaxTree, indentUnit } from '@codemirror/language';
|
||||
|
||||
/**
|
||||
|
@ -108,9 +108,12 @@ cursor is in a syntax node with one of the given names.
|
|||
*/
|
||||
function ifIn(nodes, source) {
|
||||
return (context) => {
|
||||
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent)
|
||||
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
|
||||
if (nodes.indexOf(pos.name) > -1)
|
||||
return source(context);
|
||||
if (pos.type.isTop)
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
@ -120,20 +123,24 @@ cursor is in a syntax node with one of the given names.
|
|||
*/
|
||||
function ifNotIn(nodes, source) {
|
||||
return (context) => {
|
||||
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent)
|
||||
for (let pos = syntaxTree(context.state).resolveInner(context.pos, -1); pos; pos = pos.parent) {
|
||||
if (nodes.indexOf(pos.name) > -1)
|
||||
return null;
|
||||
if (pos.type.isTop)
|
||||
break;
|
||||
}
|
||||
return source(context);
|
||||
};
|
||||
}
|
||||
class Option {
|
||||
constructor(completion, source, match) {
|
||||
constructor(completion, source, match, score) {
|
||||
this.completion = completion;
|
||||
this.source = source;
|
||||
this.match = match;
|
||||
this.score = score;
|
||||
}
|
||||
}
|
||||
function cur(state) { return state.selection.main.head; }
|
||||
function cur(state) { return state.selection.main.from; }
|
||||
// Make sure the given regexp has a $ at its end and, if `start` is
|
||||
// true, a ^ at its start.
|
||||
function ensureAnchor(expr, start) {
|
||||
|
@ -155,30 +162,17 @@ completion's text in the main selection range, and any other
|
|||
selection range that has the same text in front of it.
|
||||
*/
|
||||
function insertCompletionText(state, text, from, to) {
|
||||
let { main } = state.selection, fromOff = from - main.from, toOff = to - main.from;
|
||||
return Object.assign(Object.assign({}, state.changeByRange(range => {
|
||||
if (range == state.selection.main)
|
||||
return {
|
||||
changes: { from: from, to: to, insert: text },
|
||||
range: EditorSelection.cursor(from + text.length)
|
||||
};
|
||||
let len = to - from;
|
||||
if (!range.empty ||
|
||||
len && state.sliceDoc(range.from - len, range.from) != state.sliceDoc(from, to))
|
||||
if (range != main && from != to &&
|
||||
state.sliceDoc(range.from + fromOff, range.from + toOff) != state.sliceDoc(from, to))
|
||||
return { range };
|
||||
return {
|
||||
changes: { from: range.from - len, to: range.from, insert: text },
|
||||
range: EditorSelection.cursor(range.from - len + text.length)
|
||||
changes: { from: range.from + fromOff, to: to == main.from ? range.to : range.from + toOff, insert: text },
|
||||
range: EditorSelection.cursor(range.from + fromOff + text.length)
|
||||
};
|
||||
})), { userEvent: "input.complete" });
|
||||
}
|
||||
function applyCompletion(view, option) {
|
||||
const apply = option.completion.apply || option.completion.label;
|
||||
let result = option.source;
|
||||
if (typeof apply == "string")
|
||||
view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
|
||||
else
|
||||
apply(view, option.completion, result.from, result.to);
|
||||
}
|
||||
const SourceCache = /*@__PURE__*/new WeakMap();
|
||||
function asSource(source) {
|
||||
if (!Array.isArray(source))
|
||||
|
@ -188,6 +182,8 @@ function asSource(source) {
|
|||
SourceCache.set(source, known = completeFromList(source));
|
||||
return known;
|
||||
}
|
||||
const startCompletionEffect = /*@__PURE__*/StateEffect.define();
|
||||
const closeCompletionEffect = /*@__PURE__*/StateEffect.define();
|
||||
|
||||
// A pattern matcher for fuzzy completion matching. Create an instance
|
||||
// once for a pattern, and then use that to match any number of
|
||||
|
@ -202,6 +198,8 @@ class FuzzyMatcher {
|
|||
this.any = [];
|
||||
this.precise = [];
|
||||
this.byWord = [];
|
||||
this.score = 0;
|
||||
this.matched = [];
|
||||
for (let p = 0; p < pattern.length;) {
|
||||
let char = codePointAt(pattern, p), size = codePointSize(char);
|
||||
this.chars.push(char);
|
||||
|
@ -211,29 +209,39 @@ class FuzzyMatcher {
|
|||
}
|
||||
this.astral = pattern.length != this.chars.length;
|
||||
}
|
||||
ret(score, matched) {
|
||||
this.score = score;
|
||||
this.matched = matched;
|
||||
return true;
|
||||
}
|
||||
// Matches a given word (completion) against the pattern (input).
|
||||
// Will return null for no match, and otherwise an array that starts
|
||||
// with the match score, followed by any number of `from, to` pairs
|
||||
// indicating the matched parts of `word`.
|
||||
// Will return a boolean indicating whether there was a match and,
|
||||
// on success, set `this.score` to the score, `this.matched` to an
|
||||
// array of `from, to` pairs indicating the matched parts of `word`.
|
||||
//
|
||||
// The score is a number that is more negative the worse the match
|
||||
// is. See `Penalty` above.
|
||||
match(word) {
|
||||
if (this.pattern.length == 0)
|
||||
return [0];
|
||||
return this.ret(-100 /* NotFull */, []);
|
||||
if (word.length < this.pattern.length)
|
||||
return null;
|
||||
return false;
|
||||
let { chars, folded, any, precise, byWord } = this;
|
||||
// For single-character queries, only match when they occur right
|
||||
// at the start
|
||||
if (chars.length == 1) {
|
||||
let first = codePointAt(word, 0);
|
||||
return first == chars[0] ? [0, 0, codePointSize(first)]
|
||||
: first == folded[0] ? [-200 /* Penalty.CaseFold */, 0, codePointSize(first)] : null;
|
||||
let first = codePointAt(word, 0), firstSize = codePointSize(first);
|
||||
let score = firstSize == word.length ? 0 : -100 /* NotFull */;
|
||||
if (first == chars[0]) ;
|
||||
else if (first == folded[0])
|
||||
score += -200 /* CaseFold */;
|
||||
else
|
||||
return false;
|
||||
return this.ret(score, [0, firstSize]);
|
||||
}
|
||||
let direct = word.indexOf(this.pattern);
|
||||
if (direct == 0)
|
||||
return [0, 0, this.pattern.length];
|
||||
return this.ret(word.length == this.pattern.length ? 0 : -100 /* NotFull */, [0, this.pattern.length]);
|
||||
let len = chars.length, anyTo = 0;
|
||||
if (direct < 0) {
|
||||
for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) {
|
||||
|
@ -244,7 +252,7 @@ class FuzzyMatcher {
|
|||
}
|
||||
// No match, exit immediately
|
||||
if (anyTo < len)
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
// This tracks the extent of the precise (non-folded, not
|
||||
// necessarily adjacent) match
|
||||
|
@ -257,7 +265,7 @@ class FuzzyMatcher {
|
|||
let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1;
|
||||
let hasLower = /[a-z]/.test(word), wordAdjacent = true;
|
||||
// Go over the option's text, scanning for the various kinds of matches
|
||||
for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* Tp.NonWord */; i < e && byWordTo < len;) {
|
||||
for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* NonWord */; i < e && byWordTo < len;) {
|
||||
let next = codePointAt(word, i);
|
||||
if (direct < 0) {
|
||||
if (preciseTo < len && next == chars[preciseTo])
|
||||
|
@ -275,9 +283,9 @@ class FuzzyMatcher {
|
|||
}
|
||||
}
|
||||
let ch, type = next < 0xff
|
||||
? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Tp.Lower */ : next >= 65 && next <= 90 ? 1 /* Tp.Upper */ : 0 /* Tp.NonWord */)
|
||||
: ((ch = fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Tp.Upper */ : ch != ch.toUpperCase() ? 2 /* Tp.Lower */ : 0 /* Tp.NonWord */);
|
||||
if (!i || type == 1 /* Tp.Upper */ && hasLower || prevType == 0 /* Tp.NonWord */ && type != 0 /* Tp.NonWord */) {
|
||||
? (next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 /* Lower */ : next >= 65 && next <= 90 ? 1 /* Upper */ : 0 /* NonWord */)
|
||||
: ((ch = fromCodePoint(next)) != ch.toLowerCase() ? 1 /* Upper */ : ch != ch.toUpperCase() ? 2 /* Lower */ : 0 /* NonWord */);
|
||||
if (!i || type == 1 /* Upper */ && hasLower || prevType == 0 /* NonWord */ && type != 0 /* NonWord */) {
|
||||
if (chars[byWordTo] == next || (folded[byWordTo] == next && (byWordFolded = true)))
|
||||
byWord[byWordTo++] = i;
|
||||
else if (byWord.length)
|
||||
|
@ -287,30 +295,31 @@ class FuzzyMatcher {
|
|||
i += codePointSize(next);
|
||||
}
|
||||
if (byWordTo == len && byWord[0] == 0 && wordAdjacent)
|
||||
return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word);
|
||||
return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0), byWord, word);
|
||||
if (adjacentTo == len && adjacentStart == 0)
|
||||
return [-200 /* Penalty.CaseFold */ - word.length, 0, adjacentEnd];
|
||||
return this.ret(-200 /* CaseFold */ - word.length + (adjacentEnd == word.length ? 0 : -100 /* NotFull */), [0, adjacentEnd]);
|
||||
if (direct > -1)
|
||||
return [-700 /* Penalty.NotStart */ - word.length, direct, direct + this.pattern.length];
|
||||
return this.ret(-700 /* NotStart */ - word.length, [direct, direct + this.pattern.length]);
|
||||
if (adjacentTo == len)
|
||||
return [-200 /* Penalty.CaseFold */ + -700 /* Penalty.NotStart */ - word.length, adjacentStart, adjacentEnd];
|
||||
return this.ret(-200 /* CaseFold */ + -700 /* NotStart */ - word.length, [adjacentStart, adjacentEnd]);
|
||||
if (byWordTo == len)
|
||||
return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0) + -700 /* Penalty.NotStart */ +
|
||||
(wordAdjacent ? 0 : -1100 /* Penalty.Gap */), byWord, word);
|
||||
return chars.length == 2 ? null : this.result((any[0] ? -700 /* Penalty.NotStart */ : 0) + -200 /* Penalty.CaseFold */ + -1100 /* Penalty.Gap */, any, word);
|
||||
return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0) + -700 /* NotStart */ +
|
||||
(wordAdjacent ? 0 : -1100 /* Gap */), byWord, word);
|
||||
return chars.length == 2 ? false
|
||||
: this.result((any[0] ? -700 /* NotStart */ : 0) + -200 /* CaseFold */ + -1100 /* Gap */, any, word);
|
||||
}
|
||||
result(score, positions, word) {
|
||||
let result = [score - word.length], i = 1;
|
||||
let result = [], i = 0;
|
||||
for (let pos of positions) {
|
||||
let to = pos + (this.astral ? codePointSize(codePointAt(word, pos)) : 1);
|
||||
if (i > 1 && result[i - 1] == pos)
|
||||
if (i && result[i - 1] == pos)
|
||||
result[i - 1] = to;
|
||||
else {
|
||||
result[i++] = pos;
|
||||
result[i++] = to;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return this.ret(score - word.length, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,6 +337,7 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|||
aboveCursor: false,
|
||||
icons: true,
|
||||
addToOptions: [],
|
||||
positionInfo: defaultPositionInfo,
|
||||
compareCompletions: (a, b) => a.label.localeCompare(b.label),
|
||||
interactionDelay: 75
|
||||
}, {
|
||||
|
@ -343,6 +353,36 @@ const completionConfig = /*@__PURE__*/Facet.define({
|
|||
function joinClass(a, b) {
|
||||
return a ? b ? a + " " + b : a : b;
|
||||
}
|
||||
function defaultPositionInfo(view, list, option, info, space) {
|
||||
let rtl = view.textDirection == Direction.RTL, left = rtl, narrow = false;
|
||||
let side = "top", offset, maxWidth;
|
||||
let spaceLeft = list.left - space.left, spaceRight = space.right - list.right;
|
||||
let infoWidth = info.right - info.left, infoHeight = info.bottom - info.top;
|
||||
if (left && spaceLeft < Math.min(infoWidth, spaceRight))
|
||||
left = false;
|
||||
else if (!left && spaceRight < Math.min(infoWidth, spaceLeft))
|
||||
left = true;
|
||||
if (infoWidth <= (left ? spaceLeft : spaceRight)) {
|
||||
offset = Math.max(space.top, Math.min(option.top, space.bottom - infoHeight)) - list.top;
|
||||
maxWidth = Math.min(400 /* Width */, left ? spaceLeft : spaceRight);
|
||||
}
|
||||
else {
|
||||
narrow = true;
|
||||
maxWidth = Math.min(400 /* Width */, (rtl ? list.right : space.right - list.left) - 30 /* Margin */);
|
||||
let spaceBelow = space.bottom - list.bottom;
|
||||
if (spaceBelow >= infoHeight || spaceBelow > list.top) { // Below the completion
|
||||
offset = option.bottom - list.top;
|
||||
}
|
||||
else { // Above it
|
||||
side = "bottom";
|
||||
offset = list.bottom - option.top;
|
||||
}
|
||||
}
|
||||
return {
|
||||
style: `${side}: ${offset}px; max-width: ${maxWidth}px`,
|
||||
class: "cm-completionInfo-" + (narrow ? (rtl ? "left-narrow" : "right-narrow") : left ? "left" : "right")
|
||||
};
|
||||
}
|
||||
|
||||
function optionContent(config) {
|
||||
let content = config.addToOptions.slice();
|
||||
|
@ -362,8 +402,8 @@ function optionContent(config) {
|
|||
render(completion, _s, match) {
|
||||
let labelElt = document.createElement("span");
|
||||
labelElt.className = "cm-completionLabel";
|
||||
let { label } = completion, off = 0;
|
||||
for (let j = 1; j < match.length;) {
|
||||
let label = completion.displayLabel || completion.label, off = 0;
|
||||
for (let j = 0; j < match.length;) {
|
||||
let from = match[j++], to = match[j++];
|
||||
if (from > off)
|
||||
labelElt.appendChild(document.createTextNode(label.slice(off, from)));
|
||||
|
@ -403,13 +443,15 @@ function rangeAroundSelected(total, selected, max) {
|
|||
return { from: total - (off + 1) * max, to: total - off * max };
|
||||
}
|
||||
class CompletionTooltip {
|
||||
constructor(view, stateField) {
|
||||
constructor(view, stateField, applyCompletion) {
|
||||
this.view = view;
|
||||
this.stateField = stateField;
|
||||
this.applyCompletion = applyCompletion;
|
||||
this.info = null;
|
||||
this.placeInfo = {
|
||||
this.infoDestroy = null;
|
||||
this.placeInfoReq = {
|
||||
read: () => this.measureInfo(),
|
||||
write: (pos) => this.positionInfo(pos),
|
||||
write: (pos) => this.placeInfo(pos),
|
||||
key: this
|
||||
};
|
||||
this.space = null;
|
||||
|
@ -427,16 +469,22 @@ class CompletionTooltip {
|
|||
this.dom.addEventListener("mousedown", (e) => {
|
||||
for (let dom = e.target, match; dom && dom != this.dom; dom = dom.parentNode) {
|
||||
if (dom.nodeName == "LI" && (match = /-(\d+)$/.exec(dom.id)) && +match[1] < options.length) {
|
||||
applyCompletion(view, options[+match[1]]);
|
||||
this.applyCompletion(view, options[+match[1]]);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.dom.addEventListener("focusout", (e) => {
|
||||
let state = view.state.field(this.stateField, false);
|
||||
if (state && state.tooltip && view.state.facet(completionConfig).closeOnBlur &&
|
||||
e.relatedTarget != view.contentDOM)
|
||||
view.dispatch({ effects: closeCompletionEffect.of(null) });
|
||||
});
|
||||
this.list = this.dom.appendChild(this.createListBox(options, cState.id, this.range));
|
||||
this.list.addEventListener("scroll", () => {
|
||||
if (this.info)
|
||||
this.view.requestMeasure(this.placeInfo);
|
||||
this.view.requestMeasure(this.placeInfoReq);
|
||||
});
|
||||
}
|
||||
mount() { this.updateSel(); }
|
||||
|
@ -466,7 +514,7 @@ class CompletionTooltip {
|
|||
positioned(space) {
|
||||
this.space = space;
|
||||
if (this.info)
|
||||
this.view.requestMeasure(this.placeInfo);
|
||||
this.view.requestMeasure(this.placeInfoReq);
|
||||
}
|
||||
updateSel() {
|
||||
let cState = this.view.state.field(this.stateField), open = cState.open;
|
||||
|
@ -476,43 +524,52 @@ class CompletionTooltip {
|
|||
this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range));
|
||||
this.list.addEventListener("scroll", () => {
|
||||
if (this.info)
|
||||
this.view.requestMeasure(this.placeInfo);
|
||||
this.view.requestMeasure(this.placeInfoReq);
|
||||
});
|
||||
}
|
||||
if (this.updateSelectedOption(open.selected)) {
|
||||
if (this.info) {
|
||||
this.info.remove();
|
||||
this.info = null;
|
||||
}
|
||||
this.destroyInfo();
|
||||
let { completion } = open.options[open.selected];
|
||||
let { info } = completion;
|
||||
if (!info)
|
||||
return;
|
||||
let infoResult = typeof info === 'string' ? document.createTextNode(info) : info(completion);
|
||||
let infoResult = typeof info === "string" ? document.createTextNode(info) : info(completion);
|
||||
if (!infoResult)
|
||||
return;
|
||||
if ('then' in infoResult) {
|
||||
infoResult.then(node => {
|
||||
if (node && this.view.state.field(this.stateField, false) == cState)
|
||||
this.addInfoPane(node);
|
||||
if ("then" in infoResult) {
|
||||
infoResult.then(obj => {
|
||||
if (obj && this.view.state.field(this.stateField, false) == cState)
|
||||
this.addInfoPane(obj, completion);
|
||||
}).catch(e => logException(this.view.state, e, "completion info"));
|
||||
}
|
||||
else {
|
||||
this.addInfoPane(infoResult);
|
||||
this.addInfoPane(infoResult, completion);
|
||||
}
|
||||
}
|
||||
}
|
||||
addInfoPane(content) {
|
||||
let dom = this.info = document.createElement("div");
|
||||
dom.className = "cm-tooltip cm-completionInfo";
|
||||
dom.appendChild(content);
|
||||
this.dom.appendChild(dom);
|
||||
this.view.requestMeasure(this.placeInfo);
|
||||
addInfoPane(content, completion) {
|
||||
this.destroyInfo();
|
||||
let wrap = this.info = document.createElement("div");
|
||||
wrap.className = "cm-tooltip cm-completionInfo";
|
||||
if (content.nodeType != null) {
|
||||
wrap.appendChild(content);
|
||||
this.infoDestroy = null;
|
||||
}
|
||||
else {
|
||||
let { dom, destroy } = content;
|
||||
wrap.appendChild(dom);
|
||||
this.infoDestroy = destroy || null;
|
||||
}
|
||||
this.dom.appendChild(wrap);
|
||||
this.view.requestMeasure(this.placeInfoReq);
|
||||
}
|
||||
updateSelectedOption(selected) {
|
||||
let set = null;
|
||||
for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) {
|
||||
if (i == selected) {
|
||||
if (opt.nodeName != "LI" || !opt.id) {
|
||||
i--; // A section header
|
||||
}
|
||||
else if (i == selected) {
|
||||
if (!opt.hasAttribute("aria-selected")) {
|
||||
opt.setAttribute("aria-selected", "true");
|
||||
set = opt;
|
||||
|
@ -542,41 +599,17 @@ class CompletionTooltip {
|
|||
if (selRect.top > Math.min(space.bottom, listRect.bottom) - 10 ||
|
||||
selRect.bottom < Math.max(space.top, listRect.top) + 10)
|
||||
return null;
|
||||
let rtl = this.view.textDirection == Direction.RTL, left = rtl, narrow = false, maxWidth;
|
||||
let top = "", bottom = "";
|
||||
let spaceLeft = listRect.left - space.left, spaceRight = space.right - listRect.right;
|
||||
if (left && spaceLeft < Math.min(infoRect.width, spaceRight))
|
||||
left = false;
|
||||
else if (!left && spaceRight < Math.min(infoRect.width, spaceLeft))
|
||||
left = true;
|
||||
if (infoRect.width <= (left ? spaceLeft : spaceRight)) {
|
||||
top = (Math.max(space.top, Math.min(selRect.top, space.bottom - infoRect.height)) - listRect.top) + "px";
|
||||
maxWidth = Math.min(400 /* Info.Width */, left ? spaceLeft : spaceRight) + "px";
|
||||
}
|
||||
else {
|
||||
narrow = true;
|
||||
maxWidth = Math.min(400 /* Info.Width */, (rtl ? listRect.right : space.right - listRect.left) - 30 /* Info.Margin */) + "px";
|
||||
let spaceBelow = space.bottom - listRect.bottom;
|
||||
if (spaceBelow >= infoRect.height || spaceBelow > listRect.top) // Below the completion
|
||||
top = (selRect.bottom - listRect.top) + "px";
|
||||
else // Above it
|
||||
bottom = (listRect.bottom - selRect.top) + "px";
|
||||
}
|
||||
return {
|
||||
top, bottom, maxWidth,
|
||||
class: narrow ? (rtl ? "left-narrow" : "right-narrow") : left ? "left" : "right",
|
||||
};
|
||||
return this.view.state.facet(completionConfig).positionInfo(this.view, listRect, selRect, infoRect, space);
|
||||
}
|
||||
positionInfo(pos) {
|
||||
placeInfo(pos) {
|
||||
if (this.info) {
|
||||
if (pos) {
|
||||
this.info.style.top = pos.top;
|
||||
this.info.style.bottom = pos.bottom;
|
||||
this.info.style.maxWidth = pos.maxWidth;
|
||||
this.info.className = "cm-tooltip cm-completionInfo cm-completionInfo-" + pos.class;
|
||||
if (pos.style)
|
||||
this.info.style.cssText = pos.style;
|
||||
this.info.className = "cm-tooltip cm-completionInfo " + (pos.class || "");
|
||||
}
|
||||
else {
|
||||
this.info.style.top = "-1e6px";
|
||||
this.info.style.cssText = "top: -1e6px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -586,8 +619,22 @@ class CompletionTooltip {
|
|||
ul.setAttribute("role", "listbox");
|
||||
ul.setAttribute("aria-expanded", "true");
|
||||
ul.setAttribute("aria-label", this.view.state.phrase("Completions"));
|
||||
let curSection = null;
|
||||
for (let i = range.from; i < range.to; i++) {
|
||||
let { completion, match } = options[i];
|
||||
let { completion, match } = options[i], { section } = completion;
|
||||
if (section) {
|
||||
let name = typeof section == "string" ? section : section.name;
|
||||
if (name != curSection && (i > range.from || range.from == 0)) {
|
||||
curSection = name;
|
||||
if (typeof section != "string" && section.header) {
|
||||
ul.appendChild(section.header(section));
|
||||
}
|
||||
else {
|
||||
let header = ul.appendChild(document.createElement("completion-section"));
|
||||
header.textContent = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
const li = ul.appendChild(document.createElement("li"));
|
||||
li.id = id + "-" + i;
|
||||
li.setAttribute("role", "option");
|
||||
|
@ -606,11 +653,22 @@ class CompletionTooltip {
|
|||
ul.classList.add("cm-completionListIncompleteBottom");
|
||||
return ul;
|
||||
}
|
||||
destroyInfo() {
|
||||
if (this.info) {
|
||||
if (this.infoDestroy)
|
||||
this.infoDestroy();
|
||||
this.info.remove();
|
||||
this.info = null;
|
||||
}
|
||||
}
|
||||
destroy() {
|
||||
this.destroyInfo();
|
||||
}
|
||||
}
|
||||
// We allocate a new function instance every time the completion
|
||||
// changes to force redrawing/repositioning of the tooltip
|
||||
function completionTooltip(stateField) {
|
||||
return (view) => new CompletionTooltip(view, stateField);
|
||||
function completionTooltip(stateField, applyCompletion) {
|
||||
return (view) => new CompletionTooltip(view, stateField, applyCompletion);
|
||||
}
|
||||
function scrollIntoView(container, element) {
|
||||
let parent = container.getBoundingClientRect();
|
||||
|
@ -628,35 +686,56 @@ function score(option) {
|
|||
(option.type ? 1 : 0);
|
||||
}
|
||||
function sortOptions(active, state) {
|
||||
let options = [], i = 0;
|
||||
let options = [];
|
||||
let sections = null;
|
||||
let addOption = (option) => {
|
||||
options.push(option);
|
||||
let { section } = option.completion;
|
||||
if (section) {
|
||||
if (!sections)
|
||||
sections = [];
|
||||
let name = typeof section == "string" ? section : section.name;
|
||||
if (!sections.some(s => s.name == name))
|
||||
sections.push(typeof section == "string" ? { name } : section);
|
||||
}
|
||||
};
|
||||
for (let a of active)
|
||||
if (a.hasResult()) {
|
||||
let getMatch = a.result.getMatch;
|
||||
if (a.result.filter === false) {
|
||||
let getMatch = a.result.getMatch;
|
||||
for (let option of a.result.options) {
|
||||
let match = [1e9 - i++];
|
||||
if (getMatch)
|
||||
for (let n of getMatch(option))
|
||||
match.push(n);
|
||||
options.push(new Option(option, a, match));
|
||||
addOption(new Option(option, a.source, getMatch ? getMatch(option) : [], 1e9 - options.length));
|
||||
}
|
||||
}
|
||||
else {
|
||||
let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to)), match;
|
||||
let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to));
|
||||
for (let option of a.result.options)
|
||||
if (match = matcher.match(option.label)) {
|
||||
if (option.boost != null)
|
||||
match[0] += option.boost;
|
||||
options.push(new Option(option, a, match));
|
||||
if (matcher.match(option.label)) {
|
||||
let matched = !option.displayLabel ? matcher.matched : getMatch ? getMatch(option, matcher.matched) : [];
|
||||
addOption(new Option(option, a.source, matched, matcher.score + (option.boost || 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sections) {
|
||||
let sectionOrder = Object.create(null), pos = 0;
|
||||
let cmp = (a, b) => { var _a, _b; return ((_a = a.rank) !== null && _a !== void 0 ? _a : 1e9) - ((_b = b.rank) !== null && _b !== void 0 ? _b : 1e9) || (a.name < b.name ? -1 : 1); };
|
||||
for (let s of sections.sort(cmp)) {
|
||||
pos -= 1e5;
|
||||
sectionOrder[s.name] = pos;
|
||||
}
|
||||
for (let option of options) {
|
||||
let { section } = option.completion;
|
||||
if (section)
|
||||
option.score += sectionOrder[typeof section == "string" ? section : section.name];
|
||||
}
|
||||
}
|
||||
let result = [], prev = null;
|
||||
let compare = state.facet(completionConfig).compareCompletions;
|
||||
for (let opt of options.sort((a, b) => (b.match[0] - a.match[0]) || compare(a.completion, b.completion))) {
|
||||
if (!prev || prev.label != opt.completion.label || prev.detail != opt.completion.detail ||
|
||||
(prev.type != null && opt.completion.type != null && prev.type != opt.completion.type) ||
|
||||
prev.apply != opt.completion.apply)
|
||||
for (let opt of options.sort((a, b) => (b.score - a.score) || compare(a.completion, b.completion))) {
|
||||
let cur = opt.completion;
|
||||
if (!prev || prev.label != cur.label || prev.detail != cur.detail ||
|
||||
(prev.type != null && cur.type != null && prev.type != cur.type) ||
|
||||
prev.apply != cur.apply || prev.boost != cur.boost)
|
||||
result.push(opt);
|
||||
else if (score(opt.completion) > score(prev))
|
||||
result[result.length - 1] = opt;
|
||||
|
@ -680,7 +759,7 @@ class CompletionDialog {
|
|||
static build(active, state, id, prev, conf) {
|
||||
let options = sortOptions(active, state);
|
||||
if (!options.length) {
|
||||
return prev && active.some(a => a.state == 1 /* State.Pending */) ?
|
||||
return prev && active.some(a => a.state == 1 /* Pending */) ?
|
||||
new CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null;
|
||||
}
|
||||
let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
|
||||
|
@ -694,7 +773,7 @@ class CompletionDialog {
|
|||
}
|
||||
return new CompletionDialog(options, makeAttrs(id, selected), {
|
||||
pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
|
||||
create: completionTooltip(completionState),
|
||||
create: completionTooltip(completionState, applyCompletion),
|
||||
above: conf.aboveCursor,
|
||||
}, prev ? prev.timestamp : Date.now(), selected, false);
|
||||
}
|
||||
|
@ -717,7 +796,7 @@ class CompletionState {
|
|||
state.languageDataAt("autocomplete", cur(state)).map(asSource);
|
||||
let active = sources.map(source => {
|
||||
let value = this.active.find(s => s.source == source) ||
|
||||
new ActiveSource(source, this.active.some(a => a.state != 0 /* State.Inactive */) ? 1 /* State.Pending */ : 0 /* State.Inactive */);
|
||||
new ActiveSource(source, this.active.some(a => a.state != 0 /* Inactive */) ? 1 /* Pending */ : 0 /* Inactive */);
|
||||
return value.update(tr, conf);
|
||||
});
|
||||
if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
|
||||
|
@ -728,10 +807,10 @@ class CompletionState {
|
|||
if (tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
|
||||
!sameResults(active, this.active))
|
||||
open = CompletionDialog.build(active, state, this.id, open, conf);
|
||||
else if (open && open.disabled && !active.some(a => a.state == 1 /* State.Pending */))
|
||||
else if (open && open.disabled && !active.some(a => a.state == 1 /* Pending */))
|
||||
open = null;
|
||||
if (!open && active.every(a => a.state != 1 /* State.Pending */) && active.some(a => a.hasResult()))
|
||||
active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* State.Inactive */) : a);
|
||||
if (!open && active.every(a => a.state != 1 /* Pending */) && active.some(a => a.hasResult()))
|
||||
active = active.map(a => a.hasResult() ? new ActiveSource(a.source, 0 /* Inactive */) : a);
|
||||
for (let effect of tr.effects)
|
||||
if (effect.is(setSelectedEffect))
|
||||
open = open && open.setSelected(effect.value, this.id);
|
||||
|
@ -785,13 +864,13 @@ class ActiveSource {
|
|||
value = value.handleUserEvent(tr, event, conf);
|
||||
else if (tr.docChanged)
|
||||
value = value.handleChange(tr);
|
||||
else if (tr.selection && value.state != 0 /* State.Inactive */)
|
||||
value = new ActiveSource(value.source, 0 /* State.Inactive */);
|
||||
else if (tr.selection && value.state != 0 /* Inactive */)
|
||||
value = new ActiveSource(value.source, 0 /* Inactive */);
|
||||
for (let effect of tr.effects) {
|
||||
if (effect.is(startCompletionEffect))
|
||||
value = new ActiveSource(value.source, 1 /* State.Pending */, effect.value ? cur(tr.state) : -1);
|
||||
value = new ActiveSource(value.source, 1 /* Pending */, effect.value ? cur(tr.state) : -1);
|
||||
else if (effect.is(closeCompletionEffect))
|
||||
value = new ActiveSource(value.source, 0 /* State.Inactive */);
|
||||
value = new ActiveSource(value.source, 0 /* Inactive */);
|
||||
else if (effect.is(setActiveEffect))
|
||||
for (let active of effect.value)
|
||||
if (active.source == value.source)
|
||||
|
@ -800,10 +879,10 @@ class ActiveSource {
|
|||
return value;
|
||||
}
|
||||
handleUserEvent(tr, type, conf) {
|
||||
return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* State.Pending */);
|
||||
return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* Pending */);
|
||||
}
|
||||
handleChange(tr) {
|
||||
return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
|
||||
return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
|
||||
}
|
||||
map(changes) {
|
||||
return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos));
|
||||
|
@ -811,7 +890,7 @@ class ActiveSource {
|
|||
}
|
||||
class ActiveResult extends ActiveSource {
|
||||
constructor(source, explicitPos, result, from, to) {
|
||||
super(source, 2 /* State.Result */, explicitPos);
|
||||
super(source, 2 /* Result */, explicitPos);
|
||||
this.result = result;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
|
@ -824,17 +903,17 @@ class ActiveResult extends ActiveSource {
|
|||
if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
|
||||
pos > to ||
|
||||
type == "delete" && cur(tr.startState) == this.from)
|
||||
return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* State.Pending */ : 0 /* State.Inactive */);
|
||||
return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
|
||||
let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos), updated;
|
||||
if (checkValid(this.result.validFor, tr.state, from, to))
|
||||
return new ActiveResult(this.source, explicitPos, this.result, from, to);
|
||||
if (this.result.update &&
|
||||
(updated = this.result.update(this.result, from, to, new CompletionContext(tr.state, pos, explicitPos >= 0))))
|
||||
return new ActiveResult(this.source, explicitPos, updated, updated.from, (_a = updated.to) !== null && _a !== void 0 ? _a : cur(tr.state));
|
||||
return new ActiveSource(this.source, 1 /* State.Pending */, explicitPos);
|
||||
return new ActiveSource(this.source, 1 /* Pending */, explicitPos);
|
||||
}
|
||||
handleChange(tr) {
|
||||
return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
|
||||
return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
|
||||
}
|
||||
map(mapping) {
|
||||
return mapping.empty ? this :
|
||||
|
@ -847,8 +926,6 @@ function checkValid(validFor, state, from, to) {
|
|||
let text = state.sliceDoc(from, to);
|
||||
return typeof validFor == "function" ? validFor(text, from, to, state) : ensureAnchor(validFor, true).test(text);
|
||||
}
|
||||
const startCompletionEffect = /*@__PURE__*/StateEffect.define();
|
||||
const closeCompletionEffect = /*@__PURE__*/StateEffect.define();
|
||||
const setActiveEffect = /*@__PURE__*/StateEffect.define({
|
||||
map(sources, mapping) { return sources.map(s => s.map(mapping)); }
|
||||
});
|
||||
|
@ -861,6 +938,17 @@ const completionState = /*@__PURE__*/StateField.define({
|
|||
EditorView.contentAttributes.from(f, state => state.attrs)
|
||||
]
|
||||
});
|
||||
function applyCompletion(view, option) {
|
||||
const apply = option.completion.apply || option.completion.label;
|
||||
let result = view.state.field(completionState).active.find(a => a.source == option.source);
|
||||
if (!(result instanceof ActiveResult))
|
||||
return false;
|
||||
if (typeof apply == "string")
|
||||
view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
|
||||
else
|
||||
apply(view, option.completion, result.from, result.to);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a command that moves the completion selection forward or
|
||||
|
@ -891,12 +979,10 @@ Accept the current completion.
|
|||
*/
|
||||
const acceptCompletion = (view) => {
|
||||
let cState = view.state.field(completionState, false);
|
||||
if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 ||
|
||||
if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 || cState.open.disabled ||
|
||||
Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
|
||||
return false;
|
||||
if (!cState.open.disabled)
|
||||
applyCompletion(view, cState.open.options[cState.open.selected]);
|
||||
return true;
|
||||
return applyCompletion(view, cState.open.options[cState.open.selected]);
|
||||
};
|
||||
/**
|
||||
Explicitly start autocompletion.
|
||||
|
@ -913,7 +999,7 @@ Close the currently active completion.
|
|||
*/
|
||||
const closeCompletion = (view) => {
|
||||
let cState = view.state.field(completionState, false);
|
||||
if (!cState || !cState.active.some(a => a.state != 0 /* State.Inactive */))
|
||||
if (!cState || !cState.active.some(a => a.state != 0 /* Inactive */))
|
||||
return false;
|
||||
view.dispatch({ effects: closeCompletionEffect.of(null) });
|
||||
return true;
|
||||
|
@ -936,9 +1022,9 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|||
this.debounceUpdate = -1;
|
||||
this.running = [];
|
||||
this.debounceAccept = -1;
|
||||
this.composing = 0 /* CompositionState.None */;
|
||||
this.composing = 0 /* None */;
|
||||
for (let active of view.state.field(completionState).active)
|
||||
if (active.state == 1 /* State.Pending */)
|
||||
if (active.state == 1 /* Pending */)
|
||||
this.startQuery(active);
|
||||
}
|
||||
update(update) {
|
||||
|
@ -969,21 +1055,21 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|||
}
|
||||
if (this.debounceUpdate > -1)
|
||||
clearTimeout(this.debounceUpdate);
|
||||
this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
|
||||
this.debounceUpdate = cState.active.some(a => a.state == 1 /* Pending */ && !this.running.some(q => q.active.source == a.source))
|
||||
? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
|
||||
if (this.composing != 0 /* CompositionState.None */)
|
||||
if (this.composing != 0 /* None */)
|
||||
for (let tr of update.transactions) {
|
||||
if (getUserEvent(tr) == "input")
|
||||
this.composing = 2 /* CompositionState.Changed */;
|
||||
else if (this.composing == 2 /* CompositionState.Changed */ && tr.selection)
|
||||
this.composing = 3 /* CompositionState.ChangedAndMoved */;
|
||||
this.composing = 2 /* Changed */;
|
||||
else if (this.composing == 2 /* Changed */ && tr.selection)
|
||||
this.composing = 3 /* ChangedAndMoved */;
|
||||
}
|
||||
}
|
||||
startUpdate() {
|
||||
this.debounceUpdate = -1;
|
||||
let { state } = this.view, cState = state.field(completionState);
|
||||
for (let active of cState.active) {
|
||||
if (active.state == 1 /* State.Pending */ && !this.running.some(r => r.active.source == active.source))
|
||||
if (active.state == 1 /* Pending */ && !this.running.some(r => r.active.source == active.source))
|
||||
this.startQuery(active);
|
||||
}
|
||||
}
|
||||
|
@ -1034,14 +1120,14 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|||
}
|
||||
}
|
||||
let current = this.view.state.field(completionState).active.find(a => a.source == query.active.source);
|
||||
if (current && current.state == 1 /* State.Pending */) {
|
||||
if (current && current.state == 1 /* Pending */) {
|
||||
if (query.done == null) {
|
||||
// Explicitly failed. Should clear the pending status if it
|
||||
// hasn't been re-set in the meantime.
|
||||
let active = new ActiveSource(query.active.source, 0 /* State.Inactive */);
|
||||
let active = new ActiveSource(query.active.source, 0 /* Inactive */);
|
||||
for (let tr of query.updates)
|
||||
active = active.update(tr, conf);
|
||||
if (active.state != 1 /* State.Pending */)
|
||||
if (active.state != 1 /* Pending */)
|
||||
updated.push(active);
|
||||
}
|
||||
else {
|
||||
|
@ -1055,21 +1141,24 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|||
}
|
||||
}, {
|
||||
eventHandlers: {
|
||||
blur() {
|
||||
blur(event) {
|
||||
let state = this.view.state.field(completionState, false);
|
||||
if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur)
|
||||
this.view.dispatch({ effects: closeCompletionEffect.of(null) });
|
||||
if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
|
||||
let dialog = state.open && getTooltip(this.view, state.open.tooltip);
|
||||
if (!dialog || !dialog.dom.contains(event.relatedTarget))
|
||||
this.view.dispatch({ effects: closeCompletionEffect.of(null) });
|
||||
}
|
||||
},
|
||||
compositionstart() {
|
||||
this.composing = 1 /* CompositionState.Started */;
|
||||
this.composing = 1 /* Started */;
|
||||
},
|
||||
compositionend() {
|
||||
if (this.composing == 3 /* CompositionState.ChangedAndMoved */) {
|
||||
if (this.composing == 3 /* ChangedAndMoved */) {
|
||||
// Safari fires compositionend events synchronously, possibly
|
||||
// from inside an update, so dispatch asynchronously to avoid reentrancy
|
||||
setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20);
|
||||
}
|
||||
this.composing = 0 /* CompositionState.None */;
|
||||
this.composing = 0 /* None */;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1088,13 +1177,21 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|||
listStyle: "none",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
"& > li": {
|
||||
overflowX: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
cursor: "pointer",
|
||||
"& > li, & > completion-section": {
|
||||
padding: "1px 3px",
|
||||
lineHeight: 1.2
|
||||
},
|
||||
"& > li": {
|
||||
overflowX: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
cursor: "pointer"
|
||||
},
|
||||
"& > completion-section": {
|
||||
display: "list-item",
|
||||
borderBottom: "1px solid silver",
|
||||
paddingLeft: "0.5em",
|
||||
opacity: 0.7
|
||||
}
|
||||
}
|
||||
},
|
||||
"&light .cm-tooltip-autocomplete ul li[aria-selected]": {
|
||||
|
@ -1121,13 +1218,13 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|||
position: "absolute",
|
||||
padding: "3px 9px",
|
||||
width: "max-content",
|
||||
maxWidth: `${400 /* Info.Width */}px`,
|
||||
maxWidth: `${400 /* Width */}px`,
|
||||
boxSizing: "border-box"
|
||||
},
|
||||
".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
|
||||
".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
|
||||
".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30 /* Info.Margin */}px` },
|
||||
".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30 /* Info.Margin */}px` },
|
||||
".cm-completionInfo.cm-completionInfo-left-narrow": { right: `${30 /* Margin */}px` },
|
||||
".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30 /* Margin */}px` },
|
||||
"&light .cm-snippetField": { backgroundColor: "#00000022" },
|
||||
"&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
|
||||
".cm-snippetFieldPosition": {
|
||||
|
@ -1352,11 +1449,12 @@ interpreted as indicating a placeholder.
|
|||
*/
|
||||
function snippet(template) {
|
||||
let snippet = Snippet.parse(template);
|
||||
return (editor, _completion, from, to) => {
|
||||
return (editor, completion, from, to) => {
|
||||
let { text, ranges } = snippet.instantiate(editor.state, from);
|
||||
let spec = {
|
||||
changes: { from, to, insert: Text.of(text) },
|
||||
scrollIntoView: true
|
||||
scrollIntoView: true,
|
||||
annotations: completion ? pickedCompletion.of(completion) : undefined
|
||||
};
|
||||
if (ranges.length)
|
||||
spec.selection = fieldSelection(ranges, 0);
|
||||
|
@ -1400,6 +1498,22 @@ const nextSnippetField = /*@__PURE__*/moveField(1);
|
|||
Move to the previous snippet field, if available.
|
||||
*/
|
||||
const prevSnippetField = /*@__PURE__*/moveField(-1);
|
||||
/**
|
||||
Check if there is an active snippet with a next field for
|
||||
`nextSnippetField` to move to.
|
||||
*/
|
||||
function hasNextSnippetField(state) {
|
||||
let active = state.field(snippetState, false);
|
||||
return !!(active && active.ranges.some(r => r.field == active.active + 1));
|
||||
}
|
||||
/**
|
||||
Returns true if there is an active snippet and a previous field
|
||||
for `prevSnippetField` to move to.
|
||||
*/
|
||||
function hasPrevSnippetField(state) {
|
||||
let active = state.field(snippetState, false);
|
||||
return !!(active && active.active > 0);
|
||||
}
|
||||
const defaultSnippetKeymap = [
|
||||
{ key: "Tab", run: nextSnippetField, shift: prevSnippetField },
|
||||
{ key: "Escape", run: clearSnippet }
|
||||
|
@ -1463,7 +1577,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
|
|||
if (!seen[m[0]] && pos + m.index != ignoreAt) {
|
||||
result.push({ type: "text", label: m[0] });
|
||||
seen[m[0]] = true;
|
||||
if (result.length >= 2000 /* C.MaxList */)
|
||||
if (result.length >= 2000 /* MaxList */)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1471,7 +1585,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
|
|||
}
|
||||
}
|
||||
function collectWords(doc, cache, wordRE, to, ignoreAt) {
|
||||
let big = doc.length >= 1000 /* C.MinCacheLen */;
|
||||
let big = doc.length >= 1000 /* MinCacheLen */;
|
||||
let cached = big && cache.get(doc);
|
||||
if (cached)
|
||||
return cached;
|
||||
|
@ -1479,7 +1593,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
|
|||
if (doc.children) {
|
||||
let pos = 0;
|
||||
for (let ch of doc.children) {
|
||||
if (ch.length >= 1000 /* C.MinCacheLen */) {
|
||||
if (ch.length >= 1000 /* MinCacheLen */) {
|
||||
for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) {
|
||||
if (!seen[c.label]) {
|
||||
seen[c.label] = true;
|
||||
|
@ -1496,7 +1610,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
|
|||
else {
|
||||
storeWords(doc, wordRE, result, seen, ignoreAt);
|
||||
}
|
||||
if (big && result.length < 2000 /* C.MaxList */)
|
||||
if (big && result.length < 2000 /* MaxList */)
|
||||
cache.set(doc, result);
|
||||
return result;
|
||||
}
|
||||
|
@ -1512,7 +1626,7 @@ const completeAnyWord = context => {
|
|||
if (!token && !context.explicit)
|
||||
return null;
|
||||
let from = token ? token.from : context.pos;
|
||||
let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* C.Range */, from);
|
||||
let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* Range */, from);
|
||||
return { from, options, validFor: mapRE(re, s => "^" + s) };
|
||||
};
|
||||
|
||||
|
@ -1527,9 +1641,6 @@ const closeBracketEffect = /*@__PURE__*/StateEffect.define({
|
|||
return mapped == null ? undefined : mapped;
|
||||
}
|
||||
});
|
||||
const skipBracketEffect = /*@__PURE__*/StateEffect.define({
|
||||
map(value, mapping) { return mapping.mapPos(value); }
|
||||
});
|
||||
const closedBracket = /*@__PURE__*/new class extends RangeValue {
|
||||
};
|
||||
closedBracket.startSide = 1;
|
||||
|
@ -1544,12 +1655,9 @@ const bracketState = /*@__PURE__*/StateField.define({
|
|||
value = RangeSet.empty;
|
||||
}
|
||||
value = value.map(tr.changes);
|
||||
for (let effect of tr.effects) {
|
||||
for (let effect of tr.effects)
|
||||
if (effect.is(closeBracketEffect))
|
||||
value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] });
|
||||
else if (effect.is(skipBracketEffect))
|
||||
value = value.update({ filter: from => from != effect.value });
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
@ -1677,15 +1785,15 @@ function handleOpen(state, open, close, closeBefore) {
|
|||
});
|
||||
}
|
||||
function handleClose(state, _open, close) {
|
||||
let dont = null, moved = state.selection.ranges.map(range => {
|
||||
let dont = null, changes = state.changeByRange(range => {
|
||||
if (range.empty && nextChar(state.doc, range.head) == close)
|
||||
return EditorSelection.cursor(range.head + close.length);
|
||||
return dont = range;
|
||||
return { changes: { from: range.head, to: range.head + close.length, insert: close },
|
||||
range: EditorSelection.cursor(range.head + close.length) };
|
||||
return dont = { range };
|
||||
});
|
||||
return dont ? null : state.update({
|
||||
selection: EditorSelection.create(moved, state.selection.mainIndex),
|
||||
return dont ? null : state.update(changes, {
|
||||
scrollIntoView: true,
|
||||
effects: state.selection.ranges.map(({ from }) => skipBracketEffect.of(from))
|
||||
userEvent: "input.type"
|
||||
});
|
||||
}
|
||||
// Handles cases where the open and close token are the same, and
|
||||
|
@ -1706,8 +1814,9 @@ function handleSame(state, token, allowTriple, config) {
|
|||
}
|
||||
else if (closedBracketAt(state, pos)) {
|
||||
let isTriple = allowTriple && state.sliceDoc(pos, pos + token.length * 3) == token + token + token;
|
||||
return { range: EditorSelection.cursor(pos + token.length * (isTriple ? 3 : 1)),
|
||||
effects: skipBracketEffect.of(pos) };
|
||||
let content = isTriple ? token + token + token : token;
|
||||
return { changes: { from: pos, to: pos + content.length, insert: content },
|
||||
range: EditorSelection.cursor(pos + content.length) };
|
||||
}
|
||||
}
|
||||
else if (allowTriple && state.sliceDoc(pos - 2 * token.length, pos) == token + token &&
|
||||
|
@ -1809,8 +1918,8 @@ returns `null`.
|
|||
*/
|
||||
function completionStatus(state) {
|
||||
let cState = state.field(completionState, false);
|
||||
return cState && cState.active.some(a => a.state == 1 /* State.Pending */) ? "pending"
|
||||
: cState && cState.active.some(a => a.state != 0 /* State.Inactive */) ? "active" : null;
|
||||
return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
|
||||
: cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
|
||||
}
|
||||
const completionArrayCache = /*@__PURE__*/new WeakMap;
|
||||
/**
|
||||
|
@ -1851,4 +1960,4 @@ function setSelectedCompletion(index) {
|
|||
return setSelectedEffect.of(index);
|
||||
}
|
||||
|
||||
export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, deleteBracketPair, ifIn, ifNotIn, insertBracket, insertCompletionText, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
|
||||
export { CompletionContext, acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completeAnyWord, completeFromList, completionKeymap, completionStatus, currentCompletions, deleteBracketPair, hasNextSnippetField, hasPrevSnippetField, ifIn, ifNotIn, insertBracket, insertCompletionText, moveCompletionSelection, nextSnippetField, pickedCompletion, prevSnippetField, selectedCompletion, selectedCompletionIndex, setSelectedCompletion, snippet, snippetCompletion, snippetKeymap, startCompletion };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue