@marimo-team/frontend 0.23.16-dev4 → 0.23.16-dev41

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 (254) hide show
  1. package/dist/assets/{CellStatus-BalYv0pK.js → CellStatus-C6Cj3oJc.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-DI7mV-Gw.js → ConnectedDataExplorerComponent-CMaZapRd.js} +1 -1
  3. package/dist/assets/{ErrorBoundary-C7_5jjWi.js → ErrorBoundary-DzTD8LVq.js} +1 -1
  4. package/dist/assets/{ImperativeModal-BIavOiUv.js → ImperativeModal-fY-ZfT0b.js} +1 -1
  5. package/dist/assets/{JsonOutput-CkCD-FgM.js → JsonOutput-CyzvjIjx.js} +12 -12
  6. package/dist/assets/{LazyAnyLanguageCodeMirror-sVm_hz8A.js → LazyAnyLanguageCodeMirror-B2JvSXP-.js} +2 -2
  7. package/dist/assets/{MarimoErrorOutput-DO2k2fA5.js → MarimoErrorOutput-CIuzXFFo.js} +4 -4
  8. package/dist/assets/{RSPContexts-CgC81f0I.js → RSPContexts-WiCgGm__.js} +1 -1
  9. package/dist/assets/RenderHTML-Cd-PP5ZR.js +1 -0
  10. package/dist/assets/{RunButton-BKRupqr7.js → RunButton-CnYWedW4.js} +1 -1
  11. package/dist/assets/{add-cell-with-ai-CEZtaZCK.js → add-cell-with-ai-ByOBQT99.js} +8 -8
  12. package/dist/assets/add-connection-dialog-C97ylgk0.js +170 -0
  13. package/dist/assets/{agent-panel-CHB6t7Zy.js → agent-panel-Dxo9WUKV.js} +5 -5
  14. package/dist/assets/ai-model-dropdown-Bvqy98cI.js +5 -0
  15. package/dist/assets/{alert-dialog-BXegNC0I.js → alert-dialog-Bb8Lz8ko.js} +1 -1
  16. package/dist/assets/{any-language-editor-DCpZRrpx.js → any-language-editor--tRHs8C_.js} +1 -1
  17. package/dist/assets/{app-config-button-NrM9ywXA.js → app-config-button-v1lG63C2.js} +1 -1
  18. package/dist/assets/{button-eIihcbUw.js → button-DDGiD1NW.js} +1 -1
  19. package/dist/assets/{cache-panel-wllSTlbM.js → cache-panel-DcQUeUpg.js} +1 -1
  20. package/dist/assets/{capabilities-B09j1Eor.js → capabilities-DoEg0XwL.js} +1 -1
  21. package/dist/assets/{cell-editor-B5JVq7_q.js → cell-editor-BKrHbyX_.js} +16 -16
  22. package/dist/assets/cell-link-w5IbCQV4.js +1 -0
  23. package/dist/assets/cells-DzyDERZy.js +235 -0
  24. package/dist/assets/{chat-display-BG08ltQ3.js → chat-display-Ccgk4vbE.js} +1 -1
  25. package/dist/assets/{chat-panel-P2CzCtXJ.js → chat-panel--53TIc3t.js} +4 -4
  26. package/dist/assets/{chat-ui-fAJZAoTD.js → chat-ui-B5rBxgsw.js} +4 -4
  27. package/dist/assets/{column-preview-Dne1dIt0.js → column-preview-Cb8R9kfl.js} +1 -1
  28. package/dist/assets/{command-CAJLPEBq.js → command-Dqxie4gq.js} +1 -1
  29. package/dist/assets/{command-palette-iOCqUIs1.js → command-palette-B1S9PjZi.js} +1 -1
  30. package/dist/assets/{common-CD6Mj8n6.js → common-CJ3baa6D.js} +1 -1
  31. package/dist/assets/components-DpUIWGaj.js +1 -0
  32. package/dist/assets/config-B-Q7J_6d.js +1 -0
  33. package/dist/assets/{config-COUOIPEq.js → config-BJVx3eBW.js} +1 -1
  34. package/dist/assets/{copy-BtTOqPTS.js → copy-Bxb1_Gtw.js} +1 -1
  35. package/dist/assets/{copy-icon-C2pG0ZNK.js → copy-icon-neDQUo4Q.js} +1 -1
  36. package/dist/assets/{createReducer-C7kZ8zEe.js → createReducer-DGx5Af-C.js} +1 -1
  37. package/dist/assets/{datasource-ySAiC9gr.js → datasource-D_VcQMEn.js} +2 -2
  38. package/dist/assets/{dates-D-kIKDYA.js → dates-C2LWzsCZ.js} +1 -1
  39. package/dist/assets/{dependency-graph-panel-BF23EwcD.js → dependency-graph-panel-DY5lvPDx.js} +3 -3
  40. package/dist/assets/{dialog-D1DEsRZ2.js → dialog-BCVepWLJ.js} +1 -1
  41. package/dist/assets/{dist-ByVeMWkr.js → dist-BLN8PNJV.js} +1 -1
  42. package/dist/assets/dist-CiVShZKM.js +2 -0
  43. package/dist/assets/{documentation-panel-e9Fi9R7e.js → documentation-panel-CGhwxsXK.js} +1 -1
  44. package/dist/assets/download-DpS57jyt.js +9 -0
  45. package/dist/assets/{dropdown-menu-BFZLnWeO.js → dropdown-menu-dHmZR8bI.js} +1 -1
  46. package/dist/assets/{edit-page-7X3HYey7.js → edit-page-DA765yQV.js} +6 -6
  47. package/dist/assets/{error-banner-B6eIlxzg.js → error-banner-BSxEOIn2.js} +1 -1
  48. package/dist/assets/error-entries-CTYMwfsh.js +8 -0
  49. package/dist/assets/{error-panel-DdsUL6b7.js → error-panel-DGAkG5kW.js} +1 -1
  50. package/dist/assets/{es-1D83cgiu.js → es-gYgfF8y5.js} +1 -1
  51. package/dist/assets/{esm-BL7jQmzn.js → esm-B30N1GS0.js} +1 -1
  52. package/dist/assets/{field-BeZbVzXA.js → field-BsxD35VE.js} +1 -1
  53. package/dist/assets/{file-explorer-panel-Ntq1-VbF.js → file-explorer-panel-BKUo-MDh.js} +3 -3
  54. package/dist/assets/{file-icons-Cb54mIL8.js → file-icons-DfWENcb8.js} +1 -1
  55. package/dist/assets/{file-name-input-BWFcK1ey.js → file-name-input-CNVZtm5K.js} +1 -1
  56. package/dist/assets/floating-outline-LitP0wCD.js +1 -0
  57. package/dist/assets/focus-CNKbm-Xz.js +1 -0
  58. package/dist/assets/{form-B6BkSCJb.js → form-nHzLTU1m.js} +2 -2
  59. package/dist/assets/{formats-ClEFGPy-.js → formats-DzmLpc9A.js} +1 -1
  60. package/dist/assets/{formatting-B_41gSF5.js → formatting-CDf6w1Kt.js} +1 -1
  61. package/dist/assets/{fullscreen-dUjPYOmm.js → fullscreen-CTDqNQr6.js} +1 -1
  62. package/dist/assets/{gallery-page-CWQQAYpa.js → gallery-page-CJ3ms1Hn.js} +1 -1
  63. package/dist/assets/{glide-data-editor-lMARFWHS.js → glide-data-editor-j2igs9Y_.js} +1 -1
  64. package/dist/assets/home-page-DM9Z_IJ7.js +4 -0
  65. package/dist/assets/{html-to-image-CwmX28T9.js → html-to-image-JaxFFZcr.js} +2 -2
  66. package/dist/assets/index-C7_REKh1.js +38 -0
  67. package/dist/assets/index-D6Dp_PFj.css +2 -0
  68. package/dist/assets/{input-CqrUjynb.js → input-JxFwu-3G.js} +1 -1
  69. package/dist/assets/kiosk-mode-BumOFEtY.js +1 -0
  70. package/dist/assets/{label-BElwWzf0.js → label-CqjrpwRC.js} +1 -1
  71. package/dist/assets/{layout-CUlZijwG.js → layout-B29hqiiK.js} +5 -5
  72. package/dist/assets/{links-CToBjIIj.js → links-CZr5bjvo.js} +1 -1
  73. package/dist/assets/logs-panel-CQRPYS8j.js +1 -0
  74. package/dist/assets/{markdown-renderer-QvXG0CRk.js → markdown-renderer-sEayY9-m.js} +2 -2
  75. package/dist/assets/{menu-items-DbSLBfXR.js → menu-items-CCi6aOPm.js} +1 -1
  76. package/dist/assets/{mermaid-Bh0flEIb.js → mermaid-CYN0wOyG.js} +1 -1
  77. package/dist/assets/{name-cell-input-C6cukQ9k.js → name-cell-input-B-aj1KH3.js} +1 -1
  78. package/dist/assets/node-sql-parser-Si4oZ2P-.js +68 -0
  79. package/dist/assets/{numbers-CeeaFKqu.js → numbers-rmawRqQP.js} +1 -1
  80. package/dist/assets/{outline-panel-BPlg9_CE.js → outline-panel-BOryk60D.js} +1 -1
  81. package/dist/assets/{packages-panel-BzQF60rG.js → packages-panel-DoYDLty3.js} +1 -1
  82. package/dist/assets/pair-with-agent-modal-BCRSACei.js +4 -0
  83. package/dist/assets/panels-Bb4fIHgH.js +4 -0
  84. package/dist/assets/{popover-DrHQ3KEt.js → popover-Bcz1Zikb.js} +1 -1
  85. package/dist/assets/process-output-d-LEMtGI.js +1 -0
  86. package/dist/assets/{radio-group-CLBjGkt5.js → radio-group-DfioQthW.js} +1 -1
  87. package/dist/assets/{readonly-code-display-D63oRtBP.js → readonly-code-display-C9fu8tvK.js} +1 -1
  88. package/dist/assets/{readonly-python-code-CW_G5e4E.js → readonly-python-code-DHxOnQGj.js} +1 -1
  89. package/dist/assets/{renderShortcut-BZLr8D7H.js → renderShortcut-Bl8_FVn8.js} +1 -1
  90. package/dist/assets/{reveal-component-BLMTmd8T.js → reveal-component-5jf0W625.js} +60 -60
  91. package/dist/assets/{run-page-B6pgDYEJ.js → run-page-BMKx9ld_.js} +1 -1
  92. package/dist/assets/{runs-D51Xwrsk.js → runs-DBTXqJHS.js} +1 -1
  93. package/dist/assets/scratchpad-panel-C8z8vzBX.js +1 -0
  94. package/dist/assets/{scroll-to-bottom-button-Cgr10kaJ.js → scroll-to-bottom-button-C8yfT4wq.js} +1 -1
  95. package/dist/assets/{secrets-panel-Cc5KDBk6.js → secrets-panel-6J6wcuVR.js} +1 -1
  96. package/dist/assets/{select-B5TFNjmU.js → select-BP75_5jJ.js} +1 -1
  97. package/dist/assets/{session-CEFnN9Cq.js → session-BmukRjSi.js} +1 -1
  98. package/dist/assets/{session-panel-Y0Oon0sD.js → session-panel-BVVk-02h.js} +1 -1
  99. package/dist/assets/{share-CYpcX4N4.js → share-852X_cqy.js} +1 -1
  100. package/dist/assets/{skeleton-D3QPxqWC.js → skeleton-Bubr9pIj.js} +1 -1
  101. package/dist/assets/slides-DkEgzTJB.css +1 -0
  102. package/dist/assets/{snippets-panel-CXpGflMO.js → snippets-panel-U2-iok-c.js} +1 -1
  103. package/dist/assets/{spec-CzqcmYQk.js → spec-C7opZZRp.js} +1 -1
  104. package/dist/assets/{state-BvdK8eiw.js → state-D10U2MwA.js} +1 -1
  105. package/dist/assets/{state-WBgc7MiA.js → state-DDag0B_B.js} +1 -1
  106. package/dist/assets/state-DtziTd1T.js +3 -0
  107. package/dist/assets/{state-DBzEQtWz.js → state-DxQhUsG9.js} +1 -1
  108. package/dist/assets/{strings-Djnbwmfl.js → strings--BknHX9C.js} +1 -1
  109. package/dist/assets/{swiper-component-DInvCxhI.js → swiper-component-g8EXE911.js} +1 -1
  110. package/dist/assets/switch-OVajJBPR.js +1 -0
  111. package/dist/assets/{terminal-D3IQBBYo.js → terminal-217O8hlZ.js} +1 -1
  112. package/dist/assets/{textarea-CpFfEUet.js → textarea-Bmzmbbpo.js} +1 -1
  113. package/dist/assets/{tooltip-CFX4fYHU.js → tooltip-4bZlU7jl.js} +1 -1
  114. package/dist/assets/{tooltip-HLb6RxVp.js → tooltip-B7U4xkIN.js} +1 -1
  115. package/dist/assets/{tracing-CKn3gWHw.js → tracing-B5XFvMmV.js} +1 -1
  116. package/dist/assets/{tracing-panel-BU-o_LCd.js → tracing-panel-DnR2bYDe.js} +2 -2
  117. package/dist/assets/{tree-actions-CsC2XmGo.js → tree-actions-Dx9CDaxV.js} +1 -1
  118. package/dist/assets/{useBoolean-D89u30n-.js → useBoolean-CFj86iac.js} +1 -1
  119. package/dist/assets/useCellActionButton-DypR3yDt.js +1 -0
  120. package/dist/assets/{useDeleteCell-EPH4kcG7.js → useDeleteCell-vMXAr3rY.js} +1 -1
  121. package/dist/assets/{useDependencyPanelTab-CZnK7N2L.js → useDependencyPanelTab-CwdwKf7A.js} +1 -1
  122. package/dist/assets/useEventListener-C0195JsF.js +1 -0
  123. package/dist/assets/{useHotkey-DIuRH8Wu.js → useHotkey-DLZvrRZT.js} +1 -1
  124. package/dist/assets/{useIframeCapabilities-Ccb4fvKc.js → useIframeCapabilities-j6fR_dBA.js} +1 -1
  125. package/dist/assets/{useInstallPackage-BRbUAUFn.js → useInstallPackage-WiYBwhUO.js} +1 -1
  126. package/dist/assets/{useInterval-CC0vKpWm.js → useInterval-CWBTUy5W.js} +1 -1
  127. package/dist/assets/useNotebookActions-jWIcmpv0.js +12 -0
  128. package/dist/assets/{useRunCells-CSSF_mJ0.js → useRunCells-C2dvU2jA.js} +1 -1
  129. package/dist/assets/{useSplitCell-9Qz93yPZ.js → useSplitCell-C1tubdNi.js} +1 -1
  130. package/dist/assets/{useTheme-KXqAyDPC.js → useTheme-Bxv9B31g.js} +1 -1
  131. package/dist/assets/{utils-Z80SV4_d.js → utils-BWBBpCkT.js} +1 -1
  132. package/dist/assets/{vega-component-Cie3ag_T.js → vega-component-Db8KjZJG.js} +1 -1
  133. package/dist/assets/{write-secret-modal-DEEn7sZV.js → write-secret-modal-3-v-dHVj.js} +1 -1
  134. package/dist/index.html +68 -68
  135. package/package.json +3 -4
  136. package/src/__mocks__/requests.ts +45 -4
  137. package/src/components/data-table/__tests__/__snapshots__/chart-spec-model.test.ts.snap +174 -21
  138. package/src/components/data-table/__tests__/chart-spec-model.test.ts +102 -1
  139. package/src/components/data-table/column-summary/chart-spec-model.tsx +163 -103
  140. package/src/components/data-table/column-summary/legacy-chart-spec.ts +15 -7
  141. package/src/components/data-table/column-summary/utils.ts +26 -7
  142. package/src/components/data-table/types.ts +1 -1
  143. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +99 -18
  144. package/src/components/editor/actions/__tests__/pdf-export.test.ts +0 -4
  145. package/src/components/editor/actions/pair-with-agent-commands.ts +21 -10
  146. package/src/components/editor/actions/pair-with-agent-modal.tsx +2 -2
  147. package/src/components/editor/actions/pdf-export.ts +1 -4
  148. package/src/components/editor/actions/useNotebookActions.tsx +7 -13
  149. package/src/components/editor/cell/code/__tests__/cell-editor-activity-lifecycle.test.ts +250 -0
  150. package/src/components/editor/cell/code/cell-editor.tsx +13 -7
  151. package/src/components/editor/chrome/panels/__tests__/logs-panel.test.tsx +25 -0
  152. package/src/components/editor/chrome/panels/logs-panel.tsx +12 -2
  153. package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +50 -0
  154. package/src/components/editor/connections/storage/__tests__/as-code.test.ts +87 -8
  155. package/src/components/editor/connections/storage/as-code.ts +40 -21
  156. package/src/components/editor/connections/storage/schemas.ts +83 -42
  157. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
  158. package/src/components/slides/__tests__/cell-output-block.test.tsx +40 -0
  159. package/src/components/slides/__tests__/slide-cell-view.test.tsx +33 -0
  160. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +198 -0
  161. package/src/components/slides/reveal-component.tsx +25 -19
  162. package/src/components/slides/slide-cell-view.tsx +1 -1
  163. package/src/components/slides/slide-scroll-hint.tsx +161 -0
  164. package/src/components/slides/slides.css +4 -2
  165. package/src/components/static-html/share-modal.tsx +1 -1
  166. package/src/components/ui/input.tsx +1 -1
  167. package/src/core/cells/__tests__/cells.test.ts +12 -2
  168. package/src/core/cells/__tests__/logs.test.ts +5 -5
  169. package/src/core/cells/cells.ts +17 -4
  170. package/src/core/cells/document-changes.ts +1 -0
  171. package/src/core/cells/logs.ts +14 -4
  172. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +396 -100
  173. package/src/core/codemirror/copilot/__tests__/transport.test.ts +128 -540
  174. package/src/core/codemirror/copilot/language-server.ts +182 -70
  175. package/src/core/codemirror/copilot/transport.ts +15 -207
  176. package/src/core/codemirror/copilot/types.ts +9 -2
  177. package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +42 -30
  178. package/src/core/codemirror/find-replace/navigate.ts +2 -0
  179. package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +24 -3
  180. package/src/core/codemirror/go-to-definition/commands.ts +3 -0
  181. package/src/core/codemirror/keymaps/__tests__/keymaps.test.ts +31 -2
  182. package/src/core/codemirror/keymaps/keymaps.ts +12 -0
  183. package/src/core/codemirror/language/__tests__/sql.test.ts +443 -61
  184. package/src/core/codemirror/language/languages/python.ts +23 -11
  185. package/src/core/codemirror/language/languages/sql/completion-store.ts +5 -1
  186. package/src/core/codemirror/language/languages/sql/sql.ts +210 -3
  187. package/src/core/codemirror/lsp/__tests__/federated-lsp.test.ts +161 -0
  188. package/src/core/codemirror/lsp/__tests__/log-messages.test.ts +53 -0
  189. package/src/core/codemirror/lsp/__tests__/normalize-markdown-math.test.ts +25 -0
  190. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +598 -156
  191. package/src/core/codemirror/lsp/__tests__/transports.test.ts +112 -0
  192. package/src/core/codemirror/lsp/federated-lsp.ts +76 -23
  193. package/src/core/codemirror/lsp/log-messages.ts +37 -0
  194. package/src/core/codemirror/lsp/normalize-markdown-math.ts +8 -4
  195. package/src/core/codemirror/lsp/notebook-lsp.ts +220 -56
  196. package/src/core/codemirror/lsp/transports.ts +8 -1
  197. package/src/core/codemirror/lsp/types.ts +68 -8
  198. package/src/core/codemirror/lsp/utils.ts +14 -0
  199. package/src/core/codemirror/utils.ts +28 -0
  200. package/src/core/hotkeys/hotkeys.ts +0 -2
  201. package/src/core/islands/__tests__/bridge.test.ts +107 -0
  202. package/src/core/islands/bridge.ts +16 -0
  203. package/src/core/lsp/__tests__/transport.test.ts +509 -337
  204. package/src/core/lsp/transport.ts +304 -132
  205. package/src/core/mode.ts +10 -0
  206. package/src/core/network/__tests__/api.test.ts +42 -0
  207. package/src/core/network/__tests__/connection.test.ts +45 -0
  208. package/src/core/network/__tests__/requests-lazy.test.ts +32 -1
  209. package/src/core/network/__tests__/requests-network.test.ts +21 -0
  210. package/src/core/network/api.ts +27 -0
  211. package/src/core/network/connection.ts +15 -0
  212. package/src/core/network/requests-lazy.ts +1 -0
  213. package/src/core/network/requests-network.ts +14 -8
  214. package/src/core/network/requests-static.ts +1 -0
  215. package/src/core/network/requests-toasting.tsx +1 -0
  216. package/src/core/network/types.ts +22 -6
  217. package/src/core/rtc/state.ts +9 -0
  218. package/src/core/static/download-html.ts +5 -14
  219. package/src/core/wasm/bridge.ts +4 -2
  220. package/src/core/wasm/worker/types.ts +5 -2
  221. package/src/css/app/codemirror.css +16 -2
  222. package/src/plugins/impl/FormPlugin.tsx +1 -1
  223. package/src/plugins/impl/__tests__/FormPlugin.test.tsx +162 -0
  224. package/src/stories/log-viewer.stories.tsx +12 -6
  225. package/src/utils/__tests__/download.test.tsx +24 -1
  226. package/src/utils/download.ts +11 -6
  227. package/dist/assets/RenderHTML-BCvU9dYz.js +0 -1
  228. package/dist/assets/add-connection-dialog-B-jCRNTN.js +0 -170
  229. package/dist/assets/ai-model-dropdown-DXgLphFa.js +0 -5
  230. package/dist/assets/cell-link-DqBkyAFe.js +0 -1
  231. package/dist/assets/cells-Cf7bHHq3.js +0 -229
  232. package/dist/assets/components-BH6gDVv6.js +0 -1
  233. package/dist/assets/config-BbOTTCYY.js +0 -1
  234. package/dist/assets/dist-BCMBu0rO.js +0 -2
  235. package/dist/assets/download-BomYt3nl.js +0 -9
  236. package/dist/assets/error-entries-Birw-8VX.js +0 -8
  237. package/dist/assets/floating-outline-wz-WSRgP.js +0 -1
  238. package/dist/assets/focus-DiEyfiAG.js +0 -1
  239. package/dist/assets/home-page-DJ4jJsZj.js +0 -4
  240. package/dist/assets/index-A71LAt6h.css +0 -2
  241. package/dist/assets/index-CMZzy-dF.js +0 -38
  242. package/dist/assets/kiosk-mode-ABm3oYgq.js +0 -1
  243. package/dist/assets/logs-panel-iFV4ZJ9b.js +0 -1
  244. package/dist/assets/node-sql-parser-BWgUjcfV.js +0 -68
  245. package/dist/assets/pair-with-agent-modal-CKOYwOYw.js +0 -4
  246. package/dist/assets/panels-Dj45fW-v.js +0 -4
  247. package/dist/assets/process-output-BEhIGfkO.js +0 -1
  248. package/dist/assets/scratchpad-panel-B0mEqBNk.js +0 -1
  249. package/dist/assets/slides-MCbMDtlY.css +0 -1
  250. package/dist/assets/state-BZQc7xxL.js +0 -3
  251. package/dist/assets/switch-CvweaCXq.js +0 -1
  252. package/dist/assets/useCellActionButton-CRfIEVB5.js +0 -1
  253. package/dist/assets/useEventListener-B_w3A283.js +0 -1
  254. package/dist/assets/useNotebookActions-DTXAoukG.js +0 -12
