1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-05 02:39:46 +02:00
This commit is contained in:
DanieL 2023-02-13 14:41:08 -03:00
parent 64c36d9f4e
commit 0d0338876d
1197 changed files with 121461 additions and 179724 deletions

View file

@ -175,7 +175,7 @@ function applyCompletion(view, option) {
const apply = option.completion.apply || option.completion.label;
let result = option.source;
if (typeof apply == "string")
view.dispatch(insertCompletionText(view.state, apply, result.from, result.to));
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);
}
@ -229,7 +229,7 @@ class FuzzyMatcher {
if (chars.length == 1) {
let first = codePointAt(word, 0);
return first == chars[0] ? [0, 0, codePointSize(first)]
: first == folded[0] ? [-200 /* CaseFold */, 0, codePointSize(first)] : null;
: first == folded[0] ? [-200 /* Penalty.CaseFold */, 0, codePointSize(first)] : null;
}
let direct = word.indexOf(this.pattern);
if (direct == 0)
@ -257,7 +257,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 /* NonWord */; i < e && byWordTo < len;) {
for (let i = 0, e = Math.min(word.length, 200), prevType = 0 /* Tp.NonWord */; i < e && byWordTo < len;) {
let next = codePointAt(word, i);
if (direct < 0) {
if (preciseTo < len && next == chars[preciseTo])
@ -275,9 +275,9 @@ class FuzzyMatcher {
}
}
let ch, type = next < 0xff
? (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 */) {
? (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 */) {
if (chars[byWordTo] == next || (folded[byWordTo] == next && (byWordFolded = true)))
byWord[byWordTo++] = i;
else if (byWord.length)
@ -287,17 +287,17 @@ class FuzzyMatcher {
i += codePointSize(next);
}
if (byWordTo == len && byWord[0] == 0 && wordAdjacent)
return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0), byWord, word);
return this.result(-100 /* Penalty.ByWord */ + (byWordFolded ? -200 /* Penalty.CaseFold */ : 0), byWord, word);
if (adjacentTo == len && adjacentStart == 0)
return [-200 /* CaseFold */ - word.length, 0, adjacentEnd];
return [-200 /* Penalty.CaseFold */ - word.length, 0, adjacentEnd];
if (direct > -1)
return [-700 /* NotStart */ - word.length, direct, direct + this.pattern.length];
return [-700 /* Penalty.NotStart */ - word.length, direct, direct + this.pattern.length];
if (adjacentTo == len)
return [-200 /* CaseFold */ + -700 /* NotStart */ - word.length, adjacentStart, adjacentEnd];
return [-200 /* Penalty.CaseFold */ + -700 /* Penalty.NotStart */ - word.length, adjacentStart, adjacentEnd];
if (byWordTo == len)
return this.result(-100 /* ByWord */ + (byWordFolded ? -200 /* CaseFold */ : 0) + -700 /* NotStart */ +
(wordAdjacent ? 0 : -1100 /* Gap */), byWord, word);
return chars.length == 2 ? null : this.result((any[0] ? -700 /* NotStart */ : 0) + -200 /* CaseFold */ + -1100 /* Gap */, any, word);
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);
}
result(score, positions, word) {
let result = [score - word.length], i = 1;
@ -318,18 +318,23 @@ const completionConfig = /*@__PURE__*/Facet.define({
combine(configs) {
return combineConfig(configs, {
activateOnTyping: true,
selectOnOpen: true,
override: null,
closeOnBlur: true,
maxRenderedOptions: 100,
defaultKeymap: true,
tooltipClass: () => "",
optionClass: () => "",
aboveCursor: false,
icons: true,
addToOptions: []
addToOptions: [],
compareCompletions: (a, b) => a.label.localeCompare(b.label),
interactionDelay: 75
}, {
defaultKeymap: (a, b) => a && b,
closeOnBlur: (a, b) => a && b,
icons: (a, b) => a && b,
tooltipClass: (a, b) => c => joinClass(a(c), b(c)),
optionClass: (a, b) => c => joinClass(a(c), b(c)),
addToOptions: (a, b) => a.concat(b)
});
@ -388,6 +393,8 @@ function optionContent(config) {
function rangeAroundSelected(total, selected, max) {
if (total <= max)
return { from: 0, to: total };
if (selected < 0)
selected = 0;
if (selected <= (total >> 1)) {
let off = Math.floor(selected / max);
return { from: off * max, to: (off + 1) * max };
@ -405,14 +412,18 @@ class CompletionTooltip {
write: (pos) => this.positionInfo(pos),
key: this
};
this.space = null;
this.currentClass = "";
let cState = view.state.field(stateField);
let { options, selected } = cState.open;
let config = view.state.facet(completionConfig);
this.optionContent = optionContent(config);
this.optionClass = config.optionClass;
this.tooltipClass = config.tooltipClass;
this.range = rangeAroundSelected(options.length, selected, config.maxRenderedOptions);
this.dom = document.createElement("div");
this.dom.className = "cm-tooltip-autocomplete";
this.updateTooltipClass(view.state);
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) {
@ -430,16 +441,36 @@ class CompletionTooltip {
}
mount() { this.updateSel(); }
update(update) {
if (update.state.field(this.stateField) != update.startState.field(this.stateField))
var _a, _b, _c;
let cState = update.state.field(this.stateField);
let prevState = update.startState.field(this.stateField);
this.updateTooltipClass(update.state);
if (cState != prevState) {
this.updateSel();
if (((_a = cState.open) === null || _a === void 0 ? void 0 : _a.disabled) != ((_b = prevState.open) === null || _b === void 0 ? void 0 : _b.disabled))
this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!((_c = cState.open) === null || _c === void 0 ? void 0 : _c.disabled));
}
}
positioned() {
updateTooltipClass(state) {
let cls = this.tooltipClass(state);
if (cls != this.currentClass) {
for (let c of this.currentClass.split(" "))
if (c)
this.dom.classList.remove(c);
for (let c of cls.split(" "))
if (c)
this.dom.classList.add(c);
this.currentClass = cls;
}
}
positioned(space) {
this.space = space;
if (this.info)
this.view.requestMeasure(this.placeInfo);
}
updateSel() {
let cState = this.view.state.field(this.stateField), open = cState.open;
if (open.selected < this.range.from || open.selected >= this.range.to) {
if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) {
this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
this.list.remove();
this.list = this.dom.appendChild(this.createListBox(open.options, cState.id, this.range));
@ -503,23 +534,49 @@ class CompletionTooltip {
let listRect = this.dom.getBoundingClientRect();
let infoRect = this.info.getBoundingClientRect();
let selRect = sel.getBoundingClientRect();
if (selRect.top > Math.min(innerHeight, listRect.bottom) - 10 || selRect.bottom < Math.max(0, listRect.top) + 10)
let space = this.space;
if (!space) {
let win = this.dom.ownerDocument.defaultView || window;
space = { left: 0, top: 0, right: win.innerWidth, bottom: win.innerHeight };
}
if (selRect.top > Math.min(space.bottom, listRect.bottom) - 10 ||
selRect.bottom < Math.max(space.top, listRect.top) + 10)
return null;
let top = Math.max(0, Math.min(selRect.top, innerHeight - infoRect.height)) - listRect.top;
let left = this.view.textDirection == Direction.RTL;
let spaceLeft = listRect.left, spaceRight = innerWidth - listRect.right;
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;
return { top, left };
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",
};
}
positionInfo(pos) {
if (this.info) {
this.info.style.top = (pos ? pos.top : -1e6) + "px";
if (pos) {
this.info.classList.toggle("cm-completionInfo-left", pos.left);
this.info.classList.toggle("cm-completionInfo-right", !pos.left);
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;
}
else {
this.info.style.top = "-1e6px";
}
}
}
@ -595,7 +652,8 @@ function sortOptions(active, state) {
}
}
let result = [], prev = null;
for (let opt of options.sort(cmpOption)) {
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)
@ -607,23 +665,26 @@ function sortOptions(active, state) {
return result;
}
class CompletionDialog {
constructor(options, attrs, tooltip, timestamp, selected) {
constructor(options, attrs, tooltip, timestamp, selected, disabled) {
this.options = options;
this.attrs = attrs;
this.tooltip = tooltip;
this.timestamp = timestamp;
this.selected = selected;
this.disabled = disabled;
}
setSelected(selected, id) {
return selected == this.selected || selected >= this.options.length ? this
: new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected);
: new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
}
static build(active, state, id, prev, conf) {
let options = sortOptions(active, state);
if (!options.length)
return null;
let selected = 0;
if (prev && prev.selected) {
if (!options.length) {
return prev && active.some(a => a.state == 1 /* State.Pending */) ?
new CompletionDialog(prev.options, prev.attrs, prev.tooltip, prev.timestamp, prev.selected, true) : null;
}
let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
if (prev && prev.selected != selected && prev.selected != -1) {
let selectedValue = prev.options[prev.selected].completion;
for (let i = 0; i < options.length; i++)
if (options[i].completion == selectedValue) {
@ -635,10 +696,10 @@ class CompletionDialog {
pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
create: completionTooltip(completionState),
above: conf.aboveCursor,
}, prev ? prev.timestamp : Date.now(), selected);
}, prev ? prev.timestamp : Date.now(), selected, false);
}
map(changes) {
return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected);
return new CompletionDialog(this.options, this.attrs, Object.assign(Object.assign({}, this.tooltip), { pos: changes.mapPos(this.tooltip.pos) }), this.timestamp, this.selected, this.disabled);
}
}
class CompletionState {
@ -656,16 +717,21 @@ 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 /* Inactive */) ? 1 /* Pending */ : 0 /* Inactive */);
new ActiveSource(source, this.active.some(a => a.state != 0 /* State.Inactive */) ? 1 /* State.Pending */ : 0 /* State.Inactive */);
return value.update(tr, conf);
});
if (active.length == this.active.length && active.every((a, i) => a == this.active[i]))
active = this.active;
let open = tr.selection || active.some(a => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) ||
!sameResults(active, this.active) ? CompletionDialog.build(active, state, this.id, this.open, conf)
: this.open && tr.docChanged ? this.open.map(tr.changes) : this.open;
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);
let open = this.open;
if (open && tr.docChanged)
open = open.map(tr.changes);
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 */))
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);
for (let effect of tr.effects)
if (effect.is(setSelectedEffect))
open = open && open.setSelected(effect.value, this.id);
@ -693,20 +759,16 @@ const baseAttrs = {
"aria-autocomplete": "list"
};
function makeAttrs(id, selected) {
return {
let result = {
"aria-autocomplete": "list",
"aria-haspopup": "listbox",
"aria-activedescendant": id + "-" + selected,
"aria-controls": id
};
if (selected > -1)
result["aria-activedescendant"] = id + "-" + selected;
return result;
}
const none = [];
function cmpOption(a, b) {
let dScore = b.match[0] - a.match[0];
if (dScore)
return dScore;
return a.completion.label.localeCompare(b.completion.label);
}
function getUserEvent(tr) {
return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null;
}
@ -723,13 +785,13 @@ class ActiveSource {
value = value.handleUserEvent(tr, event, conf);
else if (tr.docChanged)
value = value.handleChange(tr);
else if (tr.selection && value.state != 0 /* Inactive */)
value = new ActiveSource(value.source, 0 /* Inactive */);
else if (tr.selection && value.state != 0 /* State.Inactive */)
value = new ActiveSource(value.source, 0 /* State.Inactive */);
for (let effect of tr.effects) {
if (effect.is(startCompletionEffect))
value = new ActiveSource(value.source, 1 /* Pending */, effect.value ? cur(tr.state) : -1);
value = new ActiveSource(value.source, 1 /* State.Pending */, effect.value ? cur(tr.state) : -1);
else if (effect.is(closeCompletionEffect))
value = new ActiveSource(value.source, 0 /* Inactive */);
value = new ActiveSource(value.source, 0 /* State.Inactive */);
else if (effect.is(setActiveEffect))
for (let active of effect.value)
if (active.source == value.source)
@ -738,10 +800,10 @@ class ActiveSource {
return value;
}
handleUserEvent(tr, type, conf) {
return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* Pending */);
return type == "delete" || !conf.activateOnTyping ? this.map(tr.changes) : new ActiveSource(this.source, 1 /* State.Pending */);
}
handleChange(tr) {
return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
return tr.changes.touchesRange(cur(tr.startState)) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
}
map(changes) {
return changes.empty || this.explicitPos < 0 ? this : new ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos));
@ -749,7 +811,7 @@ class ActiveSource {
}
class ActiveResult extends ActiveSource {
constructor(source, explicitPos, result, from, to) {
super(source, 2 /* Result */, explicitPos);
super(source, 2 /* State.Result */, explicitPos);
this.result = result;
this.from = from;
this.to = to;
@ -762,17 +824,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 /* Pending */ : 0 /* Inactive */);
return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* State.Pending */ : 0 /* State.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 /* Pending */, explicitPos);
return new ActiveSource(this.source, 1 /* State.Pending */, explicitPos);
}
handleChange(tr) {
return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* Inactive */) : this.map(tr.changes);
return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource(this.source, 0 /* State.Inactive */) : this.map(tr.changes);
}
map(mapping) {
return mapping.empty ? this :
@ -800,7 +862,6 @@ const completionState = /*@__PURE__*/StateField.define({
]
});
const CompletionInteractMargin = 75;
/**
Returns a command that moves the completion selection forward or
backward by the given amount.
@ -808,13 +869,15 @@ backward by the given amount.
function moveCompletionSelection(forward, by = "option") {
return (view) => {
let cState = view.state.field(completionState, false);
if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
if (!cState || !cState.open || cState.open.disabled ||
Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
return false;
let step = 1, tooltip;
if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip)))
step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
tooltip.dom.querySelector("li").offsetHeight) - 1);
let selected = cState.open.selected + step * (forward ? 1 : -1), { length } = cState.open.options;
let { length } = cState.open.options;
let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
if (selected < 0)
selected = by == "page" ? 0 : length - 1;
else if (selected >= length)
@ -828,9 +891,11 @@ Accept the current completion.
*/
const acceptCompletion = (view) => {
let cState = view.state.field(completionState, false);
if (view.state.readOnly || !cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
if (view.state.readOnly || !cState || !cState.open || cState.open.selected < 0 ||
Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay)
return false;
applyCompletion(view, cState.open.options[cState.open.selected]);
if (!cState.open.disabled)
applyCompletion(view, cState.open.options[cState.open.selected]);
return true;
};
/**
@ -848,7 +913,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 /* Inactive */))
if (!cState || !cState.active.some(a => a.state != 0 /* State.Inactive */))
return false;
view.dispatch({ effects: closeCompletionEffect.of(null) });
return true;
@ -871,9 +936,9 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
this.debounceUpdate = -1;
this.running = [];
this.debounceAccept = -1;
this.composing = 0 /* None */;
this.composing = 0 /* CompositionState.None */;
for (let active of view.state.field(completionState).active)
if (active.state == 1 /* Pending */)
if (active.state == 1 /* State.Pending */)
this.startQuery(active);
}
update(update) {
@ -904,21 +969,21 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
}
if (this.debounceUpdate > -1)
clearTimeout(this.debounceUpdate);
this.debounceUpdate = cState.active.some(a => a.state == 1 /* Pending */ && !this.running.some(q => q.active.source == a.source))
this.debounceUpdate = cState.active.some(a => a.state == 1 /* State.Pending */ && !this.running.some(q => q.active.source == a.source))
? setTimeout(() => this.startUpdate(), DebounceTime) : -1;
if (this.composing != 0 /* None */)
if (this.composing != 0 /* CompositionState.None */)
for (let tr of update.transactions) {
if (getUserEvent(tr) == "input")
this.composing = 2 /* Changed */;
else if (this.composing == 2 /* Changed */ && tr.selection)
this.composing = 3 /* ChangedAndMoved */;
this.composing = 2 /* CompositionState.Changed */;
else if (this.composing == 2 /* CompositionState.Changed */ && tr.selection)
this.composing = 3 /* CompositionState.ChangedAndMoved */;
}
}
startUpdate() {
this.debounceUpdate = -1;
let { state } = this.view, cState = state.field(completionState);
for (let active of cState.active) {
if (active.state == 1 /* Pending */ && !this.running.some(r => r.active.source == active.source))
if (active.state == 1 /* State.Pending */ && !this.running.some(r => r.active.source == active.source))
this.startQuery(active);
}
}
@ -969,14 +1034,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 /* Pending */) {
if (current && current.state == 1 /* State.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 /* Inactive */);
let active = new ActiveSource(query.active.source, 0 /* State.Inactive */);
for (let tr of query.updates)
active = active.update(tr, conf);
if (active.state != 1 /* Pending */)
if (active.state != 1 /* State.Pending */)
updated.push(active);
}
else {
@ -996,15 +1061,15 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
this.view.dispatch({ effects: closeCompletionEffect.of(null) });
},
compositionstart() {
this.composing = 1 /* Started */;
this.composing = 1 /* CompositionState.Started */;
},
compositionend() {
if (this.composing == 3 /* ChangedAndMoved */) {
if (this.composing == 3 /* CompositionState.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 /* None */;
this.composing = 0 /* CompositionState.None */;
}
}
});
@ -1019,6 +1084,7 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
maxWidth: "min(700px, 95vw)",
minWidth: "250px",
maxHeight: "10em",
height: "100%",
listStyle: "none",
margin: 0,
padding: 0,
@ -1035,10 +1101,16 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
background: "#17c",
color: "white",
},
"&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]": {
background: "#777",
},
"&dark .cm-tooltip-autocomplete ul li[aria-selected]": {
background: "#347",
color: "white",
},
"&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]": {
background: "#444",
},
".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": {
content: '"···"',
opacity: 0.5,
@ -1049,16 +1121,20 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
position: "absolute",
padding: "3px 9px",
width: "max-content",
maxWidth: "300px",
maxWidth: `${400 /* Info.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` },
"&light .cm-snippetField": { backgroundColor: "#00000022" },
"&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
".cm-snippetFieldPosition": {
verticalAlign: "text-top",
width: 0,
height: "1.15em",
display: "inline-block",
margin: "0 -0.7px -.7em",
borderLeft: "1.4px dotted #888"
},
@ -1075,7 +1151,8 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
display: "inline-block",
textAlign: "center",
paddingRight: ".6em",
opacity: "0.6"
opacity: "0.6",
boxSizing: "content-box"
},
".cm-completionIcon-function, .cm-completionIcon-method": {
"&:after": { content: "'ƒ'" }
@ -1177,8 +1254,8 @@ class Snippet {
positions.push(new FieldPos(found, lines.length, m.index, m.index + name.length));
line = line.slice(0, m.index) + name + line.slice(m.index + m[0].length);
}
for (let esc; esc = /([$#])\\{/.exec(line);) {
line = line.slice(0, esc.index) + esc[1] + "{" + line.slice(esc.index + esc[0].length);
for (let esc; esc = /\\([{}])/.exec(line);) {
line = line.slice(0, esc.index) + esc[1] + line.slice(esc.index + esc[0].length);
for (let pos of positions)
if (pos.line == lines.length && pos.from > esc.index) {
pos.from--;
@ -1269,10 +1346,9 @@ The order of fields defaults to textual order, but you can add
numbers to placeholders (`${1}` or `${1:defaultText}`) to provide
a custom order.
To include a literal `${` or `#{` in your template, put a
backslash after the dollar or hash and before the brace (`$\\{`).
This will be removed and the sequence will not be interpreted as a
placeholder.
To include a literal `{` or `}` in your template, put a backslash
in front of it. This will be removed and the brace will not be
interpreted as indicating a placeholder.
*/
function snippet(template) {
let snippet = Snippet.parse(template);
@ -1387,7 +1463,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 /* MaxList */)
if (result.length >= 2000 /* C.MaxList */)
return;
}
}
@ -1395,7 +1471,7 @@ function storeWords(doc, wordRE, result, seen, ignoreAt) {
}
}
function collectWords(doc, cache, wordRE, to, ignoreAt) {
let big = doc.length >= 1000 /* MinCacheLen */;
let big = doc.length >= 1000 /* C.MinCacheLen */;
let cached = big && cache.get(doc);
if (cached)
return cached;
@ -1403,7 +1479,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
if (doc.children) {
let pos = 0;
for (let ch of doc.children) {
if (ch.length >= 1000 /* MinCacheLen */) {
if (ch.length >= 1000 /* C.MinCacheLen */) {
for (let c of collectWords(ch, cache, wordRE, to - pos, ignoreAt - pos)) {
if (!seen[c.label]) {
seen[c.label] = true;
@ -1420,7 +1496,7 @@ function collectWords(doc, cache, wordRE, to, ignoreAt) {
else {
storeWords(doc, wordRE, result, seen, ignoreAt);
}
if (big && result.length < 2000 /* MaxList */)
if (big && result.length < 2000 /* C.MaxList */)
cache.set(doc, result);
return result;
}
@ -1436,13 +1512,14 @@ 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 /* Range */, from);
let options = collectWords(context.state.doc, wordCache(wordChars), re, 50000 /* C.Range */, from);
return { from, options, validFor: mapRE(re, s => "^" + s) };
};
const defaults = {
brackets: ["(", "[", "{", "'", '"'],
before: ")]}:;>"
before: ")]}:;>",
stringPrefixes: []
};
const closeBracketEffect = /*@__PURE__*/StateEffect.define({
map(value, mapping) {
@ -1525,14 +1602,13 @@ const deleteBracketPair = ({ state, dispatch }) => {
for (let token of tokens) {
if (token == before && nextChar(state.doc, range.head) == closing(codePointAt(token, 0)))
return { changes: { from: range.head - token.length, to: range.head + token.length },
range: EditorSelection.cursor(range.head - token.length),
userEvent: "delete.backward" };
range: EditorSelection.cursor(range.head - token.length) };
}
}
return { range: dont = range };
});
if (!dont)
dispatch(state.update(changes, { scrollIntoView: true }));
dispatch(state.update(changes, { scrollIntoView: true, userEvent: "delete.backward" }));
return !dont;
};
/**
@ -1559,7 +1635,7 @@ function insertBracket(state, bracket) {
for (let tok of tokens) {
let closed = closing(codePointAt(tok, 0));
if (bracket == tok)
return closed == tok ? handleSame(state, tok, tokens.indexOf(tok + tok + tok) > -1)
return closed == tok ? handleSame(state, tok, tokens.indexOf(tok + tok + tok) > -1, conf)
: handleOpen(state, tok, closed, conf.before || defaults.before);
if (bracket == closed && closedBracketAt(state, state.selection.main.from))
return handleClose(state, tok, closed);
@ -1614,13 +1690,14 @@ function handleClose(state, _open, close) {
}
// Handles cases where the open and close token are the same, and
// possibly triple quotes (as in `"""abc"""`-style quoting).
function handleSame(state, token, allowTriple) {
function handleSame(state, token, allowTriple, config) {
let stringPrefixes = config.stringPrefixes || defaults.stringPrefixes;
let dont = null, changes = state.changeByRange(range => {
if (!range.empty)
return { changes: [{ insert: token, from: range.from }, { insert: token, from: range.to }],
effects: closeBracketEffect.of(range.to + token.length),
range: EditorSelection.range(range.anchor + token.length, range.head + token.length) };
let pos = range.head, next = nextChar(state.doc, pos);
let pos = range.head, next = nextChar(state.doc, pos), start;
if (next == token) {
if (nodeStart(state, pos)) {
return { changes: { insert: token + token, from: pos },
@ -1634,14 +1711,14 @@ function handleSame(state, token, allowTriple) {
}
}
else if (allowTriple && state.sliceDoc(pos - 2 * token.length, pos) == token + token &&
nodeStart(state, pos - 2 * token.length)) {
(start = canStartStringAt(state, pos - 2 * token.length, stringPrefixes)) > -1 &&
nodeStart(state, start)) {
return { changes: { insert: token + token + token + token, from: pos },
effects: closeBracketEffect.of(pos + token.length),
range: EditorSelection.cursor(pos + token.length) };
}
else if (state.charCategorizer(pos)(next) != CharCategory.Word) {
let prev = state.sliceDoc(pos - 1, pos);
if (prev != token && state.charCategorizer(pos)(prev) != CharCategory.Word && !probablyInString(state, pos, token))
if (canStartStringAt(state, pos, stringPrefixes) > -1 && !probablyInString(state, pos, token, stringPrefixes))
return { changes: { insert: token + token, from: pos },
effects: closeBracketEffect.of(pos + token.length),
range: EditorSelection.cursor(pos + token.length) };
@ -1657,11 +1734,21 @@ function nodeStart(state, pos) {
let tree = syntaxTree(state).resolveInner(pos + 1);
return tree.parent && tree.from == pos;
}
function probablyInString(state, pos, quoteToken) {
function probablyInString(state, pos, quoteToken, prefixes) {
let node = syntaxTree(state).resolveInner(pos, -1);
let maxPrefix = prefixes.reduce((m, p) => Math.max(m, p.length), 0);
for (let i = 0; i < 5; i++) {
if (state.sliceDoc(node.from, node.from + quoteToken.length) == quoteToken)
let start = state.sliceDoc(node.from, Math.min(node.to, node.from + quoteToken.length + maxPrefix));
let quotePos = start.indexOf(quoteToken);
if (!quotePos || quotePos > -1 && prefixes.indexOf(start.slice(0, quotePos)) > -1) {
let first = node.firstChild;
while (first && first.from == node.from && first.to - first.from > quoteToken.length + quotePos) {
if (state.sliceDoc(first.to - quoteToken.length, first.to) == quoteToken)
return false;
first = first.firstChild;
}
return true;
}
let parent = node.to == pos && node.parent;
if (!parent)
break;
@ -1669,6 +1756,17 @@ function probablyInString(state, pos, quoteToken) {
}
return false;
}
function canStartStringAt(state, pos, prefixes) {
let charCat = state.charCategorizer(pos);
if (charCat(state.sliceDoc(pos - 1, pos)) != CharCategory.Word)
return pos;
for (let prefix of prefixes) {
let start = pos - prefix.length;
if (state.sliceDoc(start, pos) == prefix && charCat(state.sliceDoc(start - 1, start)) != CharCategory.Word)
return start;
}
return -1;
}
/**
Returns an extension that enables autocompletion.
@ -1711,8 +1809,8 @@ returns `null`.
*/
function completionStatus(state) {
let cState = state.field(completionState, false);
return cState && cState.active.some(a => a.state == 1 /* Pending */) ? "pending"
: cState && cState.active.some(a => a.state != 0 /* Inactive */) ? "active" : null;
return cState && cState.active.some(a => a.state == 1 /* State.Pending */) ? "pending"
: cState && cState.active.some(a => a.state != 0 /* State.Inactive */) ? "active" : null;
}
const completionArrayCache = /*@__PURE__*/new WeakMap;
/**
@ -1721,7 +1819,7 @@ Returns the available completions as an array.
function currentCompletions(state) {
var _a;
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
if (!open)
if (!open || open.disabled)
return [];
let completions = completionArrayCache.get(open.options);
if (!completions)
@ -1734,7 +1832,7 @@ Return the currently selected completion, if any.
function selectedCompletion(state) {
var _a;
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
return open ? open.options[open.selected].completion : null;
return open && !open.disabled && open.selected >= 0 ? open.options[open.selected].completion : null;
}
/**
Returns the currently selected position in the active completion
@ -1743,7 +1841,7 @@ list, or null if no completions are active.
function selectedCompletionIndex(state) {
var _a;
let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open;
return open ? open.selected : null;
return open && !open.disabled && open.selected >= 0 ? open.selected : null;
}
/**
Create an effect that can be attached to a transaction to change