@marimo-team/islands 0.21.2-dev37 → 0.21.2-dev39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js
CHANGED
|
@@ -27014,6 +27014,7 @@ ${c.sqlString}
|
|
|
27014
27014
|
function indentOneTab(e) {
|
|
27015
27015
|
return e.split("\n").map((e2) => (e2 == null ? void 0 : e2.trim()) ? ` ${e2}` : e2).join("\n");
|
|
27016
27016
|
}
|
|
27017
|
+
const loroSyncAnnotation = Annotation.define();
|
|
27017
27018
|
function initialState$4() {
|
|
27018
27019
|
return {};
|
|
27019
27020
|
}
|
|
@@ -27609,9 +27610,23 @@ ${c.sqlString}
|
|
|
27609
27610
|
}
|
|
27610
27611
|
});
|
|
27611
27612
|
}
|
|
27613
|
+
var MARKDOWN_AUTORUN_USER_EVENTS = [
|
|
27614
|
+
"input",
|
|
27615
|
+
"delete",
|
|
27616
|
+
"undo",
|
|
27617
|
+
"redo"
|
|
27618
|
+
];
|
|
27619
|
+
function shouldAutorunMarkdownUpdate({ docChanged: e, transactions: r, predicate: c = () => true, hasFocus: d = false }) {
|
|
27620
|
+
return !e || !c() || r.some((e2) => e2.effects.some((e3) => e3.is(formattingChangeEffect))) ? false : r.some((e2) => e2.annotation(loroSyncAnnotation) === void 0 ? MARKDOWN_AUTORUN_USER_EVENTS.some((r2) => e2.isUserEvent(r2)) || d : false);
|
|
27621
|
+
}
|
|
27612
27622
|
function markdownAutoRunExtension({ predicate: e }) {
|
|
27613
27623
|
return EditorView.updateListener.of((r) => {
|
|
27614
|
-
|
|
27624
|
+
shouldAutorunMarkdownUpdate({
|
|
27625
|
+
docChanged: r.docChanged,
|
|
27626
|
+
transactions: r.transactions,
|
|
27627
|
+
predicate: e,
|
|
27628
|
+
hasFocus: r.view.hasFocus
|
|
27629
|
+
}) && r.view.state.facet(cellActionsState).onRun();
|
|
27615
27630
|
});
|
|
27616
27631
|
}
|
|
27617
27632
|
const pythonCompletionSource = async (e) => {
|
|
@@ -70858,7 +70873,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
70858
70873
|
return Logger.warn("Failed to get version from mount config"), null;
|
|
70859
70874
|
}
|
|
70860
70875
|
}
|
|
70861
|
-
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.21.2-
|
|
70876
|
+
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.21.2-dev39"), showCodeInRunModeAtom = atom(true);
|
|
70862
70877
|
atom(null);
|
|
70863
70878
|
var import_compiler_runtime$89 = require_compiler_runtime();
|
|
70864
70879
|
function useKeydownOnElement(e, r) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
// @vitest-environment jsdom
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
EditorState,
|
|
6
|
+
Transaction,
|
|
7
|
+
type TransactionSpec,
|
|
8
|
+
} from "@codemirror/state";
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { formattingChangeEffect } from "../../format";
|
|
11
|
+
import { loroSyncAnnotation } from "../../rtc/loro/sync";
|
|
12
|
+
import { exportedForTesting } from "../extensions";
|
|
13
|
+
|
|
14
|
+
const { shouldAutorunMarkdownUpdate } = exportedForTesting;
|
|
15
|
+
|
|
16
|
+
function createTransaction(spec: TransactionSpec) {
|
|
17
|
+
return EditorState.create({ doc: "" }).update(spec);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe("shouldAutorunMarkdownUpdate", () => {
|
|
21
|
+
it.each([
|
|
22
|
+
"input.type",
|
|
23
|
+
"delete.backward",
|
|
24
|
+
"undo",
|
|
25
|
+
"redo",
|
|
26
|
+
])("accepts local %s transactions", (userEvent) => {
|
|
27
|
+
const transaction = createTransaction({
|
|
28
|
+
changes: { from: 0, insert: "#" },
|
|
29
|
+
annotations: [Transaction.userEvent.of(userEvent)],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
expect(
|
|
33
|
+
shouldAutorunMarkdownUpdate({
|
|
34
|
+
docChanged: transaction.docChanged,
|
|
35
|
+
transactions: [transaction],
|
|
36
|
+
}),
|
|
37
|
+
).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("ignores formatting changes", () => {
|
|
41
|
+
const transaction = createTransaction({
|
|
42
|
+
changes: { from: 0, insert: "#" },
|
|
43
|
+
annotations: [Transaction.userEvent.of("input.type")],
|
|
44
|
+
effects: [formattingChangeEffect.of(true)],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(
|
|
48
|
+
shouldAutorunMarkdownUpdate({
|
|
49
|
+
docChanged: transaction.docChanged,
|
|
50
|
+
transactions: [transaction],
|
|
51
|
+
}),
|
|
52
|
+
).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("ignores RTC sync transactions", () => {
|
|
56
|
+
const transaction = createTransaction({
|
|
57
|
+
changes: { from: 0, insert: "#" },
|
|
58
|
+
annotations: [
|
|
59
|
+
Transaction.userEvent.of("input.type"),
|
|
60
|
+
loroSyncAnnotation.of(true),
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
expect(
|
|
65
|
+
shouldAutorunMarkdownUpdate({
|
|
66
|
+
docChanged: transaction.docChanged,
|
|
67
|
+
transactions: [transaction],
|
|
68
|
+
hasFocus: true,
|
|
69
|
+
}),
|
|
70
|
+
).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("ignores programmatic doc changes without a user event", () => {
|
|
74
|
+
const transaction = createTransaction({
|
|
75
|
+
changes: { from: 0, insert: "#" },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(
|
|
79
|
+
shouldAutorunMarkdownUpdate({
|
|
80
|
+
docChanged: transaction.docChanged,
|
|
81
|
+
transactions: [transaction],
|
|
82
|
+
}),
|
|
83
|
+
).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("allows focused local doc changes without user event annotations", () => {
|
|
87
|
+
const transaction = createTransaction({
|
|
88
|
+
changes: { from: 0, insert: "#" },
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(
|
|
92
|
+
shouldAutorunMarkdownUpdate({
|
|
93
|
+
docChanged: transaction.docChanged,
|
|
94
|
+
transactions: [transaction],
|
|
95
|
+
hasFocus: true,
|
|
96
|
+
}),
|
|
97
|
+
).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("honors the predicate gate", () => {
|
|
101
|
+
const transaction = createTransaction({
|
|
102
|
+
changes: { from: 0, insert: "#" },
|
|
103
|
+
annotations: [Transaction.userEvent.of("input.type")],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(
|
|
107
|
+
shouldAutorunMarkdownUpdate({
|
|
108
|
+
docChanged: transaction.docChanged,
|
|
109
|
+
transactions: [transaction],
|
|
110
|
+
predicate: () => false,
|
|
111
|
+
}),
|
|
112
|
+
).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import { closeCompletion, completionStatus } from "@codemirror/autocomplete";
|
|
4
4
|
import { type Extension, Prec } from "@codemirror/state";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
EditorView,
|
|
7
|
+
type KeyBinding,
|
|
8
|
+
keymap,
|
|
9
|
+
type ViewUpdate,
|
|
10
|
+
} from "@codemirror/view";
|
|
6
11
|
import { createTracebackInfoAtom } from "@/core/cells/cells";
|
|
7
12
|
import { type CellId, HTMLCellId, SCRATCH_CELL_ID } from "@/core/cells/ids";
|
|
13
|
+
import { loroSyncAnnotation } from "@/core/codemirror/rtc/loro/sync";
|
|
8
14
|
import type { KeymapConfig } from "@/core/config/config-schema";
|
|
9
15
|
import type { HotkeyProvider } from "@/core/hotkeys/hotkeys";
|
|
10
16
|
import { duplicateWithCtrlModifier } from "@/core/hotkeys/shortcuts";
|
|
@@ -330,6 +336,53 @@ function cellCodeEditing(hotkeys: HotkeyProvider): Extension[] {
|
|
|
330
336
|
return [onChangePlugin, formatKeymapExtension(hotkeys)];
|
|
331
337
|
}
|
|
332
338
|
|
|
339
|
+
const MARKDOWN_AUTORUN_USER_EVENTS = ["input", "delete", "undo", "redo"];
|
|
340
|
+
|
|
341
|
+
function shouldAutorunMarkdownUpdate({
|
|
342
|
+
docChanged,
|
|
343
|
+
transactions,
|
|
344
|
+
predicate = () => true,
|
|
345
|
+
hasFocus = false,
|
|
346
|
+
}: Pick<ViewUpdate, "docChanged" | "transactions"> & {
|
|
347
|
+
predicate?: () => boolean;
|
|
348
|
+
hasFocus?: boolean;
|
|
349
|
+
}): boolean {
|
|
350
|
+
// If the doc didn't change, ignore.
|
|
351
|
+
if (!docChanged) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// The caller decides when markdown autorun is allowed, e.g. not for
|
|
356
|
+
// f-strings where rerunning on every keystroke is usually incorrect.
|
|
357
|
+
if (!predicate()) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// This happens on mount when we start in markdown mode.
|
|
362
|
+
// Ignore formatting changes so language switches don't trigger autorun.
|
|
363
|
+
const isFormattingChange = transactions.some((tr) =>
|
|
364
|
+
tr.effects.some((effect) => effect.is(formattingChangeEffect)),
|
|
365
|
+
);
|
|
366
|
+
if (isFormattingChange) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return transactions.some((tr) => {
|
|
371
|
+
// Ignore RTC sync changes to avoid duplicate runs from remote edits.
|
|
372
|
+
if (tr.annotation(loroSyncAnnotation) !== undefined) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Prefer explicit local edit transactions, but keep a focused fallback for
|
|
377
|
+
// local rewrite paths like split-cell, which can update markdown content
|
|
378
|
+
// without annotating a user event.
|
|
379
|
+
return (
|
|
380
|
+
MARKDOWN_AUTORUN_USER_EVENTS.some((kind) => tr.isUserEvent(kind)) ||
|
|
381
|
+
hasFocus
|
|
382
|
+
);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
333
386
|
/**
|
|
334
387
|
* Extension for auto-running markdown cells
|
|
335
388
|
*/
|
|
@@ -339,30 +392,16 @@ export function markdownAutoRunExtension({
|
|
|
339
392
|
predicate: () => boolean;
|
|
340
393
|
}): Extension {
|
|
341
394
|
return EditorView.updateListener.of((update) => {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
if (!predicate()) {
|
|
395
|
+
if (
|
|
396
|
+
!shouldAutorunMarkdownUpdate({
|
|
397
|
+
docChanged: update.docChanged,
|
|
398
|
+
transactions: update.transactions,
|
|
399
|
+
predicate,
|
|
400
|
+
hasFocus: update.view.hasFocus,
|
|
401
|
+
})
|
|
402
|
+
) {
|
|
354
403
|
return;
|
|
355
404
|
}
|
|
356
|
-
|
|
357
|
-
// This happens on mount when we start in markdown mode
|
|
358
|
-
const isFormattingChange = update.transactions.some((tr) =>
|
|
359
|
-
tr.effects.some((effect) => effect.is(formattingChangeEffect)),
|
|
360
|
-
);
|
|
361
|
-
if (isFormattingChange) {
|
|
362
|
-
// Ignore formatting changes
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
405
|
const actions = update.view.state.facet(cellActionsState);
|
|
367
406
|
actions.onRun();
|
|
368
407
|
});
|
|
@@ -388,3 +427,7 @@ export function cellBundle({
|
|
|
388
427
|
),
|
|
389
428
|
];
|
|
390
429
|
}
|
|
430
|
+
|
|
431
|
+
export const exportedForTesting = {
|
|
432
|
+
shouldAutorunMarkdownUpdate,
|
|
433
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { EditorState } from "@codemirror/state";
|
|
4
|
+
import type { EditorView } from "@codemirror/view";
|
|
5
|
+
import { LoroDoc, LoroText } from "loro-crdt";
|
|
6
|
+
import { describe, expect, it, vi } from "vitest";
|
|
7
|
+
import { LoroSyncPluginValue, loroSyncAnnotation } from "../sync";
|
|
8
|
+
|
|
9
|
+
describe("LoroSyncPluginValue", () => {
|
|
10
|
+
it("annotates the initial reconciliation dispatch as RTC sync", async () => {
|
|
11
|
+
const dispatch = vi.fn();
|
|
12
|
+
const view = {
|
|
13
|
+
state: EditorState.create({ doc: "local" }),
|
|
14
|
+
dispatch,
|
|
15
|
+
} as unknown as EditorView;
|
|
16
|
+
|
|
17
|
+
const doc = new LoroDoc();
|
|
18
|
+
const text = doc
|
|
19
|
+
.getMap("codes")
|
|
20
|
+
.getOrCreateContainer("cell-1", new LoroText());
|
|
21
|
+
text.insert(0, "remote");
|
|
22
|
+
|
|
23
|
+
const plugin = new LoroSyncPluginValue(
|
|
24
|
+
view,
|
|
25
|
+
doc,
|
|
26
|
+
["codes", "cell-1"],
|
|
27
|
+
() => text,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
await Promise.resolve();
|
|
31
|
+
|
|
32
|
+
expect(dispatch).toHaveBeenCalledTimes(1);
|
|
33
|
+
expect(dispatch).toHaveBeenCalledWith(
|
|
34
|
+
expect.objectContaining({
|
|
35
|
+
changes: [
|
|
36
|
+
{
|
|
37
|
+
from: 0,
|
|
38
|
+
to: view.state.doc.length,
|
|
39
|
+
insert: "remote",
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
annotations: [
|
|
43
|
+
expect.objectContaining({
|
|
44
|
+
type: loroSyncAnnotation,
|
|
45
|
+
}),
|
|
46
|
+
],
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
plugin.destroy();
|
|
51
|
+
});
|
|
52
|
+
});
|