@@ -20,6 +20,26 @@ vi.mock("@/core/cells/cells", () => ({
20
20
  getAllEditorViews: () => mockGetAllEditorViews(),
21
21
  }));
22
22
 
23
+ /**
24
+ * A view stub that only carries what navigate needs
25
+ */
26
+ function createMockView(state: EditorState): EditorView {
27
+ const cell = document.createElement("div");
28
+ cell.className = "marimo-cell";
29
+ // jsdom doesn't implement scrollIntoView.
30
+ cell.scrollIntoView = vi.fn();
31
+ const dom = document.createElement("div");
32
+ cell.append(dom);
33
+
34
+ return {
35
+ state,
36
+ dom,
37
+ // Don't actually apply changes; it's complex to mock properly and the
38
+ // assertions only care that dispatch was called.
39
+ dispatch: vi.fn(),
40
+ } as unknown as EditorView;
41
+ }
42
+
23
43
  describe("navigate", () => {
24
44
  let view1: EditorView;
25
45
  let view2: EditorView;
@@ -36,20 +56,8 @@ describe("navigate", () => {
36
56
  });
37
57
 
38
58
  // Create mock views that track dispatch calls
39
- view1 = {
40
- state: state1,
41
- dispatch: vi.fn(() => {
42
- // Mock dispatch - in real tests we just need to verify it was called
43
- // Don't actually apply changes as it's complex to mock properly
44
- }),
45
- } as unknown as EditorView;
46
-
47
- view2 = {
48
- state: state2,
49
- dispatch: vi.fn(() => {
50
- // Mock dispatch - in real tests we just need to verify it was called
51
- }),
52
- } as unknown as EditorView;
59
+ view1 = createMockView(state1);
60
+ view2 = createMockView(state2);
53
61
 
54
62
  mockViews = [view1, view2];
55
63
  mockGetAllEditorViews.mockReturnValue(mockViews);
@@ -234,6 +242,22 @@ describe("navigate", () => {
234
242
 
235
243
  expect(result).toBe(false);
236
244
  });
245
+
246
+ it("should scroll the cell owning the match into view", async () => {
247
+ const cell = view1.dom.closest(".marimo-cell");
248
+ invariant(cell, "mock view should be inside a cell");
249
+
250
+ expect(findNext()).toBeTruthy();
251
+
252
+ // The scroll is deferred a frame.
253
+ await new Promise((resolve) => requestAnimationFrame(resolve));
254
+
255
+ expect(cell.scrollIntoView).toHaveBeenCalledWith({
256
+ behavior: "instant",
257
+ block: "nearest",
258
+ inline: "nearest",
259
+ });
260
+ });
237
261
  });
