@marimo-team/islands 0.25.3-dev273 → 0.25.3-dev279

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.
Files changed (143) hide show
  1. package/dist/{ConnectedDataExplorerComponent-eLHPh6uu.js → ConnectedDataExplorerComponent-CErm132k.js} +25 -26
  2. package/dist/{ErrorBoundary-DBh-wUT9.js → ErrorBoundary-DmTMuDPR.js} +43 -44
  3. package/dist/{abnfDiagram-VCTEODGH-hqd0IBtX.js → abnfDiagram-VCTEODGH-d-Qn2fwb.js} +2 -2
  4. package/dist/{any-language-editor-DnG26QXh.js → any-language-editor-6k6F12Z3.js} +3 -3
  5. package/dist/{architectureDiagram-5GKGNRK7-BzLAFcc0.js → architectureDiagram-5GKGNRK7-DxragHYv.js} +1 -1
  6. package/dist/{assertNever-DIU3JJbt.js → assertNever-B-YzWzbL.js} +14 -14
  7. package/dist/{button-0-RqY1DW.js → button-DZuNnIZO.js} +220 -223
  8. package/dist/{capabilities-B6yy_CBN.js → capabilities-D9FskwsK.js} +1 -1
  9. package/dist/{chat-ui-BWIkve2R.js → chat-ui-v1Fdh0NA.js} +332 -333
  10. package/dist/{check-gUSZbRsl.js → check-XFzZeH-y.js} +1 -1
  11. package/dist/{chunk-IMKFNOWR-DOeVvuyE.js → chunk-IMKFNOWR-C0x0feFg.js} +1 -1
  12. package/dist/{chunk-SHT3W25Y-DZoFI8wR.js → chunk-SHT3W25Y-D0ZdASqB.js} +1 -1
  13. package/dist/{chunk-SVP7TREG-CWu86PSW.js → chunk-SVP7TREG-BHjL96zx.js} +1 -1
  14. package/dist/{chunk-TICWLB2K-BrM0GoP3.js → chunk-TICWLB2K-CzcrwGfp.js} +1 -1
  15. package/dist/{classDiagram-ZZMXUADV-DYi4V2bB.js → classDiagram-ZZMXUADV-BTqFAZTP.js} +2 -2
  16. package/dist/{classDiagram-v2-VYDZK3BY-tN7FIk-m.js → classDiagram-v2-VYDZK3BY-EPXb0Elt.js} +2 -2
  17. package/dist/{code-visibility-M_dXDGp6.js → code-visibility-Dw4-TXN0.js} +20 -20
  18. package/dist/{common-DV0fvw_I.js → common-BXMFi4lr.js} +5399 -5397
  19. package/dist/{config-BsPruWMR.js → config-C8MFHQ2E.js} +23 -22
  20. package/dist/{copy-icon-C2I8sw4h.js → copy-icon-CtllOdmg.js} +3 -3
  21. package/dist/{createReducer-DdtT_7ji.js → createReducer-DRqwmaTc.js} +2 -2
  22. package/dist/{cynefinDiagram-5FMLGOSQ-D5nCnDc-.js → cynefinDiagram-5FMLGOSQ-CBSD344q.js} +1 -1
  23. package/dist/{dagre-GXQ25YYZ-BHkd7f_i.js → dagre-GXQ25YYZ-JItjh3Ge.js} +1 -1
  24. package/dist/{data-grid-overlay-editor-Cd1zGKBt.js → data-grid-overlay-editor-hZzwX7Ia.js} +1 -1
  25. package/dist/{diagram-S7CK7UJ4-D1ALppT2.js → diagram-S7CK7UJ4-CTD9xTVb.js} +1 -1
  26. package/dist/{diagram-UQ7AKVKN-DLv0b83L.js → diagram-UQ7AKVKN-DTfnFai8.js} +1 -1
  27. package/dist/{diagram-VX7I27RA-7XJ7J6qg.js → diagram-VX7I27RA-BcSnucV-.js} +1 -1
  28. package/dist/{diagram-Z3DM3KII-7M7zbHp_.js → diagram-Z3DM3KII-C2ATIE8A.js} +1 -1
  29. package/dist/{dialog-DzCj1qQv.js → dialog-CaYm5imE.js} +33 -33
  30. package/dist/{dropdown-menu-CdXE15an.js → dropdown-menu-Bb0bFOIk.js} +149 -149
  31. package/dist/{ebnfDiagram-PWID7BFC-DHH1qlmV.js → ebnfDiagram-PWID7BFC-B7B9JPxc.js} +2 -2
  32. package/dist/{erDiagram-RLTQ6QDP-fI_0dGef.js → erDiagram-RLTQ6QDP-v6hDno1O.js} +1 -1
  33. package/dist/{error-banner-DPc9eIw5.js → error-banner-CHCdHVFB.js} +44 -45
  34. package/dist/{error-entries-CxN-Nq3V.js → error-entries-C1S-Rmyt.js} +563 -554
  35. package/dist/{feedback-button-CE2gPi4-.js → feedback-button-6Ui2TDLR.js} +12 -12
  36. package/dist/{flowDiagram-HODETNUW-Brg9MA6i.js → flowDiagram-HODETNUW-aIFlAtOy.js} +2 -2
  37. package/dist/{formats-DbSvAPY-.js → formats-PzBQMUnr.js} +3 -3
  38. package/dist/{glide-data-editor-BycATbgF.js → glide-data-editor-PZNlrSDI.js} +14 -16
  39. package/dist/{glide-utils-BSw3SSHF.js → glide-utils-BSQr4d90.js} +51 -59
  40. package/dist/{globals-CW6OvnI5.js → globals-DX6FPZYq.js} +3 -3
  41. package/dist/{html-to-image-Bc2AvXHG.js → html-to-image-CqGUd58T.js} +14529 -14531
  42. package/dist/{infoDiagram-27XIBGKW-E9e403YT.js → infoDiagram-27XIBGKW-D6YHLeCP.js} +1 -1
  43. package/dist/{ishikawaDiagram-5VMMS53U-C-RlYDRo.js → ishikawaDiagram-5VMMS53U-D1ZvprOX.js} +1 -1
  44. package/dist/{kanban-definition-UXKFOSKX-CLFl_uqK.js → kanban-definition-UXKFOSKX-Bna_3BMr.js} +1 -1
  45. package/dist/{loader-BVEtQ4F3.js → loader-DZvtzQoD.js} +1 -1
  46. package/dist/main.js +7357 -7361
  47. package/dist/{mermaid-rd09e1JL.js → mermaid-A36unKXJ.js} +50 -50
  48. package/dist/{mindmap-definition-YA3MSWOX-BQ8TWtyB.js → mindmap-definition-YA3MSWOX-CyVCs__G.js} +1 -1
  49. package/dist/{number-overlay-editor-B_rR-LdM.js → number-overlay-editor-D0CsL3_R.js} +1 -1
  50. package/dist/{pegDiagram-XKGWAZYB-CN8UHFPi.js → pegDiagram-XKGWAZYB-9hNBD2wZ.js} +2 -2
  51. package/dist/{pencil-DcT8AE0h.js → pencil-DYUlSKxZ.js} +1 -1
  52. package/dist/{pieDiagram-E7YTZNPT-DGuJ0EBd.js → pieDiagram-E7YTZNPT-8tr-NYo7.js} +1 -1
  53. package/dist/{process-output-qecD7Dk8.js → process-output-DskX9jLa.js} +4 -4
  54. package/dist/{railroadDiagram-O6MQD6OU-BPDA8wy8.js → railroadDiagram-O6MQD6OU-Dzg1dyyp.js} +2 -2
  55. package/dist/{requirementDiagram-BXWQKSXE-ChzLGbGW.js → requirementDiagram-BXWQKSXE-B7sNqwGG.js} +1 -1
  56. package/dist/{reveal-component-CngVwOSy.js → reveal-component-D7xeI1QR.js} +1003 -1003
  57. package/dist/{select-OxgozOC8.js → select-DsoP1qe8.js} +290 -290
  58. package/dist/{sequenceDiagram-WJ2MYXX4-DFX-bE6O.js → sequenceDiagram-WJ2MYXX4-oP9shbaG.js} +1 -1
  59. package/dist/{spec-oJn0RhpQ.js → spec-BZMDxAu7.js} +4 -4
  60. package/dist/{stateDiagram-D77RDMKH-BR7cI3wK.js → stateDiagram-D77RDMKH-CjCv4ogv.js} +2 -2
  61. package/dist/{stateDiagram-v2-MP3YSRHH-oGqB5UDI.js → stateDiagram-v2-MP3YSRHH-BW9X162a.js} +2 -2
  62. package/dist/{static-state-CuV6Pc3a.js → static-state-D-Q-Ajaa.js} +8 -8
  63. package/dist/style.css +1 -1
  64. package/dist/{swimlanes-42K2YHIH-DwSZl1yC.js → swimlanes-42K2YHIH-Ckfs9Wrn.js} +1 -1
  65. package/dist/{swimlanesDiagram-VR7AAH4N-BHlcd-Ri.js → swimlanesDiagram-VR7AAH4N-DpTNG9YP.js} +2 -2
  66. package/dist/{swiper-component-Dvj-goaD.js → swiper-component-DQbK_ZWm.js} +7 -7
  67. package/dist/{timeline-definition-24CTP7MA-DMmP-G2O.js → timeline-definition-24CTP7MA-BXaBlV6U.js} +1 -1
  68. package/dist/{toast-DbBHmxmB.js → toast-BhjIy3Tq.js} +158 -158
  69. package/dist/{tooltip-BfcDQd2j.js → tooltip-DMMiOn2f.js} +64 -64
  70. package/dist/use-restore-focus-CosX7-gx.js +7568 -0
  71. package/dist/{useAsyncData-BYIAoMqn.js → useAsyncData-Ci4AvJff.js} +4 -4
  72. package/dist/{useDateFormatter-ButWkdcK.js → useDateFormatter-CPlava52.js} +2 -2
  73. package/dist/{useDeepCompareMemoize-Bz0c5GN6.js → useDeepCompareMemoize-NaaWoFlX.js} +1 -1
  74. package/dist/useEvent-BRH-aCqi.js +19 -0
  75. package/dist/{useIframeCapabilities-BIolGsF1.js → useIframeCapabilities-BXhDDoCG.js} +1 -1
  76. package/dist/{useLifecycle-JjxCC7Vu.js → useLifecycle-SniivYmC.js} +2 -2
  77. package/dist/{vega-component-rxIxAAh9.js → vega-component-DIxaDQNs.js} +40 -40
  78. package/dist/{vennDiagram-4TSXK5OY-Db8GtH1G.js → vennDiagram-4TSXK5OY-C-hQ4iNJ.js} +1 -1
  79. package/dist/{wardleyDiagram-VM6X3IG4-DmIiC3FU.js → wardleyDiagram-VM6X3IG4-C2MQ_Umv.js} +1 -1
  80. package/dist/{xychartDiagram-S5SC5T6Z-DS9OPrNq.js → xychartDiagram-S5SC5T6Z-BtTTBn7Q.js} +1 -1
  81. package/package.json +1 -1
  82. package/src/__mocks__/executions.ts +4 -2
  83. package/src/__mocks__/notebook.ts +0 -2
  84. package/src/__tests__/CellStatus.test.tsx +6 -6
  85. package/src/components/editor/__tests__/data-attributes.test.tsx +0 -2
  86. package/src/components/editor/__tests__/output-persistence.test.tsx +20 -5
  87. package/src/components/editor/cell/CellStatus.tsx +6 -5
  88. package/src/components/editor/cell/__tests__/useRunCells.test.tsx +169 -0
  89. package/src/components/editor/cell/collapse.tsx +3 -4
  90. package/src/components/editor/cell/useRunCells.ts +32 -3
  91. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +2 -3
  92. package/src/components/editor/notebook-cell.tsx +23 -37
  93. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +4 -10
  94. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -2
  95. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +8 -5
  96. package/src/components/slides/minimap.tsx +3 -2
  97. package/src/components/slides/reveal-component.tsx +3 -2
  98. package/src/components/slides/slide-cell-view.tsx +8 -8
  99. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +0 -101
  100. package/src/core/cells/__tests__/actions.test.ts +0 -1
  101. package/src/core/cells/__tests__/cell.test.ts +81 -17
  102. package/src/core/cells/__tests__/cells.test.ts +0 -100
  103. package/src/core/cells/__tests__/document.test.ts +2 -8
  104. package/src/core/cells/__tests__/utils.test.ts +93 -24
  105. package/src/core/cells/actions.ts +0 -1
  106. package/src/core/cells/cell.ts +37 -14
  107. package/src/core/cells/cells.ts +10 -99
  108. package/src/core/cells/document.ts +2 -13
  109. package/src/core/cells/types.ts +0 -23
  110. package/src/core/cells/utils.ts +44 -17
  111. package/src/core/codemirror/cells/extensions.ts +0 -14
  112. package/src/core/errors/__tests__/error-entries.test.ts +40 -1
  113. package/src/core/errors/error-entries.ts +2 -3
  114. package/src/core/executions/__tests__/freshness.test.ts +420 -0
  115. package/src/core/executions/__tests__/hooks.test.tsx +106 -0
  116. package/src/core/executions/atoms.ts +22 -0
  117. package/src/core/executions/freshness.ts +164 -0
  118. package/src/core/executions/hooks.ts +17 -1
  119. package/src/core/executions/index.ts +3 -1
  120. package/src/core/islands/bootstrap.ts +0 -1
  121. package/src/core/islands/components/__tests__/web-components.test.tsx +63 -0
  122. package/src/core/islands/components/web-components.tsx +11 -0
  123. package/src/core/kernel/handlers.ts +0 -4
  124. package/src/core/session/useNotebookSession.tsx +2 -7
  125. package/src/css/globals.css +6 -2
  126. package/src/plugins/impl/DataEditorPlugin.tsx +0 -4
  127. package/src/plugins/impl/data-editor/__tests__/column-types.test.ts +5 -0
  128. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +9 -5
  129. package/src/plugins/impl/data-editor/column-types.ts +3 -0
  130. package/src/plugins/impl/data-editor/glide-data-editor.tsx +6 -5
  131. package/src/plugins/impl/data-editor/glide-utils.ts +10 -32
  132. package/src/plugins/impl/data-editor/types.ts +0 -2
  133. package/src/stories/cell-status.stories.tsx +12 -14
  134. package/src/stories/cell.stories.tsx +44 -10
  135. package/src/stories/layout/vertical/one-column.stories.tsx +0 -10
  136. package/src/theme/__tests__/islands-theme.test.tsx +276 -0
  137. package/src/theme/namespace.tsx +4 -3
  138. package/src/theme/useTheme.ts +71 -41
  139. package/dist/schemas-CdscWNy_.js +0 -4747
  140. package/dist/use-restore-focus-CmflVLWJ.js +0 -1672
  141. package/dist/useTheme-DPLobSFs.js +0 -339
  142. package/dist/utils-EBklsC5R.js +0 -813
  143. package/src/components/editor/cell/__tests__/useRunCells.test.ts +0 -45
