import { indentUnit, syntaxTree } from "./chunk-D63OSQ34.js"; import { Decoration, Direction, EditorView, ViewPlugin, WidgetType, getTooltip, keymap, logException, showTooltip } from "./chunk-LORPBXGU.js"; import { Annotation, CharCategory, EditorSelection, Facet, MapMode, Prec, RangeSet, RangeValue, StateEffect, StateField, Text, codePointAt, codePointSize, combineConfig, fromCodePoint } from "./chunk-MKFMOIK6.js"; // node_modules/@codemirror/autocomplete/dist/index.js var CompletionContext = class { /** Create a new completion context. (Mostly useful for testing completion sources—in the editor, the extension will create these for you.) */ constructor(state, pos, explicit) { this.state = state; this.pos = pos; this.explicit = explicit; this.abortListeners = []; } /** Get the extent, content, and (if there is a token) type of the token before `this.pos`. */ tokenBefore(types) { let token = syntaxTree(this.state).resolveInner(this.pos, -1); while (token && types.indexOf(token.name) < 0) token = token.parent; return token ? { from: token.from, to: this.pos, text: this.state.sliceDoc(token.from, this.pos), type: token.type } : null; } /** Get the match of the given expression directly before the cursor. */ matchBefore(expr) { let line = this.state.doc.lineAt(this.pos); let start = Math.max(line.from, this.pos - 250); let str = line.text.slice(start - line.from, this.pos - line.from); let found = str.search(ensureAnchor(expr, false)); return found < 0 ? null : { from: start + found, to: this.pos, text: str.slice(found) }; } /** Yields true when the query has been aborted. Can be useful in asynchronous queries to avoid doing work that will be ignored. */ get aborted() { return this.abortListeners == null; } /** Allows you to register abort handlers, which will be called when the query is [aborted](https://codemirror.net/6/docs/ref/#autocomplete.CompletionContext.aborted). */ addEventListener(type, listener) { if (type == "abort" && this.abortListeners) this.abortListeners.push(listener); } }; function toSet(chars) { let flat = Object.keys(chars).join(""); let words = /\w/.test(flat); if (words) flat = flat.replace(/\w/g, ""); return `[${words ? "\\w" : ""}${flat.replace(/[^\w\s]/g, "\\$&")}]`; } function prefixMatch(options) { let first = /* @__PURE__ */ Object.create(null), rest = /* @__PURE__ */ Object.create(null); for (let { label } of options) { first[label[0]] = true; for (let i = 1; i < label.length; i++) rest[label[i]] = true; } let source = toSet(first) + toSet(rest) + "*$"; return [new RegExp("^" + source), new RegExp(source)]; } function completeFromList(list) { let options = list.map((o) => typeof o == "string" ? { label: o } : o); let [validFor, match] = options.every((o) => /^\w+$/.test(o.label)) ? [/\w*$/, /\w+$/] : prefixMatch(options); return (context) => { let token = context.matchBefore(match); return token || context.explicit ? { from: token ? token.from : context.pos, options, validFor } : null; }; } function ifIn(nodes, source) { return (context) => { 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; }; } function ifNotIn(nodes, source) { return (context) => { 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); }; } var Option = class { constructor(completion, source, match, score2) { this.completion = completion; this.source = source; this.match = match; this.score = score2; } }; function cur(state) { return state.selection.main.from; } function ensureAnchor(expr, start) { var _a; let { source } = expr; let addStart = start && source[0] != "^", addEnd = source[source.length - 1] != "$"; if (!addStart && !addEnd) return expr; return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : expr.ignoreCase ? "i" : ""); } var pickedCompletion = Annotation.define(); 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 != main && from != to && state.sliceDoc(range.from + fromOff, range.from + toOff) != state.sliceDoc(from, to)) return { range }; return { 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" }); } var SourceCache = /* @__PURE__ */ new WeakMap(); function asSource(source) { if (!Array.isArray(source)) return source; let known = SourceCache.get(source); if (!known) SourceCache.set(source, known = completeFromList(source)); return known; } var startCompletionEffect = StateEffect.define(); var closeCompletionEffect = StateEffect.define(); var FuzzyMatcher = class { constructor(pattern) { this.pattern = pattern; this.chars = []; this.folded = []; 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); let part = pattern.slice(p, p + size), upper = part.toUpperCase(); this.folded.push(codePointAt(upper == part ? part.toLowerCase() : upper, 0)); p += size; } this.astral = pattern.length != this.chars.length; } ret(score2, matched) { this.score = score2; this.matched = matched; return true; } // Matches a given word (completion) against the pattern (input). // 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 this.ret(-100, []); if (word.length < this.pattern.length) return false; let { chars, folded, any, precise, byWord } = this; if (chars.length == 1) { let first = codePointAt(word, 0), firstSize = codePointSize(first); let score2 = firstSize == word.length ? 0 : -100; if (first == chars[0]) ; else if (first == folded[0]) score2 += -200; else return false; return this.ret(score2, [0, firstSize]); } let direct = word.indexOf(this.pattern); if (direct == 0) return this.ret(word.length == this.pattern.length ? 0 : -100, [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; ) { let next = codePointAt(word, i); if (next == chars[anyTo] || next == folded[anyTo]) any[anyTo++] = i; i += codePointSize(next); } if (anyTo < len) return false; } let preciseTo = 0; let byWordTo = 0, byWordFolded = false; let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1; let hasLower = /[a-z]/.test(word), wordAdjacent = true; for (let i = 0, e = Math.min(word.length, 200), prevType = 0; i < e && byWordTo < len; ) { let next = codePointAt(word, i); if (direct < 0) { if (preciseTo < len && next == chars[preciseTo]) precise[preciseTo++] = i; if (adjacentTo < len) { if (next == chars[adjacentTo] || next == folded[adjacentTo]) { if (adjacentTo == 0) adjacentStart = i; adjacentEnd = i + 1; adjacentTo++; } else { adjacentTo = 0; } } } let ch, type = next < 255 ? next >= 48 && next <= 57 || next >= 97 && next <= 122 ? 2 : next >= 65 && next <= 90 ? 1 : 0 : (ch = fromCodePoint(next)) != ch.toLowerCase() ? 1 : ch != ch.toUpperCase() ? 2 : 0; if (!i || type == 1 && hasLower || prevType == 0 && type != 0) { if (chars[byWordTo] == next || folded[byWordTo] == next && (byWordFolded = true)) byWord[byWordTo++] = i; else if (byWord.length) wordAdjacent = false; } prevType = type; i += codePointSize(next); } if (byWordTo == len && byWord[0] == 0 && wordAdjacent) return this.result(-100 + (byWordFolded ? -200 : 0), byWord, word); if (adjacentTo == len && adjacentStart == 0) return this.ret(-200 - word.length + (adjacentEnd == word.length ? 0 : -100), [0, adjacentEnd]); if (direct > -1) return this.ret(-700 - word.length, [direct, direct + this.pattern.length]); if (adjacentTo == len) return this.ret(-200 + -700 - word.length, [adjacentStart, adjacentEnd]); if (byWordTo == len) return this.result(-100 + (byWordFolded ? -200 : 0) + -700 + (wordAdjacent ? 0 : -1100), byWord, word); return chars.length == 2 ? false : this.result((any[0] ? -700 : 0) + -200 + -1100, any, word); } result(score2, positions, word) { let result = [], i = 0; for (let pos of positions) { let to = pos + (this.astral ? codePointSize(codePointAt(word, pos)) : 1); if (i && result[i - 1] == pos) result[i - 1] = to; else { result[i++] = pos; result[i++] = to; } } return this.ret(score2 - word.length, result); } }; var completionConfig = 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: [], positionInfo: defaultPositionInfo, 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) }); } }); 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, left ? spaceLeft : spaceRight); } else { narrow = true; maxWidth = Math.min( 400, (rtl ? list.right : space.right - list.left) - 30 /* Margin */ ); let spaceBelow = space.bottom - list.bottom; if (spaceBelow >= infoHeight || spaceBelow > list.top) { offset = option.bottom - list.top; } else { 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(config2) { let content = config2.addToOptions.slice(); if (config2.icons) content.push({ render(completion) { let icon = document.createElement("div"); icon.classList.add("cm-completionIcon"); if (completion.type) icon.classList.add(...completion.type.split(/\s+/g).map((cls) => "cm-completionIcon-" + cls)); icon.setAttribute("aria-hidden", "true"); return icon; }, position: 20 }); content.push({ render(completion, _s, match) { let labelElt = document.createElement("span"); labelElt.className = "cm-completionLabel"; 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))); let span = labelElt.appendChild(document.createElement("span")); span.appendChild(document.createTextNode(label.slice(from, to))); span.className = "cm-completionMatchedText"; off = to; } if (off < label.length) labelElt.appendChild(document.createTextNode(label.slice(off))); return labelElt; }, position: 50 }, { render(completion) { if (!completion.detail) return null; let detailElt = document.createElement("span"); detailElt.className = "cm-completionDetail"; detailElt.textContent = completion.detail; return detailElt; }, position: 80 }); return content.sort((a, b) => a.position - b.position).map((a) => a.render); } function rangeAroundSelected(total, selected, max) { if (total <= max) return { from: 0, to: total }; if (selected < 0) selected = 0; if (selected <= total >> 1) { let off2 = Math.floor(selected / max); return { from: off2 * max, to: (off2 + 1) * max }; } let off = Math.floor((total - selected) / max); return { from: total - (off + 1) * max, to: total - off * max }; } var CompletionTooltip = class { constructor(view, stateField, applyCompletion2) { this.view = view; this.stateField = stateField; this.applyCompletion = applyCompletion2; this.info = null; this.infoDestroy = null; this.placeInfoReq = { read: () => this.measureInfo(), write: (pos) => this.placeInfo(pos), key: this }; this.space = null; this.currentClass = ""; let cState = view.state.field(stateField); let { options, selected } = cState.open; let config2 = view.state.facet(completionConfig); this.optionContent = optionContent(config2); this.optionClass = config2.optionClass; this.tooltipClass = config2.tooltipClass; this.range = rangeAroundSelected(options.length, selected, config2.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) { 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.placeInfoReq); }); } mount() { this.updateSel(); } update(update) { 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)); } } 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.placeInfoReq); } updateSel() { let cState = this.view.state.field(this.stateField), open = cState.open; 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)); this.list.addEventListener("scroll", () => { if (this.info) this.view.requestMeasure(this.placeInfoReq); }); } if (this.updateSelectedOption(open.selected)) { this.destroyInfo(); let { completion } = open.options[open.selected]; let { info } = completion; if (!info) return; let infoResult = typeof info === "string" ? document.createTextNode(info) : info(completion); if (!infoResult) return; 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, completion); } } } 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 (opt.nodeName != "LI" || !opt.id) { i--; } else if (i == selected) { if (!opt.hasAttribute("aria-selected")) { opt.setAttribute("aria-selected", "true"); set = opt; } } else { if (opt.hasAttribute("aria-selected")) opt.removeAttribute("aria-selected"); } } if (set) scrollIntoView(this.list, set); return set; } measureInfo() { let sel = this.dom.querySelector("[aria-selected]"); if (!sel || !this.info) return null; let listRect = this.dom.getBoundingClientRect(); let infoRect = this.info.getBoundingClientRect(); let selRect = sel.getBoundingClientRect(); 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; return this.view.state.facet(completionConfig).positionInfo(this.view, listRect, selRect, infoRect, space); } placeInfo(pos) { if (this.info) { if (pos) { if (pos.style) this.info.style.cssText = pos.style; this.info.className = "cm-tooltip cm-completionInfo " + (pos.class || ""); } else { this.info.style.cssText = "top: -1e6px"; } } } createListBox(options, id, range) { const ul = document.createElement("ul"); ul.id = id; 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], { 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"); let cls = this.optionClass(completion); if (cls) li.className = cls; for (let source of this.optionContent) { let node = source(completion, this.view.state, match); if (node) li.appendChild(node); } } if (range.from) ul.classList.add("cm-completionListIncompleteTop"); if (range.to < options.length) 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(); } }; function completionTooltip(stateField, applyCompletion2) { return (view) => new CompletionTooltip(view, stateField, applyCompletion2); } function scrollIntoView(container, element) { let parent = container.getBoundingClientRect(); let self = element.getBoundingClientRect(); if (self.top < parent.top) container.scrollTop -= parent.top - self.top; else if (self.bottom > parent.bottom) container.scrollTop += self.bottom - parent.bottom; } function score(option) { return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0); } function sortOptions(active, state) { 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) { for (let option of a.result.options) { addOption(new Option(option, a.source, getMatch ? getMatch(option) : [], 1e9 - options.length)); } } else { let matcher = new FuzzyMatcher(state.sliceDoc(a.from, a.to)); for (let option of a.result.options) 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 = /* @__PURE__ */ 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.score - a.score || compare(a.completion, b.completion))) { let cur2 = opt.completion; if (!prev || prev.label != cur2.label || prev.detail != cur2.detail || prev.type != null && cur2.type != null && prev.type != cur2.type || prev.apply != cur2.apply || prev.boost != cur2.boost) result.push(opt); else if (score(opt.completion) > score(prev)) result[result.length - 1] = opt; prev = opt.completion; } return result; } var CompletionDialog = class _CompletionDialog { 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, this.disabled); } static build(active, state, id, prev, conf) { let options = sortOptions(active, state); if (!options.length) { 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; 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) { selected = i; break; } } return new _CompletionDialog(options, makeAttrs(id, selected), { pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8), create: completionTooltip(completionState, applyCompletion), above: conf.aboveCursor }, 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, this.disabled); } }; var CompletionState = class _CompletionState { constructor(active, id, open) { this.active = active; this.id = id; this.open = open; } static start() { return new _CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null); } update(tr) { let { state } = tr, conf = state.facet(completionConfig); let sources = conf.override || 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 : 0 /* 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 = 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 /* Pending */ )) open = null; 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); return active == this.active && open == this.open ? this : new _CompletionState(active, this.id, open); } get tooltip() { return this.open ? this.open.tooltip : null; } get attrs() { return this.open ? this.open.attrs : baseAttrs; } }; function sameResults(a, b) { if (a == b) return true; for (let iA = 0, iB = 0; ; ) { while (iA < a.length && !a[iA].hasResult) iA++; while (iB < b.length && !b[iB].hasResult) iB++; let endA = iA == a.length, endB = iB == b.length; if (endA || endB) return endA == endB; if (a[iA++].result != b[iB++].result) return false; } } var baseAttrs = { "aria-autocomplete": "list" }; function makeAttrs(id, selected) { let result = { "aria-autocomplete": "list", "aria-haspopup": "listbox", "aria-controls": id }; if (selected > -1) result["aria-activedescendant"] = id + "-" + selected; return result; } var none = []; function getUserEvent(tr) { return tr.isUserEvent("input.type") ? "input" : tr.isUserEvent("delete.backward") ? "delete" : null; } var ActiveSource = class _ActiveSource { constructor(source, state, explicitPos = -1) { this.source = source; this.state = state; this.explicitPos = explicitPos; } hasResult() { return false; } update(tr, conf) { let event = getUserEvent(tr), value = this; if (event) value = value.handleUserEvent(tr, event, conf); else if (tr.docChanged) value = value.handleChange(tr); else if (tr.selection && value.state != 0) value = new _ActiveSource( value.source, 0 /* Inactive */ ); for (let effect of tr.effects) { if (effect.is(startCompletionEffect)) value = new _ActiveSource(value.source, 1, effect.value ? cur(tr.state) : -1); else if (effect.is(closeCompletionEffect)) value = new _ActiveSource( value.source, 0 /* Inactive */ ); else if (effect.is(setActiveEffect)) { for (let active of effect.value) if (active.source == value.source) value = active; } } return value; } handleUserEvent(tr, type, conf) { 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 /* Inactive */ ) : this.map(tr.changes); } map(changes) { return changes.empty || this.explicitPos < 0 ? this : new _ActiveSource(this.source, this.state, changes.mapPos(this.explicitPos)); } }; var ActiveResult = class _ActiveResult extends ActiveSource { constructor(source, explicitPos, result, from, to) { super(source, 2, explicitPos); this.result = result; this.from = from; this.to = to; } hasResult() { return true; } handleUserEvent(tr, type, conf) { var _a; let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1); let pos = cur(tr.state); 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 : 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, explicitPos); } handleChange(tr) { return tr.changes.touchesRange(this.from, this.to) ? new ActiveSource( this.source, 0 /* Inactive */ ) : this.map(tr.changes); } map(mapping) { return mapping.empty ? this : new _ActiveResult(this.source, this.explicitPos < 0 ? -1 : mapping.mapPos(this.explicitPos), this.result, mapping.mapPos(this.from), mapping.mapPos(this.to, 1)); } }; function checkValid(validFor, state, from, to) { if (!validFor) return false; let text = state.sliceDoc(from, to); return typeof validFor == "function" ? validFor(text, from, to, state) : ensureAnchor(validFor, true).test(text); } var setActiveEffect = StateEffect.define({ map(sources, mapping) { return sources.map((s) => s.map(mapping)); } }); var setSelectedEffect = StateEffect.define(); var completionState = StateField.define({ create() { return CompletionState.start(); }, update(value, tr) { return value.update(tr); }, provide: (f) => [ showTooltip.from(f, (val) => val.tooltip), 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; } function moveCompletionSelection(forward, by = "option") { return (view) => { let cState = view.state.field(completionState, false); 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 { 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) selected = by == "page" ? length - 1 : 0; view.dispatch({ effects: setSelectedEffect.of(selected) }); return true; }; } var acceptCompletion = (view) => { let cState = view.state.field(completionState, false); 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; return applyCompletion(view, cState.open.options[cState.open.selected]); }; var startCompletion = (view) => { let cState = view.state.field(completionState, false); if (!cState) return false; view.dispatch({ effects: startCompletionEffect.of(true) }); return true; }; var closeCompletion = (view) => { let cState = view.state.field(completionState, false); if (!cState || !cState.active.some( (a) => a.state != 0 /* Inactive */ )) return false; view.dispatch({ effects: closeCompletionEffect.of(null) }); return true; }; var RunningQuery = class { constructor(active, context) { this.active = active; this.context = context; this.time = Date.now(); this.updates = []; this.done = void 0; } }; var DebounceTime = 50; var MaxUpdateCount = 50; var MinAbortTime = 1e3; var completionPlugin = ViewPlugin.fromClass(class { constructor(view) { this.view = view; this.debounceUpdate = -1; this.running = []; this.debounceAccept = -1; this.composing = 0; for (let active of view.state.field(completionState).active) if (active.state == 1) this.startQuery(active); } update(update) { let cState = update.state.field(completionState); if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState) return; let doesReset = update.transactions.some((tr) => { return (tr.selection || tr.docChanged) && !getUserEvent(tr); }); for (let i = 0; i < this.running.length; i++) { let query = this.running[i]; if (doesReset || query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) { for (let handler of query.context.abortListeners) { try { handler(); } catch (e) { logException(this.view.state, e); } } query.context.abortListeners = null; this.running.splice(i--, 1); } else { query.updates.push(...update.transactions); } } if (this.debounceUpdate > -1) clearTimeout(this.debounceUpdate); this.debounceUpdate = cState.active.some((a) => a.state == 1 && !this.running.some((q) => q.active.source == a.source)) ? setTimeout(() => this.startUpdate(), DebounceTime) : -1; if (this.composing != 0) for (let tr of update.transactions) { if (getUserEvent(tr) == "input") this.composing = 2; else if (this.composing == 2 && tr.selection) this.composing = 3; } } startUpdate() { this.debounceUpdate = -1; let { state } = this.view, cState = state.field(completionState); for (let active of cState.active) { if (active.state == 1 && !this.running.some((r) => r.active.source == active.source)) this.startQuery(active); } } startQuery(active) { let { state } = this.view, pos = cur(state); let context = new CompletionContext(state, pos, active.explicitPos == pos); let pending = new RunningQuery(active, context); this.running.push(pending); Promise.resolve(active.source(context)).then((result) => { if (!pending.context.aborted) { pending.done = result || null; this.scheduleAccept(); } }, (err) => { this.view.dispatch({ effects: closeCompletionEffect.of(null) }); logException(this.view.state, err); }); } scheduleAccept() { if (this.running.every((q) => q.done !== void 0)) this.accept(); else if (this.debounceAccept < 0) this.debounceAccept = setTimeout(() => this.accept(), DebounceTime); } // For each finished query in this.running, try to create a result // or, if appropriate, restart the query. accept() { var _a; if (this.debounceAccept > -1) clearTimeout(this.debounceAccept); this.debounceAccept = -1; let updated = []; let conf = this.view.state.facet(completionConfig); for (let i = 0; i < this.running.length; i++) { let query = this.running[i]; if (query.done === void 0) continue; this.running.splice(i--, 1); if (query.done) { let active = new ActiveResult(query.active.source, query.active.explicitPos, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : cur(query.updates.length ? query.updates[0].startState : this.view.state)); for (let tr of query.updates) active = active.update(tr, conf); if (active.hasResult()) { updated.push(active); continue; } } let current = this.view.state.field(completionState).active.find((a) => a.source == query.active.source); if (current && current.state == 1) { if (query.done == null) { let active = new ActiveSource( query.active.source, 0 /* Inactive */ ); for (let tr of query.updates) active = active.update(tr, conf); if (active.state != 1) updated.push(active); } else { this.startQuery(current); } } } if (updated.length) this.view.dispatch({ effects: setActiveEffect.of(updated) }); } }, { eventHandlers: { blur(event) { let state = this.view.state.field(completionState, false); 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; }, compositionend() { if (this.composing == 3) { setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20); } this.composing = 0; } } }); var baseTheme = EditorView.baseTheme({ ".cm-tooltip.cm-tooltip-autocomplete": { "& > ul": { fontFamily: "monospace", whiteSpace: "nowrap", overflow: "hidden auto", maxWidth_fallback: "700px", maxWidth: "min(700px, 95vw)", minWidth: "250px", maxHeight: "10em", height: "100%", listStyle: "none", margin: 0, padding: 0, "& > 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]": { 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, display: "block", textAlign: "center" }, ".cm-tooltip.cm-completionInfo": { position: "absolute", padding: "3px 9px", width: "max-content", maxWidth: `${400}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}px` }, ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `${30}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" }, ".cm-completionMatchedText": { textDecoration: "underline" }, ".cm-completionDetail": { marginLeft: "0.5em", fontStyle: "italic" }, ".cm-completionIcon": { fontSize: "90%", width: ".8em", display: "inline-block", textAlign: "center", paddingRight: ".6em", opacity: "0.6", boxSizing: "content-box" }, ".cm-completionIcon-function, .cm-completionIcon-method": { "&:after": { content: "'ƒ'" } }, ".cm-completionIcon-class": { "&:after": { content: "'○'" } }, ".cm-completionIcon-interface": { "&:after": { content: "'◌'" } }, ".cm-completionIcon-variable": { "&:after": { content: "'𝑥'" } }, ".cm-completionIcon-constant": { "&:after": { content: "'𝐶'" } }, ".cm-completionIcon-type": { "&:after": { content: "'𝑡'" } }, ".cm-completionIcon-enum": { "&:after": { content: "'∪'" } }, ".cm-completionIcon-property": { "&:after": { content: "'□'" } }, ".cm-completionIcon-keyword": { "&:after": { content: "'🔑︎'" } // Disable emoji rendering }, ".cm-completionIcon-namespace": { "&:after": { content: "'▢'" } }, ".cm-completionIcon-text": { "&:after": { content: "'abc'", fontSize: "50%", verticalAlign: "middle" } } }); var FieldPos = class { constructor(field, line, from, to) { this.field = field; this.line = line; this.from = from; this.to = to; } }; var FieldRange = class _FieldRange { constructor(field, from, to) { this.field = field; this.from = from; this.to = to; } map(changes) { let from = changes.mapPos(this.from, -1, MapMode.TrackDel); let to = changes.mapPos(this.to, 1, MapMode.TrackDel); return from == null || to == null ? null : new _FieldRange(this.field, from, to); } }; var Snippet = class _Snippet { constructor(lines, fieldPositions) { this.lines = lines; this.fieldPositions = fieldPositions; } instantiate(state, pos) { let text = [], lineStart = [pos]; let lineObj = state.doc.lineAt(pos), baseIndent = /^\s*/.exec(lineObj.text)[0]; for (let line of this.lines) { if (text.length) { let indent = baseIndent, tabs = /^\t*/.exec(line)[0].length; for (let i = 0; i < tabs; i++) indent += state.facet(indentUnit); lineStart.push(pos + indent.length - tabs); line = indent + line.slice(tabs); } text.push(line); pos += line.length + 1; } let ranges = this.fieldPositions.map((pos2) => new FieldRange(pos2.field, lineStart[pos2.line] + pos2.from, lineStart[pos2.line] + pos2.to)); return { text, ranges }; } static parse(template) { let fields = []; let lines = [], positions = [], m; for (let line of template.split(/\r\n?|\n/)) { while (m = /[#$]\{(?:(\d+)(?::([^}]*))?|([^}]*))\}/.exec(line)) { let seq = m[1] ? +m[1] : null, name = m[2] || m[3] || "", found = -1; for (let i = 0; i < fields.length; i++) { if (seq != null ? fields[i].seq == seq : name ? fields[i].name == name : false) found = i; } if (found < 0) { let i = 0; while (i < fields.length && (seq == null || fields[i].seq != null && fields[i].seq < seq)) i++; fields.splice(i, 0, { seq, name }); found = i; for (let pos of positions) if (pos.field >= found) pos.field++; } 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 pos of positions) if (pos.line == lines.length && pos.from > esc.index) { pos.from--; pos.to--; } } lines.push(line); } return new _Snippet(lines, positions); } }; var fieldMarker = Decoration.widget({ widget: new class extends WidgetType { toDOM() { let span = document.createElement("span"); span.className = "cm-snippetFieldPosition"; return span; } ignoreEvent() { return false; } }() }); var fieldRange = Decoration.mark({ class: "cm-snippetField" }); var ActiveSnippet = class _ActiveSnippet { constructor(ranges, active) { this.ranges = ranges; this.active = active; this.deco = Decoration.set(ranges.map((r) => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to))); } map(changes) { let ranges = []; for (let r of this.ranges) { let mapped = r.map(changes); if (!mapped) return null; ranges.push(mapped); } return new _ActiveSnippet(ranges, this.active); } selectionInsideField(sel) { return sel.ranges.every((range) => this.ranges.some((r) => r.field == this.active && r.from <= range.from && r.to >= range.to)); } }; var setActive = StateEffect.define({ map(value, changes) { return value && value.map(changes); } }); var moveToField = StateEffect.define(); var snippetState = StateField.define({ create() { return null; }, update(value, tr) { for (let effect of tr.effects) { if (effect.is(setActive)) return effect.value; if (effect.is(moveToField) && value) return new ActiveSnippet(value.ranges, effect.value); } if (value && tr.docChanged) value = value.map(tr.changes); if (value && tr.selection && !value.selectionInsideField(tr.selection)) value = null; return value; }, provide: (f) => EditorView.decorations.from(f, (val) => val ? val.deco : Decoration.none) }); function fieldSelection(ranges, field) { return EditorSelection.create(ranges.filter((r) => r.field == field).map((r) => EditorSelection.range(r.from, r.to))); } function snippet(template) { let snippet2 = Snippet.parse(template); return (editor, completion, from, to) => { let { text, ranges } = snippet2.instantiate(editor.state, from); let spec = { changes: { from, to, insert: Text.of(text) }, scrollIntoView: true, annotations: completion ? pickedCompletion.of(completion) : void 0 }; if (ranges.length) spec.selection = fieldSelection(ranges, 0); if (ranges.length > 1) { let active = new ActiveSnippet(ranges, 0); let effects = spec.effects = [setActive.of(active)]; if (editor.state.field(snippetState, false) === void 0) effects.push(StateEffect.appendConfig.of([snippetState, addSnippetKeymap, snippetPointerHandler, baseTheme])); } editor.dispatch(editor.state.update(spec)); }; } function moveField(dir) { return ({ state, dispatch }) => { let active = state.field(snippetState, false); if (!active || dir < 0 && active.active == 0) return false; let next = active.active + dir, last = dir > 0 && !active.ranges.some((r) => r.field == next + dir); dispatch(state.update({ selection: fieldSelection(active.ranges, next), effects: setActive.of(last ? null : new ActiveSnippet(active.ranges, next)) })); return true; }; } var clearSnippet = ({ state, dispatch }) => { let active = state.field(snippetState, false); if (!active) return false; dispatch(state.update({ effects: setActive.of(null) })); return true; }; var nextSnippetField = moveField(1); var prevSnippetField = moveField(-1); function hasNextSnippetField(state) { let active = state.field(snippetState, false); return !!(active && active.ranges.some((r) => r.field == active.active + 1)); } function hasPrevSnippetField(state) { let active = state.field(snippetState, false); return !!(active && active.active > 0); } var defaultSnippetKeymap = [ { key: "Tab", run: nextSnippetField, shift: prevSnippetField }, { key: "Escape", run: clearSnippet } ]; var snippetKeymap = Facet.define({ combine(maps) { return maps.length ? maps[0] : defaultSnippetKeymap; } }); var addSnippetKeymap = Prec.highest(keymap.compute([snippetKeymap], (state) => state.facet(snippetKeymap))); function snippetCompletion(template, completion) { return Object.assign(Object.assign({}, completion), { apply: snippet(template) }); } var snippetPointerHandler = EditorView.domEventHandlers({ mousedown(event, view) { let active = view.state.field(snippetState, false), pos; if (!active || (pos = view.posAtCoords({ x: event.clientX, y: event.clientY })) == null) return false; let match = active.ranges.find((r) => r.from <= pos && r.to >= pos); if (!match || match.field == active.active) return false; view.dispatch({ selection: fieldSelection(active.ranges, match.field), effects: setActive.of(active.ranges.some((r) => r.field > match.field) ? new ActiveSnippet(active.ranges, match.field) : null) }); return true; } }); function wordRE(wordChars) { let escaped = wordChars.replace(/[\\[.+*?(){|^$]/g, "\\$&"); try { return new RegExp(`[\\p{Alphabetic}\\p{Number}_${escaped}]+`, "ug"); } catch (_a) { return new RegExp(`[w${escaped}]`, "g"); } } function mapRE(re, f) { return new RegExp(f(re.source), re.unicode ? "u" : ""); } var wordCaches = /* @__PURE__ */ Object.create(null); function wordCache(wordChars) { return wordCaches[wordChars] || (wordCaches[wordChars] = /* @__PURE__ */ new WeakMap()); } function storeWords(doc, wordRE2, result, seen, ignoreAt) { for (let lines = doc.iterLines(), pos = 0; !lines.next().done; ) { let { value } = lines, m; wordRE2.lastIndex = 0; while (m = wordRE2.exec(value)) { if (!seen[m[0]] && pos + m.index != ignoreAt) { result.push({ type: "text", label: m[0] }); seen[m[0]] = true; if (result.length >= 2e3) return; } } pos += value.length + 1; } } function collectWords(doc, cache, wordRE2, to, ignoreAt) { let big = doc.length >= 1e3; let cached = big && cache.get(doc); if (cached) return cached; let result = [], seen = /* @__PURE__ */ Object.create(null); if (doc.children) { let pos = 0; for (let ch of doc.children) { if (ch.length >= 1e3) { for (let c of collectWords(ch, cache, wordRE2, to - pos, ignoreAt - pos)) { if (!seen[c.label]) { seen[c.label] = true; result.push(c); } } } else { storeWords(ch, wordRE2, result, seen, ignoreAt - pos); } pos += ch.length + 1; } } else { storeWords(doc, wordRE2, result, seen, ignoreAt); } if (big && result.length < 2e3) cache.set(doc, result); return result; } var completeAnyWord = (context) => { let wordChars = context.state.languageDataAt("wordChars", context.pos).join(""); let re = wordRE(wordChars); let token = context.matchBefore(mapRE(re, (s) => s + "$")); if (!token && !context.explicit) return null; let from = token ? token.from : context.pos; let options = collectWords(context.state.doc, wordCache(wordChars), re, 5e4, from); return { from, options, validFor: mapRE(re, (s) => "^" + s) }; }; var defaults = { brackets: ["(", "[", "{", "'", '"'], before: ")]}:;>", stringPrefixes: [] }; var closeBracketEffect = StateEffect.define({ map(value, mapping) { let mapped = mapping.mapPos(value, -1, MapMode.TrackAfter); return mapped == null ? void 0 : mapped; } }); var closedBracket = new class extends RangeValue { }(); closedBracket.startSide = 1; closedBracket.endSide = -1; var bracketState = StateField.define({ create() { return RangeSet.empty; }, update(value, tr) { if (tr.selection) { let lineStart = tr.state.doc.lineAt(tr.selection.main.head).from; let prevLineStart = tr.startState.doc.lineAt(tr.startState.selection.main.head).from; if (lineStart != tr.changes.mapPos(prevLineStart, -1)) value = RangeSet.empty; } value = value.map(tr.changes); for (let effect of tr.effects) if (effect.is(closeBracketEffect)) value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] }); return value; } }); function closeBrackets() { return [inputHandler, bracketState]; } var definedClosing = "()[]{}<>"; function closing(ch) { for (let i = 0; i < definedClosing.length; i += 2) if (definedClosing.charCodeAt(i) == ch) return definedClosing.charAt(i + 1); return fromCodePoint(ch < 128 ? ch : ch + 1); } function config(state, pos) { return state.languageDataAt("closeBrackets", pos)[0] || defaults; } var android = typeof navigator == "object" && /Android\b/.test(navigator.userAgent); var inputHandler = EditorView.inputHandler.of((view, from, to, insert) => { if ((android ? view.composing : view.compositionStarted) || view.state.readOnly) return false; let sel = view.state.selection.main; if (insert.length > 2 || insert.length == 2 && codePointSize(codePointAt(insert, 0)) == 1 || from != sel.from || to != sel.to) return false; let tr = insertBracket(view.state, insert); if (!tr) return false; view.dispatch(tr); return true; }); var deleteBracketPair = ({ state, dispatch }) => { if (state.readOnly) return false; let conf = config(state, state.selection.main.head); let tokens = conf.brackets || defaults.brackets; let dont = null, changes = state.changeByRange((range) => { if (range.empty) { let before = prevChar(state.doc, range.head); 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) }; } } return { range: dont = range }; }); if (!dont) dispatch(state.update(changes, { scrollIntoView: true, userEvent: "delete.backward" })); return !dont; }; var closeBracketsKeymap = [ { key: "Backspace", run: deleteBracketPair } ]; function insertBracket(state, bracket) { let conf = config(state, state.selection.main.head); let tokens = conf.brackets || defaults.brackets; 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, conf) : handleOpen(state, tok, closed, conf.before || defaults.before); if (bracket == closed && closedBracketAt(state, state.selection.main.from)) return handleClose(state, tok, closed); } return null; } function closedBracketAt(state, pos) { let found = false; state.field(bracketState).between(0, state.doc.length, (from) => { if (from == pos) found = true; }); return found; } function nextChar(doc, pos) { let next = doc.sliceString(pos, pos + 2); return next.slice(0, codePointSize(codePointAt(next, 0))); } function prevChar(doc, pos) { let prev = doc.sliceString(pos - 2, pos); return codePointSize(codePointAt(prev, 0)) == prev.length ? prev : prev.slice(1); } function handleOpen(state, open, close, closeBefore) { let dont = null, changes = state.changeByRange((range) => { if (!range.empty) return { changes: [{ insert: open, from: range.from }, { insert: close, from: range.to }], effects: closeBracketEffect.of(range.to + open.length), range: EditorSelection.range(range.anchor + open.length, range.head + open.length) }; let next = nextChar(state.doc, range.head); if (!next || /\s/.test(next) || closeBefore.indexOf(next) > -1) return { changes: { insert: open + close, from: range.head }, effects: closeBracketEffect.of(range.head + open.length), range: EditorSelection.cursor(range.head + open.length) }; return { range: dont = range }; }); return dont ? null : state.update(changes, { scrollIntoView: true, userEvent: "input.type" }); } function handleClose(state, _open, close) { let dont = null, changes = state.changeByRange((range) => { if (range.empty && nextChar(state.doc, range.head) == close) 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(changes, { scrollIntoView: true, userEvent: "input.type" }); } function handleSame(state, token, allowTriple, config2) { let stringPrefixes = config2.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), start; if (next == token) { if (nodeStart(state, pos)) { return { changes: { insert: token + token, from: pos }, effects: closeBracketEffect.of(pos + token.length), range: EditorSelection.cursor(pos + token.length) }; } else if (closedBracketAt(state, pos)) { let isTriple = allowTriple && state.sliceDoc(pos, pos + token.length * 3) == token + token + token; 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 && (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) { 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) }; } return { range: dont = range }; }); return dont ? null : state.update(changes, { scrollIntoView: true, userEvent: "input.type" }); } function nodeStart(state, pos) { let tree = syntaxTree(state).resolveInner(pos + 1); return tree.parent && tree.from == pos; } 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++) { 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; node = parent; } 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; } function autocompletion(config2 = {}) { return [ completionState, completionConfig.of(config2), completionPlugin, completionKeymapExt, baseTheme ]; } var completionKeymap = [ { key: "Ctrl-Space", run: startCompletion }, { key: "Escape", run: closeCompletion }, { key: "ArrowDown", run: moveCompletionSelection(true) }, { key: "ArrowUp", run: moveCompletionSelection(false) }, { key: "PageDown", run: moveCompletionSelection(true, "page") }, { key: "PageUp", run: moveCompletionSelection(false, "page") }, { key: "Enter", run: acceptCompletion } ]; var completionKeymapExt = Prec.highest(keymap.computeN([completionConfig], (state) => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : [])); 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; } var completionArrayCache = /* @__PURE__ */ new WeakMap(); function currentCompletions(state) { var _a; let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; if (!open || open.disabled) return []; let completions = completionArrayCache.get(open.options); if (!completions) completionArrayCache.set(open.options, completions = open.options.map((o) => o.completion)); return completions; } function selectedCompletion(state) { var _a; let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; return open && !open.disabled && open.selected >= 0 ? open.options[open.selected].completion : null; } function selectedCompletionIndex(state) { var _a; let open = (_a = state.field(completionState, false)) === null || _a === void 0 ? void 0 : _a.open; return open && !open.disabled && open.selected >= 0 ? open.selected : null; } function setSelectedCompletion(index) { return setSelectedEffect.of(index); } export { CompletionContext, completeFromList, ifIn, ifNotIn, pickedCompletion, insertCompletionText, moveCompletionSelection, acceptCompletion, startCompletion, closeCompletion, snippet, clearSnippet, nextSnippetField, prevSnippetField, hasNextSnippetField, hasPrevSnippetField, snippetKeymap, snippetCompletion, completeAnyWord, closeBrackets, deleteBracketPair, closeBracketsKeymap, insertBracket, autocompletion, completionKeymap, completionStatus, currentCompletions, selectedCompletion, selectedCompletionIndex, setSelectedCompletion }; //# sourceMappingURL=chunk-UFI6XSZR.js.map