@kalada/codemirror 0.1.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/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # @kalada/codemirror
2
+
3
+ Thin CodeMirror 6 lifecycle and protocol translation for `@kalada/language-service`.
4
+
5
+ ```ts
6
+ const session = createKaladaEditorSession({
7
+ service,
8
+ document: { uri: "memory:///expression.kalada", version: 1, text: "data." },
9
+ });
10
+ const view = new EditorView({ doc: "data.", extensions: [session.extension], parent });
11
+ ```
12
+
13
+ One session exclusively owns one open URI and at most one attached view. Text-changing transactions,
14
+ including undo and redo, become monotonic language-service revisions. `replaceDocument`, `format`,
15
+ `refreshEnvironment`, and `dispose` preserve request identity and stale/cancellation checks. Dispose is
16
+ idempotent; destroying a view detaches it without closing the session.
17
+
18
+ CodeMirror packages are peers so consumers use one set of state classes. This package has no parser,
19
+ schema traversal, inference, evaluation, filesystem, or network behavior. Tooltips use DOM text nodes,
20
+ and the extension includes keyboard completion, keyboard hover, Escape handling, and accessible labels.
package/dist/index.cjs ADDED
@@ -0,0 +1,474 @@
1
+ 'use strict';
2
+
3
+ var autocomplete = require('@codemirror/autocomplete');
4
+ var commands = require('@codemirror/commands');
5
+ var lint = require('@codemirror/lint');
6
+ var state = require('@codemirror/state');
7
+ var view = require('@codemirror/view');
8
+
9
+ // src/session.ts
10
+ function detectLineSeparator(text) {
11
+ if (text.includes("\r\n")) return "\r\n";
12
+ if (text.includes("\r")) return "\r";
13
+ return "\n";
14
+ }
15
+ function textForEditor(text) {
16
+ return state.Text.of(text.split(/\r\n|\r|\n/u));
17
+ }
18
+ function textFromEditor(document, lineSeparator) {
19
+ return document.sliceString(0, document.length, lineSeparator);
20
+ }
21
+
22
+ // src/render.ts
23
+ function hoverTooltip(info, position) {
24
+ return {
25
+ pos: position,
26
+ above: true,
27
+ create(view) {
28
+ const document = view.dom.ownerDocument;
29
+ const dom = document.createElement("section");
30
+ dom.className = "cm-kalada-hover";
31
+ dom.setAttribute("role", "tooltip");
32
+ dom.setAttribute("aria-label", "Kalada expression information");
33
+ appendSection(document, dom, "Input editor shape", info.input.map(shapeText));
34
+ appendSection(document, dom, "Output Kalada semantic projection", [semanticText(info)]);
35
+ appendSection(document, dom, "Presence / branch conditions", [accessText(info)]);
36
+ appendSection(document, dom, "Limit/unknown evidence", info.evidence.map(evidenceText));
37
+ return { dom };
38
+ }
39
+ };
40
+ }
41
+ function appendSection(document, parent, heading, values) {
42
+ const title = document.createElement("strong");
43
+ title.textContent = heading;
44
+ parent.append(title);
45
+ const list = document.createElement("ul");
46
+ for (const value of values.length > 0 ? values : ["None"]) {
47
+ const item = document.createElement("li");
48
+ item.textContent = value;
49
+ list.append(item);
50
+ }
51
+ parent.append(list);
52
+ }
53
+ function shapeText(summary) {
54
+ const fields = summary.fields.map(
55
+ ({ name, presence, accessible }) => `${name} (${presence}, ${accessible ? "accessible" : "inspect only"})`
56
+ ).join(", ");
57
+ const scalar = summary.scalar ? ` ${summary.scalar}` : "";
58
+ return `${summary.kind}${scalar}; ${summary.presence}; fields: ${fields || "none"}`;
59
+ }
60
+ function semanticText(info) {
61
+ const type = info.output.type === "dynamic" ? "dynamic" : JSON.stringify(info.output.type);
62
+ return `${info.output.known ? "Known" : "Unknown"}: ${type}`;
63
+ }
64
+ function accessText(info) {
65
+ return `Access: ${info.access}`;
66
+ }
67
+ function evidenceText(evidence) {
68
+ return `${evidence.code} at ${evidence.path.join(".") || "root"}`;
69
+ }
70
+
71
+ // src/translation.ts
72
+ function changesToEdits(startDoc, newDoc, changes, snapshot, lineSeparator = "\n") {
73
+ const offsets = [];
74
+ changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
75
+ offsets.push({
76
+ from: fromA,
77
+ to: toA,
78
+ insert: inserted.sliceString(0, inserted.length, lineSeparator)
79
+ });
80
+ });
81
+ const coalesced = coalesceInserts(offsets);
82
+ const translated = coalesced.map((edit) => offsetEdit(edit, startDoc, snapshot.lineIndex));
83
+ if (translated.every((edit) => edit !== null)) return translated;
84
+ return [wholeDocumentEdit(snapshot, newDoc.sliceString(0, newDoc.length, lineSeparator))];
85
+ }
86
+ function rangeToOffsets(document, range) {
87
+ const from = offsetAt(document, range.start.line, range.start.character);
88
+ const to = offsetAt(document, range.end.line, range.end.character);
89
+ return from === null || to === null || from > to ? null : { from, to };
90
+ }
91
+ function diagnosticOffsets(document, range) {
92
+ return rangeToOffsets(document, range) ?? { from: 0, to: 0 };
93
+ }
94
+ function offsetEdit(edit, document, index) {
95
+ const start = positionAt(document, edit.from);
96
+ const end = positionAt(document, edit.to);
97
+ if (index.offsetAt(start) !== edit.from || index.offsetAt(end) !== edit.to) return null;
98
+ return { range: { start, end }, text: edit.insert };
99
+ }
100
+ function positionAt(document, offset) {
101
+ const line = document.lineAt(offset);
102
+ return { line: line.number - 1, character: offset - line.from };
103
+ }
104
+ function offsetAt(document, line, character) {
105
+ if (!Number.isSafeInteger(line) || !Number.isSafeInteger(character) || line < 0 || character < 0) {
106
+ return null;
107
+ }
108
+ if (line >= document.lines) return null;
109
+ const found = document.line(line + 1);
110
+ return character <= found.length ? found.from + character : null;
111
+ }
112
+ function coalesceInserts(edits) {
113
+ const output = [];
114
+ for (const edit of edits) {
115
+ const previous = output.at(-1);
116
+ if (previous && previous.from === edit.from && previous.to === edit.to && edit.from === edit.to) {
117
+ output[output.length - 1] = { ...previous, insert: `${previous.insert}${edit.insert}` };
118
+ } else output.push(edit);
119
+ }
120
+ return output;
121
+ }
122
+ function wholeDocumentEdit(snapshot, text) {
123
+ return {
124
+ range: {
125
+ start: { line: 0, character: 0 },
126
+ end: snapshot.lineIndex.positionAt(snapshot.text.length)
127
+ },
128
+ text
129
+ };
130
+ }
131
+
132
+ // src/session-helpers.ts
133
+ function positionAt2(document, offset) {
134
+ const line = document.lineAt(offset);
135
+ return { line: line.number - 1, character: offset - line.from };
136
+ }
137
+ function translatedTooltip(result, view) {
138
+ const range = result.hover ? rangeToOffsets(view.state.doc, result.hover.range) : null;
139
+ if (!range || !result.hover) return null;
140
+ return { ...hoverTooltip(result.hover, range.from), end: range.to };
141
+ }
142
+ function translateDiagnostic(diagnostic, view) {
143
+ const range = diagnostic.source ? diagnosticOffsets(view.state.doc, diagnostic.source.range) : { from: 0, to: 0 };
144
+ return { ...range, severity: "error", message: diagnostic.message };
145
+ }
146
+ function animationWindow(view) {
147
+ const window = view.dom.ownerDocument.defaultView;
148
+ if (!window) throw new Error("CodeMirror view has no window");
149
+ return window;
150
+ }
151
+ function wholeReplacement(snapshot, text) {
152
+ return {
153
+ range: {
154
+ start: { line: 0, character: 0 },
155
+ end: snapshot.lineIndex.positionAt(snapshot.text.length)
156
+ },
157
+ text
158
+ };
159
+ }
160
+ var setKeyboardTooltip = state.StateEffect.define();
161
+ var keyboardTooltipField = state.StateField.define({
162
+ create: () => [],
163
+ update(value, transaction) {
164
+ let next = value;
165
+ for (const effect of transaction.effects) {
166
+ if (effect.is(setKeyboardTooltip)) next = effect.value ? [effect.value] : [];
167
+ }
168
+ return next;
169
+ },
170
+ provide: (field) => view.showTooltip.computeN([field], (state) => state.field(field))
171
+ });
172
+
173
+ // src/session.ts
174
+ function createKaladaEditorSession(options) {
175
+ return new EditorSession(options);
176
+ }
177
+ var EditorSession = class {
178
+ extension;
179
+ service;
180
+ uri;
181
+ onDocumentChange;
182
+ lineSeparator = new state.Compartment();
183
+ view = null;
184
+ expectedText;
185
+ revision;
186
+ disposed = false;
187
+ viewEpoch = 0;
188
+ completionEpoch = 0;
189
+ hoverEpoch = 0;
190
+ diagnosticsEpoch = 0;
191
+ diagnosticsFrame = null;
192
+ constructor(options) {
193
+ this.service = options.service;
194
+ this.uri = options.document.uri;
195
+ this.onDocumentChange = options.onDocumentChange;
196
+ const opened = this.service.openDocument(options.document);
197
+ this.expectedText = opened.text;
198
+ this.revision = opened.version;
199
+ this.extension = this.createExtension();
200
+ }
201
+ refreshEnvironment() {
202
+ this.assertOpen();
203
+ this.invalidateRequests();
204
+ const view = this.view;
205
+ if (!view) return;
206
+ this.clearEditor(view, false);
207
+ this.scheduleDiagnostics(view);
208
+ }
209
+ replaceDocument(text) {
210
+ this.assertOpen();
211
+ if (typeof text !== "string") throw new TypeError("Replacement text must be a string");
212
+ const view = this.view;
213
+ if (view) {
214
+ const separator = detectLineSeparator(text);
215
+ view.dispatch({
216
+ changes: { from: 0, to: view.state.doc.length, insert: textForEditor(text) },
217
+ selection: state.EditorSelection.cursor(0),
218
+ annotations: state.Transaction.addToHistory.of(true),
219
+ effects: separator === view.state.lineBreak ? void 0 : this.lineSeparator.reconfigure(state.EditorState.lineSeparator.of(separator))
220
+ });
221
+ return;
222
+ }
223
+ const current = this.requireDocument();
224
+ const snapshot = this.service.updateDocument({
225
+ uri: this.uri,
226
+ version: this.nextRevision(),
227
+ edits: [wholeReplacement(current, text)]
228
+ });
229
+ this.expectedText = snapshot.text;
230
+ this.invalidateRequests();
231
+ this.notify(snapshot);
232
+ }
233
+ format() {
234
+ this.assertOpen();
235
+ const view = this.view;
236
+ if (!view) return false;
237
+ const epoch = this.completionEpoch;
238
+ const result = this.service.format(this.uri, {
239
+ cancellation: this.cancellation("completion", epoch)
240
+ });
241
+ if (result.kind !== "format" || !result.edit || !this.publishable(result, view, epoch, "completion")) {
242
+ return false;
243
+ }
244
+ const range = rangeToOffsets(view.state.doc, result.edit.range);
245
+ if (!range) return false;
246
+ view.dispatch({
247
+ changes: { ...range, insert: textForEditor(result.edit.text) },
248
+ annotations: state.Transaction.addToHistory.of(true)
249
+ });
250
+ return true;
251
+ }
252
+ dispose() {
253
+ if (this.disposed) return;
254
+ this.disposed = true;
255
+ this.invalidateRequests();
256
+ this.cancelDiagnosticsFrame();
257
+ const view = this.view;
258
+ if (view) this.clearEditor(view, true);
259
+ this.view = null;
260
+ this.service.closeDocument(this.uri);
261
+ }
262
+ createExtension() {
263
+ const session = this;
264
+ const lifecycle = view.ViewPlugin.define((view) => {
265
+ session.attach(view);
266
+ return {
267
+ update(update) {
268
+ session.updateView(update);
269
+ },
270
+ destroy() {
271
+ session.detach(view);
272
+ }
273
+ };
274
+ });
275
+ return [
276
+ lifecycle,
277
+ this.lineSeparator.of(state.EditorState.lineSeparator.of(detectLineSeparator(this.expectedText))),
278
+ commands.history(),
279
+ autocomplete.autocompletion({ override: [(context) => this.complete(context)] }),
280
+ view.hoverTooltip((view, position) => this.pointerHover(view, position)),
281
+ keyboardTooltipField,
282
+ view.keymap.of([
283
+ ...autocomplete.completionKeymap,
284
+ ...commands.historyKeymap,
285
+ { key: "Mod-Shift-h", run: (view) => this.keyboardHover(view) },
286
+ { key: "Escape", run: (view) => this.clearInteractions(view) }
287
+ ]),
288
+ view.EditorView.contentAttributes.of({ "aria-label": "Kalada expression editor" })
289
+ ];
290
+ }
291
+ attach(view) {
292
+ this.assertOpen();
293
+ if (this.view && this.view !== view)
294
+ throw new Error("Kalada editor session already has a view");
295
+ if (textFromEditor(view.state.doc, view.state.lineBreak) !== this.expectedText) {
296
+ throw new Error("CodeMirror document does not match the opened Kalada document");
297
+ }
298
+ this.view = view;
299
+ this.viewEpoch += 1;
300
+ this.scheduleDiagnostics(view);
301
+ }
302
+ detach(view) {
303
+ if (this.view !== view) return;
304
+ this.cancelDiagnosticsFrame();
305
+ this.invalidateRequests();
306
+ this.view = null;
307
+ this.viewEpoch += 1;
308
+ }
309
+ updateView(update) {
310
+ if (this.disposed || !update.docChanged) return;
311
+ this.invalidateRequests();
312
+ for (const transaction of update.transactions) {
313
+ if (transaction.docChanged) this.applyTransaction(transaction);
314
+ }
315
+ this.expectedText = textFromEditor(update.state.doc, update.state.lineBreak);
316
+ this.scheduleDiagnostics(update.view);
317
+ }
318
+ applyTransaction(transaction) {
319
+ const current = this.requireDocument();
320
+ const startText = textFromEditor(transaction.startState.doc, transaction.startState.lineBreak);
321
+ if (current.text !== startText) {
322
+ throw new Error("CodeMirror and language-service snapshots diverged");
323
+ }
324
+ const edits = changesToEdits(
325
+ transaction.startState.doc,
326
+ transaction.newDoc,
327
+ transaction.changes,
328
+ current,
329
+ transaction.state.lineBreak
330
+ );
331
+ const snapshot = this.service.updateDocument({
332
+ uri: this.uri,
333
+ version: this.nextRevision(),
334
+ edits
335
+ });
336
+ if (snapshot.text !== textFromEditor(transaction.newDoc, transaction.state.lineBreak)) {
337
+ throw new Error("CodeMirror transaction translation changed document text");
338
+ }
339
+ this.expectedText = snapshot.text;
340
+ this.notify(snapshot);
341
+ }
342
+ complete(context) {
343
+ const view = this.view;
344
+ if (!view || view.state !== context.state || this.disposed) return null;
345
+ const epoch = ++this.completionEpoch;
346
+ const result = this.service.completion(this.uri, positionAt2(context.state.doc, context.pos), {
347
+ cancellation: this.cancellation("completion", epoch)
348
+ });
349
+ if (result.kind !== "completion" || !this.publishable(result, view, epoch, "completion")) {
350
+ return null;
351
+ }
352
+ const translated = result.items.map(
353
+ (item) => this.translateCompletion(item, result, view, epoch)
354
+ );
355
+ const available = translated.filter((entry) => entry !== null);
356
+ const first = available[0];
357
+ return first ? { from: first.from, to: first.to, options: available.map(({ option }) => option) } : null;
358
+ }
359
+ translateCompletion(item, identity, view, epoch) {
360
+ const range = rangeToOffsets(view.state.doc, item.edit.range);
361
+ if (!range) return null;
362
+ const option = {
363
+ label: item.label,
364
+ type: item.kind === "binding" ? "variable" : item.kind,
365
+ detail: `${item.support}, ${item.presence}`,
366
+ boost: item.support === "common" ? 10 : 0,
367
+ apply: (target) => this.applyCompletion(target, item, identity, epoch)
368
+ };
369
+ return { ...range, option };
370
+ }
371
+ applyCompletion(view, item, identity, epoch) {
372
+ if (!this.publishable(identity, view, epoch, "completion")) return;
373
+ const range = rangeToOffsets(view.state.doc, item.edit.range);
374
+ if (!range) return;
375
+ view.dispatch({ changes: { ...range, insert: item.edit.text } });
376
+ }
377
+ pointerHover(view, offset) {
378
+ return this.requestHover(view, offset);
379
+ }
380
+ keyboardHover(view) {
381
+ const tooltip = this.requestHover(view, view.state.selection.main.head);
382
+ if (!tooltip) return false;
383
+ view.dispatch({ effects: setKeyboardTooltip.of(tooltip) });
384
+ return true;
385
+ }
386
+ requestHover(view, offset) {
387
+ const epoch = ++this.hoverEpoch;
388
+ const result = this.service.hover(this.uri, positionAt2(view.state.doc, offset), {
389
+ cancellation: this.cancellation("hover", epoch)
390
+ });
391
+ if (result.kind !== "hover" || !result.hover || !this.publishable(result, view, epoch, "hover")) {
392
+ return null;
393
+ }
394
+ return translatedTooltip(result, view);
395
+ }
396
+ clearInteractions(view) {
397
+ this.clearEditor(view, false);
398
+ view.focus();
399
+ return true;
400
+ }
401
+ clearEditor(view$1, diagnostics) {
402
+ autocomplete.closeCompletion(view$1);
403
+ const interactions = { effects: [setKeyboardTooltip.of(null), view.closeHoverTooltips] };
404
+ if (diagnostics) view$1.dispatch(interactions, lint.setDiagnostics(view$1.state, []));
405
+ else view$1.dispatch(interactions);
406
+ }
407
+ scheduleDiagnostics(view) {
408
+ this.cancelDiagnosticsFrame();
409
+ const epoch = ++this.diagnosticsEpoch;
410
+ const viewEpoch = this.viewEpoch;
411
+ this.diagnosticsFrame = animationWindow(view).requestAnimationFrame(() => {
412
+ this.diagnosticsFrame = null;
413
+ const result = this.service.diagnostics(this.uri, {
414
+ cancellation: this.cancellation("diagnostics", epoch)
415
+ });
416
+ if (result.kind !== "diagnostics" || !this.publishable(result, view, epoch, "diagnostics"))
417
+ return;
418
+ if (this.viewEpoch !== viewEpoch) return;
419
+ view.dispatch(
420
+ lint.setDiagnostics(
421
+ view.state,
422
+ result.diagnostics.map((entry) => translateDiagnostic(entry, view))
423
+ )
424
+ );
425
+ });
426
+ }
427
+ cancelDiagnosticsFrame() {
428
+ if (this.diagnosticsFrame === null || !this.view) return;
429
+ animationWindow(this.view).cancelAnimationFrame(this.diagnosticsFrame);
430
+ this.diagnosticsFrame = null;
431
+ }
432
+ cancellation(kind, epoch) {
433
+ return {
434
+ isCancellationRequested: () => this.disposed || this.epoch(kind) !== epoch
435
+ };
436
+ }
437
+ publishable(identity, view, epoch, kind) {
438
+ return !this.disposed && this.view === view && this.epoch(kind) === epoch && "status" in identity && identity.status === "current" && this.service.isCurrent(identity);
439
+ }
440
+ epoch(kind) {
441
+ if (kind === "completion") return this.completionEpoch;
442
+ if (kind === "hover") return this.hoverEpoch;
443
+ return this.diagnosticsEpoch;
444
+ }
445
+ invalidateRequests() {
446
+ this.completionEpoch += 1;
447
+ this.hoverEpoch += 1;
448
+ this.diagnosticsEpoch += 1;
449
+ }
450
+ nextRevision() {
451
+ if (this.revision >= Number.MAX_SAFE_INTEGER)
452
+ throw new RangeError("Kalada document revision exhausted");
453
+ this.revision += 1;
454
+ return this.revision;
455
+ }
456
+ requireDocument() {
457
+ const document = this.service.getDocument(this.uri);
458
+ if (!document) throw new Error("Kalada editor document is not open");
459
+ return document;
460
+ }
461
+ notify(snapshot) {
462
+ try {
463
+ this.onDocumentChange?.(snapshot);
464
+ } catch {
465
+ }
466
+ }
467
+ assertOpen() {
468
+ if (this.disposed) throw new Error("Kalada editor session is disposed");
469
+ }
470
+ };
471
+
472
+ exports.createKaladaEditorSession = createKaladaEditorSession;
473
+ //# sourceMappingURL=index.cjs.map
474
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/line-separator.ts","../src/render.ts","../src/translation.ts","../src/session-helpers.ts","../src/tooltip-state.ts","../src/session.ts"],"names":["Text","positionAt","StateEffect","StateField","showTooltip","Compartment","EditorSelection","Transaction","EditorState","ViewPlugin","history","autocompletion","codeMirrorHover","keymap","completionKeymap","historyKeymap","EditorView","view","closeCompletion","closeHoverTooltips","setDiagnostics"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Text } from \"@codemirror/state\";\n\nexport function detectLineSeparator(text: string): string {\n if (text.includes(\"\\r\\n\")) return \"\\r\\n\";\n if (text.includes(\"\\r\")) return \"\\r\";\n return \"\\n\";\n}\n\nexport function textForEditor(text: string): Text {\n return Text.of(text.split(/\\r\\n|\\r|\\n/u));\n}\n\nexport function textFromEditor(document: Text, lineSeparator: string): string {\n return document.sliceString(0, document.length, lineSeparator);\n}\n","import type { EditorView, Tooltip } from \"@codemirror/view\";\nimport type { HoverInfo, ShapeSummary, ToolingEvidence } from \"@kalada/language-service\";\n\nexport function hoverTooltip(info: HoverInfo, position: number): Tooltip {\n return {\n pos: position,\n above: true,\n create(view: EditorView) {\n const document = view.dom.ownerDocument;\n const dom = document.createElement(\"section\");\n dom.className = \"cm-kalada-hover\";\n dom.setAttribute(\"role\", \"tooltip\");\n dom.setAttribute(\"aria-label\", \"Kalada expression information\");\n appendSection(document, dom, \"Input editor shape\", info.input.map(shapeText));\n appendSection(document, dom, \"Output Kalada semantic projection\", [semanticText(info)]);\n appendSection(document, dom, \"Presence / branch conditions\", [accessText(info)]);\n appendSection(document, dom, \"Limit/unknown evidence\", info.evidence.map(evidenceText));\n return { dom };\n },\n };\n}\n\nfunction appendSection(\n document: Document,\n parent: HTMLElement,\n heading: string,\n values: readonly string[],\n): void {\n const title = document.createElement(\"strong\");\n title.textContent = heading;\n parent.append(title);\n const list = document.createElement(\"ul\");\n for (const value of values.length > 0 ? values : [\"None\"]) {\n const item = document.createElement(\"li\");\n item.textContent = value;\n list.append(item);\n }\n parent.append(list);\n}\n\nfunction shapeText(summary: ShapeSummary): string {\n const fields = summary.fields\n .map(\n ({ name, presence, accessible }) =>\n `${name} (${presence}, ${accessible ? \"accessible\" : \"inspect only\"})`,\n )\n .join(\", \");\n const scalar = summary.scalar ? ` ${summary.scalar}` : \"\";\n return `${summary.kind}${scalar}; ${summary.presence}; fields: ${fields || \"none\"}`;\n}\n\nfunction semanticText(info: HoverInfo): string {\n const type = info.output.type === \"dynamic\" ? \"dynamic\" : JSON.stringify(info.output.type);\n return `${info.output.known ? \"Known\" : \"Unknown\"}: ${type}`;\n}\n\nfunction accessText(info: HoverInfo): string {\n return `Access: ${info.access}`;\n}\n\nfunction evidenceText(evidence: ToolingEvidence): string {\n return `${evidence.code} at ${evidence.path.join(\".\") || \"root\"}`;\n}\n","import type { Text } from \"@codemirror/state\";\nimport type { DocumentSnapshot, TextEdit, Utf16LineIndex } from \"@kalada/language-service\";\n\ninterface OffsetEdit {\n readonly from: number;\n readonly to: number;\n readonly insert: string;\n}\n\nexport function changesToEdits(\n startDoc: Text,\n newDoc: Text,\n changes: Readonly<{ iterChanges: (callback: ChangeCallback) => void }>,\n snapshot: DocumentSnapshot,\n lineSeparator = \"\\n\",\n): readonly TextEdit[] {\n const offsets: OffsetEdit[] = [];\n changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {\n offsets.push({\n from: fromA,\n to: toA,\n insert: inserted.sliceString(0, inserted.length, lineSeparator),\n });\n });\n const coalesced = coalesceInserts(offsets);\n const translated = coalesced.map((edit) => offsetEdit(edit, startDoc, snapshot.lineIndex));\n if (translated.every((edit) => edit !== null)) return translated as readonly TextEdit[];\n return [wholeDocumentEdit(snapshot, newDoc.sliceString(0, newDoc.length, lineSeparator))];\n}\n\nexport function rangeToOffsets(\n document: Text,\n range: TextEdit[\"range\"],\n): Readonly<{ from: number; to: number }> | null {\n const from = offsetAt(document, range.start.line, range.start.character);\n const to = offsetAt(document, range.end.line, range.end.character);\n return from === null || to === null || from > to ? null : { from, to };\n}\n\nexport function diagnosticOffsets(\n document: Text,\n range: TextEdit[\"range\"],\n): Readonly<{ from: number; to: number }> {\n return rangeToOffsets(document, range) ?? { from: 0, to: 0 };\n}\n\nfunction offsetEdit(edit: OffsetEdit, document: Text, index: Utf16LineIndex): TextEdit | null {\n const start = positionAt(document, edit.from);\n const end = positionAt(document, edit.to);\n if (index.offsetAt(start) !== edit.from || index.offsetAt(end) !== edit.to) return null;\n return { range: { start, end }, text: edit.insert };\n}\n\nfunction positionAt(document: Text, offset: number) {\n const line = document.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nfunction offsetAt(document: Text, line: number, character: number): number | null {\n if (\n !Number.isSafeInteger(line) ||\n !Number.isSafeInteger(character) ||\n line < 0 ||\n character < 0\n ) {\n return null;\n }\n if (line >= document.lines) return null;\n const found = document.line(line + 1);\n return character <= found.length ? found.from + character : null;\n}\n\nfunction coalesceInserts(edits: readonly OffsetEdit[]): OffsetEdit[] {\n const output: OffsetEdit[] = [];\n for (const edit of edits) {\n const previous = output.at(-1);\n if (\n previous &&\n previous.from === edit.from &&\n previous.to === edit.to &&\n edit.from === edit.to\n ) {\n output[output.length - 1] = { ...previous, insert: `${previous.insert}${edit.insert}` };\n } else output.push(edit);\n }\n return output;\n}\n\nfunction wholeDocumentEdit(snapshot: DocumentSnapshot, text: string): TextEdit {\n return {\n range: {\n start: { line: 0, character: 0 },\n end: snapshot.lineIndex.positionAt(snapshot.text.length),\n },\n text,\n };\n}\n\ntype ChangeCallback = (\n fromA: number,\n toA: number,\n fromB: number,\n toB: number,\n inserted: Text,\n) => void;\n","import type { Diagnostic } from \"@codemirror/lint\";\nimport type { Text } from \"@codemirror/state\";\nimport type { EditorView } from \"@codemirror/view\";\nimport type {\n DocumentSnapshot,\n HoverResult,\n LanguageServiceDiagnostic,\n} from \"@kalada/language-service\";\nimport { hoverTooltip } from \"./render.js\";\nimport { diagnosticOffsets, rangeToOffsets } from \"./translation.js\";\n\nexport function positionAt(document: Text, offset: number) {\n const line = document.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nexport function translatedTooltip(\n result: Extract<HoverResult, { kind: \"hover\" }>,\n view: EditorView,\n) {\n const range = result.hover ? rangeToOffsets(view.state.doc, result.hover.range) : null;\n if (!range || !result.hover) return null;\n return { ...hoverTooltip(result.hover, range.from), end: range.to };\n}\n\nexport function translateDiagnostic(\n diagnostic: LanguageServiceDiagnostic,\n view: EditorView,\n): Diagnostic {\n const range = diagnostic.source\n ? diagnosticOffsets(view.state.doc, diagnostic.source.range)\n : { from: 0, to: 0 };\n return { ...range, severity: \"error\", message: diagnostic.message };\n}\n\nexport function animationWindow(view: EditorView): Window {\n const window = view.dom.ownerDocument.defaultView;\n if (!window) throw new Error(\"CodeMirror view has no window\");\n return window;\n}\n\nexport function wholeReplacement(snapshot: DocumentSnapshot, text: string) {\n return {\n range: {\n start: { line: 0, character: 0 },\n end: snapshot.lineIndex.positionAt(snapshot.text.length),\n },\n text,\n };\n}\n","import { StateEffect, StateField } from \"@codemirror/state\";\nimport { showTooltip, type Tooltip } from \"@codemirror/view\";\n\nexport const setKeyboardTooltip = StateEffect.define<Tooltip | null>();\n\nexport const keyboardTooltipField = StateField.define<readonly Tooltip[]>({\n create: () => [],\n update(value, transaction) {\n let next = value;\n for (const effect of transaction.effects) {\n if (effect.is(setKeyboardTooltip)) next = effect.value ? [effect.value] : [];\n }\n return next;\n },\n provide: (field) => showTooltip.computeN([field], (state) => state.field(field)),\n});\n","import {\n autocompletion,\n type CompletionResult as CodeMirrorCompletionResult,\n type Completion,\n type CompletionContext,\n closeCompletion,\n completionKeymap,\n} from \"@codemirror/autocomplete\";\nimport { history, historyKeymap } from \"@codemirror/commands\";\nimport { setDiagnostics } from \"@codemirror/lint\";\nimport {\n Compartment,\n EditorSelection,\n EditorState,\n type Transaction as EditorTransaction,\n Transaction,\n} from \"@codemirror/state\";\nimport {\n closeHoverTooltips,\n hoverTooltip as codeMirrorHover,\n EditorView,\n keymap,\n type Tooltip,\n ViewPlugin,\n type ViewUpdate,\n} from \"@codemirror/view\";\nimport type {\n CompletionItem,\n DocumentSnapshot,\n LanguageService,\n SnapshotIdentity,\n} from \"@kalada/language-service\";\nimport type { KaladaEditorSession, KaladaEditorSessionOptions } from \"./contracts.js\";\nimport { detectLineSeparator, textForEditor, textFromEditor } from \"./line-separator.js\";\nimport {\n animationWindow,\n positionAt,\n translateDiagnostic,\n translatedTooltip,\n wholeReplacement,\n} from \"./session-helpers.js\";\nimport { keyboardTooltipField, setKeyboardTooltip } from \"./tooltip-state.js\";\nimport { changesToEdits, rangeToOffsets } from \"./translation.js\";\nexport function createKaladaEditorSession(\n options: KaladaEditorSessionOptions,\n): KaladaEditorSession {\n return new EditorSession(options);\n}\nclass EditorSession implements KaladaEditorSession {\n readonly extension;\n private readonly service: LanguageService;\n private readonly uri: string;\n private readonly onDocumentChange?: (snapshot: DocumentSnapshot) => void;\n private readonly lineSeparator = new Compartment();\n private view: EditorView | null = null;\n private expectedText: string;\n private revision: number;\n private disposed = false;\n private viewEpoch = 0;\n private completionEpoch = 0;\n private hoverEpoch = 0;\n private diagnosticsEpoch = 0;\n private diagnosticsFrame: number | null = null;\n\n constructor(options: KaladaEditorSessionOptions) {\n this.service = options.service;\n this.uri = options.document.uri;\n this.onDocumentChange = options.onDocumentChange;\n const opened = this.service.openDocument(options.document);\n this.expectedText = opened.text;\n this.revision = opened.version;\n this.extension = this.createExtension();\n }\n refreshEnvironment(): void {\n this.assertOpen();\n this.invalidateRequests();\n const view = this.view;\n if (!view) return;\n this.clearEditor(view, false);\n this.scheduleDiagnostics(view);\n }\n replaceDocument(text: string): void {\n this.assertOpen();\n if (typeof text !== \"string\") throw new TypeError(\"Replacement text must be a string\");\n const view = this.view;\n if (view) {\n const separator = detectLineSeparator(text);\n view.dispatch({\n changes: { from: 0, to: view.state.doc.length, insert: textForEditor(text) },\n selection: EditorSelection.cursor(0),\n annotations: Transaction.addToHistory.of(true),\n effects:\n separator === view.state.lineBreak\n ? undefined\n : this.lineSeparator.reconfigure(EditorState.lineSeparator.of(separator)),\n });\n return;\n }\n const current = this.requireDocument();\n const snapshot = this.service.updateDocument({\n uri: this.uri,\n version: this.nextRevision(),\n edits: [wholeReplacement(current, text)],\n });\n this.expectedText = snapshot.text;\n this.invalidateRequests();\n this.notify(snapshot);\n }\n format(): boolean {\n this.assertOpen();\n const view = this.view;\n if (!view) return false;\n const epoch = this.completionEpoch;\n const result = this.service.format(this.uri, {\n cancellation: this.cancellation(\"completion\", epoch),\n });\n if (\n result.kind !== \"format\" ||\n !result.edit ||\n !this.publishable(result, view, epoch, \"completion\")\n ) {\n return false;\n }\n const range = rangeToOffsets(view.state.doc, result.edit.range);\n if (!range) return false;\n view.dispatch({\n changes: { ...range, insert: textForEditor(result.edit.text) },\n annotations: Transaction.addToHistory.of(true),\n });\n return true;\n }\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.invalidateRequests();\n this.cancelDiagnosticsFrame();\n const view = this.view;\n if (view) this.clearEditor(view, true);\n this.view = null;\n this.service.closeDocument(this.uri);\n }\n\n private createExtension() {\n const session = this;\n const lifecycle = ViewPlugin.define((view) => {\n session.attach(view);\n return {\n update(update: ViewUpdate): void {\n session.updateView(update);\n },\n destroy(): void {\n session.detach(view);\n },\n };\n });\n return [\n lifecycle,\n this.lineSeparator.of(EditorState.lineSeparator.of(detectLineSeparator(this.expectedText))),\n history(),\n autocompletion({ override: [(context) => this.complete(context)] }),\n codeMirrorHover((view, position) => this.pointerHover(view, position)),\n keyboardTooltipField,\n keymap.of([\n ...completionKeymap,\n ...historyKeymap,\n { key: \"Mod-Shift-h\", run: (view) => this.keyboardHover(view) },\n { key: \"Escape\", run: (view) => this.clearInteractions(view) },\n ]),\n EditorView.contentAttributes.of({ \"aria-label\": \"Kalada expression editor\" }),\n ];\n }\n\n private attach(view: EditorView): void {\n this.assertOpen();\n if (this.view && this.view !== view)\n throw new Error(\"Kalada editor session already has a view\");\n if (textFromEditor(view.state.doc, view.state.lineBreak) !== this.expectedText) {\n throw new Error(\"CodeMirror document does not match the opened Kalada document\");\n }\n this.view = view;\n this.viewEpoch += 1;\n this.scheduleDiagnostics(view);\n }\n\n private detach(view: EditorView): void {\n if (this.view !== view) return;\n this.cancelDiagnosticsFrame();\n this.invalidateRequests();\n this.view = null;\n this.viewEpoch += 1;\n }\n\n private updateView(update: ViewUpdate): void {\n if (this.disposed || !update.docChanged) return;\n this.invalidateRequests();\n for (const transaction of update.transactions) {\n if (transaction.docChanged) this.applyTransaction(transaction);\n }\n this.expectedText = textFromEditor(update.state.doc, update.state.lineBreak);\n this.scheduleDiagnostics(update.view);\n }\n\n private applyTransaction(transaction: EditorTransaction): void {\n const current = this.requireDocument();\n const startText = textFromEditor(transaction.startState.doc, transaction.startState.lineBreak);\n if (current.text !== startText) {\n throw new Error(\"CodeMirror and language-service snapshots diverged\");\n }\n const edits = changesToEdits(\n transaction.startState.doc,\n transaction.newDoc,\n transaction.changes,\n current,\n transaction.state.lineBreak,\n );\n const snapshot = this.service.updateDocument({\n uri: this.uri,\n version: this.nextRevision(),\n edits,\n });\n if (snapshot.text !== textFromEditor(transaction.newDoc, transaction.state.lineBreak)) {\n throw new Error(\"CodeMirror transaction translation changed document text\");\n }\n this.expectedText = snapshot.text;\n this.notify(snapshot);\n }\n\n private complete(context: CompletionContext): CodeMirrorCompletionResult | null {\n const view = this.view;\n if (!view || view.state !== context.state || this.disposed) return null;\n const epoch = ++this.completionEpoch;\n const result = this.service.completion(this.uri, positionAt(context.state.doc, context.pos), {\n cancellation: this.cancellation(\"completion\", epoch),\n });\n if (result.kind !== \"completion\" || !this.publishable(result, view, epoch, \"completion\")) {\n return null;\n }\n const translated = result.items.map((item) =>\n this.translateCompletion(item, result, view, epoch),\n );\n const available = translated.filter((entry) => entry !== null);\n const first = available[0];\n return first\n ? { from: first.from, to: first.to, options: available.map(({ option }) => option) }\n : null;\n }\n\n private translateCompletion(\n item: CompletionItem,\n identity: SnapshotIdentity,\n view: EditorView,\n epoch: number,\n ): Readonly<{ from: number; to: number; option: Completion }> | null {\n const range = rangeToOffsets(view.state.doc, item.edit.range);\n if (!range) return null;\n const option: Completion = {\n label: item.label,\n type: item.kind === \"binding\" ? \"variable\" : item.kind,\n detail: `${item.support}, ${item.presence}`,\n boost: item.support === \"common\" ? 10 : 0,\n apply: (target) => this.applyCompletion(target, item, identity, epoch),\n };\n return { ...range, option };\n }\n\n private applyCompletion(\n view: EditorView,\n item: CompletionItem,\n identity: SnapshotIdentity,\n epoch: number,\n ): void {\n if (!this.publishable(identity, view, epoch, \"completion\")) return;\n const range = rangeToOffsets(view.state.doc, item.edit.range);\n if (!range) return;\n view.dispatch({ changes: { ...range, insert: item.edit.text } });\n }\n\n private pointerHover(view: EditorView, offset: number): Tooltip | null {\n return this.requestHover(view, offset);\n }\n\n private keyboardHover(view: EditorView): boolean {\n const tooltip = this.requestHover(view, view.state.selection.main.head);\n if (!tooltip) return false;\n view.dispatch({ effects: setKeyboardTooltip.of(tooltip) });\n return true;\n }\n\n private requestHover(view: EditorView, offset: number): Tooltip | null {\n const epoch = ++this.hoverEpoch;\n const result = this.service.hover(this.uri, positionAt(view.state.doc, offset), {\n cancellation: this.cancellation(\"hover\", epoch),\n });\n if (\n result.kind !== \"hover\" ||\n !result.hover ||\n !this.publishable(result, view, epoch, \"hover\")\n ) {\n return null;\n }\n return translatedTooltip(result, view);\n }\n\n private clearInteractions(view: EditorView): boolean {\n this.clearEditor(view, false);\n view.focus();\n return true;\n }\n\n private clearEditor(view: EditorView, diagnostics: boolean): void {\n closeCompletion(view);\n const interactions = { effects: [setKeyboardTooltip.of(null), closeHoverTooltips] };\n if (diagnostics) view.dispatch(interactions, setDiagnostics(view.state, []));\n else view.dispatch(interactions);\n }\n private scheduleDiagnostics(view: EditorView): void {\n this.cancelDiagnosticsFrame();\n const epoch = ++this.diagnosticsEpoch;\n const viewEpoch = this.viewEpoch;\n this.diagnosticsFrame = animationWindow(view).requestAnimationFrame(() => {\n this.diagnosticsFrame = null;\n const result = this.service.diagnostics(this.uri, {\n cancellation: this.cancellation(\"diagnostics\", epoch),\n });\n if (result.kind !== \"diagnostics\" || !this.publishable(result, view, epoch, \"diagnostics\"))\n return;\n if (this.viewEpoch !== viewEpoch) return;\n view.dispatch(\n setDiagnostics(\n view.state,\n result.diagnostics.map((entry) => translateDiagnostic(entry, view)),\n ),\n );\n });\n }\n private cancelDiagnosticsFrame(): void {\n if (this.diagnosticsFrame === null || !this.view) return;\n animationWindow(this.view).cancelAnimationFrame(this.diagnosticsFrame);\n this.diagnosticsFrame = null;\n }\n\n private cancellation(kind: RequestKind, epoch: number) {\n return {\n isCancellationRequested: () => this.disposed || this.epoch(kind) !== epoch,\n };\n }\n\n private publishable(\n identity: SnapshotIdentity,\n view: EditorView,\n epoch: number,\n kind: RequestKind,\n ): boolean {\n return (\n !this.disposed &&\n this.view === view &&\n this.epoch(kind) === epoch &&\n \"status\" in identity &&\n identity.status === \"current\" &&\n this.service.isCurrent(identity)\n );\n }\n\n private epoch(kind: RequestKind): number {\n if (kind === \"completion\") return this.completionEpoch;\n if (kind === \"hover\") return this.hoverEpoch;\n return this.diagnosticsEpoch;\n }\n\n private invalidateRequests(): void {\n this.completionEpoch += 1;\n this.hoverEpoch += 1;\n this.diagnosticsEpoch += 1;\n }\n\n private nextRevision(): number {\n if (this.revision >= Number.MAX_SAFE_INTEGER)\n throw new RangeError(\"Kalada document revision exhausted\");\n this.revision += 1;\n return this.revision;\n }\n\n private requireDocument(): DocumentSnapshot {\n const document = this.service.getDocument(this.uri);\n if (!document) throw new Error(\"Kalada editor document is not open\");\n return document;\n }\n\n private notify(snapshot: DocumentSnapshot): void {\n try {\n this.onDocumentChange?.(snapshot);\n } catch {}\n }\n\n private assertOpen(): void {\n if (this.disposed) throw new Error(\"Kalada editor session is disposed\");\n }\n}\ntype RequestKind = \"completion\" | \"hover\" | \"diagnostics\";\n"]}
@@ -0,0 +1,19 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import { LanguageService, DocumentOpen, DocumentSnapshot } from '@kalada/language-service';
3
+
4
+ interface KaladaEditorSessionOptions {
5
+ readonly service: LanguageService;
6
+ readonly document: DocumentOpen;
7
+ readonly onDocumentChange?: (snapshot: DocumentSnapshot) => void;
8
+ }
9
+ interface KaladaEditorSession {
10
+ readonly extension: Extension;
11
+ readonly refreshEnvironment: () => void;
12
+ readonly replaceDocument: (text: string) => void;
13
+ readonly format: () => boolean;
14
+ readonly dispose: () => void;
15
+ }
16
+
17
+ declare function createKaladaEditorSession(options: KaladaEditorSessionOptions): KaladaEditorSession;
18
+
19
+ export { type KaladaEditorSession, type KaladaEditorSessionOptions, createKaladaEditorSession };
@@ -0,0 +1,19 @@
1
+ import { Extension } from '@codemirror/state';
2
+ import { LanguageService, DocumentOpen, DocumentSnapshot } from '@kalada/language-service';
3
+
4
+ interface KaladaEditorSessionOptions {
5
+ readonly service: LanguageService;
6
+ readonly document: DocumentOpen;
7
+ readonly onDocumentChange?: (snapshot: DocumentSnapshot) => void;
8
+ }
9
+ interface KaladaEditorSession {
10
+ readonly extension: Extension;
11
+ readonly refreshEnvironment: () => void;
12
+ readonly replaceDocument: (text: string) => void;
13
+ readonly format: () => boolean;
14
+ readonly dispose: () => void;
15
+ }
16
+
17
+ declare function createKaladaEditorSession(options: KaladaEditorSessionOptions): KaladaEditorSession;
18
+
19
+ export { type KaladaEditorSession, type KaladaEditorSessionOptions, createKaladaEditorSession };
package/dist/index.js ADDED
@@ -0,0 +1,472 @@
1
+ import { autocompletion, completionKeymap, closeCompletion } from '@codemirror/autocomplete';
2
+ import { history, historyKeymap } from '@codemirror/commands';
3
+ import { setDiagnostics } from '@codemirror/lint';
4
+ import { StateEffect, StateField, Compartment, EditorState, Transaction, EditorSelection, Text } from '@codemirror/state';
5
+ import { showTooltip, ViewPlugin, hoverTooltip as hoverTooltip$1, keymap, EditorView, closeHoverTooltips } from '@codemirror/view';
6
+
7
+ // src/session.ts
8
+ function detectLineSeparator(text) {
9
+ if (text.includes("\r\n")) return "\r\n";
10
+ if (text.includes("\r")) return "\r";
11
+ return "\n";
12
+ }
13
+ function textForEditor(text) {
14
+ return Text.of(text.split(/\r\n|\r|\n/u));
15
+ }
16
+ function textFromEditor(document, lineSeparator) {
17
+ return document.sliceString(0, document.length, lineSeparator);
18
+ }
19
+
20
+ // src/render.ts
21
+ function hoverTooltip(info, position) {
22
+ return {
23
+ pos: position,
24
+ above: true,
25
+ create(view) {
26
+ const document = view.dom.ownerDocument;
27
+ const dom = document.createElement("section");
28
+ dom.className = "cm-kalada-hover";
29
+ dom.setAttribute("role", "tooltip");
30
+ dom.setAttribute("aria-label", "Kalada expression information");
31
+ appendSection(document, dom, "Input editor shape", info.input.map(shapeText));
32
+ appendSection(document, dom, "Output Kalada semantic projection", [semanticText(info)]);
33
+ appendSection(document, dom, "Presence / branch conditions", [accessText(info)]);
34
+ appendSection(document, dom, "Limit/unknown evidence", info.evidence.map(evidenceText));
35
+ return { dom };
36
+ }
37
+ };
38
+ }
39
+ function appendSection(document, parent, heading, values) {
40
+ const title = document.createElement("strong");
41
+ title.textContent = heading;
42
+ parent.append(title);
43
+ const list = document.createElement("ul");
44
+ for (const value of values.length > 0 ? values : ["None"]) {
45
+ const item = document.createElement("li");
46
+ item.textContent = value;
47
+ list.append(item);
48
+ }
49
+ parent.append(list);
50
+ }
51
+ function shapeText(summary) {
52
+ const fields = summary.fields.map(
53
+ ({ name, presence, accessible }) => `${name} (${presence}, ${accessible ? "accessible" : "inspect only"})`
54
+ ).join(", ");
55
+ const scalar = summary.scalar ? ` ${summary.scalar}` : "";
56
+ return `${summary.kind}${scalar}; ${summary.presence}; fields: ${fields || "none"}`;
57
+ }
58
+ function semanticText(info) {
59
+ const type = info.output.type === "dynamic" ? "dynamic" : JSON.stringify(info.output.type);
60
+ return `${info.output.known ? "Known" : "Unknown"}: ${type}`;
61
+ }
62
+ function accessText(info) {
63
+ return `Access: ${info.access}`;
64
+ }
65
+ function evidenceText(evidence) {
66
+ return `${evidence.code} at ${evidence.path.join(".") || "root"}`;
67
+ }
68
+
69
+ // src/translation.ts
70
+ function changesToEdits(startDoc, newDoc, changes, snapshot, lineSeparator = "\n") {
71
+ const offsets = [];
72
+ changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
73
+ offsets.push({
74
+ from: fromA,
75
+ to: toA,
76
+ insert: inserted.sliceString(0, inserted.length, lineSeparator)
77
+ });
78
+ });
79
+ const coalesced = coalesceInserts(offsets);
80
+ const translated = coalesced.map((edit) => offsetEdit(edit, startDoc, snapshot.lineIndex));
81
+ if (translated.every((edit) => edit !== null)) return translated;
82
+ return [wholeDocumentEdit(snapshot, newDoc.sliceString(0, newDoc.length, lineSeparator))];
83
+ }
84
+ function rangeToOffsets(document, range) {
85
+ const from = offsetAt(document, range.start.line, range.start.character);
86
+ const to = offsetAt(document, range.end.line, range.end.character);
87
+ return from === null || to === null || from > to ? null : { from, to };
88
+ }
89
+ function diagnosticOffsets(document, range) {
90
+ return rangeToOffsets(document, range) ?? { from: 0, to: 0 };
91
+ }
92
+ function offsetEdit(edit, document, index) {
93
+ const start = positionAt(document, edit.from);
94
+ const end = positionAt(document, edit.to);
95
+ if (index.offsetAt(start) !== edit.from || index.offsetAt(end) !== edit.to) return null;
96
+ return { range: { start, end }, text: edit.insert };
97
+ }
98
+ function positionAt(document, offset) {
99
+ const line = document.lineAt(offset);
100
+ return { line: line.number - 1, character: offset - line.from };
101
+ }
102
+ function offsetAt(document, line, character) {
103
+ if (!Number.isSafeInteger(line) || !Number.isSafeInteger(character) || line < 0 || character < 0) {
104
+ return null;
105
+ }
106
+ if (line >= document.lines) return null;
107
+ const found = document.line(line + 1);
108
+ return character <= found.length ? found.from + character : null;
109
+ }
110
+ function coalesceInserts(edits) {
111
+ const output = [];
112
+ for (const edit of edits) {
113
+ const previous = output.at(-1);
114
+ if (previous && previous.from === edit.from && previous.to === edit.to && edit.from === edit.to) {
115
+ output[output.length - 1] = { ...previous, insert: `${previous.insert}${edit.insert}` };
116
+ } else output.push(edit);
117
+ }
118
+ return output;
119
+ }
120
+ function wholeDocumentEdit(snapshot, text) {
121
+ return {
122
+ range: {
123
+ start: { line: 0, character: 0 },
124
+ end: snapshot.lineIndex.positionAt(snapshot.text.length)
125
+ },
126
+ text
127
+ };
128
+ }
129
+
130
+ // src/session-helpers.ts
131
+ function positionAt2(document, offset) {
132
+ const line = document.lineAt(offset);
133
+ return { line: line.number - 1, character: offset - line.from };
134
+ }
135
+ function translatedTooltip(result, view) {
136
+ const range = result.hover ? rangeToOffsets(view.state.doc, result.hover.range) : null;
137
+ if (!range || !result.hover) return null;
138
+ return { ...hoverTooltip(result.hover, range.from), end: range.to };
139
+ }
140
+ function translateDiagnostic(diagnostic, view) {
141
+ const range = diagnostic.source ? diagnosticOffsets(view.state.doc, diagnostic.source.range) : { from: 0, to: 0 };
142
+ return { ...range, severity: "error", message: diagnostic.message };
143
+ }
144
+ function animationWindow(view) {
145
+ const window = view.dom.ownerDocument.defaultView;
146
+ if (!window) throw new Error("CodeMirror view has no window");
147
+ return window;
148
+ }
149
+ function wholeReplacement(snapshot, text) {
150
+ return {
151
+ range: {
152
+ start: { line: 0, character: 0 },
153
+ end: snapshot.lineIndex.positionAt(snapshot.text.length)
154
+ },
155
+ text
156
+ };
157
+ }
158
+ var setKeyboardTooltip = StateEffect.define();
159
+ var keyboardTooltipField = StateField.define({
160
+ create: () => [],
161
+ update(value, transaction) {
162
+ let next = value;
163
+ for (const effect of transaction.effects) {
164
+ if (effect.is(setKeyboardTooltip)) next = effect.value ? [effect.value] : [];
165
+ }
166
+ return next;
167
+ },
168
+ provide: (field) => showTooltip.computeN([field], (state) => state.field(field))
169
+ });
170
+
171
+ // src/session.ts
172
+ function createKaladaEditorSession(options) {
173
+ return new EditorSession(options);
174
+ }
175
+ var EditorSession = class {
176
+ extension;
177
+ service;
178
+ uri;
179
+ onDocumentChange;
180
+ lineSeparator = new Compartment();
181
+ view = null;
182
+ expectedText;
183
+ revision;
184
+ disposed = false;
185
+ viewEpoch = 0;
186
+ completionEpoch = 0;
187
+ hoverEpoch = 0;
188
+ diagnosticsEpoch = 0;
189
+ diagnosticsFrame = null;
190
+ constructor(options) {
191
+ this.service = options.service;
192
+ this.uri = options.document.uri;
193
+ this.onDocumentChange = options.onDocumentChange;
194
+ const opened = this.service.openDocument(options.document);
195
+ this.expectedText = opened.text;
196
+ this.revision = opened.version;
197
+ this.extension = this.createExtension();
198
+ }
199
+ refreshEnvironment() {
200
+ this.assertOpen();
201
+ this.invalidateRequests();
202
+ const view = this.view;
203
+ if (!view) return;
204
+ this.clearEditor(view, false);
205
+ this.scheduleDiagnostics(view);
206
+ }
207
+ replaceDocument(text) {
208
+ this.assertOpen();
209
+ if (typeof text !== "string") throw new TypeError("Replacement text must be a string");
210
+ const view = this.view;
211
+ if (view) {
212
+ const separator = detectLineSeparator(text);
213
+ view.dispatch({
214
+ changes: { from: 0, to: view.state.doc.length, insert: textForEditor(text) },
215
+ selection: EditorSelection.cursor(0),
216
+ annotations: Transaction.addToHistory.of(true),
217
+ effects: separator === view.state.lineBreak ? void 0 : this.lineSeparator.reconfigure(EditorState.lineSeparator.of(separator))
218
+ });
219
+ return;
220
+ }
221
+ const current = this.requireDocument();
222
+ const snapshot = this.service.updateDocument({
223
+ uri: this.uri,
224
+ version: this.nextRevision(),
225
+ edits: [wholeReplacement(current, text)]
226
+ });
227
+ this.expectedText = snapshot.text;
228
+ this.invalidateRequests();
229
+ this.notify(snapshot);
230
+ }
231
+ format() {
232
+ this.assertOpen();
233
+ const view = this.view;
234
+ if (!view) return false;
235
+ const epoch = this.completionEpoch;
236
+ const result = this.service.format(this.uri, {
237
+ cancellation: this.cancellation("completion", epoch)
238
+ });
239
+ if (result.kind !== "format" || !result.edit || !this.publishable(result, view, epoch, "completion")) {
240
+ return false;
241
+ }
242
+ const range = rangeToOffsets(view.state.doc, result.edit.range);
243
+ if (!range) return false;
244
+ view.dispatch({
245
+ changes: { ...range, insert: textForEditor(result.edit.text) },
246
+ annotations: Transaction.addToHistory.of(true)
247
+ });
248
+ return true;
249
+ }
250
+ dispose() {
251
+ if (this.disposed) return;
252
+ this.disposed = true;
253
+ this.invalidateRequests();
254
+ this.cancelDiagnosticsFrame();
255
+ const view = this.view;
256
+ if (view) this.clearEditor(view, true);
257
+ this.view = null;
258
+ this.service.closeDocument(this.uri);
259
+ }
260
+ createExtension() {
261
+ const session = this;
262
+ const lifecycle = ViewPlugin.define((view) => {
263
+ session.attach(view);
264
+ return {
265
+ update(update) {
266
+ session.updateView(update);
267
+ },
268
+ destroy() {
269
+ session.detach(view);
270
+ }
271
+ };
272
+ });
273
+ return [
274
+ lifecycle,
275
+ this.lineSeparator.of(EditorState.lineSeparator.of(detectLineSeparator(this.expectedText))),
276
+ history(),
277
+ autocompletion({ override: [(context) => this.complete(context)] }),
278
+ hoverTooltip$1((view, position) => this.pointerHover(view, position)),
279
+ keyboardTooltipField,
280
+ keymap.of([
281
+ ...completionKeymap,
282
+ ...historyKeymap,
283
+ { key: "Mod-Shift-h", run: (view) => this.keyboardHover(view) },
284
+ { key: "Escape", run: (view) => this.clearInteractions(view) }
285
+ ]),
286
+ EditorView.contentAttributes.of({ "aria-label": "Kalada expression editor" })
287
+ ];
288
+ }
289
+ attach(view) {
290
+ this.assertOpen();
291
+ if (this.view && this.view !== view)
292
+ throw new Error("Kalada editor session already has a view");
293
+ if (textFromEditor(view.state.doc, view.state.lineBreak) !== this.expectedText) {
294
+ throw new Error("CodeMirror document does not match the opened Kalada document");
295
+ }
296
+ this.view = view;
297
+ this.viewEpoch += 1;
298
+ this.scheduleDiagnostics(view);
299
+ }
300
+ detach(view) {
301
+ if (this.view !== view) return;
302
+ this.cancelDiagnosticsFrame();
303
+ this.invalidateRequests();
304
+ this.view = null;
305
+ this.viewEpoch += 1;
306
+ }
307
+ updateView(update) {
308
+ if (this.disposed || !update.docChanged) return;
309
+ this.invalidateRequests();
310
+ for (const transaction of update.transactions) {
311
+ if (transaction.docChanged) this.applyTransaction(transaction);
312
+ }
313
+ this.expectedText = textFromEditor(update.state.doc, update.state.lineBreak);
314
+ this.scheduleDiagnostics(update.view);
315
+ }
316
+ applyTransaction(transaction) {
317
+ const current = this.requireDocument();
318
+ const startText = textFromEditor(transaction.startState.doc, transaction.startState.lineBreak);
319
+ if (current.text !== startText) {
320
+ throw new Error("CodeMirror and language-service snapshots diverged");
321
+ }
322
+ const edits = changesToEdits(
323
+ transaction.startState.doc,
324
+ transaction.newDoc,
325
+ transaction.changes,
326
+ current,
327
+ transaction.state.lineBreak
328
+ );
329
+ const snapshot = this.service.updateDocument({
330
+ uri: this.uri,
331
+ version: this.nextRevision(),
332
+ edits
333
+ });
334
+ if (snapshot.text !== textFromEditor(transaction.newDoc, transaction.state.lineBreak)) {
335
+ throw new Error("CodeMirror transaction translation changed document text");
336
+ }
337
+ this.expectedText = snapshot.text;
338
+ this.notify(snapshot);
339
+ }
340
+ complete(context) {
341
+ const view = this.view;
342
+ if (!view || view.state !== context.state || this.disposed) return null;
343
+ const epoch = ++this.completionEpoch;
344
+ const result = this.service.completion(this.uri, positionAt2(context.state.doc, context.pos), {
345
+ cancellation: this.cancellation("completion", epoch)
346
+ });
347
+ if (result.kind !== "completion" || !this.publishable(result, view, epoch, "completion")) {
348
+ return null;
349
+ }
350
+ const translated = result.items.map(
351
+ (item) => this.translateCompletion(item, result, view, epoch)
352
+ );
353
+ const available = translated.filter((entry) => entry !== null);
354
+ const first = available[0];
355
+ return first ? { from: first.from, to: first.to, options: available.map(({ option }) => option) } : null;
356
+ }
357
+ translateCompletion(item, identity, view, epoch) {
358
+ const range = rangeToOffsets(view.state.doc, item.edit.range);
359
+ if (!range) return null;
360
+ const option = {
361
+ label: item.label,
362
+ type: item.kind === "binding" ? "variable" : item.kind,
363
+ detail: `${item.support}, ${item.presence}`,
364
+ boost: item.support === "common" ? 10 : 0,
365
+ apply: (target) => this.applyCompletion(target, item, identity, epoch)
366
+ };
367
+ return { ...range, option };
368
+ }
369
+ applyCompletion(view, item, identity, epoch) {
370
+ if (!this.publishable(identity, view, epoch, "completion")) return;
371
+ const range = rangeToOffsets(view.state.doc, item.edit.range);
372
+ if (!range) return;
373
+ view.dispatch({ changes: { ...range, insert: item.edit.text } });
374
+ }
375
+ pointerHover(view, offset) {
376
+ return this.requestHover(view, offset);
377
+ }
378
+ keyboardHover(view) {
379
+ const tooltip = this.requestHover(view, view.state.selection.main.head);
380
+ if (!tooltip) return false;
381
+ view.dispatch({ effects: setKeyboardTooltip.of(tooltip) });
382
+ return true;
383
+ }
384
+ requestHover(view, offset) {
385
+ const epoch = ++this.hoverEpoch;
386
+ const result = this.service.hover(this.uri, positionAt2(view.state.doc, offset), {
387
+ cancellation: this.cancellation("hover", epoch)
388
+ });
389
+ if (result.kind !== "hover" || !result.hover || !this.publishable(result, view, epoch, "hover")) {
390
+ return null;
391
+ }
392
+ return translatedTooltip(result, view);
393
+ }
394
+ clearInteractions(view) {
395
+ this.clearEditor(view, false);
396
+ view.focus();
397
+ return true;
398
+ }
399
+ clearEditor(view, diagnostics) {
400
+ closeCompletion(view);
401
+ const interactions = { effects: [setKeyboardTooltip.of(null), closeHoverTooltips] };
402
+ if (diagnostics) view.dispatch(interactions, setDiagnostics(view.state, []));
403
+ else view.dispatch(interactions);
404
+ }
405
+ scheduleDiagnostics(view) {
406
+ this.cancelDiagnosticsFrame();
407
+ const epoch = ++this.diagnosticsEpoch;
408
+ const viewEpoch = this.viewEpoch;
409
+ this.diagnosticsFrame = animationWindow(view).requestAnimationFrame(() => {
410
+ this.diagnosticsFrame = null;
411
+ const result = this.service.diagnostics(this.uri, {
412
+ cancellation: this.cancellation("diagnostics", epoch)
413
+ });
414
+ if (result.kind !== "diagnostics" || !this.publishable(result, view, epoch, "diagnostics"))
415
+ return;
416
+ if (this.viewEpoch !== viewEpoch) return;
417
+ view.dispatch(
418
+ setDiagnostics(
419
+ view.state,
420
+ result.diagnostics.map((entry) => translateDiagnostic(entry, view))
421
+ )
422
+ );
423
+ });
424
+ }
425
+ cancelDiagnosticsFrame() {
426
+ if (this.diagnosticsFrame === null || !this.view) return;
427
+ animationWindow(this.view).cancelAnimationFrame(this.diagnosticsFrame);
428
+ this.diagnosticsFrame = null;
429
+ }
430
+ cancellation(kind, epoch) {
431
+ return {
432
+ isCancellationRequested: () => this.disposed || this.epoch(kind) !== epoch
433
+ };
434
+ }
435
+ publishable(identity, view, epoch, kind) {
436
+ return !this.disposed && this.view === view && this.epoch(kind) === epoch && "status" in identity && identity.status === "current" && this.service.isCurrent(identity);
437
+ }
438
+ epoch(kind) {
439
+ if (kind === "completion") return this.completionEpoch;
440
+ if (kind === "hover") return this.hoverEpoch;
441
+ return this.diagnosticsEpoch;
442
+ }
443
+ invalidateRequests() {
444
+ this.completionEpoch += 1;
445
+ this.hoverEpoch += 1;
446
+ this.diagnosticsEpoch += 1;
447
+ }
448
+ nextRevision() {
449
+ if (this.revision >= Number.MAX_SAFE_INTEGER)
450
+ throw new RangeError("Kalada document revision exhausted");
451
+ this.revision += 1;
452
+ return this.revision;
453
+ }
454
+ requireDocument() {
455
+ const document = this.service.getDocument(this.uri);
456
+ if (!document) throw new Error("Kalada editor document is not open");
457
+ return document;
458
+ }
459
+ notify(snapshot) {
460
+ try {
461
+ this.onDocumentChange?.(snapshot);
462
+ } catch {
463
+ }
464
+ }
465
+ assertOpen() {
466
+ if (this.disposed) throw new Error("Kalada editor session is disposed");
467
+ }
468
+ };
469
+
470
+ export { createKaladaEditorSession };
471
+ //# sourceMappingURL=index.js.map
472
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/line-separator.ts","../src/render.ts","../src/translation.ts","../src/session-helpers.ts","../src/tooltip-state.ts","../src/session.ts"],"names":["positionAt","codeMirrorHover"],"mappings":"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","file":"index.js","sourcesContent":["import { Text } from \"@codemirror/state\";\n\nexport function detectLineSeparator(text: string): string {\n if (text.includes(\"\\r\\n\")) return \"\\r\\n\";\n if (text.includes(\"\\r\")) return \"\\r\";\n return \"\\n\";\n}\n\nexport function textForEditor(text: string): Text {\n return Text.of(text.split(/\\r\\n|\\r|\\n/u));\n}\n\nexport function textFromEditor(document: Text, lineSeparator: string): string {\n return document.sliceString(0, document.length, lineSeparator);\n}\n","import type { EditorView, Tooltip } from \"@codemirror/view\";\nimport type { HoverInfo, ShapeSummary, ToolingEvidence } from \"@kalada/language-service\";\n\nexport function hoverTooltip(info: HoverInfo, position: number): Tooltip {\n return {\n pos: position,\n above: true,\n create(view: EditorView) {\n const document = view.dom.ownerDocument;\n const dom = document.createElement(\"section\");\n dom.className = \"cm-kalada-hover\";\n dom.setAttribute(\"role\", \"tooltip\");\n dom.setAttribute(\"aria-label\", \"Kalada expression information\");\n appendSection(document, dom, \"Input editor shape\", info.input.map(shapeText));\n appendSection(document, dom, \"Output Kalada semantic projection\", [semanticText(info)]);\n appendSection(document, dom, \"Presence / branch conditions\", [accessText(info)]);\n appendSection(document, dom, \"Limit/unknown evidence\", info.evidence.map(evidenceText));\n return { dom };\n },\n };\n}\n\nfunction appendSection(\n document: Document,\n parent: HTMLElement,\n heading: string,\n values: readonly string[],\n): void {\n const title = document.createElement(\"strong\");\n title.textContent = heading;\n parent.append(title);\n const list = document.createElement(\"ul\");\n for (const value of values.length > 0 ? values : [\"None\"]) {\n const item = document.createElement(\"li\");\n item.textContent = value;\n list.append(item);\n }\n parent.append(list);\n}\n\nfunction shapeText(summary: ShapeSummary): string {\n const fields = summary.fields\n .map(\n ({ name, presence, accessible }) =>\n `${name} (${presence}, ${accessible ? \"accessible\" : \"inspect only\"})`,\n )\n .join(\", \");\n const scalar = summary.scalar ? ` ${summary.scalar}` : \"\";\n return `${summary.kind}${scalar}; ${summary.presence}; fields: ${fields || \"none\"}`;\n}\n\nfunction semanticText(info: HoverInfo): string {\n const type = info.output.type === \"dynamic\" ? \"dynamic\" : JSON.stringify(info.output.type);\n return `${info.output.known ? \"Known\" : \"Unknown\"}: ${type}`;\n}\n\nfunction accessText(info: HoverInfo): string {\n return `Access: ${info.access}`;\n}\n\nfunction evidenceText(evidence: ToolingEvidence): string {\n return `${evidence.code} at ${evidence.path.join(\".\") || \"root\"}`;\n}\n","import type { Text } from \"@codemirror/state\";\nimport type { DocumentSnapshot, TextEdit, Utf16LineIndex } from \"@kalada/language-service\";\n\ninterface OffsetEdit {\n readonly from: number;\n readonly to: number;\n readonly insert: string;\n}\n\nexport function changesToEdits(\n startDoc: Text,\n newDoc: Text,\n changes: Readonly<{ iterChanges: (callback: ChangeCallback) => void }>,\n snapshot: DocumentSnapshot,\n lineSeparator = \"\\n\",\n): readonly TextEdit[] {\n const offsets: OffsetEdit[] = [];\n changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {\n offsets.push({\n from: fromA,\n to: toA,\n insert: inserted.sliceString(0, inserted.length, lineSeparator),\n });\n });\n const coalesced = coalesceInserts(offsets);\n const translated = coalesced.map((edit) => offsetEdit(edit, startDoc, snapshot.lineIndex));\n if (translated.every((edit) => edit !== null)) return translated as readonly TextEdit[];\n return [wholeDocumentEdit(snapshot, newDoc.sliceString(0, newDoc.length, lineSeparator))];\n}\n\nexport function rangeToOffsets(\n document: Text,\n range: TextEdit[\"range\"],\n): Readonly<{ from: number; to: number }> | null {\n const from = offsetAt(document, range.start.line, range.start.character);\n const to = offsetAt(document, range.end.line, range.end.character);\n return from === null || to === null || from > to ? null : { from, to };\n}\n\nexport function diagnosticOffsets(\n document: Text,\n range: TextEdit[\"range\"],\n): Readonly<{ from: number; to: number }> {\n return rangeToOffsets(document, range) ?? { from: 0, to: 0 };\n}\n\nfunction offsetEdit(edit: OffsetEdit, document: Text, index: Utf16LineIndex): TextEdit | null {\n const start = positionAt(document, edit.from);\n const end = positionAt(document, edit.to);\n if (index.offsetAt(start) !== edit.from || index.offsetAt(end) !== edit.to) return null;\n return { range: { start, end }, text: edit.insert };\n}\n\nfunction positionAt(document: Text, offset: number) {\n const line = document.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nfunction offsetAt(document: Text, line: number, character: number): number | null {\n if (\n !Number.isSafeInteger(line) ||\n !Number.isSafeInteger(character) ||\n line < 0 ||\n character < 0\n ) {\n return null;\n }\n if (line >= document.lines) return null;\n const found = document.line(line + 1);\n return character <= found.length ? found.from + character : null;\n}\n\nfunction coalesceInserts(edits: readonly OffsetEdit[]): OffsetEdit[] {\n const output: OffsetEdit[] = [];\n for (const edit of edits) {\n const previous = output.at(-1);\n if (\n previous &&\n previous.from === edit.from &&\n previous.to === edit.to &&\n edit.from === edit.to\n ) {\n output[output.length - 1] = { ...previous, insert: `${previous.insert}${edit.insert}` };\n } else output.push(edit);\n }\n return output;\n}\n\nfunction wholeDocumentEdit(snapshot: DocumentSnapshot, text: string): TextEdit {\n return {\n range: {\n start: { line: 0, character: 0 },\n end: snapshot.lineIndex.positionAt(snapshot.text.length),\n },\n text,\n };\n}\n\ntype ChangeCallback = (\n fromA: number,\n toA: number,\n fromB: number,\n toB: number,\n inserted: Text,\n) => void;\n","import type { Diagnostic } from \"@codemirror/lint\";\nimport type { Text } from \"@codemirror/state\";\nimport type { EditorView } from \"@codemirror/view\";\nimport type {\n DocumentSnapshot,\n HoverResult,\n LanguageServiceDiagnostic,\n} from \"@kalada/language-service\";\nimport { hoverTooltip } from \"./render.js\";\nimport { diagnosticOffsets, rangeToOffsets } from \"./translation.js\";\n\nexport function positionAt(document: Text, offset: number) {\n const line = document.lineAt(offset);\n return { line: line.number - 1, character: offset - line.from };\n}\n\nexport function translatedTooltip(\n result: Extract<HoverResult, { kind: \"hover\" }>,\n view: EditorView,\n) {\n const range = result.hover ? rangeToOffsets(view.state.doc, result.hover.range) : null;\n if (!range || !result.hover) return null;\n return { ...hoverTooltip(result.hover, range.from), end: range.to };\n}\n\nexport function translateDiagnostic(\n diagnostic: LanguageServiceDiagnostic,\n view: EditorView,\n): Diagnostic {\n const range = diagnostic.source\n ? diagnosticOffsets(view.state.doc, diagnostic.source.range)\n : { from: 0, to: 0 };\n return { ...range, severity: \"error\", message: diagnostic.message };\n}\n\nexport function animationWindow(view: EditorView): Window {\n const window = view.dom.ownerDocument.defaultView;\n if (!window) throw new Error(\"CodeMirror view has no window\");\n return window;\n}\n\nexport function wholeReplacement(snapshot: DocumentSnapshot, text: string) {\n return {\n range: {\n start: { line: 0, character: 0 },\n end: snapshot.lineIndex.positionAt(snapshot.text.length),\n },\n text,\n };\n}\n","import { StateEffect, StateField } from \"@codemirror/state\";\nimport { showTooltip, type Tooltip } from \"@codemirror/view\";\n\nexport const setKeyboardTooltip = StateEffect.define<Tooltip | null>();\n\nexport const keyboardTooltipField = StateField.define<readonly Tooltip[]>({\n create: () => [],\n update(value, transaction) {\n let next = value;\n for (const effect of transaction.effects) {\n if (effect.is(setKeyboardTooltip)) next = effect.value ? [effect.value] : [];\n }\n return next;\n },\n provide: (field) => showTooltip.computeN([field], (state) => state.field(field)),\n});\n","import {\n autocompletion,\n type CompletionResult as CodeMirrorCompletionResult,\n type Completion,\n type CompletionContext,\n closeCompletion,\n completionKeymap,\n} from \"@codemirror/autocomplete\";\nimport { history, historyKeymap } from \"@codemirror/commands\";\nimport { setDiagnostics } from \"@codemirror/lint\";\nimport {\n Compartment,\n EditorSelection,\n EditorState,\n type Transaction as EditorTransaction,\n Transaction,\n} from \"@codemirror/state\";\nimport {\n closeHoverTooltips,\n hoverTooltip as codeMirrorHover,\n EditorView,\n keymap,\n type Tooltip,\n ViewPlugin,\n type ViewUpdate,\n} from \"@codemirror/view\";\nimport type {\n CompletionItem,\n DocumentSnapshot,\n LanguageService,\n SnapshotIdentity,\n} from \"@kalada/language-service\";\nimport type { KaladaEditorSession, KaladaEditorSessionOptions } from \"./contracts.js\";\nimport { detectLineSeparator, textForEditor, textFromEditor } from \"./line-separator.js\";\nimport {\n animationWindow,\n positionAt,\n translateDiagnostic,\n translatedTooltip,\n wholeReplacement,\n} from \"./session-helpers.js\";\nimport { keyboardTooltipField, setKeyboardTooltip } from \"./tooltip-state.js\";\nimport { changesToEdits, rangeToOffsets } from \"./translation.js\";\nexport function createKaladaEditorSession(\n options: KaladaEditorSessionOptions,\n): KaladaEditorSession {\n return new EditorSession(options);\n}\nclass EditorSession implements KaladaEditorSession {\n readonly extension;\n private readonly service: LanguageService;\n private readonly uri: string;\n private readonly onDocumentChange?: (snapshot: DocumentSnapshot) => void;\n private readonly lineSeparator = new Compartment();\n private view: EditorView | null = null;\n private expectedText: string;\n private revision: number;\n private disposed = false;\n private viewEpoch = 0;\n private completionEpoch = 0;\n private hoverEpoch = 0;\n private diagnosticsEpoch = 0;\n private diagnosticsFrame: number | null = null;\n\n constructor(options: KaladaEditorSessionOptions) {\n this.service = options.service;\n this.uri = options.document.uri;\n this.onDocumentChange = options.onDocumentChange;\n const opened = this.service.openDocument(options.document);\n this.expectedText = opened.text;\n this.revision = opened.version;\n this.extension = this.createExtension();\n }\n refreshEnvironment(): void {\n this.assertOpen();\n this.invalidateRequests();\n const view = this.view;\n if (!view) return;\n this.clearEditor(view, false);\n this.scheduleDiagnostics(view);\n }\n replaceDocument(text: string): void {\n this.assertOpen();\n if (typeof text !== \"string\") throw new TypeError(\"Replacement text must be a string\");\n const view = this.view;\n if (view) {\n const separator = detectLineSeparator(text);\n view.dispatch({\n changes: { from: 0, to: view.state.doc.length, insert: textForEditor(text) },\n selection: EditorSelection.cursor(0),\n annotations: Transaction.addToHistory.of(true),\n effects:\n separator === view.state.lineBreak\n ? undefined\n : this.lineSeparator.reconfigure(EditorState.lineSeparator.of(separator)),\n });\n return;\n }\n const current = this.requireDocument();\n const snapshot = this.service.updateDocument({\n uri: this.uri,\n version: this.nextRevision(),\n edits: [wholeReplacement(current, text)],\n });\n this.expectedText = snapshot.text;\n this.invalidateRequests();\n this.notify(snapshot);\n }\n format(): boolean {\n this.assertOpen();\n const view = this.view;\n if (!view) return false;\n const epoch = this.completionEpoch;\n const result = this.service.format(this.uri, {\n cancellation: this.cancellation(\"completion\", epoch),\n });\n if (\n result.kind !== \"format\" ||\n !result.edit ||\n !this.publishable(result, view, epoch, \"completion\")\n ) {\n return false;\n }\n const range = rangeToOffsets(view.state.doc, result.edit.range);\n if (!range) return false;\n view.dispatch({\n changes: { ...range, insert: textForEditor(result.edit.text) },\n annotations: Transaction.addToHistory.of(true),\n });\n return true;\n }\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.invalidateRequests();\n this.cancelDiagnosticsFrame();\n const view = this.view;\n if (view) this.clearEditor(view, true);\n this.view = null;\n this.service.closeDocument(this.uri);\n }\n\n private createExtension() {\n const session = this;\n const lifecycle = ViewPlugin.define((view) => {\n session.attach(view);\n return {\n update(update: ViewUpdate): void {\n session.updateView(update);\n },\n destroy(): void {\n session.detach(view);\n },\n };\n });\n return [\n lifecycle,\n this.lineSeparator.of(EditorState.lineSeparator.of(detectLineSeparator(this.expectedText))),\n history(),\n autocompletion({ override: [(context) => this.complete(context)] }),\n codeMirrorHover((view, position) => this.pointerHover(view, position)),\n keyboardTooltipField,\n keymap.of([\n ...completionKeymap,\n ...historyKeymap,\n { key: \"Mod-Shift-h\", run: (view) => this.keyboardHover(view) },\n { key: \"Escape\", run: (view) => this.clearInteractions(view) },\n ]),\n EditorView.contentAttributes.of({ \"aria-label\": \"Kalada expression editor\" }),\n ];\n }\n\n private attach(view: EditorView): void {\n this.assertOpen();\n if (this.view && this.view !== view)\n throw new Error(\"Kalada editor session already has a view\");\n if (textFromEditor(view.state.doc, view.state.lineBreak) !== this.expectedText) {\n throw new Error(\"CodeMirror document does not match the opened Kalada document\");\n }\n this.view = view;\n this.viewEpoch += 1;\n this.scheduleDiagnostics(view);\n }\n\n private detach(view: EditorView): void {\n if (this.view !== view) return;\n this.cancelDiagnosticsFrame();\n this.invalidateRequests();\n this.view = null;\n this.viewEpoch += 1;\n }\n\n private updateView(update: ViewUpdate): void {\n if (this.disposed || !update.docChanged) return;\n this.invalidateRequests();\n for (const transaction of update.transactions) {\n if (transaction.docChanged) this.applyTransaction(transaction);\n }\n this.expectedText = textFromEditor(update.state.doc, update.state.lineBreak);\n this.scheduleDiagnostics(update.view);\n }\n\n private applyTransaction(transaction: EditorTransaction): void {\n const current = this.requireDocument();\n const startText = textFromEditor(transaction.startState.doc, transaction.startState.lineBreak);\n if (current.text !== startText) {\n throw new Error(\"CodeMirror and language-service snapshots diverged\");\n }\n const edits = changesToEdits(\n transaction.startState.doc,\n transaction.newDoc,\n transaction.changes,\n current,\n transaction.state.lineBreak,\n );\n const snapshot = this.service.updateDocument({\n uri: this.uri,\n version: this.nextRevision(),\n edits,\n });\n if (snapshot.text !== textFromEditor(transaction.newDoc, transaction.state.lineBreak)) {\n throw new Error(\"CodeMirror transaction translation changed document text\");\n }\n this.expectedText = snapshot.text;\n this.notify(snapshot);\n }\n\n private complete(context: CompletionContext): CodeMirrorCompletionResult | null {\n const view = this.view;\n if (!view || view.state !== context.state || this.disposed) return null;\n const epoch = ++this.completionEpoch;\n const result = this.service.completion(this.uri, positionAt(context.state.doc, context.pos), {\n cancellation: this.cancellation(\"completion\", epoch),\n });\n if (result.kind !== \"completion\" || !this.publishable(result, view, epoch, \"completion\")) {\n return null;\n }\n const translated = result.items.map((item) =>\n this.translateCompletion(item, result, view, epoch),\n );\n const available = translated.filter((entry) => entry !== null);\n const first = available[0];\n return first\n ? { from: first.from, to: first.to, options: available.map(({ option }) => option) }\n : null;\n }\n\n private translateCompletion(\n item: CompletionItem,\n identity: SnapshotIdentity,\n view: EditorView,\n epoch: number,\n ): Readonly<{ from: number; to: number; option: Completion }> | null {\n const range = rangeToOffsets(view.state.doc, item.edit.range);\n if (!range) return null;\n const option: Completion = {\n label: item.label,\n type: item.kind === \"binding\" ? \"variable\" : item.kind,\n detail: `${item.support}, ${item.presence}`,\n boost: item.support === \"common\" ? 10 : 0,\n apply: (target) => this.applyCompletion(target, item, identity, epoch),\n };\n return { ...range, option };\n }\n\n private applyCompletion(\n view: EditorView,\n item: CompletionItem,\n identity: SnapshotIdentity,\n epoch: number,\n ): void {\n if (!this.publishable(identity, view, epoch, \"completion\")) return;\n const range = rangeToOffsets(view.state.doc, item.edit.range);\n if (!range) return;\n view.dispatch({ changes: { ...range, insert: item.edit.text } });\n }\n\n private pointerHover(view: EditorView, offset: number): Tooltip | null {\n return this.requestHover(view, offset);\n }\n\n private keyboardHover(view: EditorView): boolean {\n const tooltip = this.requestHover(view, view.state.selection.main.head);\n if (!tooltip) return false;\n view.dispatch({ effects: setKeyboardTooltip.of(tooltip) });\n return true;\n }\n\n private requestHover(view: EditorView, offset: number): Tooltip | null {\n const epoch = ++this.hoverEpoch;\n const result = this.service.hover(this.uri, positionAt(view.state.doc, offset), {\n cancellation: this.cancellation(\"hover\", epoch),\n });\n if (\n result.kind !== \"hover\" ||\n !result.hover ||\n !this.publishable(result, view, epoch, \"hover\")\n ) {\n return null;\n }\n return translatedTooltip(result, view);\n }\n\n private clearInteractions(view: EditorView): boolean {\n this.clearEditor(view, false);\n view.focus();\n return true;\n }\n\n private clearEditor(view: EditorView, diagnostics: boolean): void {\n closeCompletion(view);\n const interactions = { effects: [setKeyboardTooltip.of(null), closeHoverTooltips] };\n if (diagnostics) view.dispatch(interactions, setDiagnostics(view.state, []));\n else view.dispatch(interactions);\n }\n private scheduleDiagnostics(view: EditorView): void {\n this.cancelDiagnosticsFrame();\n const epoch = ++this.diagnosticsEpoch;\n const viewEpoch = this.viewEpoch;\n this.diagnosticsFrame = animationWindow(view).requestAnimationFrame(() => {\n this.diagnosticsFrame = null;\n const result = this.service.diagnostics(this.uri, {\n cancellation: this.cancellation(\"diagnostics\", epoch),\n });\n if (result.kind !== \"diagnostics\" || !this.publishable(result, view, epoch, \"diagnostics\"))\n return;\n if (this.viewEpoch !== viewEpoch) return;\n view.dispatch(\n setDiagnostics(\n view.state,\n result.diagnostics.map((entry) => translateDiagnostic(entry, view)),\n ),\n );\n });\n }\n private cancelDiagnosticsFrame(): void {\n if (this.diagnosticsFrame === null || !this.view) return;\n animationWindow(this.view).cancelAnimationFrame(this.diagnosticsFrame);\n this.diagnosticsFrame = null;\n }\n\n private cancellation(kind: RequestKind, epoch: number) {\n return {\n isCancellationRequested: () => this.disposed || this.epoch(kind) !== epoch,\n };\n }\n\n private publishable(\n identity: SnapshotIdentity,\n view: EditorView,\n epoch: number,\n kind: RequestKind,\n ): boolean {\n return (\n !this.disposed &&\n this.view === view &&\n this.epoch(kind) === epoch &&\n \"status\" in identity &&\n identity.status === \"current\" &&\n this.service.isCurrent(identity)\n );\n }\n\n private epoch(kind: RequestKind): number {\n if (kind === \"completion\") return this.completionEpoch;\n if (kind === \"hover\") return this.hoverEpoch;\n return this.diagnosticsEpoch;\n }\n\n private invalidateRequests(): void {\n this.completionEpoch += 1;\n this.hoverEpoch += 1;\n this.diagnosticsEpoch += 1;\n }\n\n private nextRevision(): number {\n if (this.revision >= Number.MAX_SAFE_INTEGER)\n throw new RangeError(\"Kalada document revision exhausted\");\n this.revision += 1;\n return this.revision;\n }\n\n private requireDocument(): DocumentSnapshot {\n const document = this.service.getDocument(this.uri);\n if (!document) throw new Error(\"Kalada editor document is not open\");\n return document;\n }\n\n private notify(snapshot: DocumentSnapshot): void {\n try {\n this.onDocumentChange?.(snapshot);\n } catch {}\n }\n\n private assertOpen(): void {\n if (this.disposed) throw new Error(\"Kalada editor session is disposed\");\n }\n}\ntype RequestKind = \"completion\" | \"hover\" | \"diagnostics\";\n"]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@kalada/codemirror",
3
+ "version": "0.1.0",
4
+ "description": "Thin CodeMirror 6 integration for the Kalada language service",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/surikaterna/kalada",
9
+ "directory": "packages/codemirror"
10
+ },
11
+ "type": "module",
12
+ "sideEffects": false,
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "import": {
23
+ "types": "./dist/index.d.ts",
24
+ "default": "./dist/index.js"
25
+ },
26
+ "require": {
27
+ "types": "./dist/index.d.cts",
28
+ "default": "./dist/index.cjs"
29
+ }
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "test": "vitest run --config ../../vitest.config.ts src",
36
+ "typecheck": "tsc --noEmit"
37
+ },
38
+ "dependencies": {
39
+ "@kalada/language-service": "^0.1.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@codemirror/autocomplete": "^6.20.3",
43
+ "@codemirror/commands": "^6.11.1",
44
+ "@codemirror/lint": "^6.9.7",
45
+ "@codemirror/state": "^6.7.6",
46
+ "@codemirror/view": "^6.43.13"
47
+ },
48
+ "devDependencies": {
49
+ "@codemirror/autocomplete": "6.20.3",
50
+ "@codemirror/commands": "6.11.1",
51
+ "@codemirror/lint": "6.9.7",
52
+ "@codemirror/state": "6.7.6",
53
+ "@codemirror/view": "6.43.13"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "engines": {
59
+ "node": ">=22.0.0"
60
+ }
61
+ }