@@ -27,7 +27,6 @@ import {
27
27
  createCell,
28
28
  createCellConfig,
29
29
  createCellRuntimeState,
30
- isEdited,
31
30
  } from "./types";
32
31
 
33
32
  // Following the document ----------------------------------------------------
@@ -49,13 +48,7 @@ function followCell(current: CellData, cell: EditableCell): CellData {
49
48
  if (code === current.code) {
50
49
  return { ...current, name: cell.name, config };
51
50
  }
52
- return {
53
- ...current,
54
- code,
55
- name: cell.name,
56
- config,
57
- edited: isEdited(current.lastCodeRun, code),
58
- };
51
+ return { ...current, code, name: cell.name, config };
59
52
  }
60
53
 
61
54
  /**
@@ -83,17 +76,13 @@ export function applyDocument(
83
76
  continue;
84
77
  }
85
78
  if (current === undefined) {
86
- // A new cell with code is stale until it runs. The kernel's last run
87
- // settles it on kernel-ready.
88
- const code = cell.code ?? "";
89
79
  cellData = {
90
80
  ...cellData,
91
81
  [id]: createCell({
92
82
  id,
93
- code,
83
+ code: cell.code ?? "",
94
84
  name: cell.name,
95
85
  config: createCellConfig(cell.config),
96
- edited: isEdited(null, code),
97
86
  }),
98
87
  };
99
88
  cellRuntime = {
@@ -6,18 +6,6 @@ import type { CellId } from "./ids";
6
6
  import { DEFAULT_CELL_NAME } from "./names";
7
7
  import type { Outline } from "./outline";
8
8
 
9
- /**
10
- * Whether a cell's code has changed since it last ran. A cell that never ran
11
- * is edited once it has code. Whitespace at the ends does not count.
12
- *
13
- * TODO(MO-8403): Delete with `lastCodeRun`.
14
- */
15
- export function isEdited(lastCodeRun: string | null, code: string): boolean {
16
- return lastCodeRun === null
17
- ? code.trim().length > 0
18
- : lastCodeRun.trim() !== code.trim();
19
- }
20
-
21
9
  /**
22
10
  * Create a new cell with default state.
23
11
  */
