algraf-editor 0.67.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,1130 @@
1
+ // src/index.tsx
2
+ import React from "react";
3
+ import * as monaco2 from "monaco-editor/esm/vs/editor/editor.api";
4
+ import "monaco-editor/min/vs/editor/editor.main.css";
5
+ import "monaco-editor/esm/vs/editor/contrib/hover/browser/hoverContribution";
6
+ import EditorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
7
+ import { wireTmGrammars } from "monaco-editor-textmate";
8
+ import { Registry } from "monaco-textmate";
9
+ import { loadWASM as loadOnigasm } from "onigasm";
10
+ import onigasmWasmUrl from "onigasm/lib/onigasm.wasm?url";
11
+
12
+ // assets/algraf.tmLanguage.json
13
+ var algraf_tmLanguage_default = {
14
+ $schema: "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
15
+ name: "Algraf",
16
+ scopeName: "source.algraf",
17
+ patterns: [
18
+ {
19
+ include: "#comments"
20
+ },
21
+ {
22
+ include: "#strings"
23
+ },
24
+ {
25
+ include: "#quoted-identifiers"
26
+ },
27
+ {
28
+ include: "#numbers"
29
+ },
30
+ {
31
+ include: "#let-bindings"
32
+ },
33
+ {
34
+ include: "#declarations"
35
+ },
36
+ {
37
+ include: "#interactions"
38
+ },
39
+ {
40
+ include: "#geometries"
41
+ },
42
+ {
43
+ include: "#stats"
44
+ },
45
+ {
46
+ include: "#sources"
47
+ },
48
+ {
49
+ include: "#constants"
50
+ },
51
+ {
52
+ include: "#properties"
53
+ },
54
+ {
55
+ include: "#columns"
56
+ },
57
+ {
58
+ include: "#operators"
59
+ },
60
+ {
61
+ include: "#functions"
62
+ }
63
+ ],
64
+ repository: {
65
+ comments: {
66
+ patterns: [
67
+ {
68
+ name: "comment.line.double-slash.algraf",
69
+ match: "//.*$"
70
+ }
71
+ ]
72
+ },
73
+ strings: {
74
+ patterns: [
75
+ {
76
+ name: "string.quoted.double.algraf",
77
+ begin: '"',
78
+ end: '"',
79
+ patterns: [
80
+ {
81
+ name: "constant.character.escape.algraf",
82
+ match: '\\\\[nrt"\\\\]'
83
+ },
84
+ {
85
+ name: "invalid.illegal.escape.algraf",
86
+ match: "\\\\."
87
+ }
88
+ ]
89
+ }
90
+ ]
91
+ },
92
+ "quoted-identifiers": {
93
+ patterns: [
94
+ {
95
+ name: "variable.other.quoted.algraf",
96
+ begin: "`",
97
+ end: "`",
98
+ patterns: [
99
+ {
100
+ name: "constant.character.escape.algraf",
101
+ match: "\\\\[`\\\\]"
102
+ }
103
+ ]
104
+ }
105
+ ]
106
+ },
107
+ numbers: {
108
+ patterns: [
109
+ {
110
+ name: "constant.numeric.algraf",
111
+ match: "\\b-?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b"
112
+ }
113
+ ]
114
+ },
115
+ "let-bindings": {
116
+ patterns: [
117
+ {
118
+ match: "\\b(let)\\s+([A-Za-z_][A-Za-z0-9_]*)",
119
+ captures: {
120
+ "1": {
121
+ name: "keyword.declaration.let.algraf"
122
+ },
123
+ "2": {
124
+ name: "variable.other.declaration.algraf"
125
+ }
126
+ }
127
+ }
128
+ ]
129
+ },
130
+ declarations: {
131
+ patterns: [
132
+ {
133
+ name: "keyword.declaration.algraf",
134
+ match: "\\b(?:Algraf|Chart|Space|Inset|Derive|from|Table|Parse|Scale|Guide|Theme|Layout)\\b"
135
+ },
136
+ {
137
+ name: "keyword.declaration.let.algraf",
138
+ match: "\\blet\\b"
139
+ }
140
+ ]
141
+ },
142
+ geometries: {
143
+ patterns: [
144
+ {
145
+ name: "entity.name.function.geometry.algraf",
146
+ match: "\\b(?:Point|Line|Path|Bar|Rect|Histogram|FreqPoly|Bin2D|HexBin|Smooth|Boxplot|Violin|Density|ErrorBar|LineRange|PointRange|CrossBar|Ribbon|Tile|HLine|VLine|Rug|Area|Text|Label|Image|Segment|Geo|Graticule)\\b(?=\\s*\\()"
147
+ }
148
+ ]
149
+ },
150
+ interactions: {
151
+ patterns: [
152
+ {
153
+ name: "entity.name.function.interaction.algraf",
154
+ match: "\\bOn\\b(?=\\s*\\()"
155
+ }
156
+ ]
157
+ },
158
+ stats: {
159
+ patterns: [
160
+ {
161
+ name: "entity.name.function.stat.algraf",
162
+ match: "\\b(?:Bin|Bin2D|HexBin|Summary2D|SummaryHex|ContourLines|ContourBands|Density2D|Density2DContours|Density2DBands|Distinct|Ecdf|Qq|Summary|SummaryBin|Cut|Count|Smooth|StepVertices|JitterPoints|VectorEndpoints|CurveSample|IntervalSegments|IntervalRects|IntervalMiddles|Boxplot|Density|Centroid|Simplify|SpatialJoin)\\b(?=\\s*\\()"
163
+ }
164
+ ]
165
+ },
166
+ sources: {
167
+ patterns: [
168
+ {
169
+ name: "entity.name.function.source.algraf",
170
+ match: "\\b(?:GeoJson|Shapefile|Sqlite|TopoJson|Style|Stop)\\b(?=\\s*\\()"
171
+ },
172
+ {
173
+ name: "entity.name.function.literal.algraf",
174
+ match: "\\b(?:datetime|date)\\b(?=\\s*\\()"
175
+ }
176
+ ]
177
+ },
178
+ constants: {
179
+ patterns: [
180
+ {
181
+ name: "constant.language.algraf",
182
+ match: "\\b(?:true|false|null|stdin)\\b"
183
+ }
184
+ ]
185
+ },
186
+ properties: {
187
+ patterns: [
188
+ {
189
+ name: "variable.parameter.property.algraf",
190
+ match: "\\b(?:version|features|data|match|width|height|minSize|maxSize|padding|placement|clip|title|subtitle|caption|alt|description|marginTop|marginRight|marginBottom|marginLeft|facetColumns|facetRows|facetCols|facetScales|facetLabel|facetLabels|panelSpacing|axis|legend|grid|timeFormat|tickLabelAngle|tickLabelRows|table|column|format|formats|unit|timezone|onError|coords|zoomX|zoomY|aspect|theta|innerRadius|startAngle|direction|radius|fill|stroke|strokeWidth|dash|alpha|size|shape|src|group|sort|layout|baseline|stat|xmin|xmax|ymin|ymax|bins|binWidth|boundary|closed|interval|bandwidth|n|quantiles|outliers|span|se|taper|curvature|points|lengthScale|type|mode|domain|breaks|expand|expansion|range|reverse|integer|palette|gradient|labels|reducer|by|distribution|reference|output|method|label|at|anchor|dx|dy|nudge|nudgeData|jitter|x|y|xend|yend|sides|tooltip|highlight|projection|name|plotTitle|plotSubtitle|plotCaption|axisTitle|axisText|stripText|legendTitle|legendText|panelBackground|gridMajor|gridMinor|legendPosition|legendSpacing|fontFamily|fontSize|titleSize|pointSize|lineWidth|background|plotBackground|axisColor|gridColor|textColor|axes|style|color|value)\\b(?=\\s*:)"
191
+ },
192
+ {
193
+ name: "variable.parameter.property.unknown.algraf",
194
+ match: "\\b[A-Za-z_][A-Za-z0-9_]*\\b(?=\\s*:)"
195
+ }
196
+ ]
197
+ },
198
+ columns: {
199
+ patterns: [
200
+ {
201
+ name: "variable.other.column.algraf",
202
+ match: "\\b[A-Za-z_][A-Za-z0-9_]*\\b(?!\\s*[:(])"
203
+ }
204
+ ]
205
+ },
206
+ operators: {
207
+ patterns: [
208
+ {
209
+ name: "keyword.operator.algebra.algraf",
210
+ match: "[*/+]"
211
+ },
212
+ {
213
+ name: "keyword.operator.map.algraf",
214
+ match: "=>"
215
+ },
216
+ {
217
+ name: "keyword.operator.assignment.algraf",
218
+ match: "="
219
+ },
220
+ {
221
+ name: "punctuation.separator.comma.algraf",
222
+ match: ","
223
+ },
224
+ {
225
+ name: "punctuation.separator.key-value.algraf",
226
+ match: ":"
227
+ },
228
+ {
229
+ name: "punctuation.section.braces.algraf",
230
+ match: "[{}]"
231
+ },
232
+ {
233
+ name: "punctuation.section.parens.algraf",
234
+ match: "[()]"
235
+ },
236
+ {
237
+ name: "punctuation.section.brackets.algraf",
238
+ match: "[\\[\\]]"
239
+ }
240
+ ]
241
+ },
242
+ functions: {
243
+ patterns: [
244
+ {
245
+ name: "entity.name.function.algraf",
246
+ match: "\\b[A-Za-z_][A-Za-z0-9_]*\\b(?=\\s*\\()"
247
+ }
248
+ ]
249
+ }
250
+ }
251
+ };
252
+
253
+ // assets/language-configuration.json
254
+ var language_configuration_default = {
255
+ comments: {
256
+ lineComment: "//"
257
+ },
258
+ brackets: [
259
+ [
260
+ "{",
261
+ "}"
262
+ ],
263
+ [
264
+ "(",
265
+ ")"
266
+ ],
267
+ [
268
+ "[",
269
+ "]"
270
+ ]
271
+ ],
272
+ autoClosingPairs: [
273
+ {
274
+ open: "{",
275
+ close: "}"
276
+ },
277
+ {
278
+ open: "(",
279
+ close: ")"
280
+ },
281
+ {
282
+ open: "[",
283
+ close: "]"
284
+ },
285
+ {
286
+ open: '"',
287
+ close: '"',
288
+ notIn: [
289
+ "string",
290
+ "comment"
291
+ ]
292
+ },
293
+ {
294
+ open: "`",
295
+ close: "`",
296
+ notIn: [
297
+ "string",
298
+ "comment"
299
+ ]
300
+ }
301
+ ],
302
+ surroundingPairs: [
303
+ {
304
+ open: "{",
305
+ close: "}"
306
+ },
307
+ {
308
+ open: "(",
309
+ close: ")"
310
+ },
311
+ {
312
+ open: "[",
313
+ close: "]"
314
+ },
315
+ {
316
+ open: '"',
317
+ close: '"'
318
+ },
319
+ {
320
+ open: "`",
321
+ close: "`"
322
+ }
323
+ ],
324
+ folding: {
325
+ markers: {
326
+ start: "^\\s*//\\s*#region\\b",
327
+ end: "^\\s*//\\s*#endregion\\b"
328
+ }
329
+ },
330
+ wordPattern: "`[^`]*(?:\\\\.[^`]*)*`|[A-Za-z_][A-Za-z0-9_]*"
331
+ };
332
+
333
+ // src/providers.ts
334
+ import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
335
+ var SEMANTIC_TOKEN_TYPES = [
336
+ "keyword",
337
+ "function",
338
+ "property",
339
+ "variable",
340
+ "operator",
341
+ "string",
342
+ "number",
343
+ "comment"
344
+ ];
345
+ function registerAlgrafEditorProviders(languageId, getRuntime, getFiles) {
346
+ const disposables = [
347
+ monaco.languages.registerHoverProvider(languageId, {
348
+ provideHover(model, position) {
349
+ const hover = requestFeature(model, getRuntime, getFiles, {
350
+ kind: "hover",
351
+ position: toLspPosition(position)
352
+ });
353
+ if (!hover) {
354
+ return null;
355
+ }
356
+ return {
357
+ contents: hoverContents(hover.contents),
358
+ range: hover.range ? fromLspRange(hover.range) : void 0
359
+ };
360
+ }
361
+ }),
362
+ monaco.languages.registerCompletionItemProvider(languageId, {
363
+ triggerCharacters: [":", "*", "/", "+", "("],
364
+ provideCompletionItems(model, position) {
365
+ const response = requestFeature(
366
+ model,
367
+ getRuntime,
368
+ getFiles,
369
+ {
370
+ kind: "completion",
371
+ position: toLspPosition(position)
372
+ }
373
+ );
374
+ const items = Array.isArray(response) ? response : response?.items ?? [];
375
+ return {
376
+ suggestions: items.map((item) => completionItem(item, position))
377
+ };
378
+ }
379
+ }),
380
+ monaco.languages.registerSignatureHelpProvider(languageId, {
381
+ signatureHelpTriggerCharacters: ["(", ","],
382
+ signatureHelpRetriggerCharacters: [","],
383
+ provideSignatureHelp(model, position) {
384
+ const help = requestFeature(model, getRuntime, getFiles, {
385
+ kind: "signatureHelp",
386
+ position: toLspPosition(position)
387
+ });
388
+ if (!help) {
389
+ return null;
390
+ }
391
+ return {
392
+ value: {
393
+ activeSignature: help.activeSignature ?? 0,
394
+ activeParameter: help.activeParameter ?? 0,
395
+ signatures: help.signatures.map((signature) => ({
396
+ label: signature.label,
397
+ documentation: markdownString(signature.documentation),
398
+ parameters: (signature.parameters ?? []).map((parameter) => ({
399
+ label: parameter.label,
400
+ documentation: markdownString(parameter.documentation)
401
+ }))
402
+ }))
403
+ },
404
+ dispose: () => void 0
405
+ };
406
+ }
407
+ }),
408
+ monaco.languages.registerDocumentFormattingEditProvider(languageId, {
409
+ provideDocumentFormattingEdits(model) {
410
+ const edits = requestFeature(model, getRuntime, getFiles, {
411
+ kind: "formatting"
412
+ });
413
+ return (edits ?? []).map(textEdit);
414
+ }
415
+ }),
416
+ monaco.languages.registerDocumentRangeFormattingEditProvider(languageId, {
417
+ provideDocumentRangeFormattingEdits(model, range) {
418
+ const edits = requestFeature(model, getRuntime, getFiles, {
419
+ kind: "rangeFormatting",
420
+ range: toLspRange(range)
421
+ });
422
+ return (edits ?? []).map(textEdit);
423
+ }
424
+ }),
425
+ monaco.languages.registerDocumentSemanticTokensProvider(languageId, {
426
+ getLegend() {
427
+ return {
428
+ tokenTypes: SEMANTIC_TOKEN_TYPES,
429
+ tokenModifiers: []
430
+ };
431
+ },
432
+ provideDocumentSemanticTokens(model) {
433
+ const result = requestFeature(
434
+ model,
435
+ getRuntime,
436
+ getFiles,
437
+ {
438
+ kind: "semanticTokens"
439
+ }
440
+ );
441
+ return {
442
+ data: new Uint32Array(flattenSemanticTokens(result?.data ?? [])),
443
+ resultId: void 0
444
+ };
445
+ },
446
+ releaseDocumentSemanticTokens() {
447
+ return void 0;
448
+ }
449
+ }),
450
+ monaco.languages.registerCodeActionProvider(languageId, {
451
+ provideCodeActions(model, range, context) {
452
+ const actions = requestFeature(model, getRuntime, getFiles, {
453
+ kind: "codeActions",
454
+ range: toLspRange(range),
455
+ diagnostics: context.markers.map(markerToDiagnostic)
456
+ });
457
+ return {
458
+ actions: (actions ?? []).map((action) => codeAction(action, model.uri)),
459
+ dispose: () => void 0
460
+ };
461
+ }
462
+ }),
463
+ monaco.languages.registerDefinitionProvider(languageId, {
464
+ provideDefinition(model, position) {
465
+ const result = requestFeature(
466
+ model,
467
+ getRuntime,
468
+ getFiles,
469
+ {
470
+ kind: "definition",
471
+ position: toLspPosition(position)
472
+ }
473
+ );
474
+ return locations(result);
475
+ }
476
+ }),
477
+ monaco.languages.registerReferenceProvider(languageId, {
478
+ provideReferences(model, position, context) {
479
+ const result = requestFeature(model, getRuntime, getFiles, {
480
+ kind: "references",
481
+ position: toLspPosition(position),
482
+ includeDeclaration: context.includeDeclaration
483
+ });
484
+ return locations(result);
485
+ }
486
+ }),
487
+ monaco.languages.registerDocumentHighlightProvider(languageId, {
488
+ provideDocumentHighlights(model, position) {
489
+ const result = requestFeature(model, getRuntime, getFiles, {
490
+ kind: "documentHighlights",
491
+ position: toLspPosition(position)
492
+ });
493
+ return (result ?? []).map((highlight) => ({
494
+ range: fromLspRange(highlight.range),
495
+ kind: documentHighlightKind(highlight.kind)
496
+ }));
497
+ }
498
+ }),
499
+ monaco.languages.registerRenameProvider(languageId, {
500
+ resolveRenameLocation(model, position) {
501
+ const response = requestFeature(model, getRuntime, getFiles, {
502
+ kind: "prepareRename",
503
+ position: toLspPosition(position)
504
+ });
505
+ const range = "range" in (response ?? {}) ? response.range : response;
506
+ if (!range) {
507
+ return {
508
+ range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column),
509
+ text: "",
510
+ rejectReason: "This symbol cannot be renamed."
511
+ };
512
+ }
513
+ return {
514
+ range: fromLspRange(range),
515
+ text: model.getValueInRange(fromLspRange(range))
516
+ };
517
+ },
518
+ provideRenameEdits(model, position, newName) {
519
+ const edit = requestFeature(model, getRuntime, getFiles, {
520
+ kind: "rename",
521
+ position: toLspPosition(position),
522
+ newName
523
+ });
524
+ if (!edit) {
525
+ return { edits: [] };
526
+ }
527
+ return workspaceEdit(edit);
528
+ }
529
+ }),
530
+ monaco.languages.registerDocumentSymbolProvider(languageId, {
531
+ provideDocumentSymbols(model) {
532
+ const result = requestFeature(model, getRuntime, getFiles, {
533
+ kind: "documentSymbols"
534
+ });
535
+ return (result ?? []).map(documentSymbol);
536
+ }
537
+ })
538
+ ];
539
+ return {
540
+ dispose() {
541
+ for (const disposable of disposables) {
542
+ disposable.dispose();
543
+ }
544
+ }
545
+ };
546
+ }
547
+ function requestFeature(model, getRuntime, getFiles, request) {
548
+ const runtime = getRuntime(model);
549
+ if (!runtime) {
550
+ return null;
551
+ }
552
+ const response = runtime.editorService(model.getValue(), getFiles(model), request, model.uri.toString());
553
+ if (response.error) {
554
+ console.warn(`Algraf editor service failed: ${response.error}`);
555
+ return null;
556
+ }
557
+ return response.result;
558
+ }
559
+ function toLspPosition(position) {
560
+ return {
561
+ line: Math.max(0, position.lineNumber - 1),
562
+ character: Math.max(0, position.column - 1)
563
+ };
564
+ }
565
+ function fromLspPosition(position) {
566
+ return {
567
+ lineNumber: position.line + 1,
568
+ column: position.character + 1
569
+ };
570
+ }
571
+ function toLspRange(range) {
572
+ return {
573
+ start: toLspPosition({ lineNumber: range.startLineNumber, column: range.startColumn }),
574
+ end: toLspPosition({ lineNumber: range.endLineNumber, column: range.endColumn })
575
+ };
576
+ }
577
+ function fromLspRange(range) {
578
+ const start = fromLspPosition(range.start);
579
+ const end = fromLspPosition(range.end);
580
+ return new monaco.Range(start.lineNumber, start.column, end.lineNumber, end.column);
581
+ }
582
+ function hoverContents(contents) {
583
+ const values = Array.isArray(contents) ? contents : [contents];
584
+ return values.map((value) => ({
585
+ value: typeof value === "string" ? value : value.value,
586
+ isTrusted: false,
587
+ supportThemeIcons: false,
588
+ supportHtml: false
589
+ }));
590
+ }
591
+ function markdownString(value) {
592
+ if (!value) {
593
+ return void 0;
594
+ }
595
+ if (typeof value === "string") {
596
+ return value;
597
+ }
598
+ return {
599
+ value: value.value,
600
+ isTrusted: false,
601
+ supportHtml: false
602
+ };
603
+ }
604
+ function completionItem(item, position) {
605
+ return {
606
+ label: item.label,
607
+ kind: completionKind(item.kind),
608
+ detail: item.detail,
609
+ documentation: markdownString(item.documentation),
610
+ insertText: item.insertText ?? item.label,
611
+ insertTextRules: item.insertTextFormat === 2 ? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet : void 0,
612
+ range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column)
613
+ };
614
+ }
615
+ function completionKind(kind) {
616
+ switch (kind) {
617
+ case 3:
618
+ return monaco.languages.CompletionItemKind.Function;
619
+ case 5:
620
+ return monaco.languages.CompletionItemKind.Field;
621
+ case 10:
622
+ return monaco.languages.CompletionItemKind.Property;
623
+ case 12:
624
+ return monaco.languages.CompletionItemKind.Value;
625
+ case 14:
626
+ return monaco.languages.CompletionItemKind.Keyword;
627
+ case 15:
628
+ return monaco.languages.CompletionItemKind.Snippet;
629
+ case 16:
630
+ return monaco.languages.CompletionItemKind.Color;
631
+ case 24:
632
+ return monaco.languages.CompletionItemKind.Operator;
633
+ default:
634
+ return monaco.languages.CompletionItemKind.Text;
635
+ }
636
+ }
637
+ function textEdit(edit) {
638
+ return {
639
+ range: fromLspRange(edit.range),
640
+ text: edit.newText
641
+ };
642
+ }
643
+ function flattenSemanticTokens(data) {
644
+ if (data.length === 0 || typeof data[0] === "number") {
645
+ return data;
646
+ }
647
+ return data.flatMap((token) => [
648
+ token.deltaLine,
649
+ token.deltaStart,
650
+ token.length,
651
+ token.tokenType,
652
+ token.tokenModifiersBitset
653
+ ]);
654
+ }
655
+ function markerToDiagnostic(marker) {
656
+ return {
657
+ range: toLspRange(marker),
658
+ severity: markerSeverity(marker.severity),
659
+ code: markerCode(marker.code),
660
+ source: marker.source,
661
+ message: marker.message
662
+ };
663
+ }
664
+ function markerSeverity(severity) {
665
+ switch (severity) {
666
+ case monaco.MarkerSeverity.Error:
667
+ return 1;
668
+ case monaco.MarkerSeverity.Warning:
669
+ return 2;
670
+ case monaco.MarkerSeverity.Info:
671
+ return 3;
672
+ case monaco.MarkerSeverity.Hint:
673
+ return 4;
674
+ }
675
+ }
676
+ function markerCode(code) {
677
+ if (typeof code === "string" || typeof code === "number") {
678
+ return code;
679
+ }
680
+ return code?.value;
681
+ }
682
+ function codeAction(action, currentUri) {
683
+ return {
684
+ title: action.title,
685
+ kind: action.kind,
686
+ diagnostics: action.diagnostics?.map((diagnostic) => ({
687
+ severity: diagnosticSeverity(diagnostic.severity),
688
+ message: diagnostic.message,
689
+ startLineNumber: diagnostic.range.start.line + 1,
690
+ startColumn: diagnostic.range.start.character + 1,
691
+ endLineNumber: diagnostic.range.end.line + 1,
692
+ endColumn: diagnostic.range.end.character + 1
693
+ })),
694
+ edit: action.edit ? workspaceEdit(action.edit, currentUri) : void 0
695
+ };
696
+ }
697
+ function diagnosticSeverity(severity) {
698
+ switch (severity) {
699
+ case 1:
700
+ return monaco.MarkerSeverity.Error;
701
+ case 2:
702
+ return monaco.MarkerSeverity.Warning;
703
+ case 3:
704
+ return monaco.MarkerSeverity.Info;
705
+ case 4:
706
+ return monaco.MarkerSeverity.Hint;
707
+ default:
708
+ return monaco.MarkerSeverity.Info;
709
+ }
710
+ }
711
+ function workspaceEdit(edit, fallbackUri) {
712
+ const edits = [];
713
+ for (const [uri, textEdits] of Object.entries(edit.changes ?? {})) {
714
+ const resource = uri ? monaco.Uri.parse(uri) : fallbackUri;
715
+ if (!resource) {
716
+ continue;
717
+ }
718
+ for (const text of textEdits) {
719
+ edits.push({
720
+ resource,
721
+ textEdit: {
722
+ range: fromLspRange(text.range),
723
+ text: text.newText
724
+ },
725
+ versionId: void 0
726
+ });
727
+ }
728
+ }
729
+ return { edits };
730
+ }
731
+ function locations(result) {
732
+ const values = Array.isArray(result) ? result : result ? [result] : [];
733
+ return values.map((location) => ({
734
+ uri: monaco.Uri.parse(location.uri),
735
+ range: fromLspRange(location.range)
736
+ }));
737
+ }
738
+ function documentHighlightKind(kind) {
739
+ switch (kind) {
740
+ case 3:
741
+ return monaco.languages.DocumentHighlightKind.Write;
742
+ case 2:
743
+ return monaco.languages.DocumentHighlightKind.Read;
744
+ default:
745
+ return monaco.languages.DocumentHighlightKind.Text;
746
+ }
747
+ }
748
+ function documentSymbol(symbol) {
749
+ return {
750
+ name: symbol.name,
751
+ detail: symbol.detail ?? "",
752
+ kind: symbolKind(symbol.kind),
753
+ range: fromLspRange(symbol.range),
754
+ selectionRange: fromLspRange(symbol.selectionRange),
755
+ tags: [],
756
+ children: symbol.children?.map(documentSymbol)
757
+ };
758
+ }
759
+ function symbolKind(kind) {
760
+ switch (kind) {
761
+ case 7:
762
+ return monaco.languages.SymbolKind.Property;
763
+ case 12:
764
+ return monaco.languages.SymbolKind.Function;
765
+ case 13:
766
+ return monaco.languages.SymbolKind.Variable;
767
+ case 19:
768
+ return monaco.languages.SymbolKind.Object;
769
+ default:
770
+ return monaco.languages.SymbolKind.Object;
771
+ }
772
+ }
773
+
774
+ // src/index.tsx
775
+ import { jsx, jsxs } from "react/jsx-runtime";
776
+ var ALGRAF_LANGUAGE_ID = "algraf";
777
+ var ALGRAF_SCOPE_NAME = "source.algraf";
778
+ var ALGRAF_THEME_NAME = "algraf-playground";
779
+ var ALGRAF_MARKER_OWNER = "algraf-wasm";
780
+ var ALGRAF_DEFAULT_MODEL_URI = "inmemory://algraf/demo.ag";
781
+ var encoder = new TextEncoder();
782
+ var setupPromise = null;
783
+ var onigasmPromise = null;
784
+ var providerDisposable = null;
785
+ var editorContexts = /* @__PURE__ */ new Map();
786
+ function AlgrafEditor({
787
+ value,
788
+ files,
789
+ diagnostics,
790
+ runtime,
791
+ onChange,
792
+ modelUri,
793
+ languageId = ALGRAF_LANGUAGE_ID,
794
+ themeName = ALGRAF_THEME_NAME,
795
+ theme,
796
+ className = "algraf-editor-shell",
797
+ editorClassName = "algraf-editor",
798
+ options,
799
+ setupOptions
800
+ }) {
801
+ const hostRef = React.useRef(null);
802
+ const editorRef = React.useRef(null);
803
+ const modelRef = React.useRef(null);
804
+ const onChangeRef = React.useRef(onChange);
805
+ const diagnosticsRef = React.useRef(diagnostics);
806
+ const filesRef = React.useRef(files);
807
+ const runtimeRef = React.useRef(runtime);
808
+ const [setupError, setSetupError] = React.useState(null);
809
+ const resolvedModelUri = React.useMemo(() => monaco2.Uri.parse(modelUri ?? ALGRAF_DEFAULT_MODEL_URI), [modelUri]);
810
+ React.useEffect(() => {
811
+ onChangeRef.current = onChange;
812
+ }, [onChange]);
813
+ React.useEffect(() => {
814
+ filesRef.current = files;
815
+ }, [files]);
816
+ React.useEffect(() => {
817
+ runtimeRef.current = runtime;
818
+ }, [runtime]);
819
+ React.useEffect(() => {
820
+ diagnosticsRef.current = diagnostics;
821
+ const model = modelRef.current;
822
+ if (model) {
823
+ setAlgrafMarkers(model, diagnostics);
824
+ }
825
+ }, [diagnostics]);
826
+ React.useEffect(() => {
827
+ const model = modelRef.current;
828
+ if (model && model.getValue() !== value) {
829
+ const selection = editorRef.current?.getSelection() ?? null;
830
+ model.setValue(value);
831
+ if (selection) {
832
+ editorRef.current?.setSelection(selection);
833
+ }
834
+ setAlgrafMarkers(model, diagnosticsRef.current);
835
+ }
836
+ }, [value]);
837
+ React.useEffect(() => {
838
+ let cancelled = false;
839
+ let editor2 = null;
840
+ let model = null;
841
+ let contentDisposable = null;
842
+ let contextKey = null;
843
+ setupAlgrafMonaco({ ...setupOptions, languageId, themeName, theme }).then(() => {
844
+ if (cancelled || !hostRef.current) {
845
+ return;
846
+ }
847
+ ensureAlgrafProviders(languageId);
848
+ model = monaco2.editor.createModel(value, languageId, resolvedModelUri);
849
+ contextKey = model.uri.toString();
850
+ editorContexts.set(contextKey, {
851
+ runtime: () => runtimeRef.current,
852
+ files: () => filesRef.current
853
+ });
854
+ editor2 = monaco2.editor.create(hostRef.current, {
855
+ model,
856
+ theme: themeName,
857
+ automaticLayout: true,
858
+ bracketPairColorization: { enabled: true },
859
+ cursorBlinking: "smooth",
860
+ fixedOverflowWidgets: true,
861
+ fontFamily: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace',
862
+ fontSize: 13,
863
+ lineHeight: 20,
864
+ minimap: { enabled: false },
865
+ overviewRulerBorder: false,
866
+ padding: { top: 12, bottom: 12 },
867
+ renderLineHighlight: "line",
868
+ scrollBeyondLastLine: false,
869
+ smoothScrolling: true,
870
+ tabSize: 4,
871
+ wordWrap: "off",
872
+ ...options
873
+ });
874
+ modelRef.current = model;
875
+ editorRef.current = editor2;
876
+ setAlgrafMarkers(model, diagnosticsRef.current);
877
+ contentDisposable = model.onDidChangeContent(() => {
878
+ onChangeRef.current(model?.getValue() ?? "");
879
+ });
880
+ }).catch((err) => {
881
+ if (!cancelled) {
882
+ setSetupError(err instanceof Error ? err.message : String(err));
883
+ }
884
+ });
885
+ return () => {
886
+ cancelled = true;
887
+ contentDisposable?.dispose();
888
+ if (contextKey) {
889
+ editorContexts.delete(contextKey);
890
+ }
891
+ if (model) {
892
+ monaco2.editor.setModelMarkers(model, ALGRAF_MARKER_OWNER, []);
893
+ }
894
+ editor2?.dispose();
895
+ model?.dispose();
896
+ if (editorRef.current === editor2) {
897
+ editorRef.current = null;
898
+ }
899
+ if (modelRef.current === model) {
900
+ modelRef.current = null;
901
+ }
902
+ };
903
+ }, [languageId, options, resolvedModelUri, setupOptions, theme, themeName]);
904
+ return /* @__PURE__ */ jsxs("div", { className, children: [
905
+ /* @__PURE__ */ jsx("div", { "aria-label": "Algraf source", className: editorClassName, ref: hostRef }),
906
+ setupError ? /* @__PURE__ */ jsxs("div", { className: "algraf-editor-error", children: [
907
+ "Editor failed to load: ",
908
+ setupError
909
+ ] }) : null
910
+ ] });
911
+ }
912
+ function ensureAlgrafProviders(languageId) {
913
+ providerDisposable ?? (providerDisposable = registerAlgrafEditorProviders(
914
+ languageId,
915
+ (model) => editorContexts.get(model.uri.toString())?.runtime() ?? null,
916
+ (model) => editorContexts.get(model.uri.toString())?.files() ?? {}
917
+ ));
918
+ }
919
+ function setupAlgrafMonaco(options = {}) {
920
+ setupPromise ?? (setupPromise = setupAlgrafMonacoOnce(options).catch((error) => {
921
+ setupPromise = null;
922
+ throw error;
923
+ }));
924
+ return setupPromise;
925
+ }
926
+ function registerAlgrafLanguage(options = {}) {
927
+ const languageId = options.languageId ?? ALGRAF_LANGUAGE_ID;
928
+ if (monaco2.languages.getLanguages().some((language) => language.id === languageId)) {
929
+ return;
930
+ }
931
+ monaco2.languages.register({
932
+ id: languageId,
933
+ aliases: options.aliases ?? ["Algraf", "algraf"],
934
+ extensions: options.extensions ?? [".ag"]
935
+ });
936
+ monaco2.languages.setLanguageConfiguration(
937
+ languageId,
938
+ options.languageConfiguration ?? language_configuration_default
939
+ );
940
+ }
941
+ async function setupAlgrafMonacoOnce(options) {
942
+ if (options.configureWorker !== false) {
943
+ configureMonacoWorker();
944
+ }
945
+ registerAlgrafLanguage(options);
946
+ defineAlgrafTheme(options.themeName ?? ALGRAF_THEME_NAME, options.theme ?? defaultAlgrafTheme());
947
+ await loadOnigasmOnce(options.onigasmWasmUrl ?? onigasmWasmUrl);
948
+ const registry = new Registry({
949
+ getGrammarDefinition: async () => ({
950
+ format: "json",
951
+ content: options.grammar ?? algraf_tmLanguage_default
952
+ })
953
+ });
954
+ await wireTmGrammars(
955
+ monaco2,
956
+ registry,
957
+ /* @__PURE__ */ new Map([[options.languageId ?? ALGRAF_LANGUAGE_ID, options.scopeName ?? ALGRAF_SCOPE_NAME]])
958
+ );
959
+ }
960
+ function configureMonacoWorker() {
961
+ const target = globalThis;
962
+ target.MonacoEnvironment ?? (target.MonacoEnvironment = {
963
+ getWorker: () => new EditorWorker()
964
+ });
965
+ }
966
+ function loadOnigasmOnce(url) {
967
+ onigasmPromise ?? (onigasmPromise = loadOnigasm(url).catch((error) => {
968
+ onigasmPromise = null;
969
+ throw error;
970
+ }));
971
+ return onigasmPromise;
972
+ }
973
+ function defineAlgrafTheme(themeName = ALGRAF_THEME_NAME, theme = defaultAlgrafTheme()) {
974
+ monaco2.editor.defineTheme(themeName, theme);
975
+ }
976
+ function defaultAlgrafTheme() {
977
+ return {
978
+ base: "vs",
979
+ inherit: true,
980
+ rules: [
981
+ { token: "comment", foreground: "6b7280", fontStyle: "italic" },
982
+ { token: "string", foreground: "7a4a10" },
983
+ { token: "number", foreground: "b42318" },
984
+ { token: "keyword", foreground: "166f5c", fontStyle: "bold" },
985
+ { token: "function", foreground: "0f5f8f", fontStyle: "bold" },
986
+ { token: "property", foreground: "9a5512" },
987
+ { token: "variable", foreground: "355f8c" },
988
+ { token: "operator", foreground: "4f5b63" },
989
+ { token: "constant.character.escape", foreground: "9f5b00", fontStyle: "bold" },
990
+ { token: "constant.numeric", foreground: "b42318" },
991
+ { token: "constant.language", foreground: "6f42c1" },
992
+ { token: "invalid.illegal", foreground: "b42318", fontStyle: "underline" },
993
+ { token: "keyword.control", foreground: "166f5c", fontStyle: "bold" },
994
+ { token: "keyword.declaration", foreground: "166f5c", fontStyle: "bold" },
995
+ { token: "keyword.operator.frame", foreground: "7a3f98", fontStyle: "bold" },
996
+ { token: "keyword.operator", foreground: "4f5b63" },
997
+ { token: "support.function", foreground: "0f5f8f", fontStyle: "bold" },
998
+ { token: "support.function.aggregate", foreground: "0f5f8f", fontStyle: "bold" },
999
+ { token: "support.function.aggregate.pdl", foreground: "0f5f8f", fontStyle: "bold" },
1000
+ { token: "support.function.scalar", foreground: "0f5f8f", fontStyle: "bold" },
1001
+ { token: "support.function.scalar.pdl", foreground: "0f5f8f", fontStyle: "bold" },
1002
+ { token: "support.function.window", foreground: "0f5f8f", fontStyle: "bold" },
1003
+ { token: "support.function.window.pdl", foreground: "0f5f8f", fontStyle: "bold" },
1004
+ { token: "entity.name.function.geometry", foreground: "0f5f8f", fontStyle: "bold" },
1005
+ { token: "entity.name.function.stat", foreground: "7a3f98", fontStyle: "bold" },
1006
+ { token: "entity.name.function.source", foreground: "3c6b22", fontStyle: "bold" },
1007
+ { token: "entity.name.function.literal", foreground: "6f42c1" },
1008
+ { token: "entity.name.function", foreground: "315f7d" },
1009
+ { token: "variable.parameter.property.unknown", foreground: "a33d2d" },
1010
+ { token: "variable.parameter.property", foreground: "9a5512" },
1011
+ { token: "variable.other.declaration", foreground: "145f52", fontStyle: "bold" },
1012
+ { token: "variable.other.quoted", foreground: "385f70" },
1013
+ { token: "variable.other.column", foreground: "355f8c" },
1014
+ { token: "punctuation", foreground: "68757d" }
1015
+ ],
1016
+ colors: {
1017
+ "editor.background": "#ffffff",
1018
+ "editor.foreground": "#171f24",
1019
+ "editor.lineHighlightBackground": "#f4f7f6",
1020
+ "editorLineNumber.foreground": "#9aa6ac",
1021
+ "editorLineNumber.activeForeground": "#21695d",
1022
+ "editorCursor.foreground": "#1f6f62",
1023
+ "editor.selectionBackground": "#cfe8df",
1024
+ "editor.inactiveSelectionBackground": "#e8f2ee",
1025
+ "editorIndentGuide.background1": "#edf1f3",
1026
+ "editorIndentGuide.activeBackground1": "#c9d8d3"
1027
+ }
1028
+ };
1029
+ }
1030
+ function setAlgrafMarkers(model, diagnostics) {
1031
+ monaco2.editor.setModelMarkers(
1032
+ model,
1033
+ ALGRAF_MARKER_OWNER,
1034
+ diagnostics.map((diagnostic) => diagnosticToAlgrafMarker(model, diagnostic))
1035
+ );
1036
+ }
1037
+ function diagnosticToAlgrafMarker(model, diagnostic) {
1038
+ const start = byteOffsetToPosition(model.getValue(), diagnostic.span.start);
1039
+ const end = normalizeEndPosition(model, start, byteOffsetToPosition(model.getValue(), diagnostic.span.end));
1040
+ return {
1041
+ code: diagnostic.code,
1042
+ severity: severityToMarkerSeverity(diagnostic.severity),
1043
+ source: "Algraf",
1044
+ message: diagnostic.help ? `${diagnostic.message}
1045
+
1046
+ ${diagnostic.help}` : diagnostic.message,
1047
+ startLineNumber: start.lineNumber,
1048
+ startColumn: start.column,
1049
+ endLineNumber: end.lineNumber,
1050
+ endColumn: end.column,
1051
+ relatedInformation: diagnostic.related?.map((related) => {
1052
+ const relatedStart = byteOffsetToPosition(model.getValue(), related.span.start);
1053
+ const relatedEnd = normalizeEndPosition(model, relatedStart, byteOffsetToPosition(model.getValue(), related.span.end));
1054
+ return {
1055
+ resource: model.uri,
1056
+ message: related.message,
1057
+ startLineNumber: relatedStart.lineNumber,
1058
+ startColumn: relatedStart.column,
1059
+ endLineNumber: relatedEnd.lineNumber,
1060
+ endColumn: relatedEnd.column
1061
+ };
1062
+ })
1063
+ };
1064
+ }
1065
+ function severityToMarkerSeverity(severity) {
1066
+ switch (severity) {
1067
+ case "error":
1068
+ return monaco2.MarkerSeverity.Error;
1069
+ case "warning":
1070
+ return monaco2.MarkerSeverity.Warning;
1071
+ case "information":
1072
+ return monaco2.MarkerSeverity.Info;
1073
+ case "hint":
1074
+ return monaco2.MarkerSeverity.Hint;
1075
+ }
1076
+ }
1077
+ function byteOffsetToPosition(source, targetByteOffset) {
1078
+ const byteOffset = Math.max(0, targetByteOffset);
1079
+ let bytesSeen = 0;
1080
+ let lineNumber = 1;
1081
+ let column = 1;
1082
+ for (let index = 0; index < source.length && bytesSeen < byteOffset; ) {
1083
+ const codePoint = source.codePointAt(index);
1084
+ if (codePoint === void 0) {
1085
+ break;
1086
+ }
1087
+ const char = String.fromCodePoint(codePoint);
1088
+ const charBytes = encoder.encode(char).length;
1089
+ if (bytesSeen + charBytes > byteOffset) {
1090
+ break;
1091
+ }
1092
+ bytesSeen += charBytes;
1093
+ index += char.length;
1094
+ if (char === "\n") {
1095
+ lineNumber += 1;
1096
+ column = 1;
1097
+ } else {
1098
+ column += char.length;
1099
+ }
1100
+ }
1101
+ return { lineNumber, column };
1102
+ }
1103
+ function normalizeEndPosition(model, start, end) {
1104
+ if (end.lineNumber !== start.lineNumber || end.column !== start.column) {
1105
+ return end;
1106
+ }
1107
+ const maxColumn = model.getLineMaxColumn(start.lineNumber);
1108
+ if (start.column < maxColumn) {
1109
+ return {
1110
+ lineNumber: start.lineNumber,
1111
+ column: start.column + 1
1112
+ };
1113
+ }
1114
+ return end;
1115
+ }
1116
+ export {
1117
+ ALGRAF_DEFAULT_MODEL_URI,
1118
+ ALGRAF_LANGUAGE_ID,
1119
+ ALGRAF_MARKER_OWNER,
1120
+ ALGRAF_SCOPE_NAME,
1121
+ ALGRAF_THEME_NAME,
1122
+ AlgrafEditor,
1123
+ defaultAlgrafTheme,
1124
+ defineAlgrafTheme,
1125
+ diagnosticToAlgrafMarker,
1126
+ registerAlgrafEditorProviders,
1127
+ registerAlgrafLanguage,
1128
+ setAlgrafMarkers,
1129
+ setupAlgrafMonaco
1130
+ };