@prosemark/core 0.0.0

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