@prosemark/core 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js ADDED
@@ -0,0 +1,3933 @@
1
+ import { Decoration, Direction, EditorView, EditorView as EditorView$1, ViewPlugin, WidgetType, dropCursor, getPanel, getTooltip, hoverTooltip, keymap, logException, runScopeHandlers, showPanel, showTooltip } from "@codemirror/view";
2
+ import { Annotation, CharCategory, EditorSelection, EditorState, Facet, MapMode, Prec, RangeSet, RangeSetBuilder, RangeValue, StateEffect, StateField, codePointAt, codePointSize, combineConfig, findClusterBreak, fromCodePoint } from "@codemirror/state";
3
+ import { HighlightStyle, bracketMatching, foldGutter, foldKeymap, indentOnInput, syntaxHighlighting, syntaxTree } from "@codemirror/language";
4
+ import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
5
+ import { Tag, styleTags, tags } from "@lezer/highlight";
6
+ import * as emoji from "node-emoji";
7
+
8
+ //#region ../../node_modules/crelt/index.js
9
+ function crelt() {
10
+ var elt = arguments[0];
11
+ if (typeof elt == "string") elt = document.createElement(elt);
12
+ var i = 1, next = arguments[1];
13
+ if (next && typeof next == "object" && next.nodeType == null && !Array.isArray(next)) {
14
+ for (var name in next) if (Object.prototype.hasOwnProperty.call(next, name)) {
15
+ var value = next[name];
16
+ if (typeof value == "string") elt.setAttribute(name, value);
17
+ else if (value != null) elt[name] = value;
18
+ }
19
+ i++;
20
+ }
21
+ for (; i < arguments.length; i++) add(elt, arguments[i]);
22
+ return elt;
23
+ }
24
+ function add(elt, child) {
25
+ if (typeof child == "string") elt.appendChild(document.createTextNode(child));
26
+ else if (child == null) {} else if (child.nodeType != null) elt.appendChild(child);
27
+ else if (Array.isArray(child)) for (var i = 0; i < child.length; i++) add(elt, child[i]);
28
+ else throw new RangeError("Unsupported child node: " + child);
29
+ }
30
+
31
+ //#endregion
32
+ //#region ../../node_modules/@codemirror/search/dist/index.js
33
+ const basicNormalize = typeof String.prototype.normalize == "function" ? (x) => x.normalize("NFKD") : (x) => x;
34
+ /**
35
+ A search cursor provides an iterator over text matches in a
36
+ document.
37
+ */
38
+ var SearchCursor = class {
39
+ /**
40
+ Create a text cursor. The query is the search string, `from` to
41
+ `to` provides the region to search.
42
+
43
+ When `normalize` is given, it will be called, on both the query
44
+ string and the content it is matched against, before comparing.
45
+ You can, for example, create a case-insensitive search by
46
+ passing `s => s.toLowerCase()`.
47
+
48
+ Text is always normalized with
49
+ [`.normalize("NFKD")`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize)
50
+ (when supported).
51
+ */
52
+ constructor(text, query, from = 0, to = text.length, normalize, test) {
53
+ this.test = test;
54
+ /**
55
+ The current match (only holds a meaningful value after
56
+ [`next`](https://codemirror.net/6/docs/ref/#search.SearchCursor.next) has been called and when
57
+ `done` is false).
58
+ */
59
+ this.value = {
60
+ from: 0,
61
+ to: 0
62
+ };
63
+ /**
64
+ Whether the end of the iterated region has been reached.
65
+ */
66
+ this.done = false;
67
+ this.matches = [];
68
+ this.buffer = "";
69
+ this.bufferPos = 0;
70
+ this.iter = text.iterRange(from, to);
71
+ this.bufferStart = from;
72
+ this.normalize = normalize ? (x) => normalize(basicNormalize(x)) : basicNormalize;
73
+ this.query = this.normalize(query);
74
+ }
75
+ peek() {
76
+ if (this.bufferPos == this.buffer.length) {
77
+ this.bufferStart += this.buffer.length;
78
+ this.iter.next();
79
+ if (this.iter.done) return -1;
80
+ this.bufferPos = 0;
81
+ this.buffer = this.iter.value;
82
+ }
83
+ return codePointAt(this.buffer, this.bufferPos);
84
+ }
85
+ /**
86
+ Look for the next match. Updates the iterator's
87
+ [`value`](https://codemirror.net/6/docs/ref/#search.SearchCursor.value) and
88
+ [`done`](https://codemirror.net/6/docs/ref/#search.SearchCursor.done) properties. Should be called
89
+ at least once before using the cursor.
90
+ */
91
+ next() {
92
+ while (this.matches.length) this.matches.pop();
93
+ return this.nextOverlapping();
94
+ }
95
+ /**
96
+ The `next` method will ignore matches that partially overlap a
97
+ previous match. This method behaves like `next`, but includes
98
+ such matches.
99
+ */
100
+ nextOverlapping() {
101
+ for (;;) {
102
+ let next = this.peek();
103
+ if (next < 0) {
104
+ this.done = true;
105
+ return this;
106
+ }
107
+ let str = fromCodePoint(next), start = this.bufferStart + this.bufferPos;
108
+ this.bufferPos += codePointSize(next);
109
+ let norm = this.normalize(str);
110
+ if (norm.length) for (let i = 0, pos = start;; i++) {
111
+ let code = norm.charCodeAt(i);
112
+ let match = this.match(code, pos, this.bufferPos + this.bufferStart);
113
+ if (i == norm.length - 1) {
114
+ if (match) {
115
+ this.value = match;
116
+ return this;
117
+ }
118
+ break;
119
+ }
120
+ if (pos == start && i < str.length && str.charCodeAt(i) == code) pos++;
121
+ }
122
+ }
123
+ }
124
+ match(code, pos, end) {
125
+ let match = null;
126
+ for (let i = 0; i < this.matches.length; i += 2) {
127
+ let index = this.matches[i], keep = false;
128
+ if (this.query.charCodeAt(index) == code) if (index == this.query.length - 1) match = {
129
+ from: this.matches[i + 1],
130
+ to: end
131
+ };
132
+ else {
133
+ this.matches[i]++;
134
+ keep = true;
135
+ }
136
+ if (!keep) {
137
+ this.matches.splice(i, 2);
138
+ i -= 2;
139
+ }
140
+ }
141
+ if (this.query.charCodeAt(0) == code) if (this.query.length == 1) match = {
142
+ from: pos,
143
+ to: end
144
+ };
145
+ else this.matches.push(1, pos);
146
+ if (match && this.test && !this.test(match.from, match.to, this.buffer, this.bufferStart)) match = null;
147
+ return match;
148
+ }
149
+ };
150
+ if (typeof Symbol != "undefined") SearchCursor.prototype[Symbol.iterator] = function() {
151
+ return this;
152
+ };
153
+ const empty = {
154
+ from: -1,
155
+ to: -1,
156
+ match: /* @__PURE__ */ /.*/.exec("")
157
+ };
158
+ const baseFlags = "gm" + (/x/.unicode == null ? "" : "u");
159
+ /**
160
+ This class is similar to [`SearchCursor`](https://codemirror.net/6/docs/ref/#search.SearchCursor)
161
+ but searches for a regular expression pattern instead of a plain
162
+ string.
163
+ */
164
+ var RegExpCursor = class {
165
+ /**
166
+ Create a cursor that will search the given range in the given
167
+ document. `query` should be the raw pattern (as you'd pass it to
168
+ `new RegExp`).
169
+ */
170
+ constructor(text, query, options, from = 0, to = text.length) {
171
+ this.text = text;
172
+ this.to = to;
173
+ this.curLine = "";
174
+ /**
175
+ Set to `true` when the cursor has reached the end of the search
176
+ range.
177
+ */
178
+ this.done = false;
179
+ /**
180
+ Will contain an object with the extent of the match and the
181
+ match object when [`next`](https://codemirror.net/6/docs/ref/#search.RegExpCursor.next)
182
+ sucessfully finds a match.
183
+ */
184
+ this.value = empty;
185
+ if (/\\[sWDnr]|\n|\r|\[\^/.test(query)) return new MultilineRegExpCursor(text, query, options, from, to);
186
+ this.re = new RegExp(query, baseFlags + ((options === null || options === void 0 ? void 0 : options.ignoreCase) ? "i" : ""));
187
+ this.test = options === null || options === void 0 ? void 0 : options.test;
188
+ this.iter = text.iter();
189
+ this.curLineStart = text.lineAt(from).from;
190
+ this.matchPos = toCharEnd(text, from);
191
+ this.getLine(this.curLineStart);
192
+ }
193
+ getLine(skip) {
194
+ this.iter.next(skip);
195
+ if (this.iter.lineBreak) this.curLine = "";
196
+ else {
197
+ this.curLine = this.iter.value;
198
+ if (this.curLineStart + this.curLine.length > this.to) this.curLine = this.curLine.slice(0, this.to - this.curLineStart);
199
+ this.iter.next();
200
+ }
201
+ }
202
+ nextLine() {
203
+ this.curLineStart = this.curLineStart + this.curLine.length + 1;
204
+ if (this.curLineStart > this.to) this.curLine = "";
205
+ else this.getLine(0);
206
+ }
207
+ /**
208
+ Move to the next match, if there is one.
209
+ */
210
+ next() {
211
+ for (let off = this.matchPos - this.curLineStart;;) {
212
+ this.re.lastIndex = off;
213
+ let match = this.matchPos <= this.to && this.re.exec(this.curLine);
214
+ if (match) {
215
+ let from = this.curLineStart + match.index, to = from + match[0].length;
216
+ this.matchPos = toCharEnd(this.text, to + (from == to ? 1 : 0));
217
+ if (from == this.curLineStart + this.curLine.length) this.nextLine();
218
+ if ((from < to || from > this.value.to) && (!this.test || this.test(from, to, match))) {
219
+ this.value = {
220
+ from,
221
+ to,
222
+ match
223
+ };
224
+ return this;
225
+ }
226
+ off = this.matchPos - this.curLineStart;
227
+ } else if (this.curLineStart + this.curLine.length < this.to) {
228
+ this.nextLine();
229
+ off = 0;
230
+ } else {
231
+ this.done = true;
232
+ return this;
233
+ }
234
+ }
235
+ }
236
+ };
237
+ const flattened = /* @__PURE__ */ new WeakMap();
238
+ var FlattenedDoc = class FlattenedDoc {
239
+ constructor(from, text) {
240
+ this.from = from;
241
+ this.text = text;
242
+ }
243
+ get to() {
244
+ return this.from + this.text.length;
245
+ }
246
+ static get(doc, from, to) {
247
+ let cached = flattened.get(doc);
248
+ if (!cached || cached.from >= to || cached.to <= from) {
249
+ let flat = new FlattenedDoc(from, doc.sliceString(from, to));
250
+ flattened.set(doc, flat);
251
+ return flat;
252
+ }
253
+ if (cached.from == from && cached.to == to) return cached;
254
+ let { text, from: cachedFrom } = cached;
255
+ if (cachedFrom > from) {
256
+ text = doc.sliceString(from, cachedFrom) + text;
257
+ cachedFrom = from;
258
+ }
259
+ if (cached.to < to) text += doc.sliceString(cached.to, to);
260
+ flattened.set(doc, new FlattenedDoc(cachedFrom, text));
261
+ return new FlattenedDoc(from, text.slice(from - cachedFrom, to - cachedFrom));
262
+ }
263
+ };
264
+ var MultilineRegExpCursor = class {
265
+ constructor(text, query, options, from, to) {
266
+ this.text = text;
267
+ this.to = to;
268
+ this.done = false;
269
+ this.value = empty;
270
+ this.matchPos = toCharEnd(text, from);
271
+ this.re = new RegExp(query, baseFlags + ((options === null || options === void 0 ? void 0 : options.ignoreCase) ? "i" : ""));
272
+ this.test = options === null || options === void 0 ? void 0 : options.test;
273
+ this.flat = FlattenedDoc.get(text, from, this.chunkEnd(from + 5e3));
274
+ }
275
+ chunkEnd(pos) {
276
+ return pos >= this.to ? this.to : this.text.lineAt(pos).to;
277
+ }
278
+ next() {
279
+ for (;;) {
280
+ let off = this.re.lastIndex = this.matchPos - this.flat.from;
281
+ let match = this.re.exec(this.flat.text);
282
+ if (match && !match[0] && match.index == off) {
283
+ this.re.lastIndex = off + 1;
284
+ match = this.re.exec(this.flat.text);
285
+ }
286
+ if (match) {
287
+ let from = this.flat.from + match.index, to = from + match[0].length;
288
+ if ((this.flat.to >= this.to || match.index + match[0].length <= this.flat.text.length - 10) && (!this.test || this.test(from, to, match))) {
289
+ this.value = {
290
+ from,
291
+ to,
292
+ match
293
+ };
294
+ this.matchPos = toCharEnd(this.text, to + (from == to ? 1 : 0));
295
+ return this;
296
+ }
297
+ }
298
+ if (this.flat.to == this.to) {
299
+ this.done = true;
300
+ return this;
301
+ }
302
+ this.flat = FlattenedDoc.get(this.text, this.flat.from, this.chunkEnd(this.flat.from + this.flat.text.length * 2));
303
+ }
304
+ }
305
+ };
306
+ if (typeof Symbol != "undefined") RegExpCursor.prototype[Symbol.iterator] = MultilineRegExpCursor.prototype[Symbol.iterator] = function() {
307
+ return this;
308
+ };
309
+ function validRegExp(source) {
310
+ try {
311
+ new RegExp(source, baseFlags);
312
+ return true;
313
+ } catch (_a) {
314
+ return false;
315
+ }
316
+ }
317
+ function toCharEnd(text, pos) {
318
+ if (pos >= text.length) return pos;
319
+ let line = text.lineAt(pos), next;
320
+ while (pos < line.to && (next = line.text.charCodeAt(pos - line.from)) >= 56320 && next < 57344) pos++;
321
+ return pos;
322
+ }
323
+ function createLineDialog(view) {
324
+ let line = String(view.state.doc.lineAt(view.state.selection.main.head).number);
325
+ let input = crelt("input", {
326
+ class: "cm-textfield",
327
+ name: "line",
328
+ value: line
329
+ });
330
+ let dom = crelt("form", {
331
+ class: "cm-gotoLine",
332
+ onkeydown: (event) => {
333
+ if (event.keyCode == 27) {
334
+ event.preventDefault();
335
+ view.dispatch({ effects: dialogEffect.of(false) });
336
+ view.focus();
337
+ } else if (event.keyCode == 13) {
338
+ event.preventDefault();
339
+ go();
340
+ }
341
+ },
342
+ onsubmit: (event) => {
343
+ event.preventDefault();
344
+ go();
345
+ }
346
+ }, crelt("label", view.state.phrase("Go to line"), ": ", input), " ", crelt("button", {
347
+ class: "cm-button",
348
+ type: "submit"
349
+ }, view.state.phrase("go")), crelt("button", {
350
+ name: "close",
351
+ onclick: () => {
352
+ view.dispatch({ effects: dialogEffect.of(false) });
353
+ view.focus();
354
+ },
355
+ "aria-label": view.state.phrase("close"),
356
+ type: "button"
357
+ }, ["×"]));
358
+ function go() {
359
+ let match = /^([+-])?(\d+)?(:\d+)?(%)?$/.exec(input.value);
360
+ if (!match) return;
361
+ let { state } = view, startLine = state.doc.lineAt(state.selection.main.head);
362
+ let [, sign, ln, cl, percent] = match;
363
+ let col = cl ? +cl.slice(1) : 0;
364
+ let line$1 = ln ? +ln : startLine.number;
365
+ if (ln && percent) {
366
+ let pc = line$1 / 100;
367
+ if (sign) pc = pc * (sign == "-" ? -1 : 1) + startLine.number / state.doc.lines;
368
+ line$1 = Math.round(state.doc.lines * pc);
369
+ } else if (ln && sign) line$1 = line$1 * (sign == "-" ? -1 : 1) + startLine.number;
370
+ let docLine = state.doc.line(Math.max(1, Math.min(state.doc.lines, line$1)));
371
+ let selection = EditorSelection.cursor(docLine.from + Math.max(0, Math.min(col, docLine.length)));
372
+ view.dispatch({
373
+ effects: [dialogEffect.of(false), EditorView.scrollIntoView(selection.from, { y: "center" })],
374
+ selection
375
+ });
376
+ view.focus();
377
+ }
378
+ return { dom };
379
+ }
380
+ const dialogEffect = /* @__PURE__ */ StateEffect.define();
381
+ const dialogField = /* @__PURE__ */ StateField.define({
382
+ create() {
383
+ return true;
384
+ },
385
+ update(value, tr) {
386
+ for (let e of tr.effects) if (e.is(dialogEffect)) value = e.value;
387
+ return value;
388
+ },
389
+ provide: (f) => showPanel.from(f, (val) => val ? createLineDialog : null)
390
+ });
391
+ /**
392
+ Command that shows a dialog asking the user for a line number, and
393
+ when a valid position is provided, moves the cursor to that line.
394
+
395
+ Supports line numbers, relative line offsets prefixed with `+` or
396
+ `-`, document percentages suffixed with `%`, and an optional
397
+ column position by adding `:` and a second number after the line
398
+ number.
399
+ */
400
+ const gotoLine = (view) => {
401
+ let panel = getPanel(view, createLineDialog);
402
+ if (!panel) {
403
+ let effects = [dialogEffect.of(true)];
404
+ if (view.state.field(dialogField, false) == null) effects.push(StateEffect.appendConfig.of([dialogField, baseTheme$1$1]));
405
+ view.dispatch({ effects });
406
+ panel = getPanel(view, createLineDialog);
407
+ }
408
+ if (panel) panel.dom.querySelector("input").select();
409
+ return true;
410
+ };
411
+ const baseTheme$1$1 = /* @__PURE__ */ EditorView.baseTheme({ ".cm-panel.cm-gotoLine": {
412
+ padding: "2px 6px 4px",
413
+ position: "relative",
414
+ "& label": { fontSize: "80%" },
415
+ "& [name=close]": {
416
+ position: "absolute",
417
+ top: "0",
418
+ bottom: "0",
419
+ right: "4px",
420
+ backgroundColor: "inherit",
421
+ border: "none",
422
+ font: "inherit",
423
+ padding: "0"
424
+ }
425
+ } });
426
+ const selectWord = ({ state, dispatch }) => {
427
+ let { selection } = state;
428
+ let newSel = EditorSelection.create(selection.ranges.map((range) => state.wordAt(range.head) || EditorSelection.cursor(range.head)), selection.mainIndex);
429
+ if (newSel.eq(selection)) return false;
430
+ dispatch(state.update({ selection: newSel }));
431
+ return true;
432
+ };
433
+ function findNextOccurrence(state, query) {
434
+ let { main, ranges } = state.selection;
435
+ let word = state.wordAt(main.head), fullWord = word && word.from == main.from && word.to == main.to;
436
+ for (let cycled = false, cursor = new SearchCursor(state.doc, query, ranges[ranges.length - 1].to);;) {
437
+ cursor.next();
438
+ if (cursor.done) {
439
+ if (cycled) return null;
440
+ cursor = new SearchCursor(state.doc, query, 0, Math.max(0, ranges[ranges.length - 1].from - 1));
441
+ cycled = true;
442
+ } else {
443
+ if (cycled && ranges.some((r) => r.from == cursor.value.from)) continue;
444
+ if (fullWord) {
445
+ let word$1 = state.wordAt(cursor.value.from);
446
+ if (!word$1 || word$1.from != cursor.value.from || word$1.to != cursor.value.to) continue;
447
+ }
448
+ return cursor.value;
449
+ }
450
+ }
451
+ }
452
+ /**
453
+ Select next occurrence of the current selection. Expand selection
454
+ to the surrounding word when the selection is empty.
455
+ */
456
+ const selectNextOccurrence = ({ state, dispatch }) => {
457
+ let { ranges } = state.selection;
458
+ if (ranges.some((sel) => sel.from === sel.to)) return selectWord({
459
+ state,
460
+ dispatch
461
+ });
462
+ let searchedText = state.sliceDoc(ranges[0].from, ranges[0].to);
463
+ if (state.selection.ranges.some((r) => state.sliceDoc(r.from, r.to) != searchedText)) return false;
464
+ let range = findNextOccurrence(state, searchedText);
465
+ if (!range) return false;
466
+ dispatch(state.update({
467
+ selection: state.selection.addRange(EditorSelection.range(range.from, range.to), false),
468
+ effects: EditorView.scrollIntoView(range.to)
469
+ }));
470
+ return true;
471
+ };
472
+ const searchConfigFacet = /* @__PURE__ */ Facet.define({ combine(configs) {
473
+ return combineConfig(configs, {
474
+ top: false,
475
+ caseSensitive: false,
476
+ literal: false,
477
+ regexp: false,
478
+ wholeWord: false,
479
+ createPanel: (view) => new SearchPanel(view),
480
+ scrollToMatch: (range) => EditorView.scrollIntoView(range)
481
+ });
482
+ } });
483
+ /**
484
+ A search query. Part of the editor's search state.
485
+ */
486
+ var SearchQuery = class {
487
+ /**
488
+ Create a query object.
489
+ */
490
+ constructor(config$1) {
491
+ this.search = config$1.search;
492
+ this.caseSensitive = !!config$1.caseSensitive;
493
+ this.literal = !!config$1.literal;
494
+ this.regexp = !!config$1.regexp;
495
+ this.replace = config$1.replace || "";
496
+ this.valid = !!this.search && (!this.regexp || validRegExp(this.search));
497
+ this.unquoted = this.unquote(this.search);
498
+ this.wholeWord = !!config$1.wholeWord;
499
+ }
500
+ /**
501
+ @internal
502
+ */
503
+ unquote(text) {
504
+ return this.literal ? text : text.replace(/\\([nrt\\])/g, (_, ch) => ch == "n" ? "\n" : ch == "r" ? "\r" : ch == "t" ? " " : "\\");
505
+ }
506
+ /**
507
+ Compare this query to another query.
508
+ */
509
+ eq(other) {
510
+ return this.search == other.search && this.replace == other.replace && this.caseSensitive == other.caseSensitive && this.regexp == other.regexp && this.wholeWord == other.wholeWord;
511
+ }
512
+ /**
513
+ @internal
514
+ */
515
+ create() {
516
+ return this.regexp ? new RegExpQuery(this) : new StringQuery(this);
517
+ }
518
+ /**
519
+ Get a search cursor for this query, searching through the given
520
+ range in the given state.
521
+ */
522
+ getCursor(state, from = 0, to) {
523
+ let st = state.doc ? state : EditorState.create({ doc: state });
524
+ if (to == null) to = st.doc.length;
525
+ return this.regexp ? regexpCursor(this, st, from, to) : stringCursor(this, st, from, to);
526
+ }
527
+ };
528
+ var QueryType = class {
529
+ constructor(spec) {
530
+ this.spec = spec;
531
+ }
532
+ };
533
+ function stringCursor(spec, state, from, to) {
534
+ return new SearchCursor(state.doc, spec.unquoted, from, to, spec.caseSensitive ? void 0 : (x) => x.toLowerCase(), spec.wholeWord ? stringWordTest(state.doc, state.charCategorizer(state.selection.main.head)) : void 0);
535
+ }
536
+ function stringWordTest(doc, categorizer) {
537
+ return (from, to, buf, bufPos) => {
538
+ if (bufPos > from || bufPos + buf.length < to) {
539
+ bufPos = Math.max(0, from - 2);
540
+ buf = doc.sliceString(bufPos, Math.min(doc.length, to + 2));
541
+ }
542
+ 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);
543
+ };
544
+ }
545
+ var StringQuery = class extends QueryType {
546
+ constructor(spec) {
547
+ super(spec);
548
+ }
549
+ nextMatch(state, curFrom, curTo) {
550
+ let cursor = stringCursor(this.spec, state, curTo, state.doc.length).nextOverlapping();
551
+ if (cursor.done) {
552
+ let end = Math.min(state.doc.length, curFrom + this.spec.unquoted.length);
553
+ cursor = stringCursor(this.spec, state, 0, end).nextOverlapping();
554
+ }
555
+ return cursor.done || cursor.value.from == curFrom && cursor.value.to == curTo ? null : cursor.value;
556
+ }
557
+ prevMatchInRange(state, from, to) {
558
+ for (let pos = to;;) {
559
+ let start = Math.max(from, pos - 1e4 - this.spec.unquoted.length);
560
+ let cursor = stringCursor(this.spec, state, start, pos), range = null;
561
+ while (!cursor.nextOverlapping().done) range = cursor.value;
562
+ if (range) return range;
563
+ if (start == from) return null;
564
+ pos -= 1e4;
565
+ }
566
+ }
567
+ prevMatch(state, curFrom, curTo) {
568
+ let found = this.prevMatchInRange(state, 0, curFrom);
569
+ if (!found) found = this.prevMatchInRange(state, Math.max(0, curTo - this.spec.unquoted.length), state.doc.length);
570
+ return found && (found.from != curFrom || found.to != curTo) ? found : null;
571
+ }
572
+ getReplacement(_result) {
573
+ return this.spec.unquote(this.spec.replace);
574
+ }
575
+ matchAll(state, limit) {
576
+ let cursor = stringCursor(this.spec, state, 0, state.doc.length), ranges = [];
577
+ while (!cursor.next().done) {
578
+ if (ranges.length >= limit) return null;
579
+ ranges.push(cursor.value);
580
+ }
581
+ return ranges;
582
+ }
583
+ highlight(state, from, to, add$1) {
584
+ let cursor = stringCursor(this.spec, state, Math.max(0, from - this.spec.unquoted.length), Math.min(to + this.spec.unquoted.length, state.doc.length));
585
+ while (!cursor.next().done) add$1(cursor.value.from, cursor.value.to);
586
+ }
587
+ };
588
+ function regexpCursor(spec, state, from, to) {
589
+ return new RegExpCursor(state.doc, spec.search, {
590
+ ignoreCase: !spec.caseSensitive,
591
+ test: spec.wholeWord ? regexpWordTest(state.charCategorizer(state.selection.main.head)) : void 0
592
+ }, from, to);
593
+ }
594
+ function charBefore(str, index) {
595
+ return str.slice(findClusterBreak(str, index, false), index);
596
+ }
597
+ function charAfter(str, index) {
598
+ return str.slice(index, findClusterBreak(str, index));
599
+ }
600
+ function regexpWordTest(categorizer) {
601
+ 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);
602
+ }
603
+ var RegExpQuery = class extends QueryType {
604
+ nextMatch(state, curFrom, curTo) {
605
+ let cursor = regexpCursor(this.spec, state, curTo, state.doc.length).next();
606
+ if (cursor.done) cursor = regexpCursor(this.spec, state, 0, curFrom).next();
607
+ return cursor.done ? null : cursor.value;
608
+ }
609
+ prevMatchInRange(state, from, to) {
610
+ for (let size = 1;; size++) {
611
+ let start = Math.max(from, to - size * 1e4);
612
+ let cursor = regexpCursor(this.spec, state, start, to), range = null;
613
+ while (!cursor.next().done) range = cursor.value;
614
+ if (range && (start == from || range.from > start + 10)) return range;
615
+ if (start == from) return null;
616
+ }
617
+ }
618
+ prevMatch(state, curFrom, curTo) {
619
+ return this.prevMatchInRange(state, 0, curFrom) || this.prevMatchInRange(state, curTo, state.doc.length);
620
+ }
621
+ getReplacement(result) {
622
+ return this.spec.unquote(this.spec.replace).replace(/\$([$&]|\d+)/g, (m, i) => {
623
+ if (i == "&") return result.match[0];
624
+ if (i == "$") return "$";
625
+ for (let l = i.length; l > 0; l--) {
626
+ let n = +i.slice(0, l);
627
+ if (n > 0 && n < result.match.length) return result.match[n] + i.slice(l);
628
+ }
629
+ return m;
630
+ });
631
+ }
632
+ matchAll(state, limit) {
633
+ let cursor = regexpCursor(this.spec, state, 0, state.doc.length), ranges = [];
634
+ while (!cursor.next().done) {
635
+ if (ranges.length >= limit) return null;
636
+ ranges.push(cursor.value);
637
+ }
638
+ return ranges;
639
+ }
640
+ highlight(state, from, to, add$1) {
641
+ let cursor = regexpCursor(this.spec, state, Math.max(0, from - 250), Math.min(to + 250, state.doc.length));
642
+ while (!cursor.next().done) add$1(cursor.value.from, cursor.value.to);
643
+ }
644
+ };
645
+ /**
646
+ A state effect that updates the current search query. Note that
647
+ this only has an effect if the search state has been initialized
648
+ (by including [`search`](https://codemirror.net/6/docs/ref/#search.search) in your configuration or
649
+ by running [`openSearchPanel`](https://codemirror.net/6/docs/ref/#search.openSearchPanel) at least
650
+ once).
651
+ */
652
+ const setSearchQuery = /* @__PURE__ */ StateEffect.define();
653
+ const togglePanel$1 = /* @__PURE__ */ StateEffect.define();
654
+ const searchState = /* @__PURE__ */ StateField.define({
655
+ create(state) {
656
+ return new SearchState(defaultQuery(state).create(), null);
657
+ },
658
+ update(value, tr) {
659
+ for (let effect of tr.effects) if (effect.is(setSearchQuery)) value = new SearchState(effect.value.create(), value.panel);
660
+ else if (effect.is(togglePanel$1)) value = new SearchState(value.query, effect.value ? createSearchPanel : null);
661
+ return value;
662
+ },
663
+ provide: (f) => showPanel.from(f, (val) => val.panel)
664
+ });
665
+ var SearchState = class {
666
+ constructor(query, panel) {
667
+ this.query = query;
668
+ this.panel = panel;
669
+ }
670
+ };
671
+ const matchMark = /* @__PURE__ */ Decoration.mark({ class: "cm-searchMatch" }), selectedMatchMark = /* @__PURE__ */ Decoration.mark({ class: "cm-searchMatch cm-searchMatch-selected" });
672
+ const searchHighlighter = /* @__PURE__ */ ViewPlugin.fromClass(class {
673
+ constructor(view) {
674
+ this.view = view;
675
+ this.decorations = this.highlight(view.state.field(searchState));
676
+ }
677
+ update(update) {
678
+ let state = update.state.field(searchState);
679
+ if (state != update.startState.field(searchState) || update.docChanged || update.selectionSet || update.viewportChanged) this.decorations = this.highlight(state);
680
+ }
681
+ highlight({ query, panel }) {
682
+ if (!panel || !query.spec.valid) return Decoration.none;
683
+ let { view } = this;
684
+ let builder = new RangeSetBuilder();
685
+ for (let i = 0, ranges = view.visibleRanges, l = ranges.length; i < l; i++) {
686
+ let { from, to } = ranges[i];
687
+ while (i < l - 1 && to > ranges[i + 1].from - 500) to = ranges[++i].to;
688
+ query.highlight(view.state, from, to, (from$1, to$1) => {
689
+ let selected = view.state.selection.ranges.some((r) => r.from == from$1 && r.to == to$1);
690
+ builder.add(from$1, to$1, selected ? selectedMatchMark : matchMark);
691
+ });
692
+ }
693
+ return builder.finish();
694
+ }
695
+ }, { decorations: (v) => v.decorations });
696
+ function searchCommand(f) {
697
+ return (view) => {
698
+ let state = view.state.field(searchState, false);
699
+ return state && state.query.spec.valid ? f(view, state) : openSearchPanel(view);
700
+ };
701
+ }
702
+ /**
703
+ Open the search panel if it isn't already open, and move the
704
+ selection to the first match after the current main selection.
705
+ Will wrap around to the start of the document when it reaches the
706
+ end.
707
+ */
708
+ const findNext = /* @__PURE__ */ searchCommand((view, { query }) => {
709
+ let { to } = view.state.selection.main;
710
+ let next = query.nextMatch(view.state, to, to);
711
+ if (!next) return false;
712
+ let selection = EditorSelection.single(next.from, next.to);
713
+ let config$1 = view.state.facet(searchConfigFacet);
714
+ view.dispatch({
715
+ selection,
716
+ effects: [announceMatch(view, next), config$1.scrollToMatch(selection.main, view)],
717
+ userEvent: "select.search"
718
+ });
719
+ selectSearchInput(view);
720
+ return true;
721
+ });
722
+ /**
723
+ Move the selection to the previous instance of the search query,
724
+ before the current main selection. Will wrap past the start
725
+ of the document to start searching at the end again.
726
+ */
727
+ const findPrevious = /* @__PURE__ */ searchCommand((view, { query }) => {
728
+ let { state } = view, { from } = state.selection.main;
729
+ let prev = query.prevMatch(state, from, from);
730
+ if (!prev) return false;
731
+ let selection = EditorSelection.single(prev.from, prev.to);
732
+ let config$1 = view.state.facet(searchConfigFacet);
733
+ view.dispatch({
734
+ selection,
735
+ effects: [announceMatch(view, prev), config$1.scrollToMatch(selection.main, view)],
736
+ userEvent: "select.search"
737
+ });
738
+ selectSearchInput(view);
739
+ return true;
740
+ });
741
+ /**
742
+ Select all instances of the search query.
743
+ */
744
+ const selectMatches = /* @__PURE__ */ searchCommand((view, { query }) => {
745
+ let ranges = query.matchAll(view.state, 1e3);
746
+ if (!ranges || !ranges.length) return false;
747
+ view.dispatch({
748
+ selection: EditorSelection.create(ranges.map((r) => EditorSelection.range(r.from, r.to))),
749
+ userEvent: "select.search.matches"
750
+ });
751
+ return true;
752
+ });
753
+ /**
754
+ Select all instances of the currently selected text.
755
+ */
756
+ const selectSelectionMatches = ({ state, dispatch }) => {
757
+ let sel = state.selection;
758
+ if (sel.ranges.length > 1 || sel.main.empty) return false;
759
+ let { from, to } = sel.main;
760
+ let ranges = [], main = 0;
761
+ for (let cur$1 = new SearchCursor(state.doc, state.sliceDoc(from, to)); !cur$1.next().done;) {
762
+ if (ranges.length > 1e3) return false;
763
+ if (cur$1.value.from == from) main = ranges.length;
764
+ ranges.push(EditorSelection.range(cur$1.value.from, cur$1.value.to));
765
+ }
766
+ dispatch(state.update({
767
+ selection: EditorSelection.create(ranges, main),
768
+ userEvent: "select.search.matches"
769
+ }));
770
+ return true;
771
+ };
772
+ /**
773
+ Replace the current match of the search query.
774
+ */
775
+ const replaceNext = /* @__PURE__ */ searchCommand((view, { query }) => {
776
+ let { state } = view, { from, to } = state.selection.main;
777
+ if (state.readOnly) return false;
778
+ let match = query.nextMatch(state, from, from);
779
+ if (!match) return false;
780
+ let next = match;
781
+ let changes = [], selection, replacement;
782
+ let effects = [];
783
+ if (next.from == from && next.to == to) {
784
+ replacement = state.toText(query.getReplacement(next));
785
+ changes.push({
786
+ from: next.from,
787
+ to: next.to,
788
+ insert: replacement
789
+ });
790
+ next = query.nextMatch(state, next.from, next.to);
791
+ effects.push(EditorView.announce.of(state.phrase("replaced match on line $", state.doc.lineAt(from).number) + "."));
792
+ }
793
+ let changeSet = view.state.changes(changes);
794
+ if (next) {
795
+ selection = EditorSelection.single(next.from, next.to).map(changeSet);
796
+ effects.push(announceMatch(view, next));
797
+ effects.push(state.facet(searchConfigFacet).scrollToMatch(selection.main, view));
798
+ }
799
+ view.dispatch({
800
+ changes: changeSet,
801
+ selection,
802
+ effects,
803
+ userEvent: "input.replace"
804
+ });
805
+ return true;
806
+ });
807
+ /**
808
+ Replace all instances of the search query with the given
809
+ replacement.
810
+ */
811
+ const replaceAll = /* @__PURE__ */ searchCommand((view, { query }) => {
812
+ if (view.state.readOnly) return false;
813
+ let changes = query.matchAll(view.state, 1e9).map((match) => {
814
+ let { from, to } = match;
815
+ return {
816
+ from,
817
+ to,
818
+ insert: query.getReplacement(match)
819
+ };
820
+ });
821
+ if (!changes.length) return false;
822
+ let announceText = view.state.phrase("replaced $ matches", changes.length) + ".";
823
+ view.dispatch({
824
+ changes,
825
+ effects: EditorView.announce.of(announceText),
826
+ userEvent: "input.replace.all"
827
+ });
828
+ return true;
829
+ });
830
+ function createSearchPanel(view) {
831
+ return view.state.facet(searchConfigFacet).createPanel(view);
832
+ }
833
+ function defaultQuery(state, fallback) {
834
+ var _a, _b, _c, _d, _e;
835
+ let sel = state.selection.main;
836
+ let selText = sel.empty || sel.to > sel.from + 100 ? "" : state.sliceDoc(sel.from, sel.to);
837
+ if (fallback && !selText) return fallback;
838
+ let config$1 = state.facet(searchConfigFacet);
839
+ return new SearchQuery({
840
+ search: ((_a = fallback === null || fallback === void 0 ? void 0 : fallback.literal) !== null && _a !== void 0 ? _a : config$1.literal) ? selText : selText.replace(/\n/g, "\\n"),
841
+ caseSensitive: (_b = fallback === null || fallback === void 0 ? void 0 : fallback.caseSensitive) !== null && _b !== void 0 ? _b : config$1.caseSensitive,
842
+ literal: (_c = fallback === null || fallback === void 0 ? void 0 : fallback.literal) !== null && _c !== void 0 ? _c : config$1.literal,
843
+ regexp: (_d = fallback === null || fallback === void 0 ? void 0 : fallback.regexp) !== null && _d !== void 0 ? _d : config$1.regexp,
844
+ wholeWord: (_e = fallback === null || fallback === void 0 ? void 0 : fallback.wholeWord) !== null && _e !== void 0 ? _e : config$1.wholeWord
845
+ });
846
+ }
847
+ function getSearchInput(view) {
848
+ let panel = getPanel(view, createSearchPanel);
849
+ return panel && panel.dom.querySelector("[main-field]");
850
+ }
851
+ function selectSearchInput(view) {
852
+ let input = getSearchInput(view);
853
+ if (input && input == view.root.activeElement) input.select();
854
+ }
855
+ /**
856
+ Make sure the search panel is open and focused.
857
+ */
858
+ const openSearchPanel = (view) => {
859
+ let state = view.state.field(searchState, false);
860
+ if (state && state.panel) {
861
+ let searchInput = getSearchInput(view);
862
+ if (searchInput && searchInput != view.root.activeElement) {
863
+ let query = defaultQuery(view.state, state.query.spec);
864
+ if (query.valid) view.dispatch({ effects: setSearchQuery.of(query) });
865
+ searchInput.focus();
866
+ searchInput.select();
867
+ }
868
+ } else view.dispatch({ effects: [togglePanel$1.of(true), state ? setSearchQuery.of(defaultQuery(view.state, state.query.spec)) : StateEffect.appendConfig.of(searchExtensions)] });
869
+ return true;
870
+ };
871
+ /**
872
+ Close the search panel.
873
+ */
874
+ const closeSearchPanel = (view) => {
875
+ let state = view.state.field(searchState, false);
876
+ if (!state || !state.panel) return false;
877
+ let panel = getPanel(view, createSearchPanel);
878
+ if (panel && panel.dom.contains(view.root.activeElement)) view.focus();
879
+ view.dispatch({ effects: togglePanel$1.of(false) });
880
+ return true;
881
+ };
882
+ /**
883
+ Default search-related key bindings.
884
+
885
+ - Mod-f: [`openSearchPanel`](https://codemirror.net/6/docs/ref/#search.openSearchPanel)
886
+ - F3, Mod-g: [`findNext`](https://codemirror.net/6/docs/ref/#search.findNext)
887
+ - Shift-F3, Shift-Mod-g: [`findPrevious`](https://codemirror.net/6/docs/ref/#search.findPrevious)
888
+ - Mod-Alt-g: [`gotoLine`](https://codemirror.net/6/docs/ref/#search.gotoLine)
889
+ - Mod-d: [`selectNextOccurrence`](https://codemirror.net/6/docs/ref/#search.selectNextOccurrence)
890
+ */
891
+ const searchKeymap = [
892
+ {
893
+ key: "Mod-f",
894
+ run: openSearchPanel,
895
+ scope: "editor search-panel"
896
+ },
897
+ {
898
+ key: "F3",
899
+ run: findNext,
900
+ shift: findPrevious,
901
+ scope: "editor search-panel",
902
+ preventDefault: true
903
+ },
904
+ {
905
+ key: "Mod-g",
906
+ run: findNext,
907
+ shift: findPrevious,
908
+ scope: "editor search-panel",
909
+ preventDefault: true
910
+ },
911
+ {
912
+ key: "Escape",
913
+ run: closeSearchPanel,
914
+ scope: "editor search-panel"
915
+ },
916
+ {
917
+ key: "Mod-Shift-l",
918
+ run: selectSelectionMatches
919
+ },
920
+ {
921
+ key: "Mod-Alt-g",
922
+ run: gotoLine
923
+ },
924
+ {
925
+ key: "Mod-d",
926
+ run: selectNextOccurrence,
927
+ preventDefault: true
928
+ }
929
+ ];
930
+ var SearchPanel = class {
931
+ constructor(view) {
932
+ this.view = view;
933
+ let query = this.query = view.state.field(searchState).query.spec;
934
+ this.commit = this.commit.bind(this);
935
+ this.searchField = crelt("input", {
936
+ value: query.search,
937
+ placeholder: phrase(view, "Find"),
938
+ "aria-label": phrase(view, "Find"),
939
+ class: "cm-textfield",
940
+ name: "search",
941
+ form: "",
942
+ "main-field": "true",
943
+ onchange: this.commit,
944
+ onkeyup: this.commit
945
+ });
946
+ this.replaceField = crelt("input", {
947
+ value: query.replace,
948
+ placeholder: phrase(view, "Replace"),
949
+ "aria-label": phrase(view, "Replace"),
950
+ class: "cm-textfield",
951
+ name: "replace",
952
+ form: "",
953
+ onchange: this.commit,
954
+ onkeyup: this.commit
955
+ });
956
+ this.caseField = crelt("input", {
957
+ type: "checkbox",
958
+ name: "case",
959
+ form: "",
960
+ checked: query.caseSensitive,
961
+ onchange: this.commit
962
+ });
963
+ this.reField = crelt("input", {
964
+ type: "checkbox",
965
+ name: "re",
966
+ form: "",
967
+ checked: query.regexp,
968
+ onchange: this.commit
969
+ });
970
+ this.wordField = crelt("input", {
971
+ type: "checkbox",
972
+ name: "word",
973
+ form: "",
974
+ checked: query.wholeWord,
975
+ onchange: this.commit
976
+ });
977
+ function button(name, onclick, content) {
978
+ return crelt("button", {
979
+ class: "cm-button",
980
+ name,
981
+ onclick,
982
+ type: "button"
983
+ }, content);
984
+ }
985
+ this.dom = crelt("div", {
986
+ onkeydown: (e) => this.keydown(e),
987
+ class: "cm-search"
988
+ }, [
989
+ this.searchField,
990
+ button("next", () => findNext(view), [phrase(view, "next")]),
991
+ button("prev", () => findPrevious(view), [phrase(view, "previous")]),
992
+ button("select", () => selectMatches(view), [phrase(view, "all")]),
993
+ crelt("label", null, [this.caseField, phrase(view, "match case")]),
994
+ crelt("label", null, [this.reField, phrase(view, "regexp")]),
995
+ crelt("label", null, [this.wordField, phrase(view, "by word")]),
996
+ ...view.state.readOnly ? [] : [
997
+ crelt("br"),
998
+ this.replaceField,
999
+ button("replace", () => replaceNext(view), [phrase(view, "replace")]),
1000
+ button("replaceAll", () => replaceAll(view), [phrase(view, "replace all")])
1001
+ ],
1002
+ crelt("button", {
1003
+ name: "close",
1004
+ onclick: () => closeSearchPanel(view),
1005
+ "aria-label": phrase(view, "close"),
1006
+ type: "button"
1007
+ }, ["×"])
1008
+ ]);
1009
+ }
1010
+ commit() {
1011
+ let query = new SearchQuery({
1012
+ search: this.searchField.value,
1013
+ caseSensitive: this.caseField.checked,
1014
+ regexp: this.reField.checked,
1015
+ wholeWord: this.wordField.checked,
1016
+ replace: this.replaceField.value
1017
+ });
1018
+ if (!query.eq(this.query)) {
1019
+ this.query = query;
1020
+ this.view.dispatch({ effects: setSearchQuery.of(query) });
1021
+ }
1022
+ }
1023
+ keydown(e) {
1024
+ if (runScopeHandlers(this.view, e, "search-panel")) e.preventDefault();
1025
+ else if (e.keyCode == 13 && e.target == this.searchField) {
1026
+ e.preventDefault();
1027
+ (e.shiftKey ? findPrevious : findNext)(this.view);
1028
+ } else if (e.keyCode == 13 && e.target == this.replaceField) {
1029
+ e.preventDefault();
1030
+ replaceNext(this.view);
1031
+ }
1032
+ }
1033
+ update(update) {
1034
+ 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);
1035
+ }
1036
+ setQuery(query) {
1037
+ this.query = query;
1038
+ this.searchField.value = query.search;
1039
+ this.replaceField.value = query.replace;
1040
+ this.caseField.checked = query.caseSensitive;
1041
+ this.reField.checked = query.regexp;
1042
+ this.wordField.checked = query.wholeWord;
1043
+ }
1044
+ mount() {
1045
+ this.searchField.select();
1046
+ }
1047
+ get pos() {
1048
+ return 80;
1049
+ }
1050
+ get top() {
1051
+ return this.view.state.facet(searchConfigFacet).top;
1052
+ }
1053
+ };
1054
+ function phrase(view, phrase$1) {
1055
+ return view.state.phrase(phrase$1);
1056
+ }
1057
+ const AnnounceMargin = 30;
1058
+ const Break = /[\s\.,:;?!]/;
1059
+ function announceMatch(view, { from, to }) {
1060
+ let line = view.state.doc.lineAt(from), lineEnd = view.state.doc.lineAt(to).to;
1061
+ let start = Math.max(line.from, from - AnnounceMargin), end = Math.min(lineEnd, to + AnnounceMargin);
1062
+ let text = view.state.sliceDoc(start, end);
1063
+ if (start != line.from) {
1064
+ for (let i = 0; i < AnnounceMargin; i++) if (!Break.test(text[i + 1]) && Break.test(text[i])) {
1065
+ text = text.slice(i);
1066
+ break;
1067
+ }
1068
+ }
1069
+ if (end != lineEnd) {
1070
+ for (let i = text.length - 1; i > text.length - AnnounceMargin; i--) if (!Break.test(text[i - 1]) && Break.test(text[i])) {
1071
+ text = text.slice(0, i);
1072
+ break;
1073
+ }
1074
+ }
1075
+ return EditorView.announce.of(`${view.state.phrase("current match")}. ${text} ${view.state.phrase("on line")} ${line.number}.`);
1076
+ }
1077
+ const baseTheme$3 = /* @__PURE__ */ EditorView.baseTheme({
1078
+ ".cm-panel.cm-search": {
1079
+ padding: "2px 6px 4px",
1080
+ position: "relative",
1081
+ "& [name=close]": {
1082
+ position: "absolute",
1083
+ top: "0",
1084
+ right: "4px",
1085
+ backgroundColor: "inherit",
1086
+ border: "none",
1087
+ font: "inherit",
1088
+ padding: 0,
1089
+ margin: 0
1090
+ },
1091
+ "& input, & button, & label": { margin: ".2em .6em .2em 0" },
1092
+ "& input[type=checkbox]": { marginRight: ".2em" },
1093
+ "& label": {
1094
+ fontSize: "80%",
1095
+ whiteSpace: "pre"
1096
+ }
1097
+ },
1098
+ "&light .cm-searchMatch": { backgroundColor: "#ffff0054" },
1099
+ "&dark .cm-searchMatch": { backgroundColor: "#00ffff8a" },
1100
+ "&light .cm-searchMatch-selected": { backgroundColor: "#ff6a0054" },
1101
+ "&dark .cm-searchMatch-selected": { backgroundColor: "#ff00ff8a" }
1102
+ });
1103
+ const searchExtensions = [
1104
+ searchState,
1105
+ /* @__PURE__ */ Prec.low(searchHighlighter),
1106
+ baseTheme$3
1107
+ ];
1108
+
1109
+ //#endregion
1110
+ //#region ../../node_modules/@codemirror/autocomplete/dist/index.js
1111
+ /**
1112
+ An instance of this is passed to completion source functions.
1113
+ */
1114
+ var CompletionContext = class {
1115
+ /**
1116
+ Create a new completion context. (Mostly useful for testing
1117
+ completion sources—in the editor, the extension will create
1118
+ these for you.)
1119
+ */
1120
+ constructor(state, pos, explicit, view) {
1121
+ this.state = state;
1122
+ this.pos = pos;
1123
+ this.explicit = explicit;
1124
+ this.view = view;
1125
+ /**
1126
+ @internal
1127
+ */
1128
+ this.abortListeners = [];
1129
+ /**
1130
+ @internal
1131
+ */
1132
+ this.abortOnDocChange = false;
1133
+ }
1134
+ /**
1135
+ Get the extent, content, and (if there is a token) type of the
1136
+ token before `this.pos`.
1137
+ */
1138
+ tokenBefore(types) {
1139
+ let token = syntaxTree(this.state).resolveInner(this.pos, -1);
1140
+ while (token && types.indexOf(token.name) < 0) token = token.parent;
1141
+ return token ? {
1142
+ from: token.from,
1143
+ to: this.pos,
1144
+ text: this.state.sliceDoc(token.from, this.pos),
1145
+ type: token.type
1146
+ } : null;
1147
+ }
1148
+ /**
1149
+ Get the match of the given expression directly before the
1150
+ cursor.
1151
+ */
1152
+ matchBefore(expr) {
1153
+ let line = this.state.doc.lineAt(this.pos);
1154
+ let start = Math.max(line.from, this.pos - 250);
1155
+ let str = line.text.slice(start - line.from, this.pos - line.from);
1156
+ let found = str.search(ensureAnchor(expr, false));
1157
+ return found < 0 ? null : {
1158
+ from: start + found,
1159
+ to: this.pos,
1160
+ text: str.slice(found)
1161
+ };
1162
+ }
1163
+ /**
1164
+ Yields true when the query has been aborted. Can be useful in
1165
+ asynchronous queries to avoid doing work that will be ignored.
1166
+ */
1167
+ get aborted() {
1168
+ return this.abortListeners == null;
1169
+ }
1170
+ /**
1171
+ Allows you to register abort handlers, which will be called when
1172
+ the query is
1173
+ [aborted](https://codemirror.net/6/docs/ref/#autocomplete.CompletionContext.aborted).
1174
+
1175
+ By default, running queries will not be aborted for regular
1176
+ typing or backspacing, on the assumption that they are likely to
1177
+ return a result with a
1178
+ [`validFor`](https://codemirror.net/6/docs/ref/#autocomplete.CompletionResult.validFor) field that
1179
+ allows the result to be used after all. Passing `onDocChange:
1180
+ true` will cause this query to be aborted for any document
1181
+ change.
1182
+ */
1183
+ addEventListener(type, listener, options) {
1184
+ if (type == "abort" && this.abortListeners) {
1185
+ this.abortListeners.push(listener);
1186
+ if (options && options.onDocChange) this.abortOnDocChange = true;
1187
+ }
1188
+ }
1189
+ };
1190
+ function toSet(chars) {
1191
+ let flat = Object.keys(chars).join("");
1192
+ let words = /\w/.test(flat);
1193
+ if (words) flat = flat.replace(/\w/g, "");
1194
+ return `[${words ? "\\w" : ""}${flat.replace(/[^\w\s]/g, "\\$&")}]`;
1195
+ }
1196
+ function prefixMatch(options) {
1197
+ let first = Object.create(null), rest = Object.create(null);
1198
+ for (let { label } of options) {
1199
+ first[label[0]] = true;
1200
+ for (let i = 1; i < label.length; i++) rest[label[i]] = true;
1201
+ }
1202
+ let source = toSet(first) + toSet(rest) + "*$";
1203
+ return [/* @__PURE__ */ new RegExp("^" + source), new RegExp(source)];
1204
+ }
1205
+ /**
1206
+ Given a a fixed array of options, return an autocompleter that
1207
+ completes them.
1208
+ */
1209
+ function completeFromList(list) {
1210
+ let options = list.map((o) => typeof o == "string" ? { label: o } : o);
1211
+ let [validFor, match] = options.every((o) => /^\w+$/.test(o.label)) ? [/\w*$/, /\w+$/] : prefixMatch(options);
1212
+ return (context) => {
1213
+ let token = context.matchBefore(match);
1214
+ return token || context.explicit ? {
1215
+ from: token ? token.from : context.pos,
1216
+ options,
1217
+ validFor
1218
+ } : null;
1219
+ };
1220
+ }
1221
+ var Option = class {
1222
+ constructor(completion, source, match, score$1) {
1223
+ this.completion = completion;
1224
+ this.source = source;
1225
+ this.match = match;
1226
+ this.score = score$1;
1227
+ }
1228
+ };
1229
+ function cur(state) {
1230
+ return state.selection.main.from;
1231
+ }
1232
+ function ensureAnchor(expr, start) {
1233
+ var _a;
1234
+ let { source } = expr;
1235
+ let addStart = start && source[0] != "^", addEnd = source[source.length - 1] != "$";
1236
+ if (!addStart && !addEnd) return expr;
1237
+ return new RegExp(`${addStart ? "^" : ""}(?:${source})${addEnd ? "$" : ""}`, (_a = expr.flags) !== null && _a !== void 0 ? _a : expr.ignoreCase ? "i" : "");
1238
+ }
1239
+ /**
1240
+ This annotation is added to transactions that are produced by
1241
+ picking a completion.
1242
+ */
1243
+ const pickedCompletion = /* @__PURE__ */ Annotation.define();
1244
+ /**
1245
+ Helper function that returns a transaction spec which inserts a
1246
+ completion's text in the main selection range, and any other
1247
+ selection range that has the same text in front of it.
1248
+ */
1249
+ function insertCompletionText(state, text, from, to) {
1250
+ let { main } = state.selection, fromOff = from - main.from, toOff = to - main.from;
1251
+ return Object.assign(Object.assign({}, state.changeByRange((range) => {
1252
+ if (range != main && from != to && state.sliceDoc(range.from + fromOff, range.from + toOff) != state.sliceDoc(from, to)) return { range };
1253
+ let lines = state.toText(text);
1254
+ return {
1255
+ changes: {
1256
+ from: range.from + fromOff,
1257
+ to: to == main.from ? range.to : range.from + toOff,
1258
+ insert: lines
1259
+ },
1260
+ range: EditorSelection.cursor(range.from + fromOff + lines.length)
1261
+ };
1262
+ })), {
1263
+ scrollIntoView: true,
1264
+ userEvent: "input.complete"
1265
+ });
1266
+ }
1267
+ const SourceCache = /* @__PURE__ */ new WeakMap();
1268
+ function asSource(source) {
1269
+ if (!Array.isArray(source)) return source;
1270
+ let known = SourceCache.get(source);
1271
+ if (!known) SourceCache.set(source, known = completeFromList(source));
1272
+ return known;
1273
+ }
1274
+ const startCompletionEffect = /* @__PURE__ */ StateEffect.define();
1275
+ const closeCompletionEffect = /* @__PURE__ */ StateEffect.define();
1276
+ var FuzzyMatcher = class {
1277
+ constructor(pattern) {
1278
+ this.pattern = pattern;
1279
+ this.chars = [];
1280
+ this.folded = [];
1281
+ this.any = [];
1282
+ this.precise = [];
1283
+ this.byWord = [];
1284
+ this.score = 0;
1285
+ this.matched = [];
1286
+ for (let p = 0; p < pattern.length;) {
1287
+ let char = codePointAt(pattern, p), size = codePointSize(char);
1288
+ this.chars.push(char);
1289
+ let part = pattern.slice(p, p + size), upper = part.toUpperCase();
1290
+ this.folded.push(codePointAt(upper == part ? part.toLowerCase() : upper, 0));
1291
+ p += size;
1292
+ }
1293
+ this.astral = pattern.length != this.chars.length;
1294
+ }
1295
+ ret(score$1, matched) {
1296
+ this.score = score$1;
1297
+ this.matched = matched;
1298
+ return this;
1299
+ }
1300
+ match(word) {
1301
+ if (this.pattern.length == 0) return this.ret(-100, []);
1302
+ if (word.length < this.pattern.length) return null;
1303
+ let { chars, folded, any, precise, byWord } = this;
1304
+ if (chars.length == 1) {
1305
+ let first = codePointAt(word, 0), firstSize = codePointSize(first);
1306
+ let score$1 = firstSize == word.length ? 0 : -100;
1307
+ if (first == chars[0]);
1308
+ else if (first == folded[0]) score$1 += -200;
1309
+ else return null;
1310
+ return this.ret(score$1, [0, firstSize]);
1311
+ }
1312
+ let direct = word.indexOf(this.pattern);
1313
+ if (direct == 0) return this.ret(word.length == this.pattern.length ? 0 : -100, [0, this.pattern.length]);
1314
+ let len = chars.length, anyTo = 0;
1315
+ if (direct < 0) {
1316
+ for (let i = 0, e = Math.min(word.length, 200); i < e && anyTo < len;) {
1317
+ let next = codePointAt(word, i);
1318
+ if (next == chars[anyTo] || next == folded[anyTo]) any[anyTo++] = i;
1319
+ i += codePointSize(next);
1320
+ }
1321
+ if (anyTo < len) return null;
1322
+ }
1323
+ let preciseTo = 0;
1324
+ let byWordTo = 0, byWordFolded = false;
1325
+ let adjacentTo = 0, adjacentStart = -1, adjacentEnd = -1;
1326
+ let hasLower = /[a-z]/.test(word), wordAdjacent = true;
1327
+ for (let i = 0, e = Math.min(word.length, 200), prevType = 0; i < e && byWordTo < len;) {
1328
+ let next = codePointAt(word, i);
1329
+ if (direct < 0) {
1330
+ if (preciseTo < len && next == chars[preciseTo]) precise[preciseTo++] = i;
1331
+ if (adjacentTo < len) if (next == chars[adjacentTo] || next == folded[adjacentTo]) {
1332
+ if (adjacentTo == 0) adjacentStart = i;
1333
+ adjacentEnd = i + 1;
1334
+ adjacentTo++;
1335
+ } else adjacentTo = 0;
1336
+ }
1337
+ 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;
1338
+ if (!i || type == 1 && hasLower || prevType == 0 && type != 0) {
1339
+ if (chars[byWordTo] == next || folded[byWordTo] == next && (byWordFolded = true)) byWord[byWordTo++] = i;
1340
+ else if (byWord.length) wordAdjacent = false;
1341
+ }
1342
+ prevType = type;
1343
+ i += codePointSize(next);
1344
+ }
1345
+ if (byWordTo == len && byWord[0] == 0 && wordAdjacent) return this.result(-100 + (byWordFolded ? -200 : 0), byWord, word);
1346
+ if (adjacentTo == len && adjacentStart == 0) return this.ret(-200 - word.length + (adjacentEnd == word.length ? 0 : -100), [0, adjacentEnd]);
1347
+ if (direct > -1) return this.ret(-700 - word.length, [direct, direct + this.pattern.length]);
1348
+ if (adjacentTo == len) return this.ret(-900 - word.length, [adjacentStart, adjacentEnd]);
1349
+ if (byWordTo == len) return this.result(-100 + (byWordFolded ? -200 : 0) + -700 + (wordAdjacent ? 0 : -1100), byWord, word);
1350
+ return chars.length == 2 ? null : this.result((any[0] ? -700 : 0) + -200 + -1100, any, word);
1351
+ }
1352
+ result(score$1, positions, word) {
1353
+ let result = [], i = 0;
1354
+ for (let pos of positions) {
1355
+ let to = pos + (this.astral ? codePointSize(codePointAt(word, pos)) : 1);
1356
+ if (i && result[i - 1] == pos) result[i - 1] = to;
1357
+ else {
1358
+ result[i++] = pos;
1359
+ result[i++] = to;
1360
+ }
1361
+ }
1362
+ return this.ret(score$1 - word.length, result);
1363
+ }
1364
+ };
1365
+ var StrictMatcher = class {
1366
+ constructor(pattern) {
1367
+ this.pattern = pattern;
1368
+ this.matched = [];
1369
+ this.score = 0;
1370
+ this.folded = pattern.toLowerCase();
1371
+ }
1372
+ match(word) {
1373
+ if (word.length < this.pattern.length) return null;
1374
+ let start = word.slice(0, this.pattern.length);
1375
+ let match = start == this.pattern ? 0 : start.toLowerCase() == this.folded ? -200 : null;
1376
+ if (match == null) return null;
1377
+ this.matched = [0, start.length];
1378
+ this.score = match + (word.length == this.pattern.length ? 0 : -100);
1379
+ return this;
1380
+ }
1381
+ };
1382
+ const completionConfig = /* @__PURE__ */ Facet.define({ combine(configs) {
1383
+ return combineConfig(configs, {
1384
+ activateOnTyping: true,
1385
+ activateOnCompletion: () => false,
1386
+ activateOnTypingDelay: 100,
1387
+ selectOnOpen: true,
1388
+ override: null,
1389
+ closeOnBlur: true,
1390
+ maxRenderedOptions: 100,
1391
+ defaultKeymap: true,
1392
+ tooltipClass: () => "",
1393
+ optionClass: () => "",
1394
+ aboveCursor: false,
1395
+ icons: true,
1396
+ addToOptions: [],
1397
+ positionInfo: defaultPositionInfo,
1398
+ filterStrict: false,
1399
+ compareCompletions: (a, b) => a.label.localeCompare(b.label),
1400
+ interactionDelay: 75,
1401
+ updateSyncTime: 100
1402
+ }, {
1403
+ defaultKeymap: (a, b) => a && b,
1404
+ closeOnBlur: (a, b) => a && b,
1405
+ icons: (a, b) => a && b,
1406
+ tooltipClass: (a, b) => (c) => joinClass(a(c), b(c)),
1407
+ optionClass: (a, b) => (c) => joinClass(a(c), b(c)),
1408
+ addToOptions: (a, b) => a.concat(b),
1409
+ filterStrict: (a, b) => a || b
1410
+ });
1411
+ } });
1412
+ function joinClass(a, b) {
1413
+ return a ? b ? a + " " + b : a : b;
1414
+ }
1415
+ function defaultPositionInfo(view, list, option, info, space, tooltip) {
1416
+ let rtl = view.textDirection == Direction.RTL, left = rtl, narrow = false;
1417
+ let side = "top", offset, maxWidth;
1418
+ let spaceLeft = list.left - space.left, spaceRight = space.right - list.right;
1419
+ let infoWidth = info.right - info.left, infoHeight = info.bottom - info.top;
1420
+ if (left && spaceLeft < Math.min(infoWidth, spaceRight)) left = false;
1421
+ else if (!left && spaceRight < Math.min(infoWidth, spaceLeft)) left = true;
1422
+ if (infoWidth <= (left ? spaceLeft : spaceRight)) {
1423
+ offset = Math.max(space.top, Math.min(option.top, space.bottom - infoHeight)) - list.top;
1424
+ maxWidth = Math.min(400, left ? spaceLeft : spaceRight);
1425
+ } else {
1426
+ narrow = true;
1427
+ maxWidth = Math.min(400, (rtl ? list.right : space.right - list.left) - 30);
1428
+ let spaceBelow = space.bottom - list.bottom;
1429
+ if (spaceBelow >= infoHeight || spaceBelow > list.top) offset = option.bottom - list.top;
1430
+ else {
1431
+ side = "bottom";
1432
+ offset = list.bottom - option.top;
1433
+ }
1434
+ }
1435
+ let scaleY = (list.bottom - list.top) / tooltip.offsetHeight;
1436
+ let scaleX = (list.right - list.left) / tooltip.offsetWidth;
1437
+ return {
1438
+ style: `${side}: ${offset / scaleY}px; max-width: ${maxWidth / scaleX}px`,
1439
+ class: "cm-completionInfo-" + (narrow ? rtl ? "left-narrow" : "right-narrow" : left ? "left" : "right")
1440
+ };
1441
+ }
1442
+ function optionContent(config$1) {
1443
+ let content = config$1.addToOptions.slice();
1444
+ if (config$1.icons) content.push({
1445
+ render(completion) {
1446
+ let icon = document.createElement("div");
1447
+ icon.classList.add("cm-completionIcon");
1448
+ if (completion.type) icon.classList.add(...completion.type.split(/\s+/g).map((cls) => "cm-completionIcon-" + cls));
1449
+ icon.setAttribute("aria-hidden", "true");
1450
+ return icon;
1451
+ },
1452
+ position: 20
1453
+ });
1454
+ content.push({
1455
+ render(completion, _s, _v, match) {
1456
+ let labelElt = document.createElement("span");
1457
+ labelElt.className = "cm-completionLabel";
1458
+ let label = completion.displayLabel || completion.label, off = 0;
1459
+ for (let j = 0; j < match.length;) {
1460
+ let from = match[j++], to = match[j++];
1461
+ if (from > off) labelElt.appendChild(document.createTextNode(label.slice(off, from)));
1462
+ let span = labelElt.appendChild(document.createElement("span"));
1463
+ span.appendChild(document.createTextNode(label.slice(from, to)));
1464
+ span.className = "cm-completionMatchedText";
1465
+ off = to;
1466
+ }
1467
+ if (off < label.length) labelElt.appendChild(document.createTextNode(label.slice(off)));
1468
+ return labelElt;
1469
+ },
1470
+ position: 50
1471
+ }, {
1472
+ render(completion) {
1473
+ if (!completion.detail) return null;
1474
+ let detailElt = document.createElement("span");
1475
+ detailElt.className = "cm-completionDetail";
1476
+ detailElt.textContent = completion.detail;
1477
+ return detailElt;
1478
+ },
1479
+ position: 80
1480
+ });
1481
+ return content.sort((a, b) => a.position - b.position).map((a) => a.render);
1482
+ }
1483
+ function rangeAroundSelected(total, selected, max) {
1484
+ if (total <= max) return {
1485
+ from: 0,
1486
+ to: total
1487
+ };
1488
+ if (selected < 0) selected = 0;
1489
+ if (selected <= total >> 1) {
1490
+ let off$1 = Math.floor(selected / max);
1491
+ return {
1492
+ from: off$1 * max,
1493
+ to: (off$1 + 1) * max
1494
+ };
1495
+ }
1496
+ let off = Math.floor((total - selected) / max);
1497
+ return {
1498
+ from: total - (off + 1) * max,
1499
+ to: total - off * max
1500
+ };
1501
+ }
1502
+ var CompletionTooltip = class {
1503
+ constructor(view, stateField, applyCompletion$1) {
1504
+ this.view = view;
1505
+ this.stateField = stateField;
1506
+ this.applyCompletion = applyCompletion$1;
1507
+ this.info = null;
1508
+ this.infoDestroy = null;
1509
+ this.placeInfoReq = {
1510
+ read: () => this.measureInfo(),
1511
+ write: (pos) => this.placeInfo(pos),
1512
+ key: this
1513
+ };
1514
+ this.space = null;
1515
+ this.currentClass = "";
1516
+ let cState = view.state.field(stateField);
1517
+ let { options, selected } = cState.open;
1518
+ let config$1 = view.state.facet(completionConfig);
1519
+ this.optionContent = optionContent(config$1);
1520
+ this.optionClass = config$1.optionClass;
1521
+ this.tooltipClass = config$1.tooltipClass;
1522
+ this.range = rangeAroundSelected(options.length, selected, config$1.maxRenderedOptions);
1523
+ this.dom = document.createElement("div");
1524
+ this.dom.className = "cm-tooltip-autocomplete";
1525
+ this.updateTooltipClass(view.state);
1526
+ this.dom.addEventListener("mousedown", (e) => {
1527
+ let { options: options$1 } = view.state.field(stateField).open;
1528
+ 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$1.length) {
1529
+ this.applyCompletion(view, options$1[+match[1]]);
1530
+ e.preventDefault();
1531
+ return;
1532
+ }
1533
+ });
1534
+ this.dom.addEventListener("focusout", (e) => {
1535
+ let state = view.state.field(this.stateField, false);
1536
+ if (state && state.tooltip && view.state.facet(completionConfig).closeOnBlur && e.relatedTarget != view.contentDOM) view.dispatch({ effects: closeCompletionEffect.of(null) });
1537
+ });
1538
+ this.showOptions(options, cState.id);
1539
+ }
1540
+ mount() {
1541
+ this.updateSel();
1542
+ }
1543
+ showOptions(options, id) {
1544
+ if (this.list) this.list.remove();
1545
+ this.list = this.dom.appendChild(this.createListBox(options, id, this.range));
1546
+ this.list.addEventListener("scroll", () => {
1547
+ if (this.info) this.view.requestMeasure(this.placeInfoReq);
1548
+ });
1549
+ }
1550
+ update(update) {
1551
+ var _a;
1552
+ let cState = update.state.field(this.stateField);
1553
+ let prevState = update.startState.field(this.stateField);
1554
+ this.updateTooltipClass(update.state);
1555
+ if (cState != prevState) {
1556
+ let { options, selected, disabled } = cState.open;
1557
+ if (!prevState.open || prevState.open.options != options) {
1558
+ this.range = rangeAroundSelected(options.length, selected, update.state.facet(completionConfig).maxRenderedOptions);
1559
+ this.showOptions(options, cState.id);
1560
+ }
1561
+ this.updateSel();
1562
+ if (disabled != ((_a = prevState.open) === null || _a === void 0 ? void 0 : _a.disabled)) this.dom.classList.toggle("cm-tooltip-autocomplete-disabled", !!disabled);
1563
+ }
1564
+ }
1565
+ updateTooltipClass(state) {
1566
+ let cls = this.tooltipClass(state);
1567
+ if (cls != this.currentClass) {
1568
+ for (let c of this.currentClass.split(" ")) if (c) this.dom.classList.remove(c);
1569
+ for (let c of cls.split(" ")) if (c) this.dom.classList.add(c);
1570
+ this.currentClass = cls;
1571
+ }
1572
+ }
1573
+ positioned(space) {
1574
+ this.space = space;
1575
+ if (this.info) this.view.requestMeasure(this.placeInfoReq);
1576
+ }
1577
+ updateSel() {
1578
+ let cState = this.view.state.field(this.stateField), open = cState.open;
1579
+ if (open.selected > -1 && open.selected < this.range.from || open.selected >= this.range.to) {
1580
+ this.range = rangeAroundSelected(open.options.length, open.selected, this.view.state.facet(completionConfig).maxRenderedOptions);
1581
+ this.showOptions(open.options, cState.id);
1582
+ }
1583
+ if (this.updateSelectedOption(open.selected)) {
1584
+ this.destroyInfo();
1585
+ let { completion } = open.options[open.selected];
1586
+ let { info } = completion;
1587
+ if (!info) return;
1588
+ let infoResult = typeof info === "string" ? document.createTextNode(info) : info(completion);
1589
+ if (!infoResult) return;
1590
+ if ("then" in infoResult) infoResult.then((obj) => {
1591
+ if (obj && this.view.state.field(this.stateField, false) == cState) this.addInfoPane(obj, completion);
1592
+ }).catch((e) => logException(this.view.state, e, "completion info"));
1593
+ else this.addInfoPane(infoResult, completion);
1594
+ }
1595
+ }
1596
+ addInfoPane(content, completion) {
1597
+ this.destroyInfo();
1598
+ let wrap = this.info = document.createElement("div");
1599
+ wrap.className = "cm-tooltip cm-completionInfo";
1600
+ if (content.nodeType != null) {
1601
+ wrap.appendChild(content);
1602
+ this.infoDestroy = null;
1603
+ } else {
1604
+ let { dom, destroy } = content;
1605
+ wrap.appendChild(dom);
1606
+ this.infoDestroy = destroy || null;
1607
+ }
1608
+ this.dom.appendChild(wrap);
1609
+ this.view.requestMeasure(this.placeInfoReq);
1610
+ }
1611
+ updateSelectedOption(selected) {
1612
+ let set = null;
1613
+ for (let opt = this.list.firstChild, i = this.range.from; opt; opt = opt.nextSibling, i++) if (opt.nodeName != "LI" || !opt.id) i--;
1614
+ else if (i == selected) {
1615
+ if (!opt.hasAttribute("aria-selected")) {
1616
+ opt.setAttribute("aria-selected", "true");
1617
+ set = opt;
1618
+ }
1619
+ } else if (opt.hasAttribute("aria-selected")) opt.removeAttribute("aria-selected");
1620
+ if (set) scrollIntoView(this.list, set);
1621
+ return set;
1622
+ }
1623
+ measureInfo() {
1624
+ let sel = this.dom.querySelector("[aria-selected]");
1625
+ if (!sel || !this.info) return null;
1626
+ let listRect = this.dom.getBoundingClientRect();
1627
+ let infoRect = this.info.getBoundingClientRect();
1628
+ let selRect = sel.getBoundingClientRect();
1629
+ let space = this.space;
1630
+ if (!space) {
1631
+ let docElt = this.dom.ownerDocument.documentElement;
1632
+ space = {
1633
+ left: 0,
1634
+ top: 0,
1635
+ right: docElt.clientWidth,
1636
+ bottom: docElt.clientHeight
1637
+ };
1638
+ }
1639
+ if (selRect.top > Math.min(space.bottom, listRect.bottom) - 10 || selRect.bottom < Math.max(space.top, listRect.top) + 10) return null;
1640
+ return this.view.state.facet(completionConfig).positionInfo(this.view, listRect, selRect, infoRect, space, this.dom);
1641
+ }
1642
+ placeInfo(pos) {
1643
+ if (this.info) if (pos) {
1644
+ if (pos.style) this.info.style.cssText = pos.style;
1645
+ this.info.className = "cm-tooltip cm-completionInfo " + (pos.class || "");
1646
+ } else this.info.style.cssText = "top: -1e6px";
1647
+ }
1648
+ createListBox(options, id, range) {
1649
+ const ul = document.createElement("ul");
1650
+ ul.id = id;
1651
+ ul.setAttribute("role", "listbox");
1652
+ ul.setAttribute("aria-expanded", "true");
1653
+ ul.setAttribute("aria-label", this.view.state.phrase("Completions"));
1654
+ ul.addEventListener("mousedown", (e) => {
1655
+ if (e.target == ul) e.preventDefault();
1656
+ });
1657
+ let curSection = null;
1658
+ for (let i = range.from; i < range.to; i++) {
1659
+ let { completion, match } = options[i], { section } = completion;
1660
+ if (section) {
1661
+ let name = typeof section == "string" ? section : section.name;
1662
+ if (name != curSection && (i > range.from || range.from == 0)) {
1663
+ curSection = name;
1664
+ if (typeof section != "string" && section.header) ul.appendChild(section.header(section));
1665
+ else {
1666
+ let header = ul.appendChild(document.createElement("completion-section"));
1667
+ header.textContent = name;
1668
+ }
1669
+ }
1670
+ }
1671
+ const li = ul.appendChild(document.createElement("li"));
1672
+ li.id = id + "-" + i;
1673
+ li.setAttribute("role", "option");
1674
+ let cls = this.optionClass(completion);
1675
+ if (cls) li.className = cls;
1676
+ for (let source of this.optionContent) {
1677
+ let node = source(completion, this.view.state, this.view, match);
1678
+ if (node) li.appendChild(node);
1679
+ }
1680
+ }
1681
+ if (range.from) ul.classList.add("cm-completionListIncompleteTop");
1682
+ if (range.to < options.length) ul.classList.add("cm-completionListIncompleteBottom");
1683
+ return ul;
1684
+ }
1685
+ destroyInfo() {
1686
+ if (this.info) {
1687
+ if (this.infoDestroy) this.infoDestroy();
1688
+ this.info.remove();
1689
+ this.info = null;
1690
+ }
1691
+ }
1692
+ destroy() {
1693
+ this.destroyInfo();
1694
+ }
1695
+ };
1696
+ function completionTooltip(stateField, applyCompletion$1) {
1697
+ return (view) => new CompletionTooltip(view, stateField, applyCompletion$1);
1698
+ }
1699
+ function scrollIntoView(container, element) {
1700
+ let parent = container.getBoundingClientRect();
1701
+ let self = element.getBoundingClientRect();
1702
+ let scaleY = parent.height / container.offsetHeight;
1703
+ if (self.top < parent.top) container.scrollTop -= (parent.top - self.top) / scaleY;
1704
+ else if (self.bottom > parent.bottom) container.scrollTop += (self.bottom - parent.bottom) / scaleY;
1705
+ }
1706
+ function score(option) {
1707
+ return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0);
1708
+ }
1709
+ function sortOptions(active, state) {
1710
+ let options = [];
1711
+ let sections = null;
1712
+ let addOption = (option) => {
1713
+ options.push(option);
1714
+ let { section } = option.completion;
1715
+ if (section) {
1716
+ if (!sections) sections = [];
1717
+ let name = typeof section == "string" ? section : section.name;
1718
+ if (!sections.some((s) => s.name == name)) sections.push(typeof section == "string" ? { name } : section);
1719
+ }
1720
+ };
1721
+ let conf = state.facet(completionConfig);
1722
+ for (let a of active) if (a.hasResult()) {
1723
+ let getMatch = a.result.getMatch;
1724
+ if (a.result.filter === false) for (let option of a.result.options) addOption(new Option(option, a.source, getMatch ? getMatch(option) : [], 1e9 - options.length));
1725
+ else {
1726
+ let pattern = state.sliceDoc(a.from, a.to), match;
1727
+ let matcher = conf.filterStrict ? new StrictMatcher(pattern) : new FuzzyMatcher(pattern);
1728
+ for (let option of a.result.options) if (match = matcher.match(option.label)) {
1729
+ let matched = !option.displayLabel ? match.matched : getMatch ? getMatch(option, match.matched) : [];
1730
+ addOption(new Option(option, a.source, matched, match.score + (option.boost || 0)));
1731
+ }
1732
+ }
1733
+ }
1734
+ if (sections) {
1735
+ let sectionOrder = Object.create(null), pos = 0;
1736
+ let cmp = (a, b) => {
1737
+ var _a, _b;
1738
+ 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);
1739
+ };
1740
+ for (let s of sections.sort(cmp)) {
1741
+ pos -= 1e5;
1742
+ sectionOrder[s.name] = pos;
1743
+ }
1744
+ for (let option of options) {
1745
+ let { section } = option.completion;
1746
+ if (section) option.score += sectionOrder[typeof section == "string" ? section : section.name];
1747
+ }
1748
+ }
1749
+ let result = [], prev = null;
1750
+ let compare = conf.compareCompletions;
1751
+ for (let opt of options.sort((a, b) => b.score - a.score || compare(a.completion, b.completion))) {
1752
+ let cur$1 = opt.completion;
1753
+ if (!prev || prev.label != cur$1.label || prev.detail != cur$1.detail || prev.type != null && cur$1.type != null && prev.type != cur$1.type || prev.apply != cur$1.apply || prev.boost != cur$1.boost) result.push(opt);
1754
+ else if (score(opt.completion) > score(prev)) result[result.length - 1] = opt;
1755
+ prev = opt.completion;
1756
+ }
1757
+ return result;
1758
+ }
1759
+ var CompletionDialog = class CompletionDialog {
1760
+ constructor(options, attrs, tooltip, timestamp, selected, disabled) {
1761
+ this.options = options;
1762
+ this.attrs = attrs;
1763
+ this.tooltip = tooltip;
1764
+ this.timestamp = timestamp;
1765
+ this.selected = selected;
1766
+ this.disabled = disabled;
1767
+ }
1768
+ setSelected(selected, id) {
1769
+ return selected == this.selected || selected >= this.options.length ? this : new CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
1770
+ }
1771
+ static build(active, state, id, prev, conf, didSetActive) {
1772
+ if (prev && !didSetActive && active.some((s) => s.isPending)) return prev.setDisabled();
1773
+ let options = sortOptions(active, state);
1774
+ if (!options.length) return prev && active.some((a) => a.isPending) ? prev.setDisabled() : null;
1775
+ let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
1776
+ if (prev && prev.selected != selected && prev.selected != -1) {
1777
+ let selectedValue = prev.options[prev.selected].completion;
1778
+ for (let i = 0; i < options.length; i++) if (options[i].completion == selectedValue) {
1779
+ selected = i;
1780
+ break;
1781
+ }
1782
+ }
1783
+ return new CompletionDialog(options, makeAttrs(id, selected), {
1784
+ pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
1785
+ create: createTooltip,
1786
+ above: conf.aboveCursor
1787
+ }, prev ? prev.timestamp : Date.now(), selected, false);
1788
+ }
1789
+ map(changes) {
1790
+ 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);
1791
+ }
1792
+ setDisabled() {
1793
+ return new CompletionDialog(this.options, this.attrs, this.tooltip, this.timestamp, this.selected, true);
1794
+ }
1795
+ };
1796
+ var CompletionState = class CompletionState {
1797
+ constructor(active, id, open) {
1798
+ this.active = active;
1799
+ this.id = id;
1800
+ this.open = open;
1801
+ }
1802
+ static start() {
1803
+ return new CompletionState(none, "cm-ac-" + Math.floor(Math.random() * 2e6).toString(36), null);
1804
+ }
1805
+ update(tr) {
1806
+ let { state } = tr, conf = state.facet(completionConfig);
1807
+ let active = (conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource)).map((source) => {
1808
+ return (this.active.find((s) => s.source == source) || new ActiveSource(source, this.active.some((a) => a.state != 0) ? 1 : 0)).update(tr, conf);
1809
+ });
1810
+ if (active.length == this.active.length && active.every((a, i) => a == this.active[i])) active = this.active;
1811
+ let open = this.open, didSet = tr.effects.some((e) => e.is(setActiveEffect));
1812
+ if (open && tr.docChanged) open = open.map(tr.changes);
1813
+ if (tr.selection || active.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active, this.active) || didSet) open = CompletionDialog.build(active, state, this.id, open, conf, didSet);
1814
+ else if (open && open.disabled && !active.some((a) => a.isPending)) open = null;
1815
+ if (!open && active.every((a) => !a.isPending) && active.some((a) => a.hasResult())) active = active.map((a) => a.hasResult() ? new ActiveSource(a.source, 0) : a);
1816
+ for (let effect of tr.effects) if (effect.is(setSelectedEffect)) open = open && open.setSelected(effect.value, this.id);
1817
+ return active == this.active && open == this.open ? this : new CompletionState(active, this.id, open);
1818
+ }
1819
+ get tooltip() {
1820
+ return this.open ? this.open.tooltip : null;
1821
+ }
1822
+ get attrs() {
1823
+ return this.open ? this.open.attrs : this.active.length ? baseAttrs : noAttrs;
1824
+ }
1825
+ };
1826
+ function sameResults(a, b) {
1827
+ if (a == b) return true;
1828
+ for (let iA = 0, iB = 0;;) {
1829
+ while (iA < a.length && !a[iA].hasResult()) iA++;
1830
+ while (iB < b.length && !b[iB].hasResult()) iB++;
1831
+ let endA = iA == a.length, endB = iB == b.length;
1832
+ if (endA || endB) return endA == endB;
1833
+ if (a[iA++].result != b[iB++].result) return false;
1834
+ }
1835
+ }
1836
+ const baseAttrs = { "aria-autocomplete": "list" };
1837
+ const noAttrs = {};
1838
+ function makeAttrs(id, selected) {
1839
+ let result = {
1840
+ "aria-autocomplete": "list",
1841
+ "aria-haspopup": "listbox",
1842
+ "aria-controls": id
1843
+ };
1844
+ if (selected > -1) result["aria-activedescendant"] = id + "-" + selected;
1845
+ return result;
1846
+ }
1847
+ const none = [];
1848
+ function getUpdateType(tr, conf) {
1849
+ if (tr.isUserEvent("input.complete")) {
1850
+ let completion = tr.annotation(pickedCompletion);
1851
+ if (completion && conf.activateOnCompletion(completion)) return 12;
1852
+ }
1853
+ let typing = tr.isUserEvent("input.type");
1854
+ return typing && conf.activateOnTyping ? 5 : typing ? 1 : tr.isUserEvent("delete.backward") ? 2 : tr.selection ? 8 : tr.docChanged ? 16 : 0;
1855
+ }
1856
+ var ActiveSource = class ActiveSource {
1857
+ constructor(source, state, explicit = false) {
1858
+ this.source = source;
1859
+ this.state = state;
1860
+ this.explicit = explicit;
1861
+ }
1862
+ hasResult() {
1863
+ return false;
1864
+ }
1865
+ get isPending() {
1866
+ return this.state == 1;
1867
+ }
1868
+ update(tr, conf) {
1869
+ let type = getUpdateType(tr, conf), value = this;
1870
+ if (type & 8 || type & 16 && this.touches(tr)) value = new ActiveSource(value.source, 0);
1871
+ if (type & 4 && value.state == 0) value = new ActiveSource(this.source, 1);
1872
+ value = value.updateFor(tr, type);
1873
+ for (let effect of tr.effects) if (effect.is(startCompletionEffect)) value = new ActiveSource(value.source, 1, effect.value);
1874
+ else if (effect.is(closeCompletionEffect)) value = new ActiveSource(value.source, 0);
1875
+ else if (effect.is(setActiveEffect)) {
1876
+ for (let active of effect.value) if (active.source == value.source) value = active;
1877
+ }
1878
+ return value;
1879
+ }
1880
+ updateFor(tr, type) {
1881
+ return this.map(tr.changes);
1882
+ }
1883
+ map(changes) {
1884
+ return this;
1885
+ }
1886
+ touches(tr) {
1887
+ return tr.changes.touchesRange(cur(tr.state));
1888
+ }
1889
+ };
1890
+ var ActiveResult = class ActiveResult extends ActiveSource {
1891
+ constructor(source, explicit, limit, result, from, to) {
1892
+ super(source, 3, explicit);
1893
+ this.limit = limit;
1894
+ this.result = result;
1895
+ this.from = from;
1896
+ this.to = to;
1897
+ }
1898
+ hasResult() {
1899
+ return true;
1900
+ }
1901
+ updateFor(tr, type) {
1902
+ var _a;
1903
+ if (!(type & 3)) return this.map(tr.changes);
1904
+ let result = this.result;
1905
+ if (result.map && !tr.changes.empty) result = result.map(result, tr.changes);
1906
+ let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1);
1907
+ let pos = cur(tr.state);
1908
+ if (pos > to || !result || type & 2 && (cur(tr.startState) == this.from || pos < this.limit)) return new ActiveSource(this.source, type & 4 ? 1 : 0);
1909
+ let limit = tr.changes.mapPos(this.limit);
1910
+ if (checkValid(result.validFor, tr.state, from, to)) return new ActiveResult(this.source, this.explicit, limit, result, from, to);
1911
+ if (result.update && (result = result.update(result, from, to, new CompletionContext(tr.state, pos, false)))) return new ActiveResult(this.source, this.explicit, limit, result, result.from, (_a = result.to) !== null && _a !== void 0 ? _a : cur(tr.state));
1912
+ return new ActiveSource(this.source, 1, this.explicit);
1913
+ }
1914
+ map(mapping) {
1915
+ if (mapping.empty) return this;
1916
+ if (!(this.result.map ? this.result.map(this.result, mapping) : this.result)) return new ActiveSource(this.source, 0);
1917
+ return new ActiveResult(this.source, this.explicit, mapping.mapPos(this.limit), this.result, mapping.mapPos(this.from), mapping.mapPos(this.to, 1));
1918
+ }
1919
+ touches(tr) {
1920
+ return tr.changes.touchesRange(this.from, this.to);
1921
+ }
1922
+ };
1923
+ function checkValid(validFor, state, from, to) {
1924
+ if (!validFor) return false;
1925
+ let text = state.sliceDoc(from, to);
1926
+ return typeof validFor == "function" ? validFor(text, from, to, state) : ensureAnchor(validFor, true).test(text);
1927
+ }
1928
+ const setActiveEffect = /* @__PURE__ */ StateEffect.define({ map(sources, mapping) {
1929
+ return sources.map((s) => s.map(mapping));
1930
+ } });
1931
+ const setSelectedEffect = /* @__PURE__ */ StateEffect.define();
1932
+ const completionState = /* @__PURE__ */ StateField.define({
1933
+ create() {
1934
+ return CompletionState.start();
1935
+ },
1936
+ update(value, tr) {
1937
+ return value.update(tr);
1938
+ },
1939
+ provide: (f) => [showTooltip.from(f, (val) => val.tooltip), EditorView.contentAttributes.from(f, (state) => state.attrs)]
1940
+ });
1941
+ function applyCompletion(view, option) {
1942
+ const apply = option.completion.apply || option.completion.label;
1943
+ let result = view.state.field(completionState).active.find((a) => a.source == option.source);
1944
+ if (!(result instanceof ActiveResult)) return false;
1945
+ if (typeof apply == "string") view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, apply, result.from, result.to)), { annotations: pickedCompletion.of(option.completion) }));
1946
+ else apply(view, option.completion, result.from, result.to);
1947
+ return true;
1948
+ }
1949
+ const createTooltip = /* @__PURE__ */ completionTooltip(completionState, applyCompletion);
1950
+ /**
1951
+ Returns a command that moves the completion selection forward or
1952
+ backward by the given amount.
1953
+ */
1954
+ function moveCompletionSelection(forward, by = "option") {
1955
+ return (view) => {
1956
+ let cState = view.state.field(completionState, false);
1957
+ if (!cState || !cState.open || cState.open.disabled || Date.now() - cState.open.timestamp < view.state.facet(completionConfig).interactionDelay) return false;
1958
+ let step = 1, tooltip;
1959
+ if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip))) step = Math.max(2, Math.floor(tooltip.dom.offsetHeight / tooltip.dom.querySelector("li").offsetHeight) - 1);
1960
+ let { length } = cState.open.options;
1961
+ let selected = cState.open.selected > -1 ? cState.open.selected + step * (forward ? 1 : -1) : forward ? 0 : length - 1;
1962
+ if (selected < 0) selected = by == "page" ? 0 : length - 1;
1963
+ else if (selected >= length) selected = by == "page" ? length - 1 : 0;
1964
+ view.dispatch({ effects: setSelectedEffect.of(selected) });
1965
+ return true;
1966
+ };
1967
+ }
1968
+ /**
1969
+ Accept the current completion.
1970
+ */
1971
+ const acceptCompletion = (view) => {
1972
+ let cState = view.state.field(completionState, false);
1973
+ 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;
1974
+ return applyCompletion(view, cState.open.options[cState.open.selected]);
1975
+ };
1976
+ /**
1977
+ Explicitly start autocompletion.
1978
+ */
1979
+ const startCompletion = (view) => {
1980
+ if (!view.state.field(completionState, false)) return false;
1981
+ view.dispatch({ effects: startCompletionEffect.of(true) });
1982
+ return true;
1983
+ };
1984
+ /**
1985
+ Close the currently active completion.
1986
+ */
1987
+ const closeCompletion = (view) => {
1988
+ let cState = view.state.field(completionState, false);
1989
+ if (!cState || !cState.active.some((a) => a.state != 0)) return false;
1990
+ view.dispatch({ effects: closeCompletionEffect.of(null) });
1991
+ return true;
1992
+ };
1993
+ var RunningQuery = class {
1994
+ constructor(active, context) {
1995
+ this.active = active;
1996
+ this.context = context;
1997
+ this.time = Date.now();
1998
+ this.updates = [];
1999
+ this.done = void 0;
2000
+ }
2001
+ };
2002
+ const MaxUpdateCount = 50, MinAbortTime = 1e3;
2003
+ const completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
2004
+ constructor(view) {
2005
+ this.view = view;
2006
+ this.debounceUpdate = -1;
2007
+ this.running = [];
2008
+ this.debounceAccept = -1;
2009
+ this.pendingStart = false;
2010
+ this.composing = 0;
2011
+ for (let active of view.state.field(completionState).active) if (active.isPending) this.startQuery(active);
2012
+ }
2013
+ update(update) {
2014
+ let cState = update.state.field(completionState);
2015
+ let conf = update.state.facet(completionConfig);
2016
+ if (!update.selectionSet && !update.docChanged && update.startState.field(completionState) == cState) return;
2017
+ let doesReset = update.transactions.some((tr) => {
2018
+ let type = getUpdateType(tr, conf);
2019
+ return type & 8 || (tr.selection || tr.docChanged) && !(type & 3);
2020
+ });
2021
+ for (let i = 0; i < this.running.length; i++) {
2022
+ let query = this.running[i];
2023
+ if (doesReset || query.context.abortOnDocChange && update.docChanged || query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
2024
+ for (let handler of query.context.abortListeners) try {
2025
+ handler();
2026
+ } catch (e) {
2027
+ logException(this.view.state, e);
2028
+ }
2029
+ query.context.abortListeners = null;
2030
+ this.running.splice(i--, 1);
2031
+ } else query.updates.push(...update.transactions);
2032
+ }
2033
+ if (this.debounceUpdate > -1) clearTimeout(this.debounceUpdate);
2034
+ if (update.transactions.some((tr) => tr.effects.some((e) => e.is(startCompletionEffect)))) this.pendingStart = true;
2035
+ let delay = this.pendingStart ? 50 : conf.activateOnTypingDelay;
2036
+ this.debounceUpdate = cState.active.some((a) => a.isPending && !this.running.some((q) => q.active.source == a.source)) ? setTimeout(() => this.startUpdate(), delay) : -1;
2037
+ if (this.composing != 0) {
2038
+ for (let tr of update.transactions) if (tr.isUserEvent("input.type")) this.composing = 2;
2039
+ else if (this.composing == 2 && tr.selection) this.composing = 3;
2040
+ }
2041
+ }
2042
+ startUpdate() {
2043
+ this.debounceUpdate = -1;
2044
+ this.pendingStart = false;
2045
+ let { state } = this.view, cState = state.field(completionState);
2046
+ for (let active of cState.active) if (active.isPending && !this.running.some((r) => r.active.source == active.source)) this.startQuery(active);
2047
+ if (this.running.length && cState.open && cState.open.disabled) this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
2048
+ }
2049
+ startQuery(active) {
2050
+ let { state } = this.view, pos = cur(state);
2051
+ let context = new CompletionContext(state, pos, active.explicit, this.view);
2052
+ let pending = new RunningQuery(active, context);
2053
+ this.running.push(pending);
2054
+ Promise.resolve(active.source(context)).then((result) => {
2055
+ if (!pending.context.aborted) {
2056
+ pending.done = result || null;
2057
+ this.scheduleAccept();
2058
+ }
2059
+ }, (err) => {
2060
+ this.view.dispatch({ effects: closeCompletionEffect.of(null) });
2061
+ logException(this.view.state, err);
2062
+ });
2063
+ }
2064
+ scheduleAccept() {
2065
+ if (this.running.every((q) => q.done !== void 0)) this.accept();
2066
+ else if (this.debounceAccept < 0) this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
2067
+ }
2068
+ accept() {
2069
+ var _a;
2070
+ if (this.debounceAccept > -1) clearTimeout(this.debounceAccept);
2071
+ this.debounceAccept = -1;
2072
+ let updated = [];
2073
+ let conf = this.view.state.facet(completionConfig), cState = this.view.state.field(completionState);
2074
+ for (let i = 0; i < this.running.length; i++) {
2075
+ let query = this.running[i];
2076
+ if (query.done === void 0) continue;
2077
+ this.running.splice(i--, 1);
2078
+ if (query.done) {
2079
+ let pos = cur(query.updates.length ? query.updates[0].startState : this.view.state);
2080
+ let limit = Math.min(pos, query.done.from + (query.active.explicit ? 0 : 1));
2081
+ let active = new ActiveResult(query.active.source, query.active.explicit, limit, query.done, query.done.from, (_a = query.done.to) !== null && _a !== void 0 ? _a : pos);
2082
+ for (let tr of query.updates) active = active.update(tr, conf);
2083
+ if (active.hasResult()) {
2084
+ updated.push(active);
2085
+ continue;
2086
+ }
2087
+ }
2088
+ let current = cState.active.find((a) => a.source == query.active.source);
2089
+ if (current && current.isPending) if (query.done == null) {
2090
+ let active = new ActiveSource(query.active.source, 0);
2091
+ for (let tr of query.updates) active = active.update(tr, conf);
2092
+ if (!active.isPending) updated.push(active);
2093
+ } else this.startQuery(current);
2094
+ }
2095
+ if (updated.length || cState.open && cState.open.disabled) this.view.dispatch({ effects: setActiveEffect.of(updated) });
2096
+ }
2097
+ }, { eventHandlers: {
2098
+ blur(event) {
2099
+ let state = this.view.state.field(completionState, false);
2100
+ if (state && state.tooltip && this.view.state.facet(completionConfig).closeOnBlur) {
2101
+ let dialog = state.open && getTooltip(this.view, state.open.tooltip);
2102
+ if (!dialog || !dialog.dom.contains(event.relatedTarget)) setTimeout(() => this.view.dispatch({ effects: closeCompletionEffect.of(null) }), 10);
2103
+ }
2104
+ },
2105
+ compositionstart() {
2106
+ this.composing = 1;
2107
+ },
2108
+ compositionend() {
2109
+ if (this.composing == 3) setTimeout(() => this.view.dispatch({ effects: startCompletionEffect.of(false) }), 20);
2110
+ this.composing = 0;
2111
+ }
2112
+ } });
2113
+ const windows = typeof navigator == "object" && /* @__PURE__ */ /Win/.test(navigator.platform);
2114
+ const commitCharacters = /* @__PURE__ */ Prec.highest(/* @__PURE__ */ EditorView.domEventHandlers({ keydown(event, view) {
2115
+ let field = view.state.field(completionState, false);
2116
+ if (!field || !field.open || field.open.disabled || field.open.selected < 0 || event.key.length > 1 || event.ctrlKey && !(windows && event.altKey) || event.metaKey) return false;
2117
+ let option = field.open.options[field.open.selected];
2118
+ let result = field.active.find((a) => a.source == option.source);
2119
+ let commitChars = option.completion.commitCharacters || result.result.commitCharacters;
2120
+ if (commitChars && commitChars.indexOf(event.key) > -1) applyCompletion(view, option);
2121
+ return false;
2122
+ } }));
2123
+ const baseTheme$2 = /* @__PURE__ */ EditorView.baseTheme({
2124
+ ".cm-tooltip.cm-tooltip-autocomplete": { "& > ul": {
2125
+ fontFamily: "monospace",
2126
+ whiteSpace: "nowrap",
2127
+ overflow: "hidden auto",
2128
+ maxWidth_fallback: "700px",
2129
+ maxWidth: "min(700px, 95vw)",
2130
+ minWidth: "250px",
2131
+ maxHeight: "10em",
2132
+ height: "100%",
2133
+ listStyle: "none",
2134
+ margin: 0,
2135
+ padding: 0,
2136
+ "& > li, & > completion-section": {
2137
+ padding: "1px 3px",
2138
+ lineHeight: 1.2
2139
+ },
2140
+ "& > li": {
2141
+ overflowX: "hidden",
2142
+ textOverflow: "ellipsis",
2143
+ cursor: "pointer"
2144
+ },
2145
+ "& > completion-section": {
2146
+ display: "list-item",
2147
+ borderBottom: "1px solid silver",
2148
+ paddingLeft: "0.5em",
2149
+ opacity: .7
2150
+ }
2151
+ } },
2152
+ "&light .cm-tooltip-autocomplete ul li[aria-selected]": {
2153
+ background: "#17c",
2154
+ color: "white"
2155
+ },
2156
+ "&light .cm-tooltip-autocomplete-disabled ul li[aria-selected]": { background: "#777" },
2157
+ "&dark .cm-tooltip-autocomplete ul li[aria-selected]": {
2158
+ background: "#347",
2159
+ color: "white"
2160
+ },
2161
+ "&dark .cm-tooltip-autocomplete-disabled ul li[aria-selected]": { background: "#444" },
2162
+ ".cm-completionListIncompleteTop:before, .cm-completionListIncompleteBottom:after": {
2163
+ content: "\"···\"",
2164
+ opacity: .5,
2165
+ display: "block",
2166
+ textAlign: "center"
2167
+ },
2168
+ ".cm-tooltip.cm-completionInfo": {
2169
+ position: "absolute",
2170
+ padding: "3px 9px",
2171
+ width: "max-content",
2172
+ maxWidth: `400px`,
2173
+ boxSizing: "border-box",
2174
+ whiteSpace: "pre-line"
2175
+ },
2176
+ ".cm-completionInfo.cm-completionInfo-left": { right: "100%" },
2177
+ ".cm-completionInfo.cm-completionInfo-right": { left: "100%" },
2178
+ ".cm-completionInfo.cm-completionInfo-left-narrow": { right: `30px` },
2179
+ ".cm-completionInfo.cm-completionInfo-right-narrow": { left: `30px` },
2180
+ "&light .cm-snippetField": { backgroundColor: "#00000022" },
2181
+ "&dark .cm-snippetField": { backgroundColor: "#ffffff22" },
2182
+ ".cm-snippetFieldPosition": {
2183
+ verticalAlign: "text-top",
2184
+ width: 0,
2185
+ height: "1.15em",
2186
+ display: "inline-block",
2187
+ margin: "0 -0.7px -.7em",
2188
+ borderLeft: "1.4px dotted #888"
2189
+ },
2190
+ ".cm-completionMatchedText": { textDecoration: "underline" },
2191
+ ".cm-completionDetail": {
2192
+ marginLeft: "0.5em",
2193
+ fontStyle: "italic"
2194
+ },
2195
+ ".cm-completionIcon": {
2196
+ fontSize: "90%",
2197
+ width: ".8em",
2198
+ display: "inline-block",
2199
+ textAlign: "center",
2200
+ paddingRight: ".6em",
2201
+ opacity: "0.6",
2202
+ boxSizing: "content-box"
2203
+ },
2204
+ ".cm-completionIcon-function, .cm-completionIcon-method": { "&:after": { content: "'ƒ'" } },
2205
+ ".cm-completionIcon-class": { "&:after": { content: "'○'" } },
2206
+ ".cm-completionIcon-interface": { "&:after": { content: "'◌'" } },
2207
+ ".cm-completionIcon-variable": { "&:after": { content: "'𝑥'" } },
2208
+ ".cm-completionIcon-constant": { "&:after": { content: "'𝐶'" } },
2209
+ ".cm-completionIcon-type": { "&:after": { content: "'𝑡'" } },
2210
+ ".cm-completionIcon-enum": { "&:after": { content: "'∪'" } },
2211
+ ".cm-completionIcon-property": { "&:after": { content: "'□'" } },
2212
+ ".cm-completionIcon-keyword": { "&:after": { content: "'🔑︎'" } },
2213
+ ".cm-completionIcon-namespace": { "&:after": { content: "'▢'" } },
2214
+ ".cm-completionIcon-text": { "&:after": {
2215
+ content: "'abc'",
2216
+ fontSize: "50%",
2217
+ verticalAlign: "middle"
2218
+ } }
2219
+ });
2220
+ const defaults = {
2221
+ brackets: [
2222
+ "(",
2223
+ "[",
2224
+ "{",
2225
+ "'",
2226
+ "\""
2227
+ ],
2228
+ before: ")]}:;>",
2229
+ stringPrefixes: []
2230
+ };
2231
+ const closeBracketEffect = /* @__PURE__ */ StateEffect.define({ map(value, mapping) {
2232
+ let mapped = mapping.mapPos(value, -1, MapMode.TrackAfter);
2233
+ return mapped == null ? void 0 : mapped;
2234
+ } });
2235
+ const closedBracket = /* @__PURE__ */ new class extends RangeValue {}();
2236
+ closedBracket.startSide = 1;
2237
+ closedBracket.endSide = -1;
2238
+ const bracketState = /* @__PURE__ */ StateField.define({
2239
+ create() {
2240
+ return RangeSet.empty;
2241
+ },
2242
+ update(value, tr) {
2243
+ value = value.map(tr.changes);
2244
+ if (tr.selection) {
2245
+ let line = tr.state.doc.lineAt(tr.selection.main.head);
2246
+ value = value.update({ filter: (from) => from >= line.from && from <= line.to });
2247
+ }
2248
+ for (let effect of tr.effects) if (effect.is(closeBracketEffect)) value = value.update({ add: [closedBracket.range(effect.value, effect.value + 1)] });
2249
+ return value;
2250
+ }
2251
+ });
2252
+ /**
2253
+ Extension to enable bracket-closing behavior. When a closeable
2254
+ bracket is typed, its closing bracket is immediately inserted
2255
+ after the cursor. When closing a bracket directly in front of a
2256
+ closing bracket inserted by the extension, the cursor moves over
2257
+ that bracket.
2258
+ */
2259
+ function closeBrackets() {
2260
+ return [inputHandler, bracketState];
2261
+ }
2262
+ const definedClosing = "()[]{}<>«»»«[]{}";
2263
+ function closing(ch) {
2264
+ for (let i = 0; i < 16; i += 2) if (definedClosing.charCodeAt(i) == ch) return definedClosing.charAt(i + 1);
2265
+ return fromCodePoint(ch < 128 ? ch : ch + 1);
2266
+ }
2267
+ function config(state, pos) {
2268
+ return state.languageDataAt("closeBrackets", pos)[0] || defaults;
2269
+ }
2270
+ const android = typeof navigator == "object" && /* @__PURE__ */ /Android\b/.test(navigator.userAgent);
2271
+ const inputHandler = /* @__PURE__ */ EditorView.inputHandler.of((view, from, to, insert) => {
2272
+ if ((android ? view.composing : view.compositionStarted) || view.state.readOnly) return false;
2273
+ let sel = view.state.selection.main;
2274
+ if (insert.length > 2 || insert.length == 2 && codePointSize(codePointAt(insert, 0)) == 1 || from != sel.from || to != sel.to) return false;
2275
+ let tr = insertBracket(view.state, insert);
2276
+ if (!tr) return false;
2277
+ view.dispatch(tr);
2278
+ return true;
2279
+ });
2280
+ /**
2281
+ Command that implements deleting a pair of matching brackets when
2282
+ the cursor is between them.
2283
+ */
2284
+ const deleteBracketPair = ({ state, dispatch }) => {
2285
+ if (state.readOnly) return false;
2286
+ let tokens = config(state, state.selection.main.head).brackets || defaults.brackets;
2287
+ let dont = null, changes = state.changeByRange((range) => {
2288
+ if (range.empty) {
2289
+ let before = prevChar(state.doc, range.head);
2290
+ for (let token of tokens) if (token == before && nextChar(state.doc, range.head) == closing(codePointAt(token, 0))) return {
2291
+ changes: {
2292
+ from: range.head - token.length,
2293
+ to: range.head + token.length
2294
+ },
2295
+ range: EditorSelection.cursor(range.head - token.length)
2296
+ };
2297
+ }
2298
+ return { range: dont = range };
2299
+ });
2300
+ if (!dont) dispatch(state.update(changes, {
2301
+ scrollIntoView: true,
2302
+ userEvent: "delete.backward"
2303
+ }));
2304
+ return !dont;
2305
+ };
2306
+ /**
2307
+ Close-brackets related key bindings. Binds Backspace to
2308
+ [`deleteBracketPair`](https://codemirror.net/6/docs/ref/#autocomplete.deleteBracketPair).
2309
+ */
2310
+ const closeBracketsKeymap = [{
2311
+ key: "Backspace",
2312
+ run: deleteBracketPair
2313
+ }];
2314
+ /**
2315
+ Implements the extension's behavior on text insertion. If the
2316
+ given string counts as a bracket in the language around the
2317
+ selection, and replacing the selection with it requires custom
2318
+ behavior (inserting a closing version or skipping past a
2319
+ previously-closed bracket), this function returns a transaction
2320
+ representing that custom behavior. (You only need this if you want
2321
+ to programmatically insert brackets—the
2322
+ [`closeBrackets`](https://codemirror.net/6/docs/ref/#autocomplete.closeBrackets) extension will
2323
+ take care of running this for user input.)
2324
+ */
2325
+ function insertBracket(state, bracket) {
2326
+ let conf = config(state, state.selection.main.head);
2327
+ let tokens = conf.brackets || defaults.brackets;
2328
+ for (let tok of tokens) {
2329
+ let closed = closing(codePointAt(tok, 0));
2330
+ if (bracket == tok) return closed == tok ? handleSame(state, tok, tokens.indexOf(tok + tok + tok) > -1, conf) : handleOpen(state, tok, closed, conf.before || defaults.before);
2331
+ if (bracket == closed && closedBracketAt(state, state.selection.main.from)) return handleClose(state, tok, closed);
2332
+ }
2333
+ return null;
2334
+ }
2335
+ function closedBracketAt(state, pos) {
2336
+ let found = false;
2337
+ state.field(bracketState).between(0, state.doc.length, (from) => {
2338
+ if (from == pos) found = true;
2339
+ });
2340
+ return found;
2341
+ }
2342
+ function nextChar(doc, pos) {
2343
+ let next = doc.sliceString(pos, pos + 2);
2344
+ return next.slice(0, codePointSize(codePointAt(next, 0)));
2345
+ }
2346
+ function prevChar(doc, pos) {
2347
+ let prev = doc.sliceString(pos - 2, pos);
2348
+ return codePointSize(codePointAt(prev, 0)) == prev.length ? prev : prev.slice(1);
2349
+ }
2350
+ function handleOpen(state, open, close, closeBefore) {
2351
+ let dont = null, changes = state.changeByRange((range) => {
2352
+ if (!range.empty) return {
2353
+ changes: [{
2354
+ insert: open,
2355
+ from: range.from
2356
+ }, {
2357
+ insert: close,
2358
+ from: range.to
2359
+ }],
2360
+ effects: closeBracketEffect.of(range.to + open.length),
2361
+ range: EditorSelection.range(range.anchor + open.length, range.head + open.length)
2362
+ };
2363
+ let next = nextChar(state.doc, range.head);
2364
+ if (!next || /\s/.test(next) || closeBefore.indexOf(next) > -1) return {
2365
+ changes: {
2366
+ insert: open + close,
2367
+ from: range.head
2368
+ },
2369
+ effects: closeBracketEffect.of(range.head + open.length),
2370
+ range: EditorSelection.cursor(range.head + open.length)
2371
+ };
2372
+ return { range: dont = range };
2373
+ });
2374
+ return dont ? null : state.update(changes, {
2375
+ scrollIntoView: true,
2376
+ userEvent: "input.type"
2377
+ });
2378
+ }
2379
+ function handleClose(state, _open, close) {
2380
+ let dont = null, changes = state.changeByRange((range) => {
2381
+ if (range.empty && nextChar(state.doc, range.head) == close) return {
2382
+ changes: {
2383
+ from: range.head,
2384
+ to: range.head + close.length,
2385
+ insert: close
2386
+ },
2387
+ range: EditorSelection.cursor(range.head + close.length)
2388
+ };
2389
+ return dont = { range };
2390
+ });
2391
+ return dont ? null : state.update(changes, {
2392
+ scrollIntoView: true,
2393
+ userEvent: "input.type"
2394
+ });
2395
+ }
2396
+ function handleSame(state, token, allowTriple, config$1) {
2397
+ let stringPrefixes = config$1.stringPrefixes || defaults.stringPrefixes;
2398
+ let dont = null, changes = state.changeByRange((range) => {
2399
+ if (!range.empty) return {
2400
+ changes: [{
2401
+ insert: token,
2402
+ from: range.from
2403
+ }, {
2404
+ insert: token,
2405
+ from: range.to
2406
+ }],
2407
+ effects: closeBracketEffect.of(range.to + token.length),
2408
+ range: EditorSelection.range(range.anchor + token.length, range.head + token.length)
2409
+ };
2410
+ let pos = range.head, next = nextChar(state.doc, pos), start;
2411
+ if (next == token) {
2412
+ if (nodeStart(state, pos)) return {
2413
+ changes: {
2414
+ insert: token + token,
2415
+ from: pos
2416
+ },
2417
+ effects: closeBracketEffect.of(pos + token.length),
2418
+ range: EditorSelection.cursor(pos + token.length)
2419
+ };
2420
+ else if (closedBracketAt(state, pos)) {
2421
+ let content = allowTriple && state.sliceDoc(pos, pos + token.length * 3) == token + token + token ? token + token + token : token;
2422
+ return {
2423
+ changes: {
2424
+ from: pos,
2425
+ to: pos + content.length,
2426
+ insert: content
2427
+ },
2428
+ range: EditorSelection.cursor(pos + content.length)
2429
+ };
2430
+ }
2431
+ } 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 {
2432
+ changes: {
2433
+ insert: token + token + token + token,
2434
+ from: pos
2435
+ },
2436
+ effects: closeBracketEffect.of(pos + token.length),
2437
+ range: EditorSelection.cursor(pos + token.length)
2438
+ };
2439
+ else if (state.charCategorizer(pos)(next) != CharCategory.Word) {
2440
+ if (canStartStringAt(state, pos, stringPrefixes) > -1 && !probablyInString(state, pos, token, stringPrefixes)) return {
2441
+ changes: {
2442
+ insert: token + token,
2443
+ from: pos
2444
+ },
2445
+ effects: closeBracketEffect.of(pos + token.length),
2446
+ range: EditorSelection.cursor(pos + token.length)
2447
+ };
2448
+ }
2449
+ return { range: dont = range };
2450
+ });
2451
+ return dont ? null : state.update(changes, {
2452
+ scrollIntoView: true,
2453
+ userEvent: "input.type"
2454
+ });
2455
+ }
2456
+ function nodeStart(state, pos) {
2457
+ let tree = syntaxTree(state).resolveInner(pos + 1);
2458
+ return tree.parent && tree.from == pos;
2459
+ }
2460
+ function probablyInString(state, pos, quoteToken, prefixes) {
2461
+ let node = syntaxTree(state).resolveInner(pos, -1);
2462
+ let maxPrefix = prefixes.reduce((m, p) => Math.max(m, p.length), 0);
2463
+ for (let i = 0; i < 5; i++) {
2464
+ let start = state.sliceDoc(node.from, Math.min(node.to, node.from + quoteToken.length + maxPrefix));
2465
+ let quotePos = start.indexOf(quoteToken);
2466
+ if (!quotePos || quotePos > -1 && prefixes.indexOf(start.slice(0, quotePos)) > -1) {
2467
+ let first = node.firstChild;
2468
+ while (first && first.from == node.from && first.to - first.from > quoteToken.length + quotePos) {
2469
+ if (state.sliceDoc(first.to - quoteToken.length, first.to) == quoteToken) return false;
2470
+ first = first.firstChild;
2471
+ }
2472
+ return true;
2473
+ }
2474
+ let parent = node.to == pos && node.parent;
2475
+ if (!parent) break;
2476
+ node = parent;
2477
+ }
2478
+ return false;
2479
+ }
2480
+ function canStartStringAt(state, pos, prefixes) {
2481
+ let charCat = state.charCategorizer(pos);
2482
+ if (charCat(state.sliceDoc(pos - 1, pos)) != CharCategory.Word) return pos;
2483
+ for (let prefix of prefixes) {
2484
+ let start = pos - prefix.length;
2485
+ if (state.sliceDoc(start, pos) == prefix && charCat(state.sliceDoc(start - 1, start)) != CharCategory.Word) return start;
2486
+ }
2487
+ return -1;
2488
+ }
2489
+ /**
2490
+ Returns an extension that enables autocompletion.
2491
+ */
2492
+ function autocompletion(config$1 = {}) {
2493
+ return [
2494
+ commitCharacters,
2495
+ completionState,
2496
+ completionConfig.of(config$1),
2497
+ completionPlugin,
2498
+ completionKeymapExt,
2499
+ baseTheme$2
2500
+ ];
2501
+ }
2502
+ /**
2503
+ Basic keybindings for autocompletion.
2504
+
2505
+ - Ctrl-Space (and Alt-\` on macOS): [`startCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.startCompletion)
2506
+ - Escape: [`closeCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.closeCompletion)
2507
+ - ArrowDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true)`
2508
+ - ArrowUp: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(false)`
2509
+ - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")`
2510
+ - PageDown: [`moveCompletionSelection`](https://codemirror.net/6/docs/ref/#autocomplete.moveCompletionSelection)`(true, "page")`
2511
+ - Enter: [`acceptCompletion`](https://codemirror.net/6/docs/ref/#autocomplete.acceptCompletion)
2512
+ */
2513
+ const completionKeymap = [
2514
+ {
2515
+ key: "Ctrl-Space",
2516
+ run: startCompletion
2517
+ },
2518
+ {
2519
+ mac: "Alt-`",
2520
+ run: startCompletion
2521
+ },
2522
+ {
2523
+ key: "Escape",
2524
+ run: closeCompletion
2525
+ },
2526
+ {
2527
+ key: "ArrowDown",
2528
+ run: /* @__PURE__ */ moveCompletionSelection(true)
2529
+ },
2530
+ {
2531
+ key: "ArrowUp",
2532
+ run: /* @__PURE__ */ moveCompletionSelection(false)
2533
+ },
2534
+ {
2535
+ key: "PageDown",
2536
+ run: /* @__PURE__ */ moveCompletionSelection(true, "page")
2537
+ },
2538
+ {
2539
+ key: "PageUp",
2540
+ run: /* @__PURE__ */ moveCompletionSelection(false, "page")
2541
+ },
2542
+ {
2543
+ key: "Enter",
2544
+ run: acceptCompletion
2545
+ }
2546
+ ];
2547
+ const completionKeymapExt = /* @__PURE__ */ Prec.highest(/* @__PURE__ */ keymap.computeN([completionConfig], (state) => state.facet(completionConfig).defaultKeymap ? [completionKeymap] : []));
2548
+
2549
+ //#endregion
2550
+ //#region ../../node_modules/@codemirror/lint/dist/index.js
2551
+ var SelectedDiagnostic = class {
2552
+ constructor(from, to, diagnostic) {
2553
+ this.from = from;
2554
+ this.to = to;
2555
+ this.diagnostic = diagnostic;
2556
+ }
2557
+ };
2558
+ var LintState = class LintState {
2559
+ constructor(diagnostics, panel, selected) {
2560
+ this.diagnostics = diagnostics;
2561
+ this.panel = panel;
2562
+ this.selected = selected;
2563
+ }
2564
+ static init(diagnostics, panel, state) {
2565
+ let diagnosticFilter = state.facet(lintConfig).markerFilter;
2566
+ if (diagnosticFilter) diagnostics = diagnosticFilter(diagnostics, state);
2567
+ let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to);
2568
+ let deco = new RangeSetBuilder(), active = [], pos = 0;
2569
+ for (let i = 0;;) {
2570
+ let next = i == sorted.length ? null : sorted[i];
2571
+ if (!next && !active.length) break;
2572
+ let from, to;
2573
+ if (active.length) {
2574
+ from = pos;
2575
+ to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8);
2576
+ } else {
2577
+ from = next.from;
2578
+ to = next.to;
2579
+ active.push(next);
2580
+ i++;
2581
+ }
2582
+ while (i < sorted.length) {
2583
+ let next$1 = sorted[i];
2584
+ if (next$1.from == from && (next$1.to > next$1.from || next$1.to == from)) {
2585
+ active.push(next$1);
2586
+ i++;
2587
+ to = Math.min(next$1.to, to);
2588
+ } else {
2589
+ to = Math.min(next$1.from, to);
2590
+ break;
2591
+ }
2592
+ }
2593
+ let sev = maxSeverity(active);
2594
+ if (active.some((d) => d.from == d.to || d.from == d.to - 1 && state.doc.lineAt(d.from).to == d.from)) deco.add(from, from, Decoration.widget({
2595
+ widget: new DiagnosticWidget(sev),
2596
+ diagnostics: active.slice()
2597
+ }));
2598
+ else {
2599
+ let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, "");
2600
+ deco.add(from, to, Decoration.mark({
2601
+ class: "cm-lintRange cm-lintRange-" + sev + markClass,
2602
+ diagnostics: active.slice(),
2603
+ inclusiveEnd: active.some((a) => a.to > to)
2604
+ }));
2605
+ }
2606
+ pos = to;
2607
+ for (let i$1 = 0; i$1 < active.length; i$1++) if (active[i$1].to <= pos) active.splice(i$1--, 1);
2608
+ }
2609
+ let set = deco.finish();
2610
+ return new LintState(set, panel, findDiagnostic(set));
2611
+ }
2612
+ };
2613
+ function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
2614
+ let found = null;
2615
+ diagnostics.between(after, 1e9, (from, to, { spec }) => {
2616
+ if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0) return;
2617
+ if (!found) found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]);
2618
+ else if (spec.diagnostics.indexOf(found.diagnostic) < 0) return false;
2619
+ else found = new SelectedDiagnostic(found.from, to, found.diagnostic);
2620
+ });
2621
+ return found;
2622
+ }
2623
+ function hideTooltip(tr, tooltip) {
2624
+ let from = tooltip.pos, to = tooltip.end || from;
2625
+ let result = tr.state.facet(lintConfig).hideOn(tr, from, to);
2626
+ if (result != null) return result;
2627
+ let line = tr.startState.doc.lineAt(tooltip.pos);
2628
+ return !!(tr.effects.some((e) => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, Math.max(line.to, to)));
2629
+ }
2630
+ function maybeEnableLint(state, effects) {
2631
+ return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of(lintExtensions));
2632
+ }
2633
+ /**
2634
+ The state effect that updates the set of active diagnostics. Can
2635
+ be useful when writing an extension that needs to track these.
2636
+ */
2637
+ const setDiagnosticsEffect = /* @__PURE__ */ StateEffect.define();
2638
+ const togglePanel = /* @__PURE__ */ StateEffect.define();
2639
+ const movePanelSelection = /* @__PURE__ */ StateEffect.define();
2640
+ const lintState = /* @__PURE__ */ StateField.define({
2641
+ create() {
2642
+ return new LintState(Decoration.none, null, null);
2643
+ },
2644
+ update(value, tr) {
2645
+ if (tr.docChanged && value.diagnostics.size) {
2646
+ let mapped = value.diagnostics.map(tr.changes), selected = null, panel = value.panel;
2647
+ if (value.selected) {
2648
+ let selPos = tr.changes.mapPos(value.selected.from, 1);
2649
+ selected = findDiagnostic(mapped, value.selected.diagnostic, selPos) || findDiagnostic(mapped, null, selPos);
2650
+ }
2651
+ if (!mapped.size && panel && tr.state.facet(lintConfig).autoPanel) panel = null;
2652
+ value = new LintState(mapped, panel, selected);
2653
+ }
2654
+ for (let effect of tr.effects) if (effect.is(setDiagnosticsEffect)) {
2655
+ let panel = !tr.state.facet(lintConfig).autoPanel ? value.panel : effect.value.length ? LintPanel.open : null;
2656
+ value = LintState.init(effect.value, panel, tr.state);
2657
+ } else if (effect.is(togglePanel)) value = new LintState(value.diagnostics, effect.value ? LintPanel.open : null, value.selected);
2658
+ else if (effect.is(movePanelSelection)) value = new LintState(value.diagnostics, value.panel, effect.value);
2659
+ return value;
2660
+ },
2661
+ provide: (f) => [showPanel.from(f, (val) => val.panel), EditorView.decorations.from(f, (s) => s.diagnostics)]
2662
+ });
2663
+ const activeMark = /* @__PURE__ */ Decoration.mark({ class: "cm-lintRange cm-lintRange-active" });
2664
+ function lintTooltip(view, pos, side) {
2665
+ let { diagnostics } = view.state.field(lintState);
2666
+ let found, start = -1, end = -1;
2667
+ diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => {
2668
+ if (pos >= from && pos <= to && (from == to || (pos > from || side > 0) && (pos < to || side < 0))) {
2669
+ found = spec.diagnostics;
2670
+ start = from;
2671
+ end = to;
2672
+ return false;
2673
+ }
2674
+ });
2675
+ let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter;
2676
+ if (found && diagnosticFilter) found = diagnosticFilter(found, view.state);
2677
+ if (!found) return null;
2678
+ return {
2679
+ pos: start,
2680
+ end,
2681
+ above: view.state.doc.lineAt(start).to < end,
2682
+ create() {
2683
+ return { dom: diagnosticsTooltip(view, found) };
2684
+ }
2685
+ };
2686
+ }
2687
+ function diagnosticsTooltip(view, diagnostics) {
2688
+ return crelt("ul", { class: "cm-tooltip-lint" }, diagnostics.map((d) => renderDiagnostic(view, d, false)));
2689
+ }
2690
+ /**
2691
+ Command to open and focus the lint panel.
2692
+ */
2693
+ const openLintPanel = (view) => {
2694
+ let field = view.state.field(lintState, false);
2695
+ if (!field || !field.panel) view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]) });
2696
+ let panel = getPanel(view, LintPanel.open);
2697
+ if (panel) panel.dom.querySelector(".cm-panel-lint ul").focus();
2698
+ return true;
2699
+ };
2700
+ /**
2701
+ Command to close the lint panel, when open.
2702
+ */
2703
+ const closeLintPanel = (view) => {
2704
+ let field = view.state.field(lintState, false);
2705
+ if (!field || !field.panel) return false;
2706
+ view.dispatch({ effects: togglePanel.of(false) });
2707
+ return true;
2708
+ };
2709
+ /**
2710
+ Move the selection to the next diagnostic.
2711
+ */
2712
+ const nextDiagnostic = (view) => {
2713
+ let field = view.state.field(lintState, false);
2714
+ if (!field) return false;
2715
+ let sel = view.state.selection.main, next = field.diagnostics.iter(sel.to + 1);
2716
+ if (!next.value) {
2717
+ next = field.diagnostics.iter(0);
2718
+ if (!next.value || next.from == sel.from && next.to == sel.to) return false;
2719
+ }
2720
+ view.dispatch({
2721
+ selection: {
2722
+ anchor: next.from,
2723
+ head: next.to
2724
+ },
2725
+ scrollIntoView: true
2726
+ });
2727
+ return true;
2728
+ };
2729
+ /**
2730
+ A set of default key bindings for the lint functionality.
2731
+
2732
+ - Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel)
2733
+ - F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic)
2734
+ */
2735
+ const lintKeymap = [{
2736
+ key: "Mod-Shift-m",
2737
+ run: openLintPanel,
2738
+ preventDefault: true
2739
+ }, {
2740
+ key: "F8",
2741
+ run: nextDiagnostic
2742
+ }];
2743
+ const lintConfig = /* @__PURE__ */ Facet.define({ combine(input) {
2744
+ return Object.assign({ sources: input.map((i) => i.source).filter((x) => x != null) }, combineConfig(input.map((i) => i.config), {
2745
+ delay: 750,
2746
+ markerFilter: null,
2747
+ tooltipFilter: null,
2748
+ needsRefresh: null,
2749
+ hideOn: () => null
2750
+ }, { needsRefresh: (a, b) => !a ? b : !b ? a : (u) => a(u) || b(u) }));
2751
+ } });
2752
+ function assignKeys(actions) {
2753
+ let assigned = [];
2754
+ if (actions) actions: for (let { name } of actions) {
2755
+ for (let i = 0; i < name.length; i++) {
2756
+ let ch = name[i];
2757
+ if (/[a-zA-Z]/.test(ch) && !assigned.some((c) => c.toLowerCase() == ch.toLowerCase())) {
2758
+ assigned.push(ch);
2759
+ continue actions;
2760
+ }
2761
+ }
2762
+ assigned.push("");
2763
+ }
2764
+ return assigned;
2765
+ }
2766
+ function renderDiagnostic(view, diagnostic, inPanel) {
2767
+ var _a;
2768
+ let keys = inPanel ? assignKeys(diagnostic.actions) : [];
2769
+ 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) => {
2770
+ let fired = false, click = (e) => {
2771
+ e.preventDefault();
2772
+ if (fired) return;
2773
+ fired = true;
2774
+ let found = findDiagnostic(view.state.field(lintState).diagnostics, diagnostic);
2775
+ if (found) action.apply(view, found.from, found.to);
2776
+ };
2777
+ let { name } = action, keyIndex = keys[i] ? name.indexOf(keys[i]) : -1;
2778
+ let nameElt = keyIndex < 0 ? name : [
2779
+ name.slice(0, keyIndex),
2780
+ crelt("u", name.slice(keyIndex, keyIndex + 1)),
2781
+ name.slice(keyIndex + 1)
2782
+ ];
2783
+ return crelt("button", {
2784
+ type: "button",
2785
+ class: "cm-diagnosticAction",
2786
+ onclick: click,
2787
+ onmousedown: click,
2788
+ "aria-label": ` Action: ${name}${keyIndex < 0 ? "" : ` (access key "${keys[i]})"`}.`
2789
+ }, nameElt);
2790
+ }), diagnostic.source && crelt("div", { class: "cm-diagnosticSource" }, diagnostic.source));
2791
+ }
2792
+ var DiagnosticWidget = class extends WidgetType {
2793
+ constructor(sev) {
2794
+ super();
2795
+ this.sev = sev;
2796
+ }
2797
+ eq(other) {
2798
+ return other.sev == this.sev;
2799
+ }
2800
+ toDOM() {
2801
+ return crelt("span", { class: "cm-lintPoint cm-lintPoint-" + this.sev });
2802
+ }
2803
+ };
2804
+ var PanelItem = class {
2805
+ constructor(view, diagnostic) {
2806
+ this.diagnostic = diagnostic;
2807
+ this.id = "item_" + Math.floor(Math.random() * 4294967295).toString(16);
2808
+ this.dom = renderDiagnostic(view, diagnostic, true);
2809
+ this.dom.id = this.id;
2810
+ this.dom.setAttribute("role", "option");
2811
+ }
2812
+ };
2813
+ var LintPanel = class LintPanel {
2814
+ constructor(view) {
2815
+ this.view = view;
2816
+ this.items = [];
2817
+ let onkeydown = (event) => {
2818
+ if (event.keyCode == 27) {
2819
+ closeLintPanel(this.view);
2820
+ this.view.focus();
2821
+ } else if (event.keyCode == 38 || event.keyCode == 33) this.moveSelection((this.selectedIndex - 1 + this.items.length) % this.items.length);
2822
+ else if (event.keyCode == 40 || event.keyCode == 34) this.moveSelection((this.selectedIndex + 1) % this.items.length);
2823
+ else if (event.keyCode == 36) this.moveSelection(0);
2824
+ else if (event.keyCode == 35) this.moveSelection(this.items.length - 1);
2825
+ else if (event.keyCode == 13) this.view.focus();
2826
+ else if (event.keyCode >= 65 && event.keyCode <= 90 && this.selectedIndex >= 0) {
2827
+ let { diagnostic } = this.items[this.selectedIndex], keys = assignKeys(diagnostic.actions);
2828
+ for (let i = 0; i < keys.length; i++) if (keys[i].toUpperCase().charCodeAt(0) == event.keyCode) {
2829
+ let found = findDiagnostic(this.view.state.field(lintState).diagnostics, diagnostic);
2830
+ if (found) diagnostic.actions[i].apply(view, found.from, found.to);
2831
+ }
2832
+ } else return;
2833
+ event.preventDefault();
2834
+ };
2835
+ let onclick = (event) => {
2836
+ for (let i = 0; i < this.items.length; i++) if (this.items[i].dom.contains(event.target)) this.moveSelection(i);
2837
+ };
2838
+ this.list = crelt("ul", {
2839
+ tabIndex: 0,
2840
+ role: "listbox",
2841
+ "aria-label": this.view.state.phrase("Diagnostics"),
2842
+ onkeydown,
2843
+ onclick
2844
+ });
2845
+ this.dom = crelt("div", { class: "cm-panel-lint" }, this.list, crelt("button", {
2846
+ type: "button",
2847
+ name: "close",
2848
+ "aria-label": this.view.state.phrase("close"),
2849
+ onclick: () => closeLintPanel(this.view)
2850
+ }, "×"));
2851
+ this.update();
2852
+ }
2853
+ get selectedIndex() {
2854
+ let selected = this.view.state.field(lintState).selected;
2855
+ if (!selected) return -1;
2856
+ for (let i = 0; i < this.items.length; i++) if (this.items[i].diagnostic == selected.diagnostic) return i;
2857
+ return -1;
2858
+ }
2859
+ update() {
2860
+ let { diagnostics, selected } = this.view.state.field(lintState);
2861
+ let i = 0, needsSync = false, newSelectedItem = null;
2862
+ let seen = /* @__PURE__ */ new Set();
2863
+ diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => {
2864
+ for (let diagnostic of spec.diagnostics) {
2865
+ if (seen.has(diagnostic)) continue;
2866
+ seen.add(diagnostic);
2867
+ let found = -1, item;
2868
+ for (let j = i; j < this.items.length; j++) if (this.items[j].diagnostic == diagnostic) {
2869
+ found = j;
2870
+ break;
2871
+ }
2872
+ if (found < 0) {
2873
+ item = new PanelItem(this.view, diagnostic);
2874
+ this.items.splice(i, 0, item);
2875
+ needsSync = true;
2876
+ } else {
2877
+ item = this.items[found];
2878
+ if (found > i) {
2879
+ this.items.splice(i, found - i);
2880
+ needsSync = true;
2881
+ }
2882
+ }
2883
+ if (selected && item.diagnostic == selected.diagnostic) {
2884
+ if (!item.dom.hasAttribute("aria-selected")) {
2885
+ item.dom.setAttribute("aria-selected", "true");
2886
+ newSelectedItem = item;
2887
+ }
2888
+ } else if (item.dom.hasAttribute("aria-selected")) item.dom.removeAttribute("aria-selected");
2889
+ i++;
2890
+ }
2891
+ });
2892
+ while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) {
2893
+ needsSync = true;
2894
+ this.items.pop();
2895
+ }
2896
+ if (this.items.length == 0) {
2897
+ this.items.push(new PanelItem(this.view, {
2898
+ from: -1,
2899
+ to: -1,
2900
+ severity: "info",
2901
+ message: this.view.state.phrase("No diagnostics")
2902
+ }));
2903
+ needsSync = true;
2904
+ }
2905
+ if (newSelectedItem) {
2906
+ this.list.setAttribute("aria-activedescendant", newSelectedItem.id);
2907
+ this.view.requestMeasure({
2908
+ key: this,
2909
+ read: () => ({
2910
+ sel: newSelectedItem.dom.getBoundingClientRect(),
2911
+ panel: this.list.getBoundingClientRect()
2912
+ }),
2913
+ write: ({ sel, panel }) => {
2914
+ let scaleY = panel.height / this.list.offsetHeight;
2915
+ if (sel.top < panel.top) this.list.scrollTop -= (panel.top - sel.top) / scaleY;
2916
+ else if (sel.bottom > panel.bottom) this.list.scrollTop += (sel.bottom - panel.bottom) / scaleY;
2917
+ }
2918
+ });
2919
+ } else if (this.selectedIndex < 0) this.list.removeAttribute("aria-activedescendant");
2920
+ if (needsSync) this.sync();
2921
+ }
2922
+ sync() {
2923
+ let domPos = this.list.firstChild;
2924
+ function rm() {
2925
+ let prev = domPos;
2926
+ domPos = prev.nextSibling;
2927
+ prev.remove();
2928
+ }
2929
+ for (let item of this.items) if (item.dom.parentNode == this.list) {
2930
+ while (domPos != item.dom) rm();
2931
+ domPos = item.dom.nextSibling;
2932
+ } else this.list.insertBefore(item.dom, domPos);
2933
+ while (domPos) rm();
2934
+ }
2935
+ moveSelection(selectedIndex) {
2936
+ if (this.selectedIndex < 0) return;
2937
+ let field = this.view.state.field(lintState);
2938
+ let selection = findDiagnostic(field.diagnostics, this.items[selectedIndex].diagnostic);
2939
+ if (!selection) return;
2940
+ this.view.dispatch({
2941
+ selection: {
2942
+ anchor: selection.from,
2943
+ head: selection.to
2944
+ },
2945
+ scrollIntoView: true,
2946
+ effects: movePanelSelection.of(selection)
2947
+ });
2948
+ }
2949
+ static open(view) {
2950
+ return new LintPanel(view);
2951
+ }
2952
+ };
2953
+ function svg(content, attrs = `viewBox="0 0 40 40"`) {
2954
+ return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
2955
+ }
2956
+ function underline(color) {
2957
+ return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`);
2958
+ }
2959
+ const baseTheme$1 = /* @__PURE__ */ EditorView.baseTheme({
2960
+ ".cm-diagnostic": {
2961
+ padding: "3px 6px 3px 8px",
2962
+ marginLeft: "-1px",
2963
+ display: "block",
2964
+ whiteSpace: "pre-wrap"
2965
+ },
2966
+ ".cm-diagnostic-error": { borderLeft: "5px solid #d11" },
2967
+ ".cm-diagnostic-warning": { borderLeft: "5px solid orange" },
2968
+ ".cm-diagnostic-info": { borderLeft: "5px solid #999" },
2969
+ ".cm-diagnostic-hint": { borderLeft: "5px solid #66d" },
2970
+ ".cm-diagnosticAction": {
2971
+ font: "inherit",
2972
+ border: "none",
2973
+ padding: "2px 4px",
2974
+ backgroundColor: "#444",
2975
+ color: "white",
2976
+ borderRadius: "3px",
2977
+ marginLeft: "8px",
2978
+ cursor: "pointer"
2979
+ },
2980
+ ".cm-diagnosticSource": {
2981
+ fontSize: "70%",
2982
+ opacity: .7
2983
+ },
2984
+ ".cm-lintRange": {
2985
+ backgroundPosition: "left bottom",
2986
+ backgroundRepeat: "repeat-x",
2987
+ paddingBottom: "0.7px"
2988
+ },
2989
+ ".cm-lintRange-error": { backgroundImage: /* @__PURE__ */ underline("#d11") },
2990
+ ".cm-lintRange-warning": { backgroundImage: /* @__PURE__ */ underline("orange") },
2991
+ ".cm-lintRange-info": { backgroundImage: /* @__PURE__ */ underline("#999") },
2992
+ ".cm-lintRange-hint": { backgroundImage: /* @__PURE__ */ underline("#66d") },
2993
+ ".cm-lintRange-active": { backgroundColor: "#ffdd9980" },
2994
+ ".cm-tooltip-lint": {
2995
+ padding: 0,
2996
+ margin: 0
2997
+ },
2998
+ ".cm-lintPoint": {
2999
+ position: "relative",
3000
+ "&:after": {
3001
+ content: "\"\"",
3002
+ position: "absolute",
3003
+ bottom: 0,
3004
+ left: "-2px",
3005
+ borderLeft: "3px solid transparent",
3006
+ borderRight: "3px solid transparent",
3007
+ borderBottom: "4px solid #d11"
3008
+ }
3009
+ },
3010
+ ".cm-lintPoint-warning": { "&:after": { borderBottomColor: "orange" } },
3011
+ ".cm-lintPoint-info": { "&:after": { borderBottomColor: "#999" } },
3012
+ ".cm-lintPoint-hint": { "&:after": { borderBottomColor: "#66d" } },
3013
+ ".cm-panel.cm-panel-lint": {
3014
+ position: "relative",
3015
+ "& ul": {
3016
+ maxHeight: "100px",
3017
+ overflowY: "auto",
3018
+ "& [aria-selected]": {
3019
+ backgroundColor: "#ddd",
3020
+ "& u": { textDecoration: "underline" }
3021
+ },
3022
+ "&:focus [aria-selected]": {
3023
+ background_fallback: "#bdf",
3024
+ backgroundColor: "Highlight",
3025
+ color_fallback: "white",
3026
+ color: "HighlightText"
3027
+ },
3028
+ "& u": { textDecoration: "none" },
3029
+ padding: 0,
3030
+ margin: 0
3031
+ },
3032
+ "& [name=close]": {
3033
+ position: "absolute",
3034
+ top: "0",
3035
+ right: "2px",
3036
+ background: "inherit",
3037
+ border: "none",
3038
+ font: "inherit",
3039
+ padding: 0,
3040
+ margin: 0
3041
+ }
3042
+ }
3043
+ });
3044
+ function severityWeight(sev) {
3045
+ return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1;
3046
+ }
3047
+ function maxSeverity(diagnostics) {
3048
+ let sev = "hint", weight = 1;
3049
+ for (let d of diagnostics) {
3050
+ let w = severityWeight(d.severity);
3051
+ if (w > weight) {
3052
+ weight = w;
3053
+ sev = d.severity;
3054
+ }
3055
+ }
3056
+ return sev;
3057
+ }
3058
+ const lintExtensions = [
3059
+ lintState,
3060
+ /* @__PURE__ */ EditorView.decorations.compute([lintState], (state) => {
3061
+ let { selected, panel } = state.field(lintState);
3062
+ return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([activeMark.range(selected.from, selected.to)]);
3063
+ }),
3064
+ /* @__PURE__ */ hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
3065
+ baseTheme$1
3066
+ ];
3067
+
3068
+ //#endregion
3069
+ //#region lib/utils.ts
3070
+ function stateWORDAt(state, pos) {
3071
+ const { text, from, length } = state.doc.lineAt(pos);
3072
+ const cat = state.charCategorizer(pos);
3073
+ let start = pos - from, end = pos - from;
3074
+ while (start > 0) {
3075
+ const prev = findClusterBreak(text, start, false);
3076
+ if (cat(text.slice(prev, start)) === CharCategory.Space) break;
3077
+ start = prev;
3078
+ }
3079
+ while (end < length) {
3080
+ const next = findClusterBreak(text, end);
3081
+ if (cat(text.slice(end, next)) === CharCategory.Space) break;
3082
+ end = next;
3083
+ }
3084
+ return start == end ? null : EditorSelection.range(start + from, end + from);
3085
+ }
3086
+ function rangeTouchesRange(a, b) {
3087
+ return a.from <= b.to && b.from <= a.to;
3088
+ }
3089
+ function selectionTouchesRange(selection, b) {
3090
+ return selection.some((range) => rangeTouchesRange(range, b));
3091
+ }
3092
+ function iterChildren(cursor, enter) {
3093
+ if (!cursor.firstChild()) return;
3094
+ do
3095
+ if (enter(cursor)) break;
3096
+ while (cursor.nextSibling());
3097
+ console.assert(cursor.parent());
3098
+ }
3099
+ function eventHandlersWithClass(handlers) {
3100
+ return Object.fromEntries(Object.entries(handlers).filter(([_event, handlers$1]) => !!handlers$1).map(([event, handlers$1]) => [event, function(ev, view) {
3101
+ const res = [];
3102
+ for (const className in handlers$1) if (ev.composedPath().some((el) => {
3103
+ if (!(el instanceof Element)) return false;
3104
+ return el.classList.contains(className);
3105
+ })) res.push(handlers$1[className]?.call(this, ev, view));
3106
+ return res.some((res$1) => !!res$1);
3107
+ }]));
3108
+ }
3109
+
3110
+ //#endregion
3111
+ //#region lib/hide/core.ts
3112
+ const hideTheme = EditorView.theme({ ".cm-hidden-token": { fontSize: "0px" } });
3113
+ const hideInlineDecoration = Decoration.mark({ class: "cm-hidden-token" });
3114
+ const hideBlockDecoration = Decoration.replace({ block: true });
3115
+ const buildDecorations$1 = (state) => {
3116
+ const decorations = [];
3117
+ const specs = state.facet(hidableNodeFacet);
3118
+ syntaxTree(state).iterate({ enter: (node) => {
3119
+ if (state.selection.ranges.some((range) => rangeTouchesRange(node, range))) return;
3120
+ for (const spec of specs) {
3121
+ if (spec.nodeName instanceof Function) {
3122
+ if (!spec.nodeName(node.type.name)) continue;
3123
+ } else if (spec.nodeName instanceof Array) {
3124
+ if (!spec.nodeName.includes(node.type.name)) continue;
3125
+ } else if (node.type.name !== spec.nodeName) continue;
3126
+ if (spec.unhideZone) {
3127
+ const res = spec.unhideZone(state, node);
3128
+ if (state.selection.ranges.some((range) => rangeTouchesRange(res, range))) return;
3129
+ }
3130
+ if (spec.onHide) {
3131
+ const res = spec.onHide(state, node);
3132
+ if (res instanceof Array) decorations.push(...res);
3133
+ else if (res) decorations.push(res);
3134
+ }
3135
+ if (spec.subNodeNameToHide) {
3136
+ let names;
3137
+ if (!Array.isArray(spec.subNodeNameToHide)) names = [spec.subNodeNameToHide];
3138
+ else names = spec.subNodeNameToHide;
3139
+ const cursor = node.node.cursor();
3140
+ console.assert(cursor.firstChild(), "A hide node must have children");
3141
+ do
3142
+ if (names.includes(cursor.type.name)) decorations.push((spec.block ? hideBlockDecoration : hideInlineDecoration).range(cursor.from, cursor.to));
3143
+ while (cursor.nextSibling());
3144
+ }
3145
+ }
3146
+ } });
3147
+ return Decoration.set(decorations, true);
3148
+ };
3149
+ const hideExtension = StateField.define({
3150
+ create(state) {
3151
+ return buildDecorations$1(state);
3152
+ },
3153
+ update(deco, tr) {
3154
+ if (tr.docChanged || tr.selection) return buildDecorations$1(tr.state);
3155
+ return deco.map(tr.changes);
3156
+ },
3157
+ provide: (f) => [EditorView.decorations.from(f), hideTheme]
3158
+ });
3159
+ const hidableNodeFacet = Facet.define({
3160
+ combine(value) {
3161
+ return [...value];
3162
+ },
3163
+ enables: hideExtension
3164
+ });
3165
+
3166
+ //#endregion
3167
+ //#region lib/markdownTags.ts
3168
+ const markdownTags = {
3169
+ headerMark: Tag.define(),
3170
+ inlineCode: Tag.define(),
3171
+ fencedCode: Tag.define(),
3172
+ linkURL: Tag.define(),
3173
+ escapeMark: Tag.define(),
3174
+ emoji: Tag.define(),
3175
+ emojiMark: Tag.define(),
3176
+ listMark: Tag.define()
3177
+ };
3178
+
3179
+ //#endregion
3180
+ //#region lib/hide/index.ts
3181
+ const renderedLinkDecoration = Decoration.mark({ class: "cm-rendered-link" });
3182
+ const defaultHidableSpecs = [
3183
+ {
3184
+ nodeName: (name) => name.startsWith("ATXHeading"),
3185
+ onHide: (_view, node) => {
3186
+ const headerMark = node.node.firstChild;
3187
+ return hideInlineDecoration.range(headerMark.from, Math.min(headerMark.to + 1, node.to));
3188
+ }
3189
+ },
3190
+ {
3191
+ nodeName: (name) => name.startsWith("SetextHeading"),
3192
+ subNodeNameToHide: "HeaderMark",
3193
+ block: true
3194
+ },
3195
+ {
3196
+ nodeName: ["StrongEmphasis", "Emphasis"],
3197
+ subNodeNameToHide: "EmphasisMark"
3198
+ },
3199
+ {
3200
+ nodeName: "InlineCode",
3201
+ subNodeNameToHide: "CodeMark"
3202
+ },
3203
+ {
3204
+ nodeName: "Link",
3205
+ subNodeNameToHide: ["LinkMark", "URL"],
3206
+ onHide: (_state, node) => {
3207
+ return renderedLinkDecoration.range(node.from, node.to);
3208
+ }
3209
+ },
3210
+ {
3211
+ nodeName: "Strikethrough",
3212
+ subNodeNameToHide: "StrikethroughMark"
3213
+ },
3214
+ {
3215
+ nodeName: "Escape",
3216
+ subNodeNameToHide: "EscapeMark",
3217
+ unhideZone: (state, node) => {
3218
+ const WORDAt = stateWORDAt(state, node.from);
3219
+ if (WORDAt && WORDAt.to > node.from + 1) return WORDAt;
3220
+ return state.doc.lineAt(node.from);
3221
+ }
3222
+ },
3223
+ {
3224
+ nodeName: "FencedCode",
3225
+ subNodeNameToHide: ["CodeMark", "CodeInfo"]
3226
+ },
3227
+ {
3228
+ nodeName: "Blockquote",
3229
+ subNodeNameToHide: "QuoteMark"
3230
+ }
3231
+ ];
3232
+ const defaultHideExtensions = defaultHidableSpecs.map((spec) => hidableNodeFacet.of(spec));
3233
+ const escapeMarkdownSyntaxExtension = {
3234
+ defineNodes: [{
3235
+ name: "EscapeMark",
3236
+ style: markdownTags.escapeMark
3237
+ }],
3238
+ parseInline: [{
3239
+ name: "EscapeMark",
3240
+ parse: (cx, next, pos) => {
3241
+ if (next !== 92) return -1;
3242
+ return cx.addElement(cx.elt("Escape", pos, pos + 2, [cx.elt("EscapeMark", pos, pos + 1)]));
3243
+ },
3244
+ before: "Escape"
3245
+ }]
3246
+ };
3247
+
3248
+ //#endregion
3249
+ //#region lib/fold/core.ts
3250
+ const buildDecorations = (state) => {
3251
+ const decorations = [];
3252
+ const specs = state.facet(foldableSyntaxFacet);
3253
+ syntaxTree(state).iterate({ enter: (node) => {
3254
+ if (selectionTouchesRange(state.selection.ranges, node)) return;
3255
+ for (const spec of specs) {
3256
+ const lineage = [];
3257
+ let node_ = node;
3258
+ while (node_) {
3259
+ lineage.push(node_.name);
3260
+ node_ = node_.node.parent;
3261
+ }
3262
+ const path = lineage.reverse().join("/");
3263
+ if (spec.nodePath instanceof Function) {
3264
+ if (!spec.nodePath(path)) continue;
3265
+ } else if (spec.nodePath instanceof Array) {
3266
+ if (!spec.nodePath.some((testPath) => path.endsWith(testPath))) continue;
3267
+ } else if (!path.endsWith(spec.nodePath)) continue;
3268
+ if (spec.unfoldZone) {
3269
+ if (selectionTouchesRange(state.selection.ranges, spec.unfoldZone(state, node))) return;
3270
+ }
3271
+ if (spec.onFold) {
3272
+ const res = spec.onFold(state, node);
3273
+ if (res instanceof Array) decorations.push(...res);
3274
+ else if (res) decorations.push(res);
3275
+ }
3276
+ }
3277
+ } });
3278
+ return Decoration.set(decorations, true);
3279
+ };
3280
+ const foldDecorationExtension = StateField.define({
3281
+ create(state) {
3282
+ return buildDecorations(state);
3283
+ },
3284
+ update(deco, tr) {
3285
+ if (tr.docChanged || tr.selection) return buildDecorations(tr.state);
3286
+ return deco.map(tr.changes);
3287
+ },
3288
+ provide: (f) => [EditorView.decorations.from(f)]
3289
+ });
3290
+ const foldExtension = [foldDecorationExtension];
3291
+ const foldableSyntaxFacet = Facet.define({
3292
+ combine(value) {
3293
+ return [...value];
3294
+ },
3295
+ enables: foldExtension
3296
+ });
3297
+ const selectAllDecorationsOnSelectExtension = (widgetClass) => EditorView.domEventHandlers(eventHandlersWithClass({ mousedown: { [widgetClass]: (e, view) => {
3298
+ const ranges = view.state.selection.ranges;
3299
+ if (ranges.length === 0 || ranges[0]?.anchor !== ranges[0]?.head) return;
3300
+ const target = e.target;
3301
+ const pos = view.posAtDOM(target);
3302
+ view.state.field(foldDecorationExtension).between(pos, pos, (from, to) => {
3303
+ setTimeout(() => {
3304
+ view.dispatch({ selection: EditorSelection.single(to, from) });
3305
+ }, 0);
3306
+ return false;
3307
+ });
3308
+ } } }));
3309
+
3310
+ //#endregion
3311
+ //#region lib/fold/bulletList.ts
3312
+ var BulletPoint = class extends WidgetType {
3313
+ toDOM() {
3314
+ const span = document.createElement("span");
3315
+ span.className = "cm-rendered-list-mark";
3316
+ span.innerHTML = "•";
3317
+ return span;
3318
+ }
3319
+ ignoreEvent(_event) {
3320
+ return false;
3321
+ }
3322
+ };
3323
+ const bulletListExtension = foldableSyntaxFacet.of({
3324
+ nodePath: "BulletList/ListItem/ListMark",
3325
+ onFold: (_state, node) => {
3326
+ const cursor = node.node.cursor();
3327
+ if (cursor.nextSibling() && cursor.name === "Task") return;
3328
+ return Decoration.replace({ widget: new BulletPoint() }).range(node.from, node.to);
3329
+ }
3330
+ });
3331
+
3332
+ //#endregion
3333
+ //#region lib/fold/emoji.ts
3334
+ const emojiDelimiter = {
3335
+ resolve: "Emoji",
3336
+ mark: "EmojiMark"
3337
+ };
3338
+ const emojiMarkdownSyntaxExtension = {
3339
+ defineNodes: [{
3340
+ name: "Emoji",
3341
+ style: markdownTags.emoji
3342
+ }, {
3343
+ name: "EmojiMark",
3344
+ style: markdownTags.emojiMark
3345
+ }],
3346
+ parseInline: [{
3347
+ name: "Emoji",
3348
+ parse: (cx, next, pos) => {
3349
+ if (next !== 58) return -1;
3350
+ const open = /^\w+:/.test(cx.slice(pos + 1, cx.end));
3351
+ const close = /:\w+$/.test(cx.slice(cx.offset, pos));
3352
+ if (!open && !close) return -1;
3353
+ return cx.addDelimiter(emojiDelimiter, pos, pos + 1, open, close);
3354
+ },
3355
+ before: "Emphasis"
3356
+ }]
3357
+ };
3358
+ var EmojiWidget = class extends WidgetType {
3359
+ constructor(emoji$1) {
3360
+ super();
3361
+ this.emoji = emoji$1;
3362
+ }
3363
+ toDOM() {
3364
+ const span = document.createElement("span");
3365
+ span.className = "cm-emoji";
3366
+ span.innerHTML = this.emoji;
3367
+ return span;
3368
+ }
3369
+ };
3370
+ const emojiExtension = foldableSyntaxFacet.of({
3371
+ nodePath: "Emoji",
3372
+ onFold: (state, node) => {
3373
+ const emojiName = state.doc.sliceString(node.from + 1, node.to - 1);
3374
+ const emoji_ = emoji.get(emojiName);
3375
+ if (!emoji_) return;
3376
+ return Decoration.replace({ widget: new EmojiWidget(emoji_) }).range(node.from, node.to);
3377
+ }
3378
+ });
3379
+
3380
+ //#endregion
3381
+ //#region lib/fold/horizontalRule.ts
3382
+ var HorizontalRuleWidget = class extends WidgetType {
3383
+ toDOM() {
3384
+ const div = document.createElement("div");
3385
+ div.className = "cm-horizontal-rule-container";
3386
+ const hr = document.createElement("hr");
3387
+ div.appendChild(hr);
3388
+ return div;
3389
+ }
3390
+ ignoreEvent(_event) {
3391
+ return false;
3392
+ }
3393
+ destroy(dom) {
3394
+ dom.remove();
3395
+ }
3396
+ };
3397
+ const horizontalRuleTheme = EditorView.theme({ ".cm-horizontal-rule-container": {
3398
+ height: "1.4em",
3399
+ display: "flow-root",
3400
+ "align-items": "center",
3401
+ padding: "0 2px 0 6px"
3402
+ } });
3403
+ const horizonalRuleExtension = [
3404
+ foldableSyntaxFacet.of({
3405
+ nodePath: "HorizontalRule",
3406
+ onFold: (_state, node) => {
3407
+ return Decoration.replace({
3408
+ widget: new HorizontalRuleWidget(),
3409
+ block: true,
3410
+ inclusiveStart: true
3411
+ }).range(node.from, node.to);
3412
+ }
3413
+ }),
3414
+ horizontalRuleTheme,
3415
+ selectAllDecorationsOnSelectExtension("cm-horizontal-rule-container")
3416
+ ];
3417
+
3418
+ //#endregion
3419
+ //#region lib/fold/image.ts
3420
+ var ImageWidget = class extends WidgetType {
3421
+ constructor(url) {
3422
+ super();
3423
+ this.url = url;
3424
+ }
3425
+ toDOM() {
3426
+ const span = document.createElement("span");
3427
+ span.className = "cm-image";
3428
+ if (this.url) span.innerHTML = `<img src="${this.url}" />`;
3429
+ return span;
3430
+ }
3431
+ ignoreEvent(_event) {
3432
+ return false;
3433
+ }
3434
+ };
3435
+ const imageExtension = [foldableSyntaxFacet.of({
3436
+ nodePath: "Image",
3437
+ onFold: (state, node) => {
3438
+ let imageUrl;
3439
+ iterChildren(node.node.cursor(), (node$1) => {
3440
+ if (node$1.name === "URL") imageUrl = state.doc.sliceString(node$1.from, node$1.to);
3441
+ });
3442
+ if (imageUrl) return Decoration.replace({ widget: new ImageWidget(imageUrl) }).range(node.from, node.to);
3443
+ }
3444
+ }), selectAllDecorationsOnSelectExtension("cm-image")];
3445
+
3446
+ //#endregion
3447
+ //#region lib/fold/task.ts
3448
+ var Checkbox = class extends WidgetType {
3449
+ value;
3450
+ constructor(value) {
3451
+ super();
3452
+ this.value = value;
3453
+ }
3454
+ toDOM() {
3455
+ const el = document.createElement("input");
3456
+ el.type = "checkbox";
3457
+ el.className = "cm-checkbox";
3458
+ el.checked = this.value;
3459
+ return el;
3460
+ }
3461
+ ignoreEvent(_event) {
3462
+ return false;
3463
+ }
3464
+ };
3465
+ const taskExtension = [foldableSyntaxFacet.of({
3466
+ nodePath: "BulletList/ListItem/Task/TaskMarker",
3467
+ onFold: (state, node) => {
3468
+ const value = state.doc.sliceString(node.from + 1, node.to - 1).toLowerCase() === "x";
3469
+ return Decoration.replace({ widget: new Checkbox(value) }).range(node.from - 2, node.to);
3470
+ },
3471
+ unfoldZone: (_state, node) => ({
3472
+ from: node.from - 2,
3473
+ to: node.to
3474
+ })
3475
+ }), EditorView.domEventHandlers(eventHandlersWithClass({ mousedown: { "cm-checkbox": (ev, view) => {
3476
+ const pos = view.posAtDOM(ev.target);
3477
+ const change = {
3478
+ from: pos + 3,
3479
+ to: pos + 4,
3480
+ insert: ev.target.checked ? " " : "x"
3481
+ };
3482
+ view.dispatch({ changes: change });
3483
+ return true;
3484
+ } } }))];
3485
+
3486
+ //#endregion
3487
+ //#region lib/fold/blockQuote.ts
3488
+ var BlockQuoteVerticalLine = class extends WidgetType {
3489
+ toDOM() {
3490
+ const span = document.createElement("span");
3491
+ span.className = "cm-blockquote-vertical-line";
3492
+ return span;
3493
+ }
3494
+ ignoreEvent(_event) {
3495
+ return false;
3496
+ }
3497
+ };
3498
+ const blockQuoteExtension = foldableSyntaxFacet.of({
3499
+ nodePath: (nodePath) => nodePath.endsWith("Blockquote/QuoteMark") || nodePath.endsWith("Blockquote/Paragraph/QuoteMark"),
3500
+ onFold: (_state, node) => {
3501
+ return Decoration.replace({ widget: new BlockQuoteVerticalLine() }).range(node.from, node.to);
3502
+ }
3503
+ });
3504
+
3505
+ //#endregion
3506
+ //#region lib/syntaxHighlighting.ts
3507
+ const additionalMarkdownSyntaxTags = {
3508
+ defineNodes: [],
3509
+ props: [styleTags({
3510
+ HeaderMark: markdownTags.headerMark,
3511
+ FencedCode: markdownTags.fencedCode,
3512
+ InlineCode: markdownTags.inlineCode,
3513
+ URL: markdownTags.linkURL,
3514
+ ListMark: markdownTags.listMark
3515
+ })]
3516
+ };
3517
+ const headingTagStyles = (fontSizes) => fontSizes.map((fontSize, i) => ({
3518
+ tag: tags[`heading${(i + 1).toString()}`],
3519
+ fontSize,
3520
+ fontWeight: "bold"
3521
+ }));
3522
+ const baseSyntaxHighlights = syntaxHighlighting(HighlightStyle.define([
3523
+ ...headingTagStyles([
3524
+ "1.6em",
3525
+ "1.4em",
3526
+ "1.2em",
3527
+ null,
3528
+ null,
3529
+ null
3530
+ ]),
3531
+ {
3532
+ tag: markdownTags.headerMark,
3533
+ color: "var(--pm-header-mark-color)"
3534
+ },
3535
+ {
3536
+ tag: tags.strong,
3537
+ fontWeight: "bold"
3538
+ },
3539
+ {
3540
+ tag: tags.emphasis,
3541
+ fontStyle: "italic"
3542
+ },
3543
+ {
3544
+ tag: tags.strikethrough,
3545
+ textDecoration: "line-through"
3546
+ },
3547
+ {
3548
+ tag: tags.meta,
3549
+ color: "var(--pm-muted-color)"
3550
+ },
3551
+ {
3552
+ tag: tags.comment,
3553
+ color: "var(--pm-muted-color)"
3554
+ },
3555
+ {
3556
+ tag: markdownTags.listMark,
3557
+ color: "var(--pm-muted-color)"
3558
+ },
3559
+ {
3560
+ tag: markdownTags.escapeMark,
3561
+ color: "var(--pm-muted-color)"
3562
+ },
3563
+ {
3564
+ tag: markdownTags.inlineCode,
3565
+ fontFamily: "monospace",
3566
+ padding: "0.2rem",
3567
+ borderRadius: "0.4rem",
3568
+ fontSize: "0.8rem",
3569
+ backgroundColor: "var(--pm-code-background-color)"
3570
+ },
3571
+ {
3572
+ tag: markdownTags.linkURL,
3573
+ color: "var(--pm-link-color)",
3574
+ textDecoration: "underline",
3575
+ cursor: "pointer"
3576
+ }
3577
+ ]));
3578
+ const baseTheme = EditorView.theme({
3579
+ ".cm-content": {
3580
+ fontFamily: "var(--font)",
3581
+ fontSize: "0.9rem",
3582
+ caretColor: "var(--pm-cursor-color)"
3583
+ },
3584
+ ".cm-editor .cm-cursor, .cm-editor .cm-dropCursor": { borderLeftColor: "var(--pm-cursor-color)" },
3585
+ "&.cm-focused": { outline: "none" },
3586
+ ".cm-gutters": {
3587
+ backgroundColor: "transparent",
3588
+ border: "none"
3589
+ },
3590
+ ".cm-rendered-link": {
3591
+ textDecoration: "underline",
3592
+ cursor: "pointer",
3593
+ color: "var(--pm-link-color)"
3594
+ },
3595
+ ".cm-rendered-list-mark": {
3596
+ color: "var(--pm-muted-color)",
3597
+ margin: "0 0.2em"
3598
+ },
3599
+ ".cm-blockquote-vertical-line": {
3600
+ display: "inline-block",
3601
+ width: "4px",
3602
+ marginRight: "4px",
3603
+ marginLeft: "4px",
3604
+ height: "1.4em",
3605
+ verticalAlign: "bottom",
3606
+ backgroundColor: "var(--pm-blockquote-vertical-line-background-color)"
3607
+ }
3608
+ });
3609
+ const generalSyntaxHighlights = syntaxHighlighting(HighlightStyle.define([
3610
+ {
3611
+ tag: tags.link,
3612
+ color: "var(--pm-syntax-link)"
3613
+ },
3614
+ {
3615
+ tag: tags.keyword,
3616
+ color: "var(--pm-syntax-keyword)"
3617
+ },
3618
+ {
3619
+ tag: [
3620
+ tags.atom,
3621
+ tags.bool,
3622
+ tags.url,
3623
+ tags.contentSeparator,
3624
+ tags.labelName
3625
+ ],
3626
+ color: "var(--pm-syntax-atom)"
3627
+ },
3628
+ {
3629
+ tag: [tags.literal, tags.inserted],
3630
+ color: "var(--pm-syntax-literal)"
3631
+ },
3632
+ {
3633
+ tag: [tags.string, tags.deleted],
3634
+ color: "var(--pm-syntax-string)"
3635
+ },
3636
+ {
3637
+ tag: [
3638
+ tags.regexp,
3639
+ tags.escape,
3640
+ tags.special(tags.string)
3641
+ ],
3642
+ color: "var(--pm-syntax-regexp)"
3643
+ },
3644
+ {
3645
+ tag: tags.definition(tags.variableName),
3646
+ color: "var(--pm-syntax-definition-variable)"
3647
+ },
3648
+ {
3649
+ tag: tags.local(tags.variableName),
3650
+ color: "var(--pm-syntax-local-variable)"
3651
+ },
3652
+ {
3653
+ tag: [tags.typeName, tags.namespace],
3654
+ color: "var(--pm-syntax-type-namespace)"
3655
+ },
3656
+ {
3657
+ tag: tags.className,
3658
+ color: "var(--pm-syntax-class-name)"
3659
+ },
3660
+ {
3661
+ tag: [tags.special(tags.variableName), tags.macroName],
3662
+ color: "var(--pm-syntax-special-variable-macro)"
3663
+ },
3664
+ {
3665
+ tag: tags.definition(tags.propertyName),
3666
+ color: "var(--pm-syntax-definition-property)"
3667
+ },
3668
+ {
3669
+ tag: tags.comment,
3670
+ color: "var(--pm-syntax-comment)"
3671
+ },
3672
+ {
3673
+ tag: tags.invalid,
3674
+ color: "var(--pm-syntax-invalid)"
3675
+ }
3676
+ ]));
3677
+ const lightTheme = EditorView.theme({ ".cm-content": {
3678
+ "--pm-cursor-color": "black",
3679
+ "--pm-header-mark-color": "oklch(82.8% 0.111 230.318)",
3680
+ "--pm-link-color": "oklch(58.8% 0.158 241.966)",
3681
+ "--pm-muted-color": "oklch(37.2% 0.044 257.287)",
3682
+ "--pm-code-background-color": "oklch(92.9% 0.013 255.508)",
3683
+ "--pm-code-btn-background-color": "oklch(86.9% 0.022 252.894)",
3684
+ "--pm-code-btn-hover-background-color": "oklch(70.4% 0.04 256.788)",
3685
+ "--pm-blockquote-vertical-line-background-color": "oklch(70.4% 0.04 256.788)",
3686
+ "--pm-syntax-link": "oklch(62.75% 0.188 259.38)",
3687
+ "--pm-syntax-keyword": "oklch(58.13% 0.248 297.57)",
3688
+ "--pm-syntax-atom": "oklch(51.29% 0.219 260.63)",
3689
+ "--pm-syntax-literal": "oklch(57.38% 0.111 170.31)",
3690
+ "--pm-syntax-string": "oklch(54.86% 0.184 25.53)",
3691
+ "--pm-syntax-regexp": "oklch(65.88% 0.184 43.8)",
3692
+ "--pm-syntax-definition-variable": "oklch(45.32% 0.171 260.3)",
3693
+ "--pm-syntax-local-variable": "oklch(64.13% 0.09 184.42)",
3694
+ "--pm-syntax-type-namespace": "oklch(49.1% 0.091 165.52)",
3695
+ "--pm-syntax-class-name": "oklch(64.42% 0.11 168.83)",
3696
+ "--pm-syntax-special-variable-macro": "oklch(52.58% 0.212 282.71)",
3697
+ "--pm-syntax-definition-property": "oklch(42.1% 0.142 260.08)",
3698
+ "--pm-syntax-comment": "oklch(62.79% 0.022 252.89)",
3699
+ "--pm-syntax-invalid": "oklch(64.62% 0.203 29.2)"
3700
+ } });
3701
+
3702
+ //#endregion
3703
+ //#region lib/clickLink.ts
3704
+ function getUrlFromLink(view, pos) {
3705
+ const tree = syntaxTree(view.state);
3706
+ let url;
3707
+ tree.iterate({
3708
+ to: pos,
3709
+ from: pos,
3710
+ enter(node) {
3711
+ if (node.name !== "Link") return;
3712
+ iterChildren(node.node.cursor(), (cursor) => {
3713
+ if (cursor.name === "URL") {
3714
+ url = view.state.doc.sliceString(cursor.from, cursor.to);
3715
+ return true;
3716
+ }
3717
+ });
3718
+ return true;
3719
+ }
3720
+ });
3721
+ return url;
3722
+ }
3723
+ const clickLinkHandler = Facet.define();
3724
+ const defaultClickLinkHandler = clickLinkHandler.of((url) => {
3725
+ window.open(url, "_blank");
3726
+ });
3727
+ const clickFullLinkExtension = EditorView$1.domEventHandlers(eventHandlersWithClass({ mousedown: { "cm-rendered-link": (e, view) => {
3728
+ const pos = view.posAtCoords(e);
3729
+ if (pos === null) return;
3730
+ const url = getUrlFromLink(view, pos);
3731
+ if (!url) return;
3732
+ view.state.facet(clickLinkHandler).map((handler) => {
3733
+ handler(url);
3734
+ });
3735
+ } } }));
3736
+ const getRawUrl = (view, pos) => {
3737
+ const tree = syntaxTree(view.state);
3738
+ let url;
3739
+ tree.iterate({
3740
+ to: pos,
3741
+ from: pos,
3742
+ enter(node) {
3743
+ if (node.name !== "URL") return;
3744
+ if (node.node.parent?.name === "Link") return;
3745
+ url = view.state.doc.sliceString(node.from, node.to);
3746
+ return true;
3747
+ }
3748
+ });
3749
+ return url;
3750
+ };
3751
+ const addClassToUrl = syntaxHighlighting(HighlightStyle.define([{
3752
+ tag: markdownTags.linkURL,
3753
+ class: "cm-url"
3754
+ }]));
3755
+ const clickRawUrlExtension = EditorView$1.domEventHandlers(eventHandlersWithClass({ mousedown: { "cm-url": (e, view) => {
3756
+ const pos = view.posAtCoords(e);
3757
+ if (pos === null) return;
3758
+ const url = getRawUrl(view, pos);
3759
+ if (!url) return;
3760
+ view.state.facet(clickLinkHandler).map((handler) => {
3761
+ handler(url);
3762
+ });
3763
+ } } }));
3764
+ const clickLinkExtension = [
3765
+ clickFullLinkExtension,
3766
+ addClassToUrl,
3767
+ clickRawUrlExtension
3768
+ ];
3769
+
3770
+ //#endregion
3771
+ //#region lib/codeFenceExtension.ts
3772
+ const codeBlockDecorations = (view) => {
3773
+ const builder = new RangeSetBuilder();
3774
+ const visited = /* @__PURE__ */ new Set();
3775
+ for (const { from, to } of view.visibleRanges) syntaxTree(view.state).iterate({
3776
+ from,
3777
+ to,
3778
+ enter: (node) => {
3779
+ if (node.name === "FencedCode") {
3780
+ const key = JSON.stringify([node.from, node.to]);
3781
+ if (visited.has(key)) return;
3782
+ visited.add(key);
3783
+ let lang = "";
3784
+ const codeInfoNode = node.node.getChild("CodeInfo");
3785
+ if (codeInfoNode) lang = view.state.doc.sliceString(codeInfoNode.from, codeInfoNode.to).toUpperCase();
3786
+ for (let pos = node.from; pos <= node.to;) {
3787
+ const line = view.state.doc.lineAt(pos);
3788
+ const isFirstLine = pos === node.from;
3789
+ const isLastLine = line.to >= node.to;
3790
+ builder.add(line.from, line.from, Decoration.line({ class: `cm-fenced-code-line ${isFirstLine ? "cm-fenced-code-line-first" : ""} ${isLastLine ? "cm-fenced-code-line-last" : ""}` }));
3791
+ if (isFirstLine) builder.add(line.from, line.from, Decoration.widget({ widget: new CodeBlockInfoWidget(lang, view.state.doc.sliceString(line.to + 1, node.to - 4)) }));
3792
+ pos = line.to + 1;
3793
+ }
3794
+ }
3795
+ }
3796
+ });
3797
+ return builder.finish();
3798
+ };
3799
+ var CodeBlockInfoWidget = class extends WidgetType {
3800
+ constructor(lang, code) {
3801
+ super();
3802
+ this.lang = lang;
3803
+ this.code = code;
3804
+ }
3805
+ eq(other) {
3806
+ return other.lang === this.lang && other.code === this.code;
3807
+ }
3808
+ toDOM() {
3809
+ const container = document.createElement("div");
3810
+ container.className = "cm-code-block-info";
3811
+ const langContainer = document.createElement("span");
3812
+ langContainer.className = "cm-code-block-lang-container";
3813
+ langContainer.innerText = this.lang;
3814
+ container.appendChild(langContainer);
3815
+ const copyButton = document.createElement("button");
3816
+ copyButton.className = "cm-code-block-copy-button";
3817
+ copyButton.innerHTML = `
3818
+ <svg xmlns="http://www.w3.org/2000/svg"
3819
+ width="16" height="16" viewBox="0 0 24 24"
3820
+ fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
3821
+ class="lucide lucide-copy-icon lucide-copy">
3822
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
3823
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
3824
+ </svg>`;
3825
+ copyButton.onclick = () => {
3826
+ navigator.clipboard.writeText(this.code);
3827
+ };
3828
+ container.appendChild(copyButton);
3829
+ return container;
3830
+ }
3831
+ };
3832
+ const codeBlockDecorationsExtension = ViewPlugin.fromClass(class {
3833
+ decorations;
3834
+ constructor(view) {
3835
+ this.decorations = codeBlockDecorations(view);
3836
+ }
3837
+ update(update) {
3838
+ if (update.docChanged || update.viewportChanged) this.decorations = codeBlockDecorations(update.view);
3839
+ }
3840
+ }, { decorations: (v) => v.decorations });
3841
+ const codeFenceTheme = EditorView.theme({
3842
+ ".cm-fenced-code-line": {
3843
+ display: "block",
3844
+ marginLeft: "6px",
3845
+ backgroundColor: "var(--pm-code-background-color)"
3846
+ },
3847
+ ".cm-activeLine.cm-fenced-code-line": { backgroundColor: "var(--pm-code-background-color)" },
3848
+ ".cm-fenced-code-line-first": {
3849
+ borderTopLeftRadius: "0.4rem",
3850
+ borderTopRightRadius: "0.4rem"
3851
+ },
3852
+ ".cm-fenced-code-line-last": {
3853
+ borderBottomLeftRadius: "0.4rem",
3854
+ borderBottomRightRadius: "0.4rem"
3855
+ },
3856
+ ".cm-code-block-info": {
3857
+ float: "right",
3858
+ padding: "0.2rem",
3859
+ display: "flex",
3860
+ gap: "0.3rem",
3861
+ alignItems: "center"
3862
+ },
3863
+ ".cm-code-block-lang-container": {
3864
+ fontSize: "0.8rem",
3865
+ color: "var(--pm-muted-color)"
3866
+ },
3867
+ ".cm-code-block-copy-button": {
3868
+ display: "flex",
3869
+ alignItems: "center",
3870
+ justifyContent: "center",
3871
+ border: "none",
3872
+ padding: "0.2rem",
3873
+ borderRadius: "0.2rem",
3874
+ cursor: "pointer",
3875
+ backgroundColor: "var(--pm-code-btn-background-color)",
3876
+ color: "var(--pm-muted-color)"
3877
+ },
3878
+ ".cm-code-block-copy-button:hover": { backgroundColor: "var(--pm-code-btn-hover-background-color)" },
3879
+ ".cm-code-block-copy-button svg": {
3880
+ width: "16px",
3881
+ height: "16px"
3882
+ }
3883
+ });
3884
+
3885
+ //#endregion
3886
+ //#region lib/basicSetup.ts
3887
+ const prosemarkMarkdownSyntaxExtensions = [
3888
+ additionalMarkdownSyntaxTags,
3889
+ escapeMarkdownSyntaxExtension,
3890
+ emojiMarkdownSyntaxExtension
3891
+ ];
3892
+ const defaultFoldableSyntaxExtensions = [
3893
+ blockQuoteExtension,
3894
+ bulletListExtension,
3895
+ taskExtension,
3896
+ imageExtension,
3897
+ emojiExtension,
3898
+ horizonalRuleExtension
3899
+ ];
3900
+ const prosemarkBasicSetup = () => [
3901
+ history(),
3902
+ dropCursor(),
3903
+ indentOnInput(),
3904
+ bracketMatching(),
3905
+ closeBrackets(),
3906
+ autocompletion(),
3907
+ keymap.of([
3908
+ ...closeBracketsKeymap,
3909
+ ...defaultKeymap,
3910
+ ...searchKeymap,
3911
+ ...historyKeymap,
3912
+ ...foldKeymap,
3913
+ ...completionKeymap,
3914
+ ...lintKeymap,
3915
+ indentWithTab
3916
+ ]),
3917
+ foldGutter(),
3918
+ EditorView.lineWrapping,
3919
+ defaultHideExtensions,
3920
+ defaultFoldableSyntaxExtensions,
3921
+ clickLinkExtension,
3922
+ codeBlockDecorationsExtension
3923
+ ];
3924
+ const prosemarkBaseThemeSetup = () => [
3925
+ baseSyntaxHighlights,
3926
+ generalSyntaxHighlights,
3927
+ baseTheme,
3928
+ codeFenceTheme
3929
+ ];
3930
+ const prosemarkLightThemeSetup = () => lightTheme;
3931
+
3932
+ //#endregion
3933
+ export { additionalMarkdownSyntaxTags, baseSyntaxHighlights, baseTheme, blockQuoteExtension, bulletListExtension, clickLinkExtension, clickLinkHandler, codeBlockDecorationsExtension, codeFenceTheme, defaultClickLinkHandler, defaultFoldableSyntaxExtensions, defaultHideExtensions, emojiExtension, emojiMarkdownSyntaxExtension, escapeMarkdownSyntaxExtension, eventHandlersWithClass, foldDecorationExtension, foldableSyntaxFacet, generalSyntaxHighlights, horizonalRuleExtension, imageExtension, lightTheme, markdownTags, prosemarkBaseThemeSetup, prosemarkBasicSetup, prosemarkLightThemeSetup, prosemarkMarkdownSyntaxExtensions, selectAllDecorationsOnSelectExtension, taskExtension };