import { defaultKeymap, history, historyKeymap } from "./chunk-JXETLIGR.js"; import { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from "./chunk-FTVURZJQ.js"; import { bracketMatching, defaultHighlightStyle, foldGutter, foldKeymap, indentOnInput, syntaxHighlighting } from "./chunk-UIRP74HC.js"; import { Decoration, EditorView, GutterMarker, ViewPlugin, WidgetType, activateHover, crelt, crosshairCursor, drawSelection, dropCursor, getPanel, gutter, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, hoverTooltip, keymap, lineNumbers, logException, rectangularSelection, runScopeHandlers, showDialog, showPanel, showTooltip } from "./chunk-M6T3QFJD.js"; import { CharCategory, EditorSelection, EditorState, Facet, Prec, RangeSet, RangeSetBuilder, StateEffect, StateField, codePointAt, codePointSize, combineConfig, findClusterBreak, fromCodePoint } from "./chunk-4MUKC4ON.js"; // node_modules/@codemirror/search/dist/index.js var basicNormalize = typeof String.prototype.normalize == "function" ? (x) => x.normalize("NFKD") : (x) => x; var SearchCursor = class { /** Create a text cursor. The query is the search string, `from` to `to` provides the region to search. When `normalize` is given, it will be called, on both the query string and the content it is matched against, before comparing. You can, for example, create a case-insensitive search by passing `s => s.toLowerCase()`. Text is always normalized with [`.normalize("NFKD")`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) (when supported). */ constructor(text, query, from = 0, to = text.length, normalize, test) { this.test = test; this.value = { from: 0, to: 0, precise: false }; this.done = false; this.matches = []; this.buffer = ""; this.bufferPos = 0; this.iter = text.iterRange(from, to); this.bufferStart = from; this.normalize = normalize ? (x) => normalize(basicNormalize(x)) : basicNormalize; this.query = this.normalize(query); } peek() { if (this.bufferPos == this.buffer.length) { this.bufferStart += this.buffer.length; this.iter.next(); if (this.iter.done) return -1; this.bufferPos = 0; this.buffer = this.iter.value; } return codePointAt(this.buffer, this.bufferPos); } /** Look for the next match. Updates the iterator's [`value`](https://codemirror.net/6/docs/ref/#search.SearchCursor.value) and [`done`](https://codemirror.net/6/docs/ref/#search.SearchCursor.done) properties. Should be called at least once before using the cursor. */ next() { while (this.matches.length) this.matches.pop(); return this.nextOverlapping(); } /** The `next` method will ignore matches that partially overlap a previous match. This method behaves like `next`, but includes such matches. */ nextOverlapping() { for (; ; ) { let next = this.peek(); if (next < 0) { this.done = true; return this; } let str = fromCodePoint(next), start = this.bufferStart + this.bufferPos; this.bufferPos += codePointSize(next); let norm = this.normalize(str); if (norm.length) for (let i = 0, pos = start, posPrecise = true; ; i++) { let code = norm.charCodeAt(i); let match = this.match(code, pos, posPrecise, this.bufferPos + this.bufferStart, i == norm.length - 1); if (match) { this.value = match; return this; } if (i == norm.length - 1) break; if (posPrecise && i < str.length && str.charCodeAt(i) == code) pos++; else posPrecise = false; } } } match(code, pos, posPrecise, end, endPrecise) { let match = null; for (let i = 0; i < this.matches.length; ) { let partial = this.matches[i], keep = false; if (this.query.charCodeAt(partial.index) == code) { if (partial.index == this.query.length - 1) { match = { from: partial.from, to: end, precise: endPrecise && partial.precise }; } else { partial.index++; keep = true; } } if (keep) i++; else this.matches.splice(i, 1); } if (this.query.charCodeAt(0) == code) { if (this.query.length == 1) match = { from: pos, to: end, precise: posPrecise && endPrecise }; else this.matches.push({ from: pos, index: 1, precise: posPrecise }); } if (match && this.test && !this.test(match.from, match.to, this.buffer, this.bufferStart)) match = null; return match; } }; if (typeof Symbol != "undefined") SearchCursor.prototype[Symbol.iterator] = function() { return this; }; var empty = { from: -1, to: -1, match: /.*/.exec(""), precise: true }; var baseFlags = "gm" + (/x/.unicode == null ? "" : "u"); var RegExpCursor = class { /** Create a cursor that will search the given range in the given document. `query` should be the raw pattern (as you'd pass it to `new RegExp`). */ constructor(text, query, options, from = 0, to = text.length) { this.text = text; this.to = to; this.curLine = ""; this.done = false; this.value = empty; if (/\\[sWDnr]|\n|\r|\[\^/.test(query)) return new MultilineRegExpCursor(text, query, options, from, to); this.re = new RegExp(query, baseFlags + ((options === null || options === void 0 ? void 0 : options.ignoreCase) ? "i" : "")); this.test = options === null || options === void 0 ? void 0 : options.test; this.iter = text.iter(); let startLine = text.lineAt(from); this.curLineStart = startLine.from; this.matchPos = toCharEnd(text, from); this.getLine(this.curLineStart); } getLine(skip) { this.iter.next(skip); if (this.iter.lineBreak) { this.curLine = ""; } else { this.curLine = this.iter.value; if (this.curLineStart + this.curLine.length > this.to) this.curLine = this.curLine.slice(0, this.to - this.curLineStart); this.iter.next(); } } nextLine() { this.curLineStart = this.curLineStart + this.curLine.length + 1; if (this.curLineStart > this.to) this.curLine = ""; else this.getLine(0); } /** Move to the next match, if there is one. */ next() { for (let off = this.matchPos - this.curLineStart; ; ) { this.re.lastIndex = off; let match = this.matchPos <= this.to && this.re.exec(this.curLine); if (match) { let from = this.curLineStart + match.index, to = from + match[0].length; this.matchPos = toCharEnd(this.text, to + (from == to ? 1 : 0)); if (from == this.curLineStart + this.curLine.length) this.nextLine(); if ((from < to || from > this.value.to) && (!this.test || this.test(from, to, match))) { this.value = { from, to, precise: true, match }; return this; } off = this.matchPos - this.curLineStart; } else if (this.curLineStart + this.curLine.length < this.to) { this.nextLine(); off = 0; } else { this.done = true; return this; } } } }; var flattened = /* @__PURE__ */ new WeakMap(); var FlattenedDoc = class _FlattenedDoc { constructor(from, text) { this.from = from; this.text = text; } get to() { return this.from + this.text.length; } static get(doc, from, to) { let cached = flattened.get(doc); if (!cached || cached.from >= to || cached.to <= from) { let flat = new _FlattenedDoc(from, doc.sliceString(from, to)); flattened.set(doc, flat); return flat; } if (cached.from == from && cached.to == to) return cached; let { text, from: cachedFrom } = cached; if (cachedFrom > from) { text = doc.sliceString(from, cachedFrom) + text; cachedFrom = from; } if (cached.to < to) text += doc.sliceString(cached.to, to); flattened.set(doc, new _FlattenedDoc(cachedFrom, text)); return new _FlattenedDoc(from, text.slice(from - cachedFrom, to - cachedFrom)); } }; var MultilineRegExpCursor = class { constructor(text, query, options, from, to) { this.text = text; this.to = to; this.done = false; this.value = empty; this.matchPos = toCharEnd(text, from); this.re = new RegExp(query, baseFlags + ((options === null || options === void 0 ? void 0 : options.ignoreCase) ? "i" : "")); this.test = options === null || options === void 0 ? void 0 : options.test; this.flat = FlattenedDoc.get(text, from, this.chunkEnd( from + 5e3 /* Chunk.Base */ )); } chunkEnd(pos) { return pos >= this.to ? this.to : this.text.lineAt(pos).to; } next() { for (; ; ) { let off = this.re.lastIndex = this.matchPos - this.flat.from; let match = this.re.exec(this.flat.text); if (match && !match[0] && match.index == off) { this.re.lastIndex = off + 1; match = this.re.exec(this.flat.text); } if (match) { let from = this.flat.from + match.index, to = from + match[0].length; if ((this.flat.to >= this.to || match.index + match[0].length <= this.flat.text.length - 10) && (!this.test || this.test(from, to, match))) { this.value = { from, to, precise: true, match }; this.matchPos = toCharEnd(this.text, to + (from == to ? 1 : 0)); return this; } } if (this.flat.to == this.to) { this.done = true; return this; } this.flat = FlattenedDoc.get(this.text, this.flat.from, this.chunkEnd(this.flat.from + this.flat.text.length * 2)); } } }; if (typeof Symbol != "undefined") { RegExpCursor.prototype[Symbol.iterator] = MultilineRegExpCursor.prototype[Symbol.iterator] = function() { return this; }; } function validRegExp(source) { try { new RegExp(source, baseFlags); return true; } catch (_a) { return false; } } function toCharEnd(text, pos) { if (pos >= text.length) return pos; let line = text.lineAt(pos), next; while (pos < line.to && (next = line.text.charCodeAt(pos - line.from)) >= 56320 && next < 57344) pos++; return pos; } var gotoLine = (view) => { let { state } = view; let line = String(state.doc.lineAt(view.state.selection.main.head).number); let { close, result } = showDialog(view, { label: state.phrase("Go to line"), input: { type: "text", name: "line", value: line }, focus: true, submitLabel: state.phrase("go") }); result.then((form) => { let match = form && /^([+-])?(\d+)?(:\d+)?(%)?$/.exec(form.elements["line"].value); if (!match) { view.dispatch({ effects: close }); return; } let startLine = state.doc.lineAt(state.selection.main.head); let [, sign, ln, cl, percent] = match; let col = cl ? +cl.slice(1) : 0; let line2 = ln ? +ln : startLine.number; if (ln && percent) { let pc = line2 / 100; if (sign) pc = pc * (sign == "-" ? -1 : 1) + startLine.number / state.doc.lines; line2 = Math.round(state.doc.lines * pc); } else if (ln && sign) { line2 = line2 * (sign == "-" ? -1 : 1) + startLine.number; } let docLine = state.doc.line(Math.max(1, Math.min(state.doc.lines, line2))); let selection = EditorSelection.cursor(docLine.from + Math.max(0, Math.min(col, docLine.length))); view.dispatch({ effects: [close, EditorView.scrollIntoView(selection.from, { y: "center" })], selection }); }); return true; }; var defaultHighlightOptions = { highlightWordAroundCursor: false, minSelectionLength: 1, maxMatches: 100, wholeWords: false }; var highlightConfig = Facet.define({ combine(options) { return combineConfig(options, defaultHighlightOptions, { highlightWordAroundCursor: (a, b) => a || b, minSelectionLength: Math.min, maxMatches: Math.min }); } }); function highlightSelectionMatches(options) { let ext = [defaultTheme, matchHighlighter]; if (options) ext.push(highlightConfig.of(options)); return ext; } var matchDeco = Decoration.mark({ class: "cm-selectionMatch" }); var mainMatchDeco = Decoration.mark({ class: "cm-selectionMatch cm-selectionMatch-main" }); function insideWordBoundaries(check, state, from, to) { return (from == 0 || check(state.sliceDoc(from - 1, from)) != CharCategory.Word) && (to == state.doc.length || check(state.sliceDoc(to, to + 1)) != CharCategory.Word); } function insideWord(check, state, from, to) { return check(state.sliceDoc(from, from + 1)) == CharCategory.Word && check(state.sliceDoc(to - 1, to)) == CharCategory.Word; } var matchHighlighter = ViewPlugin.fromClass(class { constructor(view) { this.decorations = this.getDeco(view); } update(update) { if (update.selectionSet || update.docChanged || update.viewportChanged) this.decorations = this.getDeco(update.view); } getDeco(view) { let conf = view.state.facet(highlightConfig); let { state } = view, sel = state.selection; if (sel.ranges.length > 1) return Decoration.none; let range = sel.main, query, check = null; if (range.empty) { if (!conf.highlightWordAroundCursor) return Decoration.none; let word = state.wordAt(range.head); if (!word) return Decoration.none; check = state.charCategorizer(range.head); query = state.sliceDoc(word.from, word.to); } else { let len = range.to - range.from; if (len < conf.minSelectionLength || len > 200) return Decoration.none; if (conf.wholeWords) { query = state.sliceDoc(range.from, range.to); check = state.charCategorizer(range.head); if (!(insideWordBoundaries(check, state, range.from, range.to) && insideWord(check, state, range.from, range.to))) return Decoration.none; } else { query = state.sliceDoc(range.from, range.to); if (!query) return Decoration.none; } } let deco = []; for (let part of view.visibleRanges) { let cursor = new SearchCursor(state.doc, query, part.from, part.to); while (!cursor.next().done) { let { from, to } = cursor.value; if (!check || insideWordBoundaries(check, state, from, to)) { if (range.empty && from <= range.from && to >= range.to) deco.push(mainMatchDeco.range(from, to)); else if (from >= range.to || to <= range.from) deco.push(matchDeco.range(from, to)); if (deco.length > conf.maxMatches) return Decoration.none; } } } return Decoration.set(deco); } }, { decorations: (v) => v.decorations }); var defaultTheme = EditorView.baseTheme({ ".cm-selectionMatch": { backgroundColor: "#99ff7780" }, ".cm-searchMatch .cm-selectionMatch": { backgroundColor: "transparent" } }); var selectWord = ({ state, dispatch }) => { let { selection } = state; let newSel = EditorSelection.create(selection.ranges.map((range) => state.wordAt(range.head) || EditorSelection.cursor(range.head)), selection.mainIndex); if (newSel.eq(selection)) return false; dispatch(state.update({ selection: newSel })); return true; }; function findNextOccurrence(state, query) { let { main, ranges } = state.selection; let word = state.wordAt(main.head), fullWord = word && word.from == main.from && word.to == main.to; for (let cycled = false, cursor = new SearchCursor(state.doc, query, ranges[ranges.length - 1].to); ; ) { cursor.next(); if (cursor.done) { if (cycled) return null; cursor = new SearchCursor(state.doc, query, 0, Math.max(0, ranges[ranges.length - 1].from - 1)); cycled = true; } else { if (cycled && ranges.some((r) => r.from == cursor.value.from)) continue; if (fullWord) { let word2 = state.wordAt(cursor.value.from); if (!word2 || word2.from != cursor.value.from || word2.to != cursor.value.to) continue; } return cursor.value; } } } var selectNextOccurrence = ({ state, dispatch }) => { let { ranges } = state.selection; if (ranges.some((sel) => sel.from === sel.to)) return selectWord({ state, dispatch }); let searchedText = state.sliceDoc(ranges[0].from, ranges[0].to); if (state.selection.ranges.some((r) => state.sliceDoc(r.from, r.to) != searchedText)) return false; let range = findNextOccurrence(state, searchedText); if (!range) return false; dispatch(state.update({ selection: state.selection.addRange(EditorSelection.range(range.from, range.to), false), effects: EditorView.scrollIntoView(range.to) })); return true; }; var searchConfigFacet = Facet.define({ combine(configs) { return combineConfig(configs, { top: false, caseSensitive: false, literal: false, regexp: false, wholeWord: false, createPanel: (view) => new SearchPanel(view), scrollToMatch: (range) => EditorView.scrollIntoView(range) }); } }); var SearchQuery = class { /** Create a query object. */ constructor(config) { this.search = config.search; this.caseSensitive = !!config.caseSensitive; this.literal = !!config.literal; this.regexp = !!config.regexp; this.replace = config.replace || ""; this.valid = !!this.search && (!this.regexp || validRegExp(this.search)); this.unquoted = this.unquote(this.search); this.wholeWord = !!config.wholeWord; this.test = config.test; } /** @internal */ unquote(text) { return this.literal ? text : text.replace(/\\([nrt\\])/g, (_, ch) => ch == "n" ? "\n" : ch == "r" ? "\r" : ch == "t" ? " " : "\\"); } /** Compare this query to another query. */ eq(other) { return this.search == other.search && this.replace == other.replace && this.caseSensitive == other.caseSensitive && this.regexp == other.regexp && this.wholeWord == other.wholeWord && this.test == other.test; } /** @internal */ create() { return this.regexp ? new RegExpQuery(this) : new StringQuery(this); } /** Get a search cursor for this query, searching through the given range in the given state. */ getCursor(state, from = 0, to) { let st = state.doc ? state : EditorState.create({ doc: state }); if (to == null) to = st.doc.length; return this.regexp ? regexpCursor(this, st, from, to) : stringCursor(this, st, from, to); } }; var QueryType = class { constructor(spec) { this.spec = spec; } }; function wrapStringTest(test, state, inner) { return (from, to, buffer, bufferPos) => { if (inner && !inner(from, to, buffer, bufferPos)) return false; let match = from >= bufferPos && to <= bufferPos + buffer.length ? buffer.slice(from - bufferPos, to - bufferPos) : state.doc.sliceString(from, to); return test(match, state, from, to); }; } function stringCursor(spec, state, from, to) { let test; if (spec.wholeWord) test = stringWordTest(state.doc, state.charCategorizer(state.selection.main.head)); if (spec.test) test = wrapStringTest(spec.test, state, test); return new SearchCursor(state.doc, spec.unquoted, from, to, spec.caseSensitive ? void 0 : (x) => x.toLowerCase(), test); } function stringWordTest(doc, categorizer) { return (from, to, buf, bufPos) => { if (bufPos > from || bufPos + buf.length < to) { bufPos = Math.max(0, from - 2); buf = doc.sliceString(bufPos, Math.min(doc.length, to + 2)); } return (categorizer(charBefore(buf, from - bufPos)) != CharCategory.Word || categorizer(charAfter(buf, from - bufPos)) != CharCategory.Word) && (categorizer(charAfter(buf, to - bufPos)) != CharCategory.Word || categorizer(charBefore(buf, to - bufPos)) != CharCategory.Word); }; } var StringQuery = class extends QueryType { constructor(spec) { super(spec); } nextMatch(state, curFrom, curTo) { let cursor = stringCursor(this.spec, state, curTo, state.doc.length).nextOverlapping(); if (cursor.done) { let end = Math.min(state.doc.length, curFrom + this.spec.unquoted.length); cursor = stringCursor(this.spec, state, 0, end).nextOverlapping(); } return cursor.done || cursor.value.from == curFrom && cursor.value.to == curTo ? null : cursor.value; } // Searching in reverse is, rather than implementing an inverted search // cursor, done by scanning chunk after chunk forward. prevMatchInRange(state, from, to) { for (let pos = to; ; ) { let start = Math.max(from, pos - 1e4 - this.spec.unquoted.length); let cursor = stringCursor(this.spec, state, start, pos), range = null; while (!cursor.nextOverlapping().done) range = cursor.value; if (range) return range; if (start == from) return null; pos -= 1e4; } } prevMatch(state, curFrom, curTo) { let found = this.prevMatchInRange(state, 0, curFrom); if (!found) found = this.prevMatchInRange(state, Math.max(0, curTo - this.spec.unquoted.length), state.doc.length); return found && (found.from != curFrom || found.to != curTo) ? found : null; } getReplacement(_result) { return this.spec.unquote(this.spec.replace); } matchAll(state, limit) { let cursor = stringCursor(this.spec, state, 0, state.doc.length), ranges = []; while (!cursor.next().done) { if (ranges.length >= limit) return null; ranges.push(cursor.value); } return ranges; } highlight(state, from, to, add) { let cursor = stringCursor(this.spec, state, Math.max(0, from - this.spec.unquoted.length), Math.min(to + this.spec.unquoted.length, state.doc.length)); while (!cursor.next().done) add(cursor.value.from, cursor.value.to); } }; function wrapRegexpTest(test, state, inner) { return (from, to, match) => { return (!inner || inner(from, to, match)) && test(match[0], state, from, to); }; } function regexpCursor(spec, state, from, to) { let test; if (spec.wholeWord) test = regexpWordTest(state.charCategorizer(state.selection.main.head)); if (spec.test) test = wrapRegexpTest(spec.test, state, test); return new RegExpCursor(state.doc, spec.search, { ignoreCase: !spec.caseSensitive, test }, from, to); } function charBefore(str, index) { return str.slice(findClusterBreak(str, index, false), index); } function charAfter(str, index) { return str.slice(index, findClusterBreak(str, index)); } function regexpWordTest(categorizer) { return (_from, _to, match) => !match[0].length || (categorizer(charBefore(match.input, match.index)) != CharCategory.Word || categorizer(charAfter(match.input, match.index)) != CharCategory.Word) && (categorizer(charAfter(match.input, match.index + match[0].length)) != CharCategory.Word || categorizer(charBefore(match.input, match.index + match[0].length)) != CharCategory.Word); } var RegExpQuery = class extends QueryType { nextMatch(state, curFrom, curTo) { let cursor = regexpCursor(this.spec, state, curTo, state.doc.length).next(); if (cursor.done) cursor = regexpCursor(this.spec, state, 0, curFrom).next(); return cursor.done ? null : cursor.value; } prevMatchInRange(state, from, to) { for (let size = 1; ; size++) { let start = Math.max( from, to - size * 1e4 /* FindPrev.ChunkSize */ ); let cursor = regexpCursor(this.spec, state, start, to), range = null; while (!cursor.next().done) range = cursor.value; if (range && (start == from || range.from > start + 10)) return range; if (start == from) return null; } } prevMatch(state, curFrom, curTo) { return this.prevMatchInRange(state, 0, curFrom) || this.prevMatchInRange(state, curTo, state.doc.length); } getReplacement(result) { return this.spec.unquote(this.spec.replace).replace(/\$([$&]|\d+)/g, (m, i) => { if (i == "&") return result.match[0]; if (i == "$") return "$"; for (let l = i.length; l > 0; l--) { let n = +i.slice(0, l); if (n > 0 && n < result.match.length) return result.match[n] + i.slice(l); } return m; }); } matchAll(state, limit) { let cursor = regexpCursor(this.spec, state, 0, state.doc.length), ranges = []; while (!cursor.next().done) { if (ranges.length >= limit) return null; ranges.push(cursor.value); } return ranges; } highlight(state, from, to, add) { let cursor = regexpCursor(this.spec, state, Math.max( 0, from - 250 /* RegExp.HighlightMargin */ ), Math.min(to + 250, state.doc.length)); while (!cursor.next().done) add(cursor.value.from, cursor.value.to); } }; var setSearchQuery = StateEffect.define(); var togglePanel = StateEffect.define(); var searchState = StateField.define({ create(state) { return new SearchState(defaultQuery(state).create(), null); }, update(value, tr) { for (let effect of tr.effects) { if (effect.is(setSearchQuery)) value = new SearchState(effect.value.create(), value.panel); else if (effect.is(togglePanel)) value = new SearchState(value.query, effect.value ? createSearchPanel : null); } return value; }, provide: (f) => showPanel.from(f, (val) => val.panel) }); var SearchState = class { constructor(query, panel) { this.query = query; this.panel = panel; } }; var matchMark = Decoration.mark({ class: "cm-searchMatch" }); var selectedMatchMark = Decoration.mark({ class: "cm-searchMatch cm-searchMatch-selected" }); var searchHighlighter = ViewPlugin.fromClass(class { constructor(view) { this.view = view; this.decorations = this.highlight(view.state.field(searchState)); } update(update) { let state = update.state.field(searchState); if (state != update.startState.field(searchState) || update.docChanged || update.selectionSet || update.viewportChanged) this.decorations = this.highlight(state); } highlight({ query, panel }) { if (!panel || !query.spec.valid) return Decoration.none; let { view } = this; let builder = new RangeSetBuilder(); for (let i = 0, ranges = view.visibleRanges, l = ranges.length; i < l; i++) { let { from, to } = ranges[i]; while (i < l - 1 && to > ranges[i + 1].from - 2 * 250) to = ranges[++i].to; query.highlight(view.state, from, to, (from2, to2) => { let selected = view.state.selection.ranges.some((r) => r.from == from2 && r.to == to2); builder.add(from2, to2, selected ? selectedMatchMark : matchMark); }); } return builder.finish(); } }, { decorations: (v) => v.decorations }); function searchCommand(f) { return (view) => { let state = view.state.field(searchState, false); return state && state.query.spec.valid ? f(view, state) : openSearchPanel(view); }; } var findNext = searchCommand((view, { query }) => { let { to } = view.state.selection.main; let next = query.nextMatch(view.state, to, to); if (!next) return false; let selection = EditorSelection.single(next.from, next.to); let config = view.state.facet(searchConfigFacet); view.dispatch({ selection, effects: [announceMatch(view, next), config.scrollToMatch(selection.main, view)], userEvent: "select.search" }); selectSearchInput(view); return true; }); var findPrevious = searchCommand((view, { query }) => { let { state } = view, { from } = state.selection.main; let prev = query.prevMatch(state, from, from); if (!prev) return false; let selection = EditorSelection.single(prev.from, prev.to); let config = view.state.facet(searchConfigFacet); view.dispatch({ selection, effects: [announceMatch(view, prev), config.scrollToMatch(selection.main, view)], userEvent: "select.search" }); selectSearchInput(view); return true; }); var selectMatches = searchCommand((view, { query }) => { let ranges = query.matchAll(view.state, 1e3); if (!ranges || !ranges.length) return false; view.dispatch({ selection: EditorSelection.create(ranges.map((r) => EditorSelection.range(r.from, r.to))), userEvent: "select.search.matches" }); return true; }); var selectSelectionMatches = ({ state, dispatch }) => { let sel = state.selection; if (sel.ranges.length > 1 || sel.main.empty) return false; let { from, to } = sel.main; let ranges = [], main = 0; for (let cur = new SearchCursor(state.doc, state.sliceDoc(from, to)); !cur.next().done; ) { if (ranges.length > 1e3) return false; if (cur.value.from == from) main = ranges.length; ranges.push(EditorSelection.range(cur.value.from, cur.value.to)); } dispatch(state.update({ selection: EditorSelection.create(ranges, main), userEvent: "select.search.matches" })); return true; }; var replaceNext = searchCommand((view, { query }) => { let { state } = view, { from, to } = state.selection.main; if (state.readOnly) return false; let match = query.nextMatch(state, from, from); if (!match) return false; let next = match; let changes = [], selection, replacement; let effects = []; if (!next.precise) { next = query.nextMatch(state, next.from, next.to); } else if (next.from == from && next.to == to) { replacement = state.toText(query.getReplacement(next)); changes.push({ from: next.from, to: next.to, insert: replacement }); effects.push(EditorView.announce.of(state.phrase("replaced match on line $", state.doc.lineAt(from).number) + ".")); } let changeSet = view.state.changes(changes); if (next) { selection = EditorSelection.single(next.from, next.to).map(changeSet); effects.push(announceMatch(view, next)); effects.push(state.facet(searchConfigFacet).scrollToMatch(selection.main, view)); } view.dispatch({ changes: changeSet, selection, effects, userEvent: "input.replace" }); return true; }); var replaceAll = searchCommand((view, { query }) => { if (view.state.readOnly) return false; let changes = []; for (let match of query.matchAll(view.state, 1e9)) { let { from, to, precise } = match; if (precise) changes.push({ from, to, insert: query.getReplacement(match) }); } if (!changes.length) return false; let announceText = view.state.phrase("replaced $ matches", changes.length) + "."; view.dispatch({ changes, effects: EditorView.announce.of(announceText), userEvent: "input.replace.all" }); return true; }); function createSearchPanel(view) { return view.state.facet(searchConfigFacet).createPanel(view); } function defaultQuery(state, fallback) { var _a, _b, _c, _d, _e; let sel = state.selection.main; let selText = sel.empty || sel.to > sel.from + 100 ? "" : state.sliceDoc(sel.from, sel.to); if (fallback && !selText) return fallback; let config = state.facet(searchConfigFacet); return new SearchQuery({ search: ((_a = fallback === null || fallback === void 0 ? void 0 : fallback.literal) !== null && _a !== void 0 ? _a : config.literal) ? selText : selText.replace(/\n/g, "\\n"), caseSensitive: (_b = fallback === null || fallback === void 0 ? void 0 : fallback.caseSensitive) !== null && _b !== void 0 ? _b : config.caseSensitive, literal: (_c = fallback === null || fallback === void 0 ? void 0 : fallback.literal) !== null && _c !== void 0 ? _c : config.literal, regexp: (_d = fallback === null || fallback === void 0 ? void 0 : fallback.regexp) !== null && _d !== void 0 ? _d : config.regexp, wholeWord: (_e = fallback === null || fallback === void 0 ? void 0 : fallback.wholeWord) !== null && _e !== void 0 ? _e : config.wholeWord }); } function getSearchInput(view) { let panel = getPanel(view, createSearchPanel); return panel && panel.dom.querySelector("[main-field]"); } function selectSearchInput(view) { let input = getSearchInput(view); if (input && input == view.root.activeElement) input.select(); } var openSearchPanel = (view) => { let state = view.state.field(searchState, false); if (state && state.panel) { let searchInput = getSearchInput(view); if (searchInput && searchInput != view.root.activeElement) { let query = defaultQuery(view.state, state.query.spec); if (query.valid) view.dispatch({ effects: setSearchQuery.of(query) }); searchInput.focus(); searchInput.select(); } } else { view.dispatch({ effects: [ togglePanel.of(true), state ? setSearchQuery.of(defaultQuery(view.state, state.query.spec)) : StateEffect.appendConfig.of(searchExtensions) ] }); } return true; }; var closeSearchPanel = (view) => { let state = view.state.field(searchState, false); if (!state || !state.panel) return false; let panel = getPanel(view, createSearchPanel); if (panel && panel.dom.contains(view.root.activeElement)) view.focus(); view.dispatch({ effects: togglePanel.of(false) }); return true; }; var searchKeymap = [ { key: "Mod-f", run: openSearchPanel, scope: "editor search-panel" }, { key: "F3", run: findNext, shift: findPrevious, scope: "editor search-panel", preventDefault: true }, { key: "Mod-g", run: findNext, shift: findPrevious, scope: "editor search-panel", preventDefault: true }, { key: "Escape", run: closeSearchPanel, scope: "editor search-panel" }, { key: "Mod-Shift-l", run: selectSelectionMatches }, { key: "Mod-Alt-g", run: gotoLine }, { key: "Mod-d", run: selectNextOccurrence, preventDefault: true } ]; var SearchPanel = class { constructor(view) { this.view = view; let query = this.query = view.state.field(searchState).query.spec; this.commit = this.commit.bind(this); this.searchField = crelt("input", { value: query.search, placeholder: phrase(view, "Find"), "aria-label": phrase(view, "Find"), class: "cm-textfield", name: "search", form: "", "main-field": "true", onchange: this.commit, onkeyup: this.commit }); this.replaceField = crelt("input", { value: query.replace, placeholder: phrase(view, "Replace"), "aria-label": phrase(view, "Replace"), class: "cm-textfield", name: "replace", form: "", onchange: this.commit, onkeyup: this.commit }); this.caseField = crelt("input", { type: "checkbox", name: "case", form: "", checked: query.caseSensitive, onchange: this.commit }); this.reField = crelt("input", { type: "checkbox", name: "re", form: "", checked: query.regexp, onchange: this.commit }); this.wordField = crelt("input", { type: "checkbox", name: "word", form: "", checked: query.wholeWord, onchange: this.commit }); function button(name, onclick, content) { return crelt("button", { class: "cm-button", name, onclick, type: "button" }, content); } this.dom = crelt("div", { onkeydown: (e) => this.keydown(e), class: "cm-search" }, [ this.searchField, button("next", () => findNext(view), [phrase(view, "next")]), button("prev", () => findPrevious(view), [phrase(view, "previous")]), button("select", () => selectMatches(view), [phrase(view, "all")]), crelt("label", null, [this.caseField, phrase(view, "match case")]), crelt("label", null, [this.reField, phrase(view, "regexp")]), crelt("label", null, [this.wordField, phrase(view, "by word")]), ...view.state.readOnly ? [] : [ crelt("br"), this.replaceField, button("replace", () => replaceNext(view), [phrase(view, "replace")]), button("replaceAll", () => replaceAll(view), [phrase(view, "replace all")]) ], crelt("button", { name: "close", onclick: () => closeSearchPanel(view), "aria-label": phrase(view, "close"), type: "button" }, ["×"]) ]); } commit() { let query = new SearchQuery({ search: this.searchField.value, caseSensitive: this.caseField.checked, regexp: this.reField.checked, wholeWord: this.wordField.checked, replace: this.replaceField.value }); if (!query.eq(this.query)) { this.query = query; this.view.dispatch({ effects: setSearchQuery.of(query) }); } } keydown(e) { if (runScopeHandlers(this.view, e, "search-panel")) { e.preventDefault(); } else if (e.keyCode == 13 && e.target == this.searchField) { e.preventDefault(); (e.shiftKey ? findPrevious : findNext)(this.view); } else if (e.keyCode == 13 && e.target == this.replaceField) { e.preventDefault(); replaceNext(this.view); } } update(update) { for (let tr of update.transactions) for (let effect of tr.effects) { if (effect.is(setSearchQuery) && !effect.value.eq(this.query)) this.setQuery(effect.value); } } setQuery(query) { this.query = query; this.searchField.value = query.search; this.replaceField.value = query.replace; this.caseField.checked = query.caseSensitive; this.reField.checked = query.regexp; this.wordField.checked = query.wholeWord; } mount() { this.searchField.select(); } get pos() { return 80; } get top() { return this.view.state.facet(searchConfigFacet).top; } }; function phrase(view, phrase2) { return view.state.phrase(phrase2); } var AnnounceMargin = 30; var Break = /[\s\.,:;?!]/; function announceMatch(view, { from, to }) { let line = view.state.doc.lineAt(from), lineEnd = view.state.doc.lineAt(to).to; let start = Math.max(line.from, from - AnnounceMargin), end = Math.min(lineEnd, to + AnnounceMargin); let text = view.state.sliceDoc(start, end); if (start != line.from) { for (let i = 0; i < AnnounceMargin; i++) if (!Break.test(text[i + 1]) && Break.test(text[i])) { text = text.slice(i); break; } } if (end != lineEnd) { for (let i = text.length - 1; i > text.length - AnnounceMargin; i--) if (!Break.test(text[i - 1]) && Break.test(text[i])) { text = text.slice(0, i); break; } } return EditorView.announce.of(`${view.state.phrase("current match")}. ${text} ${view.state.phrase("on line")} ${line.number}.`); } var baseTheme = EditorView.baseTheme({ ".cm-panel.cm-search": { padding: "2px 6px 4px", position: "relative", "& [name=close]": { position: "absolute", top: "0", right: "4px", backgroundColor: "inherit", border: "none", font: "inherit", padding: 0, margin: 0 }, "& input, & button, & label": { margin: ".2em .6em .2em 0" }, "& input[type=checkbox]": { marginRight: ".2em" }, "& label": { fontSize: "80%", whiteSpace: "pre" } }, "&light .cm-searchMatch": { backgroundColor: "#ffff0054" }, "&dark .cm-searchMatch": { backgroundColor: "#00ffff8a" }, "&light .cm-searchMatch-selected": { backgroundColor: "#ff6a0054" }, "&dark .cm-searchMatch-selected": { backgroundColor: "#ff00ff8a" } }); var searchExtensions = [ searchState, Prec.low(searchHighlighter), baseTheme ]; // node_modules/@codemirror/lint/dist/index.js var SelectedDiagnostic = class { constructor(from, to, diagnostic) { this.from = from; this.to = to; this.diagnostic = diagnostic; } }; var LintState = class _LintState { constructor(diagnostics, panel, selected) { this.diagnostics = diagnostics; this.panel = panel; this.selected = selected; } static init(diagnostics, panel, state) { let diagnosticFilter = state.facet(lintConfig).markerFilter; if (diagnosticFilter) diagnostics = diagnosticFilter(diagnostics, state); let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to); let deco = new RangeSetBuilder(), active = [], pos = 0; let scan = state.doc.iter(), scanPos = 0, docLen = state.doc.length; for (let i = 0; ; ) { let next = i == sorted.length ? null : sorted[i]; if (!next && !active.length) break; let from, to; if (active.length) { from = pos; to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8); } else { from = next.from; if (from > docLen) break; to = next.to; active.push(next); i++; } while (i < sorted.length) { let next2 = sorted[i]; if (next2.from == from && (next2.to > next2.from || next2.to == from)) { active.push(next2); i++; to = Math.min(next2.to, to); } else { to = Math.min(next2.from, to); break; } } to = Math.min(to, docLen); let widget = false; if (active.some((d) => d.from == from && (d.to == to || to == docLen))) { widget = from == to; if (!widget && to - from < 10) { let behind = from - (scanPos + scan.value.length); if (behind > 0) { scan.next(behind); scanPos = from; } for (let check = from; ; ) { if (check >= to) { widget = true; break; } if (!scan.lineBreak && scanPos + scan.value.length > check) break; check = scanPos + scan.value.length; scanPos += scan.value.length; scan.next(); } } } let sev = maxSeverity(active); if (widget) { deco.add(from, from, Decoration.widget({ widget: new DiagnosticWidget(sev), diagnostics: active.slice() })); } else { let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, ""); deco.add(from, to, Decoration.mark({ class: "cm-lintRange cm-lintRange-" + sev + markClass, diagnostics: active.slice(), inclusiveEnd: active.some((a) => a.to > to) })); } pos = to; if (pos == docLen) break; for (let i2 = 0; i2 < active.length; i2++) if (active[i2].to <= pos) active.splice(i2--, 1); } let set = deco.finish(); return new _LintState(set, panel, findDiagnostic(set)); } }; function findDiagnostic(diagnostics, diagnostic = null, after = 0) { let found = null; diagnostics.between(after, 1e9, (from, to, { spec }) => { if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0) return; if (!found) found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]); else if (spec.diagnostics.indexOf(found.diagnostic) < 0) return false; else found = new SelectedDiagnostic(found.from, to, found.diagnostic); }); return found; } function hideTooltip(tr, tooltip) { let from = tooltip.pos, to = tooltip.end || from; let result = tr.state.facet(lintConfig).hideOn(tr, from, to); if (result != null) return result; let line = tr.startState.doc.lineAt(tooltip.pos); return !!(tr.effects.some((e) => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, Math.max(line.to, to))); } function maybeEnableLint(state, effects) { return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of(lintExtensions)); } function setDiagnostics(state, diagnostics) { return { effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)]) }; } var setDiagnosticsEffect = StateEffect.define(); var togglePanel2 = StateEffect.define(); var movePanelSelection = StateEffect.define(); var lintState = StateField.define({ create() { return new LintState(Decoration.none, null, null); }, update(value, tr) { if (tr.docChanged && value.diagnostics.size) { let mapped = value.diagnostics.map(tr.changes), selected = null, panel = value.panel; if (value.selected) { let selPos = tr.changes.mapPos(value.selected.from, 1); selected = findDiagnostic(mapped, value.selected.diagnostic, selPos) || findDiagnostic(mapped, null, selPos); } if (!mapped.size && panel && tr.state.facet(lintConfig).autoPanel) panel = null; value = new LintState(mapped, panel, selected); } for (let effect of tr.effects) { if (effect.is(setDiagnosticsEffect)) { let panel = !tr.state.facet(lintConfig).autoPanel ? value.panel : effect.value.length ? LintPanel.open : null; value = LintState.init(effect.value, panel, tr.state); } else if (effect.is(togglePanel2)) { value = new LintState(value.diagnostics, effect.value ? LintPanel.open : null, value.selected); } else if (effect.is(movePanelSelection)) { value = new LintState(value.diagnostics, value.panel, effect.value); } } return value; }, provide: (f) => [ showPanel.from(f, (val) => val.panel), EditorView.decorations.from(f, (s) => s.diagnostics) ] }); var activeMark = Decoration.mark({ class: "cm-lintRange cm-lintRange-active" }); function lintTooltip(view, pos, side) { let { diagnostics } = view.state.field(lintState); let found, start = -1, end = -1; diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => { if (pos >= from && pos <= to && (from == to || (pos > from || side > 0) && (pos < to || side < 0))) { found = spec.diagnostics; start = from; end = to; return false; } }); let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter; if (found && diagnosticFilter) found = diagnosticFilter(found, view.state); if (!found) return null; return { pos: start, end, above: view.state.doc.lineAt(start).to < end, create() { return { dom: diagnosticsTooltip(view, found) }; } }; } function diagnosticsTooltip(view, diagnostics) { return crelt("ul", { class: "cm-tooltip-lint" }, diagnostics.map((d) => renderDiagnostic(view, d, false))); } var openLintPanel = (view) => { let field = view.state.field(lintState, false); if (!field || !field.panel) view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel2.of(true)]) }); let panel = getPanel(view, LintPanel.open); if (panel) panel.dom.querySelector(".cm-panel-lint ul").focus(); return true; }; var closeLintPanel = (view) => { let field = view.state.field(lintState, false); if (!field || !field.panel) return false; view.dispatch({ effects: togglePanel2.of(false) }); return true; }; var nextDiagnostic = (view) => { let field = view.state.field(lintState, false); if (!field) return false; let sel = view.state.selection.main, next = findDiagnostic(field.diagnostics, null, sel.to + 1); if (!next) { next = findDiagnostic(field.diagnostics, null, 0); if (!next || next.from == sel.from && next.to == sel.to) return false; } view.dispatch({ selection: { anchor: next.from, head: next.to }, scrollIntoView: true }); activateHover(view, next.from, 1, { tooltip: lintHover, until: (tr) => tr.docChanged || tr.newSelection.main.head < next.from || tr.newSelection.main.head > next.to }); return true; }; var lintKeymap = [ { key: "Mod-Shift-m", run: openLintPanel, preventDefault: true }, { key: "F8", run: nextDiagnostic } ]; var lintPlugin = ViewPlugin.fromClass(class { constructor(view) { this.view = view; this.timeout = -1; this.set = true; let { delay } = view.state.facet(lintConfig); this.lintTime = Date.now() + delay; this.run = this.run.bind(this); this.timeout = setTimeout(this.run, delay); } run() { clearTimeout(this.timeout); let now = Date.now(); if (now < this.lintTime - 10) { this.timeout = setTimeout(this.run, this.lintTime - now); } else { this.set = false; let { state } = this.view, { sources } = state.facet(lintConfig); if (sources.length) batchResults(sources.map((s) => Promise.resolve(s(this.view))), (annotations) => { if (this.view.state.doc == state.doc) this.view.dispatch(setDiagnostics(this.view.state, annotations.reduce((a, b) => a.concat(b)))); }, (error) => { logException(this.view.state, error); }); } } update(update) { let config = update.state.facet(lintConfig); if (update.docChanged || config != update.startState.facet(lintConfig) || config.needsRefresh && config.needsRefresh(update)) { this.lintTime = Date.now() + config.delay; if (!this.set) { this.set = true; this.timeout = setTimeout(this.run, config.delay); } } } force() { if (this.set) { this.lintTime = Date.now(); this.run(); } } destroy() { clearTimeout(this.timeout); } }); function batchResults(promises, sink, error) { let collected = [], timeout = -1; for (let p of promises) p.then((value) => { collected.push(value); clearTimeout(timeout); if (collected.length == promises.length) sink(collected); else timeout = setTimeout(() => sink(collected), 200); }, error); } var lintConfig = Facet.define({ combine(input) { return { sources: input.map((i) => i.source).filter((x) => x != null), ...combineConfig(input.map((i) => i.config), { delay: 750, markerFilter: null, tooltipFilter: null, needsRefresh: null, hideOn: () => null }, { delay: Math.max, markerFilter: combineFilter, tooltipFilter: combineFilter, needsRefresh: (a, b) => !a ? b : !b ? a : (u) => a(u) || b(u), hideOn: (a, b) => !a ? b : !b ? a : (t, x, y) => a(t, x, y) || b(t, x, y), autoPanel: (a, b) => a || b }) }; } }); function combineFilter(a, b) { return !a ? b : !b ? a : (d, s) => b(a(d, s), s); } function assignKeys(actions) { let assigned = []; if (actions) actions: for (let { name } of actions) { for (let i = 0; i < name.length; i++) { let ch = name[i]; if (/[a-zA-Z]/.test(ch) && !assigned.some((c) => c.toLowerCase() == ch.toLowerCase())) { assigned.push(ch); continue actions; } } assigned.push(""); } return assigned; } function renderDiagnostic(view, diagnostic, inPanel) { var _a; let keys = inPanel ? assignKeys(diagnostic.actions) : []; return crelt("li", { class: "cm-diagnostic cm-diagnostic-" + diagnostic.severity }, crelt("span", { class: "cm-diagnosticText" }, diagnostic.renderMessage ? diagnostic.renderMessage(view) : diagnostic.message), (_a = diagnostic.actions) === null || _a === void 0 ? void 0 : _a.map((action, i) => { let fired = false, click = (e) => { e.preventDefault(); if (fired) return; fired = true; let found = findDiagnostic(view.state.field(lintState).diagnostics, diagnostic); if (found) action.apply(view, found.from, found.to); }; let { name } = action, keyIndex = keys[i] ? name.indexOf(keys[i]) : -1; let nameElt = keyIndex < 0 ? name : [ name.slice(0, keyIndex), crelt("u", name.slice(keyIndex, keyIndex + 1)), name.slice(keyIndex + 1) ]; let markClass = action.markClass ? " " + action.markClass : ""; return crelt("button", { type: "button", class: "cm-diagnosticAction" + markClass, onclick: click, onmousedown: click, "aria-label": ` Action: ${name}${keyIndex < 0 ? "" : ` (access key "${keys[i]})"`}.` }, nameElt); }), diagnostic.source && crelt("div", { class: "cm-diagnosticSource" }, diagnostic.source)); } var DiagnosticWidget = class extends WidgetType { constructor(sev) { super(); this.sev = sev; } eq(other) { return other.sev == this.sev; } toDOM() { return crelt("span", { class: "cm-lintPoint cm-lintPoint-" + this.sev }); } }; var PanelItem = class { constructor(view, diagnostic) { this.diagnostic = diagnostic; this.id = "item_" + Math.floor(Math.random() * 4294967295).toString(16); this.dom = renderDiagnostic(view, diagnostic, true); this.dom.id = this.id; this.dom.setAttribute("role", "option"); } }; var LintPanel = class _LintPanel { constructor(view) { this.view = view; this.items = []; let onkeydown = (event) => { if (event.ctrlKey || event.altKey || event.metaKey) return; if (event.keyCode == 27) { closeLintPanel(this.view); this.view.focus(); } else if (event.keyCode == 38 || event.keyCode == 33) { this.moveSelection((this.selectedIndex - 1 + this.items.length) % this.items.length); } else if (event.keyCode == 40 || event.keyCode == 34) { this.moveSelection((this.selectedIndex + 1) % this.items.length); } else if (event.keyCode == 36) { this.moveSelection(0); } else if (event.keyCode == 35) { this.moveSelection(this.items.length - 1); } else if (event.keyCode == 13) { this.view.focus(); } else if (event.keyCode >= 65 && event.keyCode <= 90 && this.selectedIndex >= 0) { let { diagnostic } = this.items[this.selectedIndex], keys = assignKeys(diagnostic.actions); for (let i = 0; i < keys.length; i++) if (keys[i].toUpperCase().charCodeAt(0) == event.keyCode) { let found = findDiagnostic(this.view.state.field(lintState).diagnostics, diagnostic); if (found) diagnostic.actions[i].apply(view, found.from, found.to); } } else { return; } event.preventDefault(); }; let onclick = (event) => { for (let i = 0; i < this.items.length; i++) { if (this.items[i].dom.contains(event.target)) this.moveSelection(i); } }; this.list = crelt("ul", { tabIndex: 0, role: "listbox", "aria-label": this.view.state.phrase("Diagnostics"), onkeydown, onclick }); this.dom = crelt("div", { class: "cm-panel-lint" }, this.list, crelt("button", { type: "button", name: "close", "aria-label": this.view.state.phrase("close"), onclick: () => closeLintPanel(this.view) }, "×")); this.update(); } get selectedIndex() { let selected = this.view.state.field(lintState).selected; if (!selected) return -1; for (let i = 0; i < this.items.length; i++) if (this.items[i].diagnostic == selected.diagnostic) return i; return -1; } update() { let { diagnostics, selected } = this.view.state.field(lintState); let i = 0, needsSync = false, newSelectedItem = null; let seen = /* @__PURE__ */ new Set(); diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => { for (let diagnostic of spec.diagnostics) { if (seen.has(diagnostic)) continue; seen.add(diagnostic); let found = -1, item; for (let j = i; j < this.items.length; j++) if (this.items[j].diagnostic == diagnostic) { found = j; break; } if (found < 0) { item = new PanelItem(this.view, diagnostic); this.items.splice(i, 0, item); needsSync = true; } else { item = this.items[found]; if (found > i) { this.items.splice(i, found - i); needsSync = true; } } if (selected && item.diagnostic == selected.diagnostic) { if (!item.dom.hasAttribute("aria-selected")) { item.dom.setAttribute("aria-selected", "true"); newSelectedItem = item; } } else if (item.dom.hasAttribute("aria-selected")) { item.dom.removeAttribute("aria-selected"); } i++; } }); while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) { needsSync = true; this.items.pop(); } if (this.items.length == 0) { this.items.push(new PanelItem(this.view, { from: -1, to: -1, severity: "info", message: this.view.state.phrase("No diagnostics") })); needsSync = true; } if (newSelectedItem) { this.list.setAttribute("aria-activedescendant", newSelectedItem.id); this.view.requestMeasure({ key: this, read: () => ({ sel: newSelectedItem.dom.getBoundingClientRect(), panel: this.list.getBoundingClientRect() }), write: ({ sel, panel }) => { let scaleY = panel.height / this.list.offsetHeight; if (sel.top < panel.top) this.list.scrollTop -= (panel.top - sel.top) / scaleY; else if (sel.bottom > panel.bottom) this.list.scrollTop += (sel.bottom - panel.bottom) / scaleY; } }); } else if (this.selectedIndex < 0) { this.list.removeAttribute("aria-activedescendant"); } if (needsSync) this.sync(); } sync() { let domPos = this.list.firstChild; function rm() { let prev = domPos; domPos = prev.nextSibling; prev.remove(); } for (let item of this.items) { if (item.dom.parentNode == this.list) { while (domPos != item.dom) rm(); domPos = item.dom.nextSibling; } else { this.list.insertBefore(item.dom, domPos); } } while (domPos) rm(); } moveSelection(selectedIndex) { if (this.selectedIndex < 0) return; let field = this.view.state.field(lintState); let selection = findDiagnostic(field.diagnostics, this.items[selectedIndex].diagnostic); if (!selection) return; this.view.dispatch({ selection: { anchor: selection.from, head: selection.to }, scrollIntoView: true, effects: movePanelSelection.of(selection) }); } static open(view) { return new _LintPanel(view); } }; function svg(content, attrs = `viewBox="0 0 40 40"`) { return `url('data:image/svg+xml,${encodeURIComponent(content)}')`; } function underline(color) { return svg(``, `width="6" height="3"`); } var baseTheme2 = EditorView.baseTheme({ ".cm-diagnostic": { padding: "3px 6px 3px 8px", marginLeft: "-1px", display: "block", whiteSpace: "pre-wrap" }, ".cm-diagnostic-error": { borderLeft: "5px solid #d11" }, ".cm-diagnostic-warning": { borderLeft: "5px solid orange" }, ".cm-diagnostic-info": { borderLeft: "5px solid #999" }, ".cm-diagnostic-hint": { borderLeft: "5px solid #66d" }, ".cm-diagnosticAction": { font: "inherit", border: "none", padding: "2px 4px", backgroundColor: "#444", color: "white", borderRadius: "3px", marginLeft: "8px", cursor: "pointer" }, ".cm-diagnosticSource": { fontSize: "70%", opacity: 0.7 }, ".cm-lintRange": { backgroundPosition: "left bottom", backgroundRepeat: "repeat-x", paddingBottom: "0.7px" }, ".cm-lintRange-error": { backgroundImage: underline("#f11") }, ".cm-lintRange-warning": { backgroundImage: underline("orange") }, ".cm-lintRange-info": { backgroundImage: underline("#999") }, ".cm-lintRange-hint": { backgroundImage: underline("#66d") }, ".cm-lintRange-active": { backgroundColor: "#ffdd9980" }, ".cm-tooltip-lint": { padding: 0, margin: 0 }, ".cm-lintPoint": { position: "relative", "&:after": { content: '""', position: "absolute", bottom: 0, left: "-2px", borderLeft: "3px solid transparent", borderRight: "3px solid transparent", borderBottom: "4px solid #d11" } }, ".cm-lintPoint-warning": { "&:after": { borderBottomColor: "orange" } }, ".cm-lintPoint-info": { "&:after": { borderBottomColor: "#999" } }, ".cm-lintPoint-hint": { "&:after": { borderBottomColor: "#66d" } }, ".cm-panel.cm-panel-lint": { position: "relative", "& ul": { maxHeight: "100px", overflowY: "auto", "& [aria-selected]": { backgroundColor: "#ddd", "& u": { textDecoration: "underline" } }, "&:focus [aria-selected]": { background_fallback: "#bdf", backgroundColor: "Highlight", color_fallback: "white", color: "HighlightText" }, "& u": { textDecoration: "none" }, padding: 0, margin: 0 }, "& [name=close]": { position: "absolute", top: "0", right: "2px", background: "inherit", border: "none", font: "inherit", padding: 0, margin: 0 } }, "&dark .cm-lintRange-active": { backgroundColor: "#86714a80" }, "&dark .cm-panel.cm-panel-lint ul": { "& [aria-selected]": { backgroundColor: "#2e343e" } } }); function severityWeight(sev) { return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1; } function maxSeverity(diagnostics) { let sev = "hint", weight = 1; for (let d of diagnostics) { let w = severityWeight(d.severity); if (w > weight) { weight = w; sev = d.severity; } } return sev; } var LintGutterMarker = class extends GutterMarker { constructor(diagnostics) { super(); this.diagnostics = diagnostics; this.severity = maxSeverity(diagnostics); } toDOM(view) { let elt = document.createElement("div"); elt.className = "cm-lint-marker cm-lint-marker-" + this.severity; let diagnostics = this.diagnostics; let diagnosticsFilter = view.state.facet(lintGutterConfig).tooltipFilter; if (diagnosticsFilter) diagnostics = diagnosticsFilter(diagnostics, view.state); if (diagnostics.length) elt.onmouseover = () => gutterMarkerMouseOver(view, elt, diagnostics); return elt; } }; function trackHoverOn(view, marker) { let mousemove = (event) => { let rect = marker.getBoundingClientRect(); if (event.clientX > rect.left - 10 && event.clientX < rect.right + 10 && event.clientY > rect.top - 10 && event.clientY < rect.bottom + 10) return; for (let target = event.target; target; target = target.parentNode) { if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint")) return; } window.removeEventListener("mousemove", mousemove); if (view.state.field(lintGutterTooltip)) view.dispatch({ effects: setLintGutterTooltip.of(null) }); }; window.addEventListener("mousemove", mousemove); } function gutterMarkerMouseOver(view, marker, diagnostics) { function hovered() { let line = view.elementAtHeight(marker.getBoundingClientRect().top + 5 - view.documentTop); const linePos = view.coordsAtPos(line.from); if (linePos) { view.dispatch({ effects: setLintGutterTooltip.of({ pos: line.from, above: false, clip: false, create() { return { dom: diagnosticsTooltip(view, diagnostics), getCoords: () => marker.getBoundingClientRect() }; } }) }); } marker.onmouseout = marker.onmousemove = null; trackHoverOn(view, marker); } let { hoverTime } = view.state.facet(lintGutterConfig); let hoverTimeout = setTimeout(hovered, hoverTime); marker.onmouseout = () => { clearTimeout(hoverTimeout); marker.onmouseout = marker.onmousemove = null; }; marker.onmousemove = () => { clearTimeout(hoverTimeout); hoverTimeout = setTimeout(hovered, hoverTime); }; } function markersForDiagnostics(doc, diagnostics) { let byLine = /* @__PURE__ */ Object.create(null); for (let diagnostic of diagnostics) { let line = doc.lineAt(diagnostic.from); (byLine[line.from] || (byLine[line.from] = [])).push(diagnostic); } let markers = []; for (let line in byLine) { markers.push(new LintGutterMarker(byLine[line]).range(+line)); } return RangeSet.of(markers, true); } var lintGutterExtension = gutter({ class: "cm-gutter-lint", markers: (view) => view.state.field(lintGutterMarkers), widgetMarker: (view, widget, block) => { let diagnostics = []; view.state.field(lintGutterMarkers).between(block.from, block.to, (from, to, value) => { if (from > block.from && from < block.to) diagnostics.push(...value.diagnostics); }); return diagnostics.length ? new LintGutterMarker(diagnostics) : null; } }); var lintGutterMarkers = StateField.define({ create() { return RangeSet.empty; }, update(markers, tr) { markers = markers.map(tr.changes); let diagnosticFilter = tr.state.facet(lintGutterConfig).markerFilter; for (let effect of tr.effects) { if (effect.is(setDiagnosticsEffect)) { let diagnostics = effect.value; if (diagnosticFilter) diagnostics = diagnosticFilter(diagnostics || [], tr.state); markers = markersForDiagnostics(tr.state.doc, diagnostics.slice(0)); } } return markers; } }); var setLintGutterTooltip = StateEffect.define(); var lintGutterTooltip = StateField.define({ create() { return null; }, update(tooltip, tr) { if (tooltip && tr.docChanged) tooltip = hideTooltip(tr, tooltip) ? null : { ...tooltip, pos: tr.changes.mapPos(tooltip.pos) }; return tr.effects.reduce((t, e) => e.is(setLintGutterTooltip) ? e.value : t, tooltip); }, provide: (field) => showTooltip.from(field) }); var lintGutterTheme = EditorView.baseTheme({ ".cm-gutter-lint": { width: "1.4em", "& .cm-gutterElement": { padding: ".2em" } }, ".cm-lint-marker": { width: "1em", height: "1em" }, ".cm-lint-marker-info": { content: svg(``) }, ".cm-lint-marker-warning": { content: svg(``) }, ".cm-lint-marker-error": { content: svg(``) } }); var lintHover = hoverTooltip(lintTooltip, { hideOn: hideTooltip }); var lintExtensions = [ lintState, EditorView.decorations.compute([lintState], (state) => { let { selected, panel } = state.field(lintState); return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([ activeMark.range(selected.from, selected.to) ]); }), lintHover, baseTheme2 ]; var lintGutterConfig = Facet.define({ combine(configs) { return combineConfig(configs, { hoverTime: 300, markerFilter: null, tooltipFilter: null }); } }); // node_modules/codemirror/dist/index.js var basicSetup = (() => [ lineNumbers(), highlightActiveLineGutter(), highlightSpecialChars(), history(), foldGutter(), drawSelection(), dropCursor(), EditorState.allowMultipleSelections.of(true), indentOnInput(), syntaxHighlighting(defaultHighlightStyle, { fallback: true }), bracketMatching(), closeBrackets(), autocompletion(), rectangularSelection(), crosshairCursor(), highlightActiveLine(), highlightSelectionMatches(), keymap.of([ ...closeBracketsKeymap, ...defaultKeymap, ...searchKeymap, ...historyKeymap, ...foldKeymap, ...completionKeymap, ...lintKeymap ]) ])(); var minimalSetup = (() => [ highlightSpecialChars(), history(), drawSelection(), syntaxHighlighting(defaultHighlightStyle, { fallback: true }), keymap.of([ ...defaultKeymap, ...historyKeymap ]) ])(); export { EditorView, basicSetup, minimalSetup }; //# sourceMappingURL=codemirror.js.map