238
262
 
239
263
  describe("findPrev", () => {
@@ -319,10 +343,7 @@ describe("navigate", () => {
319
343
  extensions: [EditorState.readOnly.of(true)],
320
344
  });
321
345
 
322
- const readOnlyView = {
323
- state: readOnlyState,
324
- dispatch: vi.fn(),
325
- } as unknown as EditorView;
346
+ const readOnlyView = createMockView(readOnlyState);
326
347
 
327
348
  // Replace view1 with read-only view temporarily
328
349
  mockGetAllEditorViews.mockReturnValueOnce([readOnlyView, view2]);
@@ -568,10 +589,7 @@ describe("navigate", () => {
568
589
  doc: Text.of(["hello world hello there hello"]),
569
590
  });
570
591
 
571
- const testView = {
572
- state: testDoc,
573
- dispatch: vi.fn(),
574
- } as unknown as EditorView;
592
+ const testView = createMockView(testDoc);
575
593
 
576
594
  mockGetAllEditorViews.mockReturnValue([testView]);
577
595
 
@@ -613,10 +631,7 @@ describe("navigate", () => {
613
631
  doc: Text.of([""]),
614
632
  });
615
633
 
616
- const emptyView = {
617
- state: emptyState,
618
- dispatch: vi.fn(),
619
- } as unknown as EditorView;
634
+ const emptyView = createMockView(emptyState);
620
635
 
621
636
  mockGetAllEditorViews.mockReturnValue([emptyView]);
622
637
 
@@ -629,10 +644,7 @@ describe("navigate", () => {
629
644
  doc: Text.of(["orphan content"]),
630
645
  });
631
646
 
632
- const orphanView = {
633
- state: orphanState,
634
- dispatch: vi.fn(),
635
- } as unknown as EditorView;
647
+ const orphanView = createMockView(orphanState);
636
648
 
637
649
  store.set(findReplaceAtom, {
638
650
  type: "setCurrentView",
@@ -6,6 +6,7 @@ import { EditorView } from "@codemirror/view";
6
6
  import { getAllEditorViews } from "@/core/cells/cells";
7
7
  import { replaceEditorContent } from "@/core/codemirror/replace-editor-content";
8
8
  import { store } from "@/core/state/jotai";
9
+ import { scrollOwnerCell } from "../utils";
9
10
  import { asQueryCreator, type QueryType } from "./query";
10
11
  import { findReplaceAtom } from "./state";
11
12
 
@@ -85,6 +86,7 @@ const findInDirection = (direction: "next" | "prev") =>
85
86
  effects: [EditorView.scrollIntoView(selection.main, { y: "center" })],
86
87
  userEvent: "select.search",
87
88
  });
89
+ scrollOwnerCell(view);
88
90
  store.set(findReplaceAtom, {
89
91
  type: "setCurrentView",
90
92
  view,
@@ -3,14 +3,14 @@
3
3
  import { python } from "@codemirror/lang-python";
4
4
  import { EditorState } from "@codemirror/state";
5
5
  import { EditorView } from "@codemirror/view";
6
- import { afterEach, describe, expect, test } from "vitest";
6
+ import { afterEach, describe, expect, test, vi } from "vitest";
7
7
  import { goToVariableDefinition } from "../commands";
8
8
 
9
9
  async function tick(): Promise<void> {
10
10
  await new Promise((resolve) => requestAnimationFrame(resolve));
11
11
  }
12
12
 
13
- function createEditor(content: string) {
13
+ function createEditor(content: string, parent: HTMLElement = document.body) {
14
14
  const state = EditorState.create({
15
15
  doc: content,
16
16
  extensions: [python()],
@@ -18,7 +18,7 @@ function createEditor(content: string) {
18
18
 
19
19
  const view = new EditorView({
20
20
  state,
21
- parent: document.body,
21
+ parent,
22
22
  });
23
23
 
24
24
  return view;
@@ -383,6 +383,27 @@ print('myVar')`);
383
383
  "
384
384
  `);
385
385
  });
386
+
387
+ test("scrolls the cell owning the definition into view", async () => {
388
+ const cell = document.createElement("div");
389
+ cell.className = "marimo-cell";
390
+ // jsdom doesn't implement scrollIntoView.
391
+ cell.scrollIntoView = vi.fn();
392
+ document.body.append(cell);
393
+
394
+ view = createEditor("myVar = 10\nprint(myVar)", cell);
395
+ expect(goToVariableDefinition(view, "myVar")).toBe(true);
396
+ // The jump and the scroll are both deferred to the next frame.
397
+ await tick();
398
+
399
+ expect(cell.scrollIntoView).toHaveBeenCalledWith({
400
+ behavior: "instant",
401
+ block: "nearest",
402
+ inline: "nearest",
403
+ });
404
+
405
+ cell.remove();
406
+ });
386
407
  });
387
408
 
388
409
  /**
@@ -4,6 +4,7 @@ import { syntaxTree } from "@codemirror/language";
4
4
  import type { EditorState } from "@codemirror/state";
5
5
  import { EditorView } from "@codemirror/view";
6
6
  import type { SyntaxNode, Tree, TreeCursor } from "@lezer/common";
7
+ import { scrollOwnerCell } from "../utils";
7
8
 
8
9
  const SCOPE_CREATING_NODES = new Set([
9
10
  "FunctionDefinition",
@@ -45,6 +46,8 @@ function goToPosition(view: EditorView, from: number): void {
45
46
  }),
46
47
  });
47
48
  });
49
+
50
+ scrollOwnerCell(view);
48
51
  }
49
52
 
50
53
  function findFirstMatchingVariable(
@@ -1,8 +1,15 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { defaultKeymap as originalDefaultKeymap } from "@codemirror/commands";
3
+ import {
4
+ copyLineDown,
5
+ copyLineUp,
6
+ defaultKeymap as originalDefaultKeymap,
7
+ } from "@codemirror/commands";
4
8
  import { describe, expect, it } from "vitest";
5
- import { HotkeyProvider } from "@/core/hotkeys/hotkeys";
9
+ import {
10
+ HotkeyProvider,
11
+ OverridingHotkeyProvider,
12
+ } from "@/core/hotkeys/hotkeys";
6
13
  import { visibleForTesting } from "../keymaps";
7
14
 
8
15
  const { defaultKeymap, defaultVimKeymap, overrideKeymap, OVERRIDDEN_COMMANDS } =
@@ -40,4 +47,26 @@ describe("keymaps", () => {
40
47
  expect(keys.some((k) => k.run === command)).toBe(true);
41
48
  }
42
49
  });
50
+
51
+ it.each([
52
+ ["cell.copyLineUp", copyLineUp, "Alt-Shift-ArrowUp"],
53
+ ["cell.copyLineDown", copyLineDown, "Alt-Shift-ArrowDown"],
54
+ ] as const)(
55
+ "%s is bound to the configured hotkey, not CodeMirror's default",
56
+ (action, command, defaultKey) => {
57
+ // Without an override, the binding matches CodeMirror's default key.
58
+ expect(
59
+ overrideKeymap(HotkeyProvider.create()).find((k) => k.run === command)
60
+ ?.key,
61
+ ).toBe(defaultKey);
62
+
63
+ // With an override, the binding follows the user's configured key.
64
+ // This is what `editable: true` on these hotkeys promises.
65
+ expect(
66
+ overrideKeymap(
67
+ new OverridingHotkeyProvider({ [action]: "Ctrl-d" }),
68
+ ).find((k) => k.run === command)?.key,
69
+ ).toBe("Ctrl-d");
70
+ },
71
+ );
43
72
  });
@@ -1,6 +1,8 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import {
4
+ copyLineDown,
5
+ copyLineUp,
4
6
  cursorCharLeft,
5
7
  cursorCharRight,
6
8
  cursorLineDown,
@@ -94,6 +96,8 @@ export function keymapBundle(
94
96
  const OVERRIDDEN_COMMANDS = new Set<Command | undefined>([
95
97
  toggleComment,
96
98
  toggleBlockComment,
99
+ copyLineUp,
100
+ copyLineDown,
97
101
  ]);
98
102
 
99
103
  const defaultKeymap = once(() => {
@@ -111,6 +115,14 @@ const overrideKeymap = (keymap: HotkeyProvider): readonly KeyBinding[] => {
111
115
  key: keymap.getHotkey("cell.toggleBlockComment").key,
112
116
  run: toggleBlockComment,
113
117
  },
118
+ {
119
+ key: keymap.getHotkey("cell.copyLineUp").key,
120
+ run: copyLineUp,
121
+ },
122
+ {
123
+ key: keymap.getHotkey("cell.copyLineDown").key,
124
+ run: copyLineDown,
125
+ },
114
126
  ];
115
127
  };
116
128