@actis/codemirror 26.9.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/index.mjs ADDED
@@ -0,0 +1,715 @@
1
+ import { autocompletion, snippetCompletion } from "@codemirror/autocomplete";
2
+ import { cpp } from "@codemirror/lang-cpp";
3
+ import { Decoration, EditorView, ViewPlugin, scrollPastEnd } from "@codemirror/view";
4
+ import { basicSetup } from "codemirror";
5
+ import { RangeSetBuilder } from "@codemirror/state";
6
+ import { HighlightStyle, codeFolding, syntaxHighlighting } from "@codemirror/language";
7
+ import { forEachDiagnostic } from "@codemirror/lint";
8
+ import { tags } from "@lezer/highlight";
9
+ //#region src/plugin/bracket-match.ts
10
+ const MATCH = new Map([
11
+ ["(", ")"],
12
+ ["[", "]"],
13
+ ["{", "}"]
14
+ ]);
15
+ const OPEN = new Set(MATCH.keys());
16
+ const CLOSE = new Set(MATCH.values());
17
+ function findUnmatchedBrackets(doc) {
18
+ const stack = [];
19
+ const unmatched = [];
20
+ let offset = 0;
21
+ const iter = doc.iter();
22
+ while (!iter.next().done) {
23
+ const chunk = iter.value;
24
+ for (let i = 0; i < chunk.length; i++) {
25
+ const ch = chunk[i];
26
+ if (OPEN.has(ch)) stack.push({
27
+ char: ch,
28
+ pos: offset + i
29
+ });
30
+ else if (CLOSE.has(ch)) {
31
+ const top = stack.at(-1);
32
+ if (top && MATCH.get(top.char) === ch) stack.pop();
33
+ else unmatched.push(offset + i);
34
+ }
35
+ }
36
+ offset += chunk.length;
37
+ }
38
+ for (const { pos } of stack) unmatched.push(pos);
39
+ return unmatched.sort((a, b) => a - b);
40
+ }
41
+ const unmatchedDecoration = Decoration.mark({ class: "cm-nonmatchingBracket" });
42
+ function buildDecorations(doc) {
43
+ const builder = new RangeSetBuilder();
44
+ for (const pos of findUnmatchedBrackets(doc)) builder.add(pos, pos + 1, unmatchedDecoration);
45
+ return builder.finish();
46
+ }
47
+ const nonMatchingBracketPlugin = ViewPlugin.fromClass(class {
48
+ constructor(view) {
49
+ this.decorations = buildDecorations(view.state.doc);
50
+ }
51
+ update(update) {
52
+ if (update.docChanged) this.decorations = buildDecorations(update.state.doc);
53
+ }
54
+ }, { decorations: (v) => v.decorations });
55
+ //#endregion
56
+ //#region src/plugin/completions.ts
57
+ const WEBGL_KEYWORDS = [
58
+ "precision",
59
+ "lowp",
60
+ "mediump",
61
+ "highp",
62
+ "attribute",
63
+ "uniform",
64
+ "varying",
65
+ "break",
66
+ "continue",
67
+ "do",
68
+ "for",
69
+ "while",
70
+ "if",
71
+ "else",
72
+ "float",
73
+ "int",
74
+ "void",
75
+ "bool",
76
+ "mat2",
77
+ "mat3",
78
+ "mat4",
79
+ "vec2",
80
+ "vec3",
81
+ "vec4",
82
+ "ivec2",
83
+ "ivec3",
84
+ "ivec4",
85
+ "bvec2",
86
+ "bvec3",
87
+ "bvec4",
88
+ "sampler2D",
89
+ "samplerCube",
90
+ "struct",
91
+ "discard",
92
+ "return"
93
+ ];
94
+ const WEBGL2_KEYWORDS = [
95
+ "layout",
96
+ "flat",
97
+ "smooth",
98
+ "noperspective",
99
+ "switch",
100
+ "case",
101
+ "default",
102
+ "uint",
103
+ "uvec2",
104
+ "uvec3",
105
+ "uvec4",
106
+ "mat2x2",
107
+ "mat2x3",
108
+ "mat2x4",
109
+ "mat3x2",
110
+ "mat3x3",
111
+ "mat3x4",
112
+ "mat4x2",
113
+ "mat4x3",
114
+ "mat4x4",
115
+ "isampler2D",
116
+ "isampler3D",
117
+ "isamplerCube",
118
+ "usampler2D",
119
+ "usampler3D",
120
+ "usamplerCube"
121
+ ];
122
+ const SNIPPETS = [{
123
+ label: "main",
124
+ detail: "main entry point",
125
+ type: "function",
126
+ template: "void main() {\n ${}\n gl_FragColor = vec4(1.0);\n}"
127
+ }, {
128
+ label: "for",
129
+ detail: "for loop",
130
+ type: "keyword",
131
+ template: "for (int i = 0; i < ${count}; i++) {\n ${}\n}"
132
+ }];
133
+ const WORD_PATTERN = /\w*/;
134
+ function glslCompletions(options = {}) {
135
+ const completions = [...[...WEBGL_KEYWORDS, ...options.webgl2 ? WEBGL2_KEYWORDS : []].map((kw) => ({
136
+ label: kw,
137
+ type: "keyword"
138
+ })), ...SNIPPETS.map((s) => snippetCompletion(s.template, {
139
+ label: s.label,
140
+ detail: s.detail,
141
+ type: s.type
142
+ }))];
143
+ return (context) => {
144
+ const word = context.matchBefore(WORD_PATTERN);
145
+ if (!word || word.from === word.to && !context.explicit) return null;
146
+ return {
147
+ from: word.from,
148
+ options: completions
149
+ };
150
+ };
151
+ }
152
+ //#endregion
153
+ //#region src/plugin/folding.ts
154
+ function codeFoldingExtension() {
155
+ return [codeFolding({
156
+ preparePlaceholder(state, range) {
157
+ const from = state.doc.lineAt(range.from).number;
158
+ return `${state.doc.lineAt(range.to).number - from} lines`;
159
+ },
160
+ placeholderDOM(_view, onclick, text) {
161
+ const placeholder = document.createElement("span");
162
+ placeholder.className = "cm-fold-placeholder";
163
+ placeholder.textContent = text;
164
+ placeholder.setAttribute("role", "button");
165
+ placeholder.setAttribute("aria-label", "unfold code");
166
+ placeholder.setAttribute("title", "Click to unfold");
167
+ placeholder.setAttribute("tabindex", "0");
168
+ placeholder.style.touchAction = "manipulation";
169
+ placeholder.addEventListener("click", onclick);
170
+ placeholder.addEventListener("keydown", (e) => {
171
+ if (e.key === "Enter" || e.key === " ") {
172
+ e.preventDefault();
173
+ onclick(e);
174
+ }
175
+ });
176
+ return placeholder;
177
+ }
178
+ })];
179
+ }
180
+ //#endregion
181
+ //#region src/plugin/scrollbar.ts
182
+ const scrollbarRuler = ViewPlugin.fromClass(class {
183
+ constructor(view) {
184
+ this.view = view;
185
+ this.rectPool = [];
186
+ this.trackHeight = 0;
187
+ this.scrollHeight = 0;
188
+ this.clientHeight = 0;
189
+ this.thumbHeight = 0;
190
+ this.TRACK_WIDTH = 15;
191
+ this.onThumbPointerDown = (e) => {
192
+ e.stopPropagation();
193
+ e.preventDefault();
194
+ this.thumb.setPointerCapture(e.pointerId);
195
+ const startY = e.clientY;
196
+ const startScrollTop = this.view.scrollDOM.scrollTop;
197
+ const onMove = (ev) => {
198
+ const maxThumbTop = this.trackHeight - this.thumbHeight;
199
+ const maxScrollTop = this.scrollHeight - this.clientHeight;
200
+ if (maxThumbTop <= 0) return;
201
+ this.view.scrollDOM.scrollTop = startScrollTop + (ev.clientY - startY) * (maxScrollTop / maxThumbTop);
202
+ };
203
+ const onUp = () => {
204
+ this.thumb.removeEventListener("pointermove", onMove);
205
+ this.thumb.removeEventListener("pointerup", onUp);
206
+ };
207
+ this.thumb.addEventListener("pointermove", onMove);
208
+ this.thumb.addEventListener("pointerup", onUp);
209
+ };
210
+ this.onTrackPointerDown = (e) => {
211
+ if (e.target === this.thumb) return;
212
+ e.preventDefault();
213
+ const rect = this.inner.getBoundingClientRect();
214
+ const clickFraction = Math.max(0, Math.min(1, (e.clientY - rect.top - this.thumbHeight / 2) / (this.trackHeight - this.thumbHeight)));
215
+ this.view.scrollDOM.scrollTop = clickFraction * (this.scrollHeight - this.clientHeight);
216
+ };
217
+ this.syncThumb = () => {
218
+ const maxScroll = this.scrollHeight - this.clientHeight;
219
+ if (maxScroll <= 0) {
220
+ this.thumb.style.display = "none";
221
+ return;
222
+ }
223
+ this.thumb.style.display = "";
224
+ const thumbTop = this.view.scrollDOM.scrollTop / maxScroll * (this.trackHeight - this.thumbHeight);
225
+ this.thumb.style.transform = `translate3d(0, ${thumbTop}px, 0)`;
226
+ };
227
+ this.gutter = document.createElement("div");
228
+ this.gutter.className = "cm-scrollbar-gutter";
229
+ this.inner = document.createElement("div");
230
+ this.inner.className = "cm-scrollbar-inner";
231
+ this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
232
+ this.svg.setAttribute("aria-hidden", "true");
233
+ this.svg.style.display = "block";
234
+ this.svg.style.width = "100%";
235
+ this.thumb = document.createElement("div");
236
+ this.thumb.className = "cm-scrollbar-thumb";
237
+ this.thumb.style.willChange = "transform";
238
+ this.inner.appendChild(this.svg);
239
+ this.inner.appendChild(this.thumb);
240
+ this.gutter.appendChild(this.inner);
241
+ view.dom.classList.add("cm-with-scrollbar");
242
+ view.dom.appendChild(this.gutter);
243
+ this.cursorRect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
244
+ this.cursorRect.setAttribute("x", "0");
245
+ this.cursorRect.setAttribute("y", "0");
246
+ this.cursorRect.setAttribute("width", `${this.TRACK_WIDTH}`);
247
+ this.cursorRect.setAttribute("height", "2");
248
+ this.cursorRect.setAttribute("fill", "var(--cm-foreground, #888)");
249
+ this.cursorRect.style.willChange = "transform";
250
+ this.svg.appendChild(this.cursorRect);
251
+ this.thumb.addEventListener("pointerdown", this.onThumbPointerDown);
252
+ this.inner.addEventListener("pointerdown", this.onTrackPointerDown);
253
+ this.view.scrollDOM.addEventListener("scroll", this.syncThumb, { passive: true });
254
+ this.measureAndPaint();
255
+ }
256
+ update(update) {
257
+ let needsFullPaint = false;
258
+ if (update.geometryChanged) {
259
+ this.measure();
260
+ needsFullPaint = true;
261
+ }
262
+ if (update.docChanged || update.transactions.some((t) => t.effects.length > 0)) needsFullPaint = true;
263
+ if (needsFullPaint) this.paintMarkers();
264
+ if (update.selectionSet || needsFullPaint) this.paintCursor();
265
+ }
266
+ measure() {
267
+ const scrollDOM = this.view.scrollDOM;
268
+ this.scrollHeight = scrollDOM.scrollHeight;
269
+ this.clientHeight = scrollDOM.clientHeight;
270
+ const scrollerRect = scrollDOM.getBoundingClientRect();
271
+ const editorRect = this.view.dom.getBoundingClientRect();
272
+ this.trackHeight = scrollerRect.height;
273
+ this.gutter.style.top = `${scrollerRect.top - editorRect.top}px`;
274
+ this.gutter.style.height = `${this.trackHeight}px`;
275
+ this.svg.setAttribute("height", `${this.trackHeight}`);
276
+ const newThumbHeight = Math.max(20, this.clientHeight / this.scrollHeight * this.trackHeight);
277
+ if (Math.abs(this.thumbHeight - newThumbHeight) > .5) {
278
+ this.thumbHeight = newThumbHeight;
279
+ this.thumb.style.height = `${newThumbHeight}px`;
280
+ }
281
+ }
282
+ measureAndPaint() {
283
+ this.measure();
284
+ this.paintMarkers();
285
+ this.paintCursor();
286
+ this.syncThumb();
287
+ }
288
+ paintCursor() {
289
+ const { state } = this.view;
290
+ if (state.doc.length === 0 || this.scrollHeight <= 0) return;
291
+ const y = this.posToY(state.selection.main.head);
292
+ this.cursorRect.style.transform = `translate3d(0, ${y}px, 0)`;
293
+ }
294
+ paintMarkers() {
295
+ const { state } = this.view;
296
+ if (state.doc.length === 0 || this.trackHeight <= 0 || this.scrollHeight <= 0) return;
297
+ let i = 0;
298
+ forEachDiagnostic(state, (diag) => {
299
+ if (diag.severity !== "error") return;
300
+ const top = this.posToY(diag.from);
301
+ const bottom = this.posToY(diag.to);
302
+ const height = Math.max(3, bottom - top);
303
+ let rect;
304
+ if (i < this.rectPool.length) rect = this.rectPool[i];
305
+ else {
306
+ rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
307
+ rect.setAttribute("x", "0");
308
+ rect.setAttribute("y", "0");
309
+ rect.setAttribute("width", `${this.TRACK_WIDTH}`);
310
+ rect.setAttribute("height", "1");
311
+ rect.setAttribute("fill", "#ff5555");
312
+ rect.style.transformOrigin = "0 0";
313
+ this.svg.insertBefore(rect, this.cursorRect);
314
+ this.rectPool.push(rect);
315
+ }
316
+ rect.style.transform = `translate3d(0, ${top}px, 0) scaleY(${height})`;
317
+ rect.style.display = "";
318
+ i++;
319
+ });
320
+ while (i < this.rectPool.length) {
321
+ this.rectPool[i].style.display = "none";
322
+ i++;
323
+ }
324
+ }
325
+ posToY(pos) {
326
+ if (this.scrollHeight <= 0) return 0;
327
+ const safePos = Math.max(0, Math.min(pos, this.view.state.doc.length));
328
+ return (this.view.lineBlockAt(safePos).top + this.view.documentPadding.top) / this.scrollHeight * this.trackHeight;
329
+ }
330
+ destroy() {
331
+ this.thumb.removeEventListener("pointerdown", this.onThumbPointerDown);
332
+ this.inner.removeEventListener("pointerdown", this.onTrackPointerDown);
333
+ this.view.scrollDOM.removeEventListener("scroll", this.syncThumb);
334
+ this.gutter.remove();
335
+ }
336
+ });
337
+ const scrollbarRulerTheme = EditorView.baseTheme({
338
+ ".cm-scrollbar-gutter": {
339
+ position: "absolute",
340
+ right: "0",
341
+ width: "0.938rem",
342
+ pointerEvents: "auto",
343
+ overflow: "hidden",
344
+ zIndex: 10,
345
+ userSelect: "none"
346
+ },
347
+ ".cm-scrollbar-inner": {
348
+ position: "relative",
349
+ width: "100%",
350
+ height: "100%",
351
+ backgroundColor: "rgba(0, 0, 0, 0.1)",
352
+ cursor: "pointer"
353
+ },
354
+ ".cm-scrollbar-inner svg": {
355
+ position: "absolute",
356
+ top: "0",
357
+ left: "0",
358
+ height: "100%",
359
+ pointerEvents: "none"
360
+ },
361
+ ".cm-scrollbar-thumb": {
362
+ position: "absolute",
363
+ left: "0",
364
+ right: "0",
365
+ backgroundColor: "rgba(128, 128, 128, 0.3)",
366
+ pointerEvents: "auto",
367
+ cursor: "default",
368
+ zIndex: 11
369
+ },
370
+ ".cm-scrollbar-thumb:hover": { backgroundColor: "rgba(128, 128, 128, 0.5)" },
371
+ ".cm-scrollbar-thumb:active": { backgroundColor: "rgba(128, 128, 128, 0.6)" },
372
+ ".cm-scroller": {
373
+ scrollbarWidth: "none",
374
+ msOverflowStyle: "none"
375
+ },
376
+ ".cm-scroller::-webkit-scrollbar": { display: "none" }
377
+ });
378
+ function scrollbarRulerExtension() {
379
+ return [scrollbarRuler, scrollbarRulerTheme];
380
+ }
381
+ //#endregion
382
+ //#region src/plugin/selection.ts
383
+ const selectionLineHighlightPlugin = ViewPlugin.fromClass(class {
384
+ update(update) {
385
+ if (update.selectionSet || update.docChanged) {
386
+ const { state, dom } = update.view;
387
+ if (state.selection.ranges.some((r) => !r.empty)) {
388
+ dom.style.setProperty("--cm-line-highlight-background", "transparent");
389
+ dom.style.setProperty("--cm-line-highlight-border", "transparent");
390
+ } else {
391
+ dom.style.removeProperty("--cm-line-highlight-background");
392
+ dom.style.removeProperty("--cm-line-highlight-border");
393
+ }
394
+ }
395
+ }
396
+ });
397
+ //#endregion
398
+ //#region src/plugin/theme.ts
399
+ const keyword = "var(--cm-keyword)";
400
+ const property = "var(--cm-property)";
401
+ const punctuation = "var(--cm-punctuation)";
402
+ const invalid = "var(--cm-invalid, #ffffff)";
403
+ const foreground = "var(--cm-foreground)";
404
+ const lineNumber = "var(--cm-line-number)";
405
+ const comment = "var(--cm-comment)";
406
+ const variable = "var(--cm-variable)";
407
+ const string = "var(--cm-string)";
408
+ const darkBackground = "var(--cm-background)";
409
+ const highlightBackground = "var(--cm-line-highlight-background)";
410
+ const background = "var(--cm-background)";
411
+ const tooltipBackground = "var(--cm-tooltip-background)";
412
+ const selection = "var(--cm-selection-background)";
413
+ const border = "var(--cm-border)";
414
+ const cursor = "var(--cm-cursor, #888)";
415
+ const vitesseTheme = EditorView.theme({
416
+ "&": {
417
+ color: foreground,
418
+ backgroundColor: background,
419
+ fontFamily: "var(--cm-font-family)",
420
+ fontSize: "var(--cm-font-size, 14px)",
421
+ lineHeight: "var(--cm-line-height, 1.6)",
422
+ fontVariantLigatures: "var(--cm-font-ligatures, normal)",
423
+ fontFeatureSettings: "var(--cm-font-feature-settings, \"calt\" 1)"
424
+ },
425
+ "& div": { flexDirection: "initial" },
426
+ "&.cm-focused": { outline: "none" },
427
+ ".cm-content": { caretColor: cursor },
428
+ ".cm-completionIcon": { display: "none" },
429
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: cursor },
430
+ "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { backgroundColor: `${selection} !important` },
431
+ ".cm-panels": {
432
+ backgroundColor: darkBackground,
433
+ color: foreground
434
+ },
435
+ ".cm-panels.cm-panels-top": { borderBottom: "1px solid var(--cm-border)" },
436
+ ".cm-panels.cm-panels-bottom": { borderTop: "1px solid var(--cm-border)" },
437
+ ".cm-searchMatch": {
438
+ backgroundColor: "var(--cm-search-match-background, #72a1ff59)",
439
+ outline: "1px solid var(--cm-search-match-outline, #457dff)"
440
+ },
441
+ ".cm-searchMatch.cm-searchMatch-selected": { backgroundColor: "var(--cm-search-match-selected-background, #6199ff2f)" },
442
+ ".cm-line": {
443
+ border: "1px solid transparent",
444
+ lineHeight: "inherit"
445
+ },
446
+ ".cm-activeLine": {
447
+ backgroundColor: highlightBackground,
448
+ border: "1px solid var(--cm-line-highlight-border)"
449
+ },
450
+ ".cm-selectionMatch": { backgroundColor: "var(--cm-selection-match-background, #aafe661a)" },
451
+ "&.cm-focused .cm-matchingBracket": {
452
+ backgroundColor: "var(--cm-matching-bracket-background)",
453
+ textDecoration: "underline",
454
+ textUnderlineOffset: "var(--cm-bracket-underline-offset, 2px)"
455
+ },
456
+ "&.cm-focused .cm-nonmatchingBracket": {
457
+ backgroundColor: "var(--cm-nonmatching-bracket-background)",
458
+ outline: "1px solid color-mix(in srgb, var(--cm-nonmatching-bracket-background), white 25%)",
459
+ borderRadius: "2px"
460
+ },
461
+ ".cm-gutters": {
462
+ backgroundColor: background,
463
+ color: lineNumber,
464
+ border: "none",
465
+ fontFamily: "var(--cm-font-family)"
466
+ },
467
+ ".cm-activeLineGutter": {
468
+ backgroundColor: "transparent",
469
+ color: "var(--cm-active-line-gutter, #bfbaaa)"
470
+ },
471
+ ".cm-foldPlaceholder": {
472
+ backgroundColor: "transparent",
473
+ border: "none",
474
+ color: "var(--cm-fold-placeholder-color, #ddd)"
475
+ },
476
+ ".cm-tooltip": {
477
+ border: `1px solid ${border}`,
478
+ borderRadius: "4px",
479
+ backgroundColor: tooltipBackground,
480
+ color: "var(--cm-tooltip-foreground, #c2beb3)",
481
+ fontFamily: "var(--cm-font-family)"
482
+ },
483
+ ".cm-tooltip .cm-tooltip-arrow:before": {
484
+ borderTopColor: "transparent",
485
+ borderBottomColor: "transparent"
486
+ },
487
+ ".cm-tooltip .cm-tooltip-arrow:after": {
488
+ borderTopColor: tooltipBackground,
489
+ borderBottomColor: tooltipBackground
490
+ },
491
+ ".cm-tooltip-autocomplete": { "& > ul > li[aria-selected]": {
492
+ backgroundColor: selection,
493
+ color: "var(--cm-tooltip-foreground, #c2beb3)"
494
+ } }
495
+ }, { dark: true });
496
+ const vitesseHighlightStyle = HighlightStyle.define([
497
+ {
498
+ tag: [tags.variableName, tags.regexp],
499
+ color: "var(--cm-decorator)"
500
+ },
501
+ {
502
+ tag: [
503
+ tags.name,
504
+ tags.deleted,
505
+ tags.character,
506
+ tags.propertyName,
507
+ tags.macroName
508
+ ],
509
+ color: property
510
+ },
511
+ {
512
+ tag: [tags.function(tags.variableName), tags.labelName],
513
+ color: variable
514
+ },
515
+ {
516
+ tag: [
517
+ tags.color,
518
+ tags.constant(tags.name),
519
+ tags.standard(tags.name)
520
+ ],
521
+ color: "var(--cm-constant, #c99076)"
522
+ },
523
+ {
524
+ tag: [tags.definition(tags.name), tags.separator],
525
+ color: foreground
526
+ },
527
+ {
528
+ tag: [tags.angleBracket],
529
+ color: "var(--cm-angle-bracket, #666666)"
530
+ },
531
+ {
532
+ tag: [tags.brace],
533
+ color: "var(--cm-brace, #5eaab5)"
534
+ },
535
+ {
536
+ tag: [tags.bracket],
537
+ color: "var(--cm-bracket, #4d9375)"
538
+ },
539
+ {
540
+ tag: [
541
+ tags.typeName,
542
+ tags.className,
543
+ tags.number,
544
+ tags.changed,
545
+ tags.annotation,
546
+ tags.modifier,
547
+ tags.self,
548
+ tags.namespace,
549
+ tags.keyword,
550
+ tags.atom,
551
+ tags.bool,
552
+ tags.special(tags.variableName)
553
+ ],
554
+ color: keyword
555
+ },
556
+ {
557
+ tag: [tags.definitionKeyword],
558
+ color: "var(--cm-definition-keyword)"
559
+ },
560
+ {
561
+ tag: [
562
+ tags.operator,
563
+ tags.operatorKeyword,
564
+ tags.url,
565
+ tags.escape,
566
+ tags.link,
567
+ tags.special(tags.string)
568
+ ],
569
+ color: punctuation
570
+ },
571
+ {
572
+ tag: [tags.meta, tags.comment],
573
+ color: comment
574
+ },
575
+ {
576
+ tag: tags.strong,
577
+ fontWeight: "var(--cm-font-weight-bold, bold)"
578
+ },
579
+ {
580
+ tag: tags.emphasis,
581
+ fontStyle: "var(--cm-font-style-italic, italic)"
582
+ },
583
+ {
584
+ tag: tags.strikethrough,
585
+ textDecoration: "line-through"
586
+ },
587
+ {
588
+ tag: tags.link,
589
+ color: lineNumber,
590
+ textDecoration: "underline"
591
+ },
592
+ {
593
+ tag: tags.heading,
594
+ fontWeight: "var(--cm-font-weight-bold, bold)",
595
+ color: property
596
+ },
597
+ {
598
+ tag: [
599
+ tags.processingInstruction,
600
+ tags.string,
601
+ tags.inserted
602
+ ],
603
+ color: string
604
+ },
605
+ {
606
+ tag: tags.invalid,
607
+ color: invalid
608
+ }
609
+ ]);
610
+ const vitesse = [vitesseTheme, syntaxHighlighting(vitesseHighlightStyle)];
611
+ //#endregion
612
+ //#region src/plugin/word-highlight.ts
613
+ const WORD_BEFORE_PATTERN = /\w*$/;
614
+ const WORD_AFTER_PATTERN = /^\w*/;
615
+ const ESCAPE_REGEX_PATTERN = /[.*+?^${}()|[\]\\]/g;
616
+ function escapeRegExp(string) {
617
+ return string.replace(ESCAPE_REGEX_PATTERN, "\\$&");
618
+ }
619
+ const wordHighlightPlugin = ViewPlugin.fromClass(class {
620
+ constructor() {
621
+ this.decorations = Decoration.none;
622
+ this.cachedWord = null;
623
+ this.cachedDecorations = null;
624
+ }
625
+ update(update) {
626
+ if (update.selectionSet || update.docChanged) {
627
+ const word = this.getCurrentWord(update.view);
628
+ if (word !== this.cachedWord || update.docChanged) {
629
+ this.cachedWord = word;
630
+ if (word) this.cachedDecorations = this.buildDecorations(update.view, word);
631
+ else this.cachedDecorations = Decoration.none;
632
+ this.decorations = this.cachedDecorations;
633
+ }
634
+ }
635
+ }
636
+ getCurrentWord(view) {
637
+ const { state } = view;
638
+ const { selection, doc } = state;
639
+ for (const range of selection.ranges) if (range.empty) {
640
+ const pos = range.head;
641
+ const line = doc.lineAt(pos);
642
+ const text = line.text;
643
+ const offset = pos - line.from;
644
+ const beforeMatch = text.slice(0, offset).match(WORD_BEFORE_PATTERN);
645
+ const afterMatch = text.slice(offset).match(WORD_AFTER_PATTERN);
646
+ if (beforeMatch && afterMatch) {
647
+ const wordStart = offset - beforeMatch[0].length;
648
+ const word = text.slice(wordStart, wordStart + beforeMatch[0].length + afterMatch[0].length);
649
+ if (word.length > 0) {
650
+ if ((wordStart > 0 ? text[wordStart - 1] : "") === ".") return null;
651
+ return word;
652
+ }
653
+ }
654
+ }
655
+ return null;
656
+ }
657
+ buildDecorations(view, word) {
658
+ const { doc } = view.state;
659
+ const builder = new RangeSetBuilder();
660
+ const escapedWord = escapeRegExp(word);
661
+ const pattern = new RegExp(`(?<!\\.)\\b${escapedWord}\\b`, "g");
662
+ for (let lineNum = 1; lineNum <= doc.lines; lineNum++) {
663
+ const line = doc.line(lineNum);
664
+ pattern.lastIndex = 0;
665
+ let match;
666
+ while (true) {
667
+ match = pattern.exec(line.text);
668
+ if (match === null) break;
669
+ const from = line.from + match.index;
670
+ const to = from + match[0].length;
671
+ builder.add(from, to, Decoration.mark({ class: "cm-word-highlight" }));
672
+ }
673
+ }
674
+ return builder.finish();
675
+ }
676
+ }, { decorations: (v) => v.decorations });
677
+ const wordHighlightTheme = EditorView.baseTheme({ ".cm-word-highlight": {
678
+ backgroundColor: "var(--cm-word-highlight-background, hsl(210 91% 61% / 0.15))",
679
+ borderRadius: "2px"
680
+ } });
681
+ function wordHighlightExtension() {
682
+ return [wordHighlightPlugin, wordHighlightTheme];
683
+ }
684
+ //#endregion
685
+ //#region src/glsl.ts
686
+ const actisCodeMirrorClassName = "cm-actis-editor";
687
+ function glslLanguage() {
688
+ return cpp();
689
+ }
690
+ function glslEditorExtensions(options = {}) {
691
+ const extensions = [];
692
+ const basicSetup$1 = options.basicSetup === void 0 ? basicSetup : options.basicSetup;
693
+ if (basicSetup$1 !== false) extensions.push(basicSetup$1);
694
+ const language = options.language === void 0 ? glslLanguage() : options.language;
695
+ if (language !== false) extensions.push(language);
696
+ const theme = options.theme === void 0 ? vitesse : options.theme;
697
+ if (theme !== false) extensions.push(theme);
698
+ if (options.nonMatchingBrackets !== false) extensions.push(nonMatchingBracketPlugin);
699
+ if (options.wordHighlight !== false) extensions.push(wordHighlightExtension());
700
+ if (options.selectionLineHighlight !== false) extensions.push(selectionLineHighlightPlugin);
701
+ if (options.scrollbar !== false) extensions.push(scrollbarRulerExtension());
702
+ if (options.scrollPastEnd !== false) extensions.push(scrollPastEnd());
703
+ if (options.folding !== false) extensions.push(codeFoldingExtension());
704
+ const completionSource = options.completionSource === void 0 ? glslCompletions(options) : options.completionSource;
705
+ if (completionSource !== false) extensions.push(autocompletion({
706
+ activateOnTyping: true,
707
+ override: [completionSource]
708
+ }));
709
+ if (options.onChange) extensions.push(EditorView.updateListener.of((update) => {
710
+ if (update.docChanged) options.onChange?.(update.state.doc.toString(), update);
711
+ }));
712
+ return extensions;
713
+ }
714
+ //#endregion
715
+ export { actisCodeMirrorClassName, codeFoldingExtension, glslCompletions, glslEditorExtensions, glslLanguage, nonMatchingBracketPlugin, scrollbarRuler, scrollbarRulerExtension, scrollbarRulerTheme, selectionLineHighlightPlugin, vitesse, vitesseHighlightStyle, vitesseTheme, wordHighlightExtension, wordHighlightPlugin, wordHighlightTheme };