@@ -25,8 +13,6 @@ export function createCell({
25
13
  id,
26
14
  name = DEFAULT_CELL_NAME,
27
15
  code = "",
28
- lastCodeRun = null,
29
- edited = false,
30
16
  config,
31
17
  }: Partial<CellData> & { id: CellId }): CellData {
32
18
  return {
@@ -39,8 +25,6 @@ export function createCell({
39
25
  },
40
26
  name: name,
41
27
  code: code,
42
- edited: edited,
43
- lastCodeRun: lastCodeRun,
44
28
  };
45
29
  }
46
30
 
@@ -61,7 +45,6 @@ export function createCellRuntimeState(
61
45
  outline: null,
62
46
  output: null,
63
47
  consoleOutputs: [],
64
- staleInputs: false,
65
48
  debuggerActive: false,
66
49
  ...state,
67
50
  };
@@ -76,10 +59,6 @@ export interface CellData {
76
59
  name: string;
77
60
  /** current contents of the editor */
78
61
  code: string;
79
- /** whether this cell has been modified since its last run */
80
- edited: boolean;
81
- /** snapshot of code that was last run */
82
- lastCodeRun: string | null;
83
62
  /** cell configuration */
84
63
  config: CellConfig;
85
64
  }
@@ -97,8 +76,6 @@ export interface CellRuntimeState {
97
76
  outline: Outline | null;
98
77
  /** messages encoding the cell's console outputs. TODO(MO-8405) */
99
78
  consoleOutputs: ConsoleOutputMessage[];
100
- /** whether the cell has stale inputs. TODO(MO-8403) */
101
- staleInputs: boolean;
102
79
  /** debugger active */
103
80
  debuggerActive: boolean;
104
81
  /** serialization message. TODO(MO-8414) */
@@ -4,8 +4,11 @@ import type { EditorView } from "@codemirror/view";
4
4
  import {
5
5
  type CellExecutionInputs,
6
6
  type CellExecutionView,
7
+ type CellFreshness,
8
+ type CellFreshnessLookup,
7
9
  cellExecutionView,
8
10
  } from "@/core/executions";
11
+ import type { Executions } from "@/core/notebook/replica";
9
12
  import { Objects } from "@/utils/objects";
10
13
  import type { MarimoError, OutputMessage } from "../kernel/messages";
11
14
  import { isErrorMime } from "../mime";
@@ -15,8 +18,9 @@ import type { CellId } from "./ids";
15
18
  export function notebookNeedsRun(
16
19
  state: NotebookState,
17
20
  executions: CellExecutionInputs,
21
+ freshness: CellFreshnessLookup,
18
22
  ) {
19
- return staleCellIds(state, executions).length > 0;
23
+ return staleCellIds(state, executions, freshness).length > 0;
20
24
  }
21
25
 
22
26
  export function notebookCells(state: NotebookState) {
@@ -78,13 +82,13 @@ export function getUndoLabel(state: NotebookState): string {
78
82
  * errored, or running.
79
83
  */
80
84
  export function getDescendantsStatus(
81
- state: NotebookState,
82
85
  executions: CellExecutionInputs,
86
+ freshness: CellFreshnessLookup,
83
87
  descendants: readonly CellId[],
84
88
  ) {
85
89
  const views = descendants.map((id) => cellExecutionView(executions, id));
86
90
  const stale = descendants.some(
87
- (id) => state.cellRuntime[id]?.staleInputs || state.cellData[id]?.edited,
91
+ (id) => freshness(id).sourceChanged || freshness(id).inputsChanged,
88
92
  );
89
93
  const errored = views.some((view) => view.outcome === "error");
90
94
  const runningOrQueued = views.some(
@@ -104,21 +108,41 @@ export function getDescendantsStatus(
104
108
  export function staleCellIds(
105
109
  state: NotebookState,
106
110
  executions: CellExecutionInputs,
111
+ freshness: CellFreshnessLookup,
107
112
  ) {
108
- const { cellIds, cellData, cellRuntime } = state;
113
+ const { cellIds, cellData } = state;
109
114
  return cellIds.filter((cellId) => {
110
115
  const execution = cellExecutionView(executions, cellId);
116
+ if (execution.status !== "idle") {
117
+ // A run in progress covers the source it was asked for. Only an edit
118
+ // since then, visible once the host has planned the run, needs another.
119
+ return (
120
+ inFlight(executions.executions, cellId) &&
121
+ freshness(cellId).sourceChanged
122
+ );
123
+ }
111
124
  return (
112
125
  isUninstantiated(execution) ||
113
- cellData[cellId].edited ||
114
- execution.outcome === "interrupted" ||
115
- (cellRuntime[cellId].staleInputs &&
116
- // if a cell is disabled, it can't be run ...
117
- !(execution.blocked || cellData[cellId].config.disabled))
126
+ cellNeedsRun({
127
+ freshness: freshness(cellId),
128
+ interrupted: execution.outcome === "interrupted",
129
+ disabled: cellData[cellId].config.disabled,
130
+ blocked: execution.blocked,
131
+ })
118
132
  );
119
133
  });
120
134
  }
121
135
 
136
+ /** Whether the host holds a planned or started execution of the cell that has not completed. */
137
+ function inFlight(executions: Executions, cellId: CellId): boolean {
138
+ const latest = executions.latest.get(cellId);
139
+ const record =
140
+ latest === undefined
141
+ ? undefined
142
+ : executions.executions.get(latest)?.record;
143
+ return record !== undefined && record.status !== "completed";
144
+ }
145
+
122
146
  /** Whether a cell has never run: no result to show and nothing in flight. */
123
147
  export function isUninstantiated({
124
148
  status,
@@ -128,24 +152,27 @@ export function isUninstantiated({
128
152
  }
129
153
 
130
154
  /**
131
- * Whether a cell needs to be run given its edited / interrupted / stale
132
- * inputs, while accounting for ancestor-disabled cells (which should not be
133
- * flagged as needing a run until re-enabled).
155
+ * Whether a cell needs to be run: its source changed, its last run was
156
+ * interrupted, or an input changed and the cell can run. A disabled cell,
157
+ * or one blocked by a disabled ancestor, is not flagged for changed inputs
158
+ * until it can run again.
134
159
  */
135
160
  export function cellNeedsRun({
136
- edited,
161
+ freshness,
137
162
  interrupted,
138
- staleInputs,
139
163
  disabled,
140
164
  blocked,
141
165
  }: {
142
- edited: boolean;
166
+ freshness: CellFreshness;
143
167
  interrupted: boolean;
144
- staleInputs: boolean;
145
168
  disabled: boolean | undefined;
146
169
  blocked: boolean;
147
170
  }): boolean {
148
- return edited || interrupted || (staleInputs && !(disabled || blocked));
171
+ return (
172
+ freshness.sourceChanged ||
173
+ interrupted ||
174
+ (freshness.inputsChanged && !(disabled || blocked))
175
+ );
149
176
  }
150
177
 
151
178
  export function cellStatusClasses({
@@ -23,7 +23,6 @@ import { createObservable } from "@/core/state/observable";
23
23
  import { formatKeymapExtension } from "../extensions";
24
24
  import { formattingChangeEffect } from "../format";
25
25
  import { goToDefinitionAtCursorPosition } from "../go-to-definition/utils";
26
- import { getCellCode } from "../language/cell-code";
27
26
  import { isAtEndOfEditor, isAtStartOfEditor } from "../utils";
28
27
  import {
29
28
  breakpointGutter,
@@ -327,19 +326,6 @@ function cellCodeEditing(hotkeys: HotkeyProvider): Extension[] {
327
326
  return;
328
327
  }
329
328
  const cellId = update.view.state.facet(cellIdState);
330
- // The code itself reaches the document through the editor's binding.
331
- // Formatting, including a language switch, rewrites the code without
332
- // editing it, so the cell stays as run or as edited as it was.
333
- const formatted = update.transactions.some((tr) =>
334
- tr.effects.some((effect) => effect.is(formattingChangeEffect)),
335
- );
336
- if (formatted) {
337
- update.view.state.facet(cellActionsState).codeFormatted({
338
- cellId,
339
- before: getCellCode(update.startState),
340
- after: getCellCode(update.state),
341
- });
342
- }
343
329
 
344
330
  // Clear pending cut state if this cell was marked for cut
345
331
  const pendingCutCellIds = store.get(pendingCutCellIdsAtom);
@@ -1,8 +1,15 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import { createStore } from "jotai";
3
4
  import { describe, expect, it } from "vitest";
5
+ import { MockNotebook } from "@/__mocks__/notebook";
4
6
  import { cellId } from "@/__tests__/branded";
5
- import { type CellErrorEntry, formatCellError } from "../error-entries";
7
+ import { notebookAtom } from "@/core/cells/cells";
8
+ import {
9
+ type CellErrorEntry,
10
+ formatCellError,
11
+ getCellErrorEntries,
12
+ } from "../error-entries";
6
13
 
7
14
  describe("formatCellError", () => {
8
15
  it("formats current tracebacks without notebook source", () => {
@@ -23,3 +30,35 @@ describe("formatCellError", () => {
23
30
  expect(text).not.toContain("<span");
24
31
  });
25
32
  });
33
+
34
+ describe("getCellErrorEntries", () => {
35
+ it("pairs an error with the source that raised it, not a later edit", () => {
36
+ const id = cellId("c1");
37
+ const store = createStore();
38
+ store.set(
39
+ notebookAtom,
40
+ MockNotebook.notebookState({
41
+ cellData: { [id]: { code: "print('fixed')" } },
42
+ cellRuntime: {
43
+ [id]: {
44
+ output: {
45
+ channel: "marimo-error",
46
+ mimetype: "application/vnd.marimo+error",
47
+ data: [
48
+ {
49
+ type: "exception",
50
+ exception_type: "ZeroDivisionError",
51
+ msg: "division by zero",
52
+ },
53
+ ],
54
+ timestamp: 0,
55
+ code: "1 / 0",
56
+ },
57
+ },
58
+ },
59
+ }),
60
+ );
61
+
62
+ expect(getCellErrorEntries(store)[0]?.cellCode).toBe("1 / 0");
63
+ });
64
+ });
@@ -93,9 +93,8 @@ export function getCellErrorEntries(store: JotaiStore): CellErrorEntry[] {
93
93
  }
94
94
 
95
95
  const cellName = displayCellName(cellData[cellId].name, cellIndex);
96
- // Prefer the code from the last execution: runtime errors correspond to
97
- // the previous run, while `code` may already contain unsaved edits.
98
- const cellCode = cellData[cellId].lastCodeRun ?? cellData[cellId].code;
96
+ // The source that raised, since the cell may have been edited since.
97
+ const cellCode = output.code ?? cellData[cellId].code;
99
98
 
100
99
  entries.push({
101
100
  cellId,