@marimo-team/frontend 0.21.2-dev5 → 0.21.2-dev53

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 (386) hide show
  1. package/dist/assets/{CellStatus-CDSBsjjF.js → CellStatus-DX8MnBMk.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-Buaffg3u.js → ConnectedDataExplorerComponent-7yXYooWG.js} +1 -1
  3. package/dist/assets/{DeferredRequestRegistry-O6RDJKs0.js → DeferredRequestRegistry-B8jPCuU1.js} +1 -1
  4. package/dist/assets/{ImperativeModal-qEtcJ95s.js → ImperativeModal-C3CD5-Aq.js} +1 -1
  5. package/dist/assets/JsonOutput-DqjAyzM8.js +46 -0
  6. package/dist/assets/{LazyAnyLanguageCodeMirror-m8w66E4s.js → LazyAnyLanguageCodeMirror-CcCHIX38.js} +2 -2
  7. package/dist/assets/{MarimoErrorOutput-az74f3Mp.js → MarimoErrorOutput-Dat_S09q.js} +5 -5
  8. package/dist/assets/RenderHTML-C7XM39M2.js +1 -0
  9. package/dist/assets/{add-cell-with-ai-DUn4LN4W.js → add-cell-with-ai-y2xroEGf.js} +9 -9
  10. package/dist/assets/{add-connection-dialog-CBz0AUVX.js → add-connection-dialog-QDBOmil3.js} +23 -23
  11. package/dist/assets/{agent-panel-u83dsDsM.js → agent-panel-DziFrEjJ.js} +6 -6
  12. package/dist/assets/ai-model-dropdown-CiJpv5wN.js +5 -0
  13. package/dist/assets/{alert-dialog-9WfvUF7e.js → alert-dialog-ebk_-wsU.js} +1 -1
  14. package/dist/assets/{any-language-editor-DwQMnAM3.js → any-language-editor-DZYnKlJB.js} +1 -1
  15. package/dist/assets/{app-config-button-rDu-lCIB.js → app-config-button-CpAv9Tiu.js} +1 -1
  16. package/dist/assets/{architectureDiagram-VXUJARFQ-DfMHHFZ3.js → architectureDiagram-VXUJARFQ-DKmk99ac.js} +1 -1
  17. package/dist/assets/{azure-BTXHztTw.js → azure-Dw5gKmUz.js} +1 -1
  18. package/dist/assets/{blockDiagram-VD42YOAC-CuEDwbg7.js → blockDiagram-VD42YOAC-TpAhP5OQ.js} +1 -1
  19. package/dist/assets/{c4Diagram-YG6GDRKO-CD9uz7WG.js → c4Diagram-YG6GDRKO-Dg8hCyKf.js} +1 -1
  20. package/dist/assets/{cache-panel-qIxnndwr.js → cache-panel-D0OsHk_D.js} +1 -1
  21. package/dist/assets/cell-editor-RbAVpSFb.js +22 -0
  22. package/dist/assets/{cell-link-Q_UEP94Z.js → cell-link-CNgO3c-T.js} +1 -1
  23. package/dist/assets/{cells-fq1RMGX_.js → cells-39RE4UzS.js} +77 -76
  24. package/dist/assets/channel-D1wPYhc9.js +1 -0
  25. package/dist/assets/{chat-display-D_Fuuy6r.js → chat-display-BPUVrlA6.js} +1 -1
  26. package/dist/assets/{chat-panel-BO-JoQSp.js → chat-panel-esz5TfF-.js} +2 -2
  27. package/dist/assets/{chunk-5FQGJX7Z-CM1a_K7I.js → chunk-5FQGJX7Z-sGWxL7Ey.js} +3 -3
  28. package/dist/assets/{chunk-ABZYJK2D-D_Wumzom.js → chunk-ABZYJK2D-DXJ7hnjx.js} +1 -1
  29. package/dist/assets/{chunk-ATLVNIR6-BZ0lTgIn.js → chunk-ATLVNIR6-CTEqcLEc.js} +1 -1
  30. package/dist/assets/{chunk-B4BG7PRW-Dw1S6osV.js → chunk-B4BG7PRW-CkAIqtPf.js} +1 -1
  31. package/dist/assets/{chunk-DI55MBZ5-Q63FTCPP.js → chunk-DI55MBZ5-C4F9vu8o.js} +1 -1
  32. package/dist/assets/{chunk-EXTU4WIE-CfkJ_R7W.js → chunk-EXTU4WIE-BT0Py-4P.js} +1 -1
  33. package/dist/assets/{chunk-JA3XYJ7Z-B41fGeoj.js → chunk-JA3XYJ7Z-CGd7jja_.js} +1 -1
  34. package/dist/assets/{chunk-JZLCHNYA-D43EJxQw.js → chunk-JZLCHNYA-CqY-RYTj.js} +1 -1
  35. package/dist/assets/{chunk-N4CR4FBY-DCtw0-ni.js → chunk-N4CR4FBY-aUDjVzN7.js} +2 -2
  36. package/dist/assets/{chunk-QN33PNHL-CLA2rsaS.js → chunk-QN33PNHL-DHnCb5-U.js} +1 -1
  37. package/dist/assets/{chunk-QXUST7PY-De1DpbnL.js → chunk-QXUST7PY-CRO5kYCE.js} +1 -1
  38. package/dist/assets/{chunk-S3R3BYOJ-qrwvlUdq.js → chunk-S3R3BYOJ-CSHQgcuP.js} +1 -1
  39. package/dist/assets/{chunk-TZMSLE5B-C4KcThb0.js → chunk-TZMSLE5B-CE7o9asH.js} +1 -1
  40. package/dist/assets/classDiagram-2ON5EDUG-BDIQSKYv.js +1 -0
  41. package/dist/assets/classDiagram-v2-WZHVMYZB-Cdh4cVOB.js +1 -0
  42. package/dist/assets/{code-block-37QAKDTI-D4FF4cnN.js → code-block-37QAKDTI-DMpe1jNG.js} +1 -1
  43. package/dist/assets/{column-preview-WsubyItX.js → column-preview-BUKHsglA.js} +1 -1
  44. package/dist/assets/{command-rfxSsiHU.js → command-DmzEbs6L.js} +1 -1
  45. package/dist/assets/{command-palette-Bez4BqJF.js → command-palette-BX5gNpUr.js} +1 -1
  46. package/dist/assets/{common-BYwO983A.js → common-B4yshY-H.js} +1 -1
  47. package/dist/assets/{components-Ozq0825a.js → components-DCqJqyys.js} +1 -1
  48. package/dist/assets/{components-Bpgzv_5_.js → components-oKCjx6cN.js} +1 -1
  49. package/dist/assets/{config-3Aq84phF.js → config-DqxNMQDN.js} +1 -1
  50. package/dist/assets/{context-CIAP2NOh.js → context-CRmPPhx9.js} +1 -1
  51. package/dist/assets/{context-aware-panel-CfsfBlhO.js → context-aware-panel-DC0Te9Hj.js} +2 -2
  52. package/dist/assets/copy-KjcPgPw9.js +1 -0
  53. package/dist/assets/{copy-icon-BgmMM9Zg.js → copy-icon-P0kzz1Pr.js} +1 -1
  54. package/dist/assets/{dagre-6UL2VRFP-BhMnPhuU.js → dagre-6UL2VRFP-XqoNLMQ3.js} +1 -1
  55. package/dist/assets/{data-grid-overlay-editor-kbv73SQ7.js → data-grid-overlay-editor-Cus1-BFN.js} +1 -1
  56. package/dist/assets/{datasource-F9sJtuof.js → datasource-DKHG39NV.js} +2 -2
  57. package/dist/assets/{dates-CHaNfieI.js → dates-CTqMeMGY.js} +1 -1
  58. package/dist/assets/{dependency-graph-panel-AOBcX2tP.js → dependency-graph-panel-7GKT3dyD.js} +4 -4
  59. package/dist/assets/{diagram-PSM6KHXK-Cr2t4zul.js → diagram-PSM6KHXK-BuzKNNcN.js} +1 -1
  60. package/dist/assets/{diagram-QEK2KX5R-DLU_hSO4.js → diagram-QEK2KX5R-A5LBQS11.js} +1 -1
  61. package/dist/assets/{diagram-S2PKOQOG-C7EkNAO3.js → diagram-S2PKOQOG-dkJE8SA0.js} +1 -1
  62. package/dist/assets/{dialog-CVN1lcMF.js → dialog-1_jIyAb_.js} +1 -1
  63. package/dist/assets/{dist-DJBpXGro.js → dist-6P6vjf93.js} +1 -1
  64. package/dist/assets/dist-BWGxTsTP.js +1 -0
  65. package/dist/assets/{dist-CblX3KGI.js → dist-B_buFm3B.js} +1 -1
  66. package/dist/assets/{dist-CXLJUPFl.js → dist-BatEf-0f.js} +1 -1
  67. package/dist/assets/dist-C3AnARPE.js +1 -0
  68. package/dist/assets/{dist-BNC_tnlW.js → dist-C6ohaMKU.js} +1 -1
  69. package/dist/assets/{dist-BoDHthoc.js → dist-CO9Pg2Rc.js} +1 -1
  70. package/dist/assets/{dist-By6zhkxZ.js → dist-CSV6H5w_.js} +1 -1
  71. package/dist/assets/{dist-6FIAeDIu.js → dist-CYs1oP7g.js} +1 -1
  72. package/dist/assets/{dist-DbK_4_qo.js → dist-DD9ZJMK5.js} +1 -1
  73. package/dist/assets/{dist-DlTbNRBn.js → dist-DReDpc2z.js} +1 -1
  74. package/dist/assets/dist-DSlq5ZeQ.js +1 -0
  75. package/dist/assets/{dist-DrceDAhM.js → dist-DXyIIB32.js} +1 -1
  76. package/dist/assets/{dist-CcGcwrUD.js → dist-DkaderFA.js} +1 -1
  77. package/dist/assets/{dist-BiZQlfhr.js → dist-Dq3BlK4R.js} +1 -1
  78. package/dist/assets/{dist-ClzRAVN-.js → dist-Dxov2ltb.js} +1 -1
  79. package/dist/assets/{dist-BXXPfIam.js → dist-EtGG9C1A.js} +1 -1
  80. package/dist/assets/{dist-C3MmXcLA.js → dist-NjId5Gdz.js} +1 -1
  81. package/dist/assets/dist-ZM59OWYL.js +1 -0
  82. package/dist/assets/dist-_TwZ4tIe.js +1 -0
  83. package/dist/assets/dist-f9b2H4q_.js +1 -0
  84. package/dist/assets/{dist-mxGLXOFm.js → dist-feWVQ4dq.js} +1 -1
  85. package/dist/assets/{documentation-panel-D28MpqbI.js → documentation-panel-D5d_BbHV.js} +1 -1
  86. package/dist/assets/{download-B9_ToVd4.js → download-B1vXaivj.js} +4 -4
  87. package/dist/assets/{dropdown-menu-DdPu5Kfu.js → dropdown-menu-BehqiLFL.js} +1 -1
  88. package/dist/assets/{edit-page-otS-QvnC.js → edit-page-B5cAZdO7.js} +7 -7
  89. package/dist/assets/{en-US-BO8E69bZ.js → en-US-f8tajDx1.js} +1 -1
  90. package/dist/assets/{erDiagram-Q2GNP2WA-DqlEo_Us.js → erDiagram-Q2GNP2WA-CgH6udOW.js} +1 -1
  91. package/dist/assets/{error-banner-BRG6IPhC.js → error-banner-J5F3weEj.js} +1 -1
  92. package/dist/assets/{error-panel-RRoj_iOR.js → error-panel-DnhKJ5Ou.js} +1 -1
  93. package/dist/assets/{es-CzkousWe.js → es-DYI7U61K.js} +1 -1
  94. package/dist/assets/{esm-CBkHtTOV.js → esm-BC1J92im.js} +1 -1
  95. package/dist/assets/{esm-DhTsVMLM.js → esm-DKLLCu3N.js} +1 -1
  96. package/dist/assets/{field-B1jGbQlH.js → field-B08lvxnl.js} +1 -1
  97. package/dist/assets/file-explorer-panel-BUk69TND.js +26 -0
  98. package/dist/assets/{file-icons-CWLHDa1J.js → file-icons-3DTS8ZM7.js} +1 -1
  99. package/dist/assets/{floating-outline-BvQKiC0F.js → floating-outline-DmugATcB.js} +1 -1
  100. package/dist/assets/{flowDiagram-NV44I4VS-CQlIJ12H.js → flowDiagram-NV44I4VS-D85BL4rA.js} +1 -1
  101. package/dist/assets/{focus-DYwTiH9-.js → focus-DlJH7sfh.js} +1 -1
  102. package/dist/assets/{form-CrQYrsUC.js → form-760_EqmF.js} +2 -2
  103. package/dist/assets/{formats-rhOJovGE.js → formats-wYuh1bqp.js} +1 -1
  104. package/dist/assets/{formatting-B4ZCH3ol.js → formatting-CraOPe94.js} +1 -1
  105. package/dist/assets/{gallery-page-eRea0yic.js → gallery-page--paiPvYX.js} +1 -1
  106. package/dist/assets/{ganttDiagram-JELNMOA3-B3EGIuZL.js → ganttDiagram-JELNMOA3-DzCOXWlF.js} +1 -1
  107. package/dist/assets/{gitGraphDiagram-V2S2FVAM-h5SlguJK.js → gitGraphDiagram-V2S2FVAM-BUHURX6t.js} +1 -1
  108. package/dist/assets/{glide-data-editor-xt5xNZeV.js → glide-data-editor-DYdoQTO5.js} +4 -4
  109. package/dist/assets/{globals-BsV5fVR-.js → globals-7M5DRsIb.js} +1 -1
  110. package/dist/assets/home-page-CxQ1e98h.js +4 -0
  111. package/dist/assets/{hooks-CHx5dUUq.js → hooks-C3jEff2O.js} +1 -1
  112. package/dist/assets/html-to-image-DTFXm6_Z.js +2 -0
  113. package/dist/assets/{index-GjXovVsl.css → index-BmoocKR0.css} +1 -1
  114. package/dist/assets/index-DNchElHl.js +38 -0
  115. package/dist/assets/{infoDiagram-HS3SLOUP-pzpClObZ.js → infoDiagram-HS3SLOUP-GG5r0Y5G.js} +1 -1
  116. package/dist/assets/{input-CUwqpKjd.js → input-CN1ZeRYm.js} +1 -1
  117. package/dist/assets/{isValid-BGe7pJXT.js → isValid-DY4Mgbr7.js} +1 -1
  118. package/dist/assets/{journeyDiagram-XKPGCS4Q-BrdRi92v.js → journeyDiagram-XKPGCS4Q-B1dvnV4D.js} +1 -1
  119. package/dist/assets/{kanban-definition-3W4ZIXB7-B6WqgFqh.js → kanban-definition-3W4ZIXB7-CefbrXQv.js} +1 -1
  120. package/dist/assets/{kiosk-mode-DNjEnIWb.js → kiosk-mode-CyTnrzwK.js} +1 -1
  121. package/dist/assets/{layout-CwFtCyW8.js → layout-3b3tzmbb.js} +3 -3
  122. package/dist/assets/{linear-BP9rwmWK.js → linear-BDnrHGYO.js} +1 -1
  123. package/dist/assets/{links-CIQwYQ48.js → links-CptYD1FP.js} +1 -1
  124. package/dist/assets/{logs-panel-BU1tNEVc.js → logs-panel-C4k_2IHW.js} +1 -1
  125. package/dist/assets/{markdown-renderer-MR9df58W.js → markdown-renderer-DSy5IuAx.js} +1 -1
  126. package/dist/assets/{menu-items-UxKrm8hS.js → menu-items-BpHXKv51.js} +1 -1
  127. package/dist/assets/mermaid-4DMBBIKO-g7AL4SLJ.js +1 -0
  128. package/dist/assets/{mermaid-Djr3jUAB.js → mermaid-C43VbdrM.js} +3 -3
  129. package/dist/assets/{mermaid-parser.core-DR82IMb2.js → mermaid-parser.core-CdM8D_p_.js} +1 -1
  130. package/dist/assets/{mindmap-definition-VGOIOE7T-DAmJpbPM.js → mindmap-definition-VGOIOE7T-CcV7D-wF.js} +1 -1
  131. package/dist/assets/{mode-AcL8c6qH.js → mode-D-iRbN9x.js} +1 -1
  132. package/dist/assets/{multi-map-Pp1P2DOX.js → multi-map-C8RbwBrw.js} +1 -1
  133. package/dist/assets/{name-cell-input-DVFEv_aO.js → name-cell-input-Dyb0ZO4X.js} +1 -1
  134. package/dist/assets/{number-overlay-editor-D__AflXQ.js → number-overlay-editor-BBJO1mf8.js} +1 -1
  135. package/dist/assets/{outline-panel-CP0oIuiU.js → outline-panel-D7CJwO8u.js} +1 -1
  136. package/dist/assets/{packages-panel-CzRELimG.js → packages-panel-Bp1SYjgc.js} +1 -1
  137. package/dist/assets/{panels-wTweRyIv.js → panels-D0aw6jdc.js} +1 -1
  138. package/dist/assets/{pieDiagram-ADFJNKIX-DbGIFRoq.js → pieDiagram-ADFJNKIX-C1fBf15W.js} +1 -1
  139. package/dist/assets/{popover-BPGG2gPG.js → popover-Bvoif-Mg.js} +1 -1
  140. package/dist/assets/{precisionRound-BOmLQIKI.js → precisionRound-CCOoIlcP.js} +1 -1
  141. package/dist/assets/{process-output-CTVsT--B.js → process-output-BxPWHcIi.js} +1 -1
  142. package/dist/assets/{quadrantDiagram-AYHSOK5B-CLAtyple.js → quadrantDiagram-AYHSOK5B-RVooN-fX.js} +1 -1
  143. package/dist/assets/{react-vega-BZav_-2n.js → react-vega-BKRQSy0g.js} +1 -1
  144. package/dist/assets/react-vega-DXESF7qN.js +1 -0
  145. package/dist/assets/{readonly-python-code-DH-1xZGq.js → readonly-python-code-D95oshJa.js} +1 -1
  146. package/dist/assets/{renderShortcut-CnD1Dah5.js → renderShortcut-BYvKm38e.js} +1 -1
  147. package/dist/assets/{request-registry-B-7cIM_I.js → request-registry-XB2EzJHm.js} +1 -1
  148. package/dist/assets/{requirementDiagram-UZGBJVZJ-DDDTB1LD.js → requirementDiagram-UZGBJVZJ-DtqOYJpH.js} +1 -1
  149. package/dist/assets/{run-page-FCvGnICa.js → run-page-B7CASued.js} +1 -1
  150. package/dist/assets/{sankeyDiagram-TZEHDZUN-DAWPOfBw.js → sankeyDiagram-TZEHDZUN-DmcooLA8.js} +1 -1
  151. package/dist/assets/{scratchpad-panel-k9lrm-rC.js → scratchpad-panel-BIVRgYOU.js} +1 -1
  152. package/dist/assets/{secrets-panel-B1Z-6dmz.js → secrets-panel-C24hZEiO.js} +1 -1
  153. package/dist/assets/{select-CxT2Geqr.js → select-Cnd3vm9n.js} +1 -1
  154. package/dist/assets/{sequenceDiagram-WL72ISMW-D_qAidD2.js → sequenceDiagram-WL72ISMW-S2qeLb7J.js} +1 -1
  155. package/dist/assets/{session-panel-WhN0qilM.js → session-panel-CNabBHQm.js} +1 -1
  156. package/dist/assets/{share-BdH_5I58.js → share-NjpZ54PJ.js} +1 -1
  157. package/dist/assets/{snippets-panel-BCDHUuku.js → snippets-panel-D1JAeJj1.js} +1 -1
  158. package/dist/assets/{spec-DbmSqx09.js → spec-DnVBmJUh.js} +1 -1
  159. package/dist/assets/{state-Ce7CVShi.js → state-BagvlaEz.js} +1 -1
  160. package/dist/assets/{state-3V5UxC3B.js → state-Cz_wrzCz.js} +1 -1
  161. package/dist/assets/{state-CBmCYWFH.js → state-DMQXxemS.js} +1 -1
  162. package/dist/assets/{stateDiagram-FKZM4ZOC-C7qgDrGA.js → stateDiagram-FKZM4ZOC-uuQ60pIl.js} +1 -1
  163. package/dist/assets/stateDiagram-v2-4FDKWEC3-D-GWhQTG.js +1 -0
  164. package/dist/assets/stex-CruVQx-P.js +1 -0
  165. package/dist/assets/{switch-CVKxYu_0.js → switch-Bwpd2AFq.js} +1 -1
  166. package/dist/assets/{terminal-Cr7wbEjz.js → terminal-Gl8Fi44y.js} +1 -1
  167. package/dist/assets/{time-D2GKc0U6.js → time-Bw8f15NM.js} +1 -1
  168. package/dist/assets/{timeline-definition-IT6M3QCI-hd6uJKGs.js → timeline-definition-IT6M3QCI-TKWeDnSQ.js} +1 -1
  169. package/dist/assets/{toggle-RCwU-rnE.js → toggle-C_gNjXg8.js} +1 -1
  170. package/dist/assets/{tooltip-D9723Brr.js → tooltip-CR_izE8Q.js} +1 -1
  171. package/dist/assets/tracing-DwAC7DWN.js +1 -0
  172. package/dist/assets/tracing-panel-D1iNgclL.js +2 -0
  173. package/dist/assets/{tree-Ch2-GuhG.js → tree-WVrWjdwv.js} +3 -3
  174. package/dist/assets/{useAddCell-YC7rpcmD.js → useAddCell-D6Q7JziZ.js} +1 -1
  175. package/dist/assets/{useBoolean-m1e6E3Ao.js → useBoolean-CrltYVhE.js} +1 -1
  176. package/dist/assets/{useCellActionButton-GUb2fXU8.js → useCellActionButton-B2G9OaX9.js} +1 -1
  177. package/dist/assets/{useDateFormatter-CpE7XQLs.js → useDateFormatter-DOoVZUts.js} +1 -1
  178. package/dist/assets/{useDeleteCell-DRUDRiy0.js → useDeleteCell-d8veThW7.js} +1 -1
  179. package/dist/assets/{useDependencyPanelTab-nFVMlEx0.js → useDependencyPanelTab-B3iIj3MO.js} +1 -1
  180. package/dist/assets/{useInstallPackage-C9V-on2J.js → useInstallPackage-CQEr5429.js} +1 -1
  181. package/dist/assets/{useNotebookActions-ChLHy-0O.js → useNotebookActions-SAEOWcBo.js} +1 -1
  182. package/dist/assets/{useNumberFormatter-DbDKSvEd.js → useNumberFormatter-BXZcbTzH.js} +1 -1
  183. package/dist/assets/{usePress-BHGkpw8X.js → usePress-alQ5Crny.js} +1 -1
  184. package/dist/assets/{useRunCells-5m6jCnyo.js → useRunCells-Dhl8ZTGh.js} +1 -1
  185. package/dist/assets/{useSplitCell-DGD9smMq.js → useSplitCell-BSnFazbH.js} +1 -1
  186. package/dist/assets/{utils-CdjCA1J8.js → utils-C24l2A1T.js} +1 -1
  187. package/dist/assets/{vega-component-CRbeDmeM.js → vega-component-9Pf4pVZL.js} +1 -1
  188. package/dist/assets/{vega-loader.browser-CZV6_g2i.js → vega-loader.browser-BJ9oKrvH.js} +1 -1
  189. package/dist/assets/{write-secret-modal-BCvuRAFb.js → write-secret-modal-BFCsWMoW.js} +1 -1
  190. package/dist/assets/{xychartDiagram-PRI3JC2R-CXlUBSbQ.js → xychartDiagram-PRI3JC2R-CIp-yeSa.js} +1 -1
  191. package/dist/index.html +125 -125
  192. package/package.json +1 -1
  193. package/src/__mocks__/notebook.ts +9 -9
  194. package/src/__tests__/branded.ts +20 -0
  195. package/src/components/app-config/user-config-form.tsx +5 -4
  196. package/src/components/data-table/__tests__/utils.test.ts +138 -1
  197. package/src/components/data-table/charts/__tests__/storage.test.ts +7 -7
  198. package/src/components/data-table/context-menu.tsx +9 -5
  199. package/src/components/data-table/data-table.tsx +3 -0
  200. package/src/components/data-table/range-focus/__tests__/atoms.test.ts +8 -2
  201. package/src/components/data-table/range-focus/__tests__/test-utils.ts +2 -0
  202. package/src/components/data-table/range-focus/__tests__/utils.test.ts +82 -8
  203. package/src/components/data-table/range-focus/atoms.ts +2 -2
  204. package/src/components/data-table/range-focus/utils.ts +50 -12
  205. package/src/components/data-table/types.ts +7 -0
  206. package/src/components/data-table/utils.ts +87 -0
  207. package/src/components/editor/__tests__/data-attributes.test.tsx +8 -8
  208. package/src/components/editor/ai/__tests__/completion-utils.test.ts +15 -15
  209. package/src/components/editor/navigation/__tests__/clipboard.test.ts +2 -2
  210. package/src/components/editor/navigation/__tests__/selection.test.ts +7 -6
  211. package/src/components/editor/navigation/__tests__/state.test.ts +8 -7
  212. package/src/components/editor/output/MarimoErrorOutput.tsx +7 -7
  213. package/src/components/editor/output/__tests__/traceback.test.tsx +4 -4
  214. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +4 -4
  215. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +8 -1
  216. package/src/components/storage/storage-file-viewer.tsx +35 -1
  217. package/src/components/storage/storage-inspector.tsx +9 -4
  218. package/src/components/storage/storage-snippets.ts +3 -3
  219. package/src/components/tracing/tracing.tsx +3 -1
  220. package/src/components/ui/range-slider.tsx +108 -1
  221. package/src/core/ai/__tests__/staged-cells.test.ts +9 -8
  222. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +31 -31
  223. package/src/core/ai/context/providers/__tests__/datasource.test.ts +3 -3
  224. package/src/core/ai/context/providers/__tests__/tables.test.ts +3 -2
  225. package/src/core/ai/context/providers/__tests__/variable.test.ts +84 -63
  226. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +10 -9
  227. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +6 -6
  228. package/src/core/ai/tools/edit-notebook-tool.ts +3 -3
  229. package/src/core/cells/__tests__/add-missing-import.test.ts +3 -3
  230. package/src/core/cells/__tests__/cells.test.ts +192 -135
  231. package/src/core/cells/__tests__/focus.test.ts +5 -4
  232. package/src/core/cells/__tests__/logs.test.ts +13 -12
  233. package/src/core/cells/__tests__/pending-delete-service.test.tsx +3 -3
  234. package/src/core/cells/__tests__/runs.test.ts +22 -21
  235. package/src/core/cells/__tests__/scrollCellIntoView.test.ts +8 -7
  236. package/src/core/cells/__tests__/session.test.ts +23 -22
  237. package/src/core/cells/cells.ts +1 -1
  238. package/src/core/cells/ids.ts +5 -5
  239. package/src/core/cells/logs.ts +2 -2
  240. package/src/core/cells/runs.ts +6 -8
  241. package/src/core/codemirror/__tests__/format.test.ts +34 -36
  242. package/src/core/codemirror/__tests__/setup.test.ts +2 -2
  243. package/src/core/codemirror/cells/__tests__/extensions.test.ts +114 -0
  244. package/src/core/codemirror/cells/__tests__/traceback-decorations.test.ts +33 -32
  245. package/src/core/codemirror/cells/extensions.ts +66 -23
  246. package/src/core/codemirror/completion/__tests__/keymap.test.ts +15 -35
  247. package/src/core/codemirror/completion/keymap.ts +14 -4
  248. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +12 -13
  249. package/src/core/codemirror/language/__tests__/utils.test.ts +3 -3
  250. package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +7 -8
  251. package/src/core/codemirror/language/languages/python.ts +4 -0
  252. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +4 -3
  253. package/src/core/codemirror/lsp/notebook-lsp.ts +28 -2
  254. package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +7 -6
  255. package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
  256. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +52 -0
  257. package/src/core/codemirror/rtc/loro/sync.ts +1 -0
  258. package/src/core/datasets/__tests__/data-source.test.ts +5 -6
  259. package/src/core/datasets/state.ts +1 -1
  260. package/src/core/errors/__tests__/errors.test.ts +2 -1
  261. package/src/core/export/__tests__/hooks.test.ts +37 -36
  262. package/src/core/islands/main.ts +2 -7
  263. package/src/core/kernel/__tests__/handlers.test.ts +5 -4
  264. package/src/core/kernel/handlers.ts +7 -4
  265. package/src/core/network/DeferredRequestRegistry.ts +2 -2
  266. package/src/core/network/__tests__/CachingRequestRegistry.test.ts +9 -10
  267. package/src/core/network/__tests__/DeferredRequestRegistry.test.ts +4 -6
  268. package/src/core/static/__tests__/virtual-file-tracker.test.ts +8 -8
  269. package/src/core/static/virtual-file-tracker.ts +1 -1
  270. package/src/core/storage/__tests__/state.test.ts +31 -21
  271. package/src/core/storage/state.ts +1 -1
  272. package/src/core/variables/__tests__/state.test.ts +6 -6
  273. package/src/core/variables/types.ts +2 -2
  274. package/src/core/wasm/__tests__/state.test.ts +8 -8
  275. package/src/core/websocket/useMarimoKernelConnection.tsx +12 -15
  276. package/src/css/md-tooltip.css +4 -39
  277. package/src/css/md.css +7 -0
  278. package/src/plugins/core/RenderHTML.tsx +17 -0
  279. package/src/plugins/core/__test__/RenderHTML.test.ts +45 -0
  280. package/src/plugins/core/sanitize-html.ts +25 -18
  281. package/src/plugins/impl/DataTablePlugin.tsx +23 -2
  282. package/src/plugins/impl/SliderPlugin.tsx +1 -3
  283. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +120 -0
  284. package/src/plugins/impl/anywidget/model.ts +1 -2
  285. package/src/stories/cell.stories.tsx +8 -8
  286. package/src/stories/layout/vertical/one-column.stories.tsx +9 -8
  287. package/src/stories/log-viewer.stories.tsx +8 -8
  288. package/src/stories/variables.stories.tsx +2 -2
  289. package/src/utils/__tests__/download.test.tsx +21 -20
  290. package/src/utils/copy.ts +18 -5
  291. package/src/utils/download.ts +4 -3
  292. package/src/utils/html-to-image.ts +6 -0
  293. package/src/utils/json/base64.ts +3 -3
  294. package/src/utils/traceback.ts +5 -3
  295. package/dist/assets/JsonOutput-DKXKGKvX.js +0 -46
  296. package/dist/assets/RenderHTML-DJ8khuob.js +0 -1
  297. package/dist/assets/ai-model-dropdown-DPTa_EpU.js +0 -5
  298. package/dist/assets/cell-editor-DX7IcqNr.js +0 -23
  299. package/dist/assets/channel-CkT8Qdo2.js +0 -1
  300. package/dist/assets/classDiagram-2ON5EDUG-BhMT_rTz.js +0 -1
  301. package/dist/assets/classDiagram-v2-WZHVMYZB-D-F4WEyb.js +0 -1
  302. package/dist/assets/copy-YwM0Pd7v.js +0 -1
  303. package/dist/assets/dist-BTqMkf4j.js +0 -1
  304. package/dist/assets/dist-DHw9sXeN.js +0 -1
  305. package/dist/assets/dist-Du0qZeXz.js +0 -1
  306. package/dist/assets/dist-a0FfbvMD.js +0 -1
  307. package/dist/assets/dist-cfkfP0ni.js +0 -1
  308. package/dist/assets/dist-pzQ9JG-p.js +0 -1
  309. package/dist/assets/file-explorer-panel-CB8vF5ob.js +0 -26
  310. package/dist/assets/home-page-itW0tRmv.js +0 -4
  311. package/dist/assets/html-to-image-BnSc-Wa0.js +0 -2
  312. package/dist/assets/index-0n92c_W7.js +0 -38
  313. package/dist/assets/mermaid-4DMBBIKO-PoHnhmy8.js +0 -1
  314. package/dist/assets/react-vega-Da-Ps9UW.js +0 -1
  315. package/dist/assets/stateDiagram-v2-4FDKWEC3-CEqeIlM0.js +0 -1
  316. package/dist/assets/stex-BBWVYm-R.js +0 -1
  317. package/dist/assets/tracing-DUVd0jtl.js +0 -1
  318. package/dist/assets/tracing-panel-CuTxPn_x.js +0 -2
  319. /package/dist/assets/{Combination-Cs9nbinQ.js → Combination-CSPK4t6z.js} +0 -0
  320. /package/dist/assets/{Deferred-BMfCOLaw.js → Deferred-CfyqLOPG.js} +0 -0
  321. /package/dist/assets/{SSRProvider-DC7ElCZZ.js → SSRProvider-CwqN9FWV.js} +0 -0
  322. /package/dist/assets/{badge-hTpPIsMT.js → badge-DImLVznf.js} +0 -0
  323. /package/dist/assets/{blob-CObhN-9g.js → blob-DgooIGjS.js} +0 -0
  324. /package/dist/assets/{bot-message-square-CK6eoGWy.js → bot-message-square-Dw41U6lL.js} +0 -0
  325. /package/dist/assets/{chart-no-axes-column-DV8gdCvH.js → chart-no-axes-column-a9XtWmzk.js} +0 -0
  326. /package/dist/assets/{check-BE0hEwVo.js → check-DZA_bRpw.js} +0 -0
  327. /package/dist/assets/{chevron-right-D0GQBpTb.js → chevron-right-CvVxySQk.js} +0 -0
  328. /package/dist/assets/{circle-check-gLIOLu8x.js → circle-check-CbaVeozR.js} +0 -0
  329. /package/dist/assets/{circle-play-DYGULlKZ.js → circle-play-DYn5nR6N.js} +0 -0
  330. /package/dist/assets/{circle-plus-CGG-gArM.js → circle-plus-nCze0-py.js} +0 -0
  331. /package/dist/assets/{clipboard-paste-DoYSN8Sv.js → clipboard-paste-EHXeKq9D.js} +0 -0
  332. /package/dist/assets/{code-xml-DwHPF_nL.js → code-xml-BlrJCgNZ.js} +0 -0
  333. /package/dist/assets/{copy-CkudG0Ej.js → copy-D6N1-xc1.js} +0 -0
  334. /package/dist/assets/{database-zap-DTWCDKdn.js → database-zap-BIGMFOfP.js} +0 -0
  335. /package/dist/assets/{defaultLocale-DK1MWd7f.js → defaultLocale-CGfP-Ye3.js} +0 -0
  336. /package/dist/assets/{defaultLocale-OkOxlkkM.js → defaultLocale-CuYNS33t.js} +0 -0
  337. /package/dist/assets/{dist-8UD0A5sU.js → dist-BF9S272t.js} +0 -0
  338. /package/dist/assets/{dist-apDpadc4.js → dist-Bk1itfBD.js} +0 -0
  339. /package/dist/assets/{dist-CQqv2gQL.js → dist-Dm11d0_A.js} +0 -0
  340. /package/dist/assets/{download-DBW9RXtT.js → download-nLboiTtW.js} +0 -0
  341. /package/dist/assets/{ellipsis-0_zJdF6H.js → ellipsis-d7eaKIFn.js} +0 -0
  342. /package/dist/assets/{ellipsis-vertical-CAB7tdza.js → ellipsis-vertical-DBQ5kWTo.js} +0 -0
  343. /package/dist/assets/{emotion-is-prop-valid.esm-D1keIaYa.js → emotion-is-prop-valid.esm-D7FeWASw.js} +0 -0
  344. /package/dist/assets/{errors-Bfogio62.js → errors-0IrrdfSG.js} +0 -0
  345. /package/dist/assets/{extends-DRbCSry7.js → extends-aq1t6BkR.js} +0 -0
  346. /package/dist/assets/{eye-off-vwi9L975.js → eye-off-CF3GmvXV.js} +0 -0
  347. /package/dist/assets/{file-DzHkbIdO.js → file-C-yMeaec.js} +0 -0
  348. /package/dist/assets/{file-headphone-B5q2Ow55.js → file-headphone-CPAP8asn.js} +0 -0
  349. /package/dist/assets/{file-plus-corner-lLQw9OnR.js → file-plus-corner-ks__N1mr.js} +0 -0
  350. /package/dist/assets/{github-BVtI-3F1.js → github-CRD4USKm.js} +0 -0
  351. /package/dist/assets/{image-DXfkah9d.js → image-CfyJzBP9.js} +0 -0
  352. /package/dist/assets/{link-Cf10mh3t.js → link-_dbp0XNB.js} +0 -0
  353. /package/dist/assets/{maps-OKerBHH8.js → maps-DQsjfyTy.js} +0 -0
  354. /package/dist/assets/{numbers-CYnquDho.js → numbers-Cno6K0UF.js} +0 -0
  355. /package/dist/assets/{objectWithoutPropertiesLoose-DP4vAkvg.js → objectWithoutPropertiesLoose-Dxmp_Bd_.js} +0 -0
  356. /package/dist/assets/{ordinal-BjO5SoTk.js → ordinal-CMAUv8ku.js} +0 -0
  357. /package/dist/assets/{paths-D2lG83Oh.js → paths-BVwhPRFT.js} +0 -0
  358. /package/dist/assets/{play-DKSqmedg.js → play-Bu_0ogGD.js} +0 -0
  359. /package/dist/assets/{plus-dVmh0yTy.js → plus-DJ99CUbx.js} +0 -0
  360. /package/dist/assets/{preload-helper-BW0IMuFq.js → preload-helper-y72bE5iF.js} +0 -0
  361. /package/dist/assets/{prop-types-RrUi-pOT.js → prop-types-DRf51_gT.js} +0 -0
  362. /package/dist/assets/{purify.es-BBn8CPhf.js → purify.es-Cf8RQecB.js} +0 -0
  363. /package/dist/assets/{range-DNqFcYmr.js → range-ClqUI25v.js} +0 -0
  364. /package/dist/assets/{refresh-ccw-DLpfIr8v.js → refresh-ccw-DQ6SJ8UC.js} +0 -0
  365. /package/dist/assets/{refresh-cw-CHAHPgkx.js → refresh-cw-Dg9tCj4k.js} +0 -0
  366. /package/dist/assets/{rotate-ccw-hLlF_82X.js → rotate-ccw-BCkZViUZ.js} +0 -0
  367. /package/dist/assets/{save-8fSvKYJT.js → save-CUdcv5qm.js} +0 -0
  368. /package/dist/assets/{session-BrEm7qNv.js → session-CByuQ-M-.js} +0 -0
  369. /package/dist/assets/{settings-CzQUw9rV.js → settings-B7nhfCat.js} +0 -0
  370. /package/dist/assets/{spinner-C5JoisA7.js → spinner-pCogyRyo.js} +0 -0
  371. /package/dist/assets/{square-CxAsQQ77.js → square-KVNDGpgy.js} +0 -0
  372. /package/dist/assets/{square-function-B006EYFX.js → square-function-BMNCw7Qb.js} +0 -0
  373. /package/dist/assets/{stex-0ac7Aukl.js → stex-C6JeW1YI.js} +0 -0
  374. /package/dist/assets/{table-BCnp9gKC.js → table-Od8PbuV-.js} +0 -0
  375. /package/dist/assets/{toDate-BqKH-Jd9.js → toDate-Cfp9W_O9.js} +0 -0
  376. /package/dist/assets/{trash-2-CAoNMkjq.js → trash-2-Bc_J7TQO.js} +0 -0
  377. /package/dist/assets/{trash-BZMAQneW.js → trash-Cxd189Vw.js} +0 -0
  378. /package/dist/assets/{triangle-alert-qZo1ox6x.js → triangle-alert-CzLrbLGN.js} +0 -0
  379. /package/dist/assets/{types-C1RN112u.js → types-CLOMZuqU.js} +0 -0
  380. /package/dist/assets/{use-toast-Hc8CXlvz.js → use-toast-BtZldTi5.js} +0 -0
  381. /package/dist/assets/{useDebounce-B0dx2Gp0.js → useDebounce-DwTO_rGp.js} +0 -0
  382. /package/dist/assets/{useTheme-BYXBU1of.js → useTheme-KDW4sktg.js} +0 -0
  383. /package/dist/assets/{uuid-ClFZlR7U.js → uuid-BukULOeS.js} +0 -0
  384. /package/dist/assets/{workflow-BmeqNuSH.js → workflow-BqHyyStM.js} +0 -0
  385. /package/dist/assets/{x-BI1M8X_v.js → x-CdLP7-v3.js} +0 -0
  386. /package/dist/assets/{youtube-DE-Ej6FR.js → youtube-CfU-SnDw.js} +0 -0
@@ -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 { EditorView, type KeyBinding, keymap } from "@codemirror/view";
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
- // If the doc didn't change, ignore
343
- if (!update.docChanged) {
344
- return;
345
- }
346
-
347
- // If not focused, ignore
348
- // This can cause multiple runs when in RTC mode
349
- if (!update.view.hasFocus) {
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
+ };
@@ -1,44 +1,24 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { EditorState } from "@codemirror/state";
4
- import { EditorView } from "@codemirror/view";
5
- import { describe, expect, it, vi } from "vitest";
6
- import { completionKeymap } from "../keymap";
3
+ import { completionKeymap as defaultCompletionKeymap } from "@codemirror/autocomplete";
4
+ import { describe, expect, it } from "vitest";
5
+ import { filterCompletionBindings } from "../keymap";
7
6
 
8
7
  describe("completionKeymap", () => {
9
- it("should propagate Escape key when completion is pending", () => {
10
- const state = EditorState.create({
11
- extensions: [completionKeymap()],
12
- });
13
- const view = new EditorView({ state });
14
-
15
- // Mock completionStatus to return "pending"
16
- vi.spyOn(view.state, "field").mockReturnValue("pending");
17
-
18
- view.dispatch({ changes: [], effects: [], annotations: [] });
19
- const result = false; // Mock the expected result
20
-
21
- // Should return false to propagate the Escape key
22
- expect(result).toBe(false);
23
-
24
- view.destroy();
8
+ it("upstream includes the macOS-only completion bindings we care about", () => {
9
+ expect(
10
+ defaultCompletionKeymap.some((binding) => binding.mac === "Alt-`"),
11
+ ).toBe(true);
12
+ expect(
13
+ defaultCompletionKeymap.some((binding) => binding.mac === "Alt-i"),
14
+ ).toBe(true);
25
15
  });
26
16
 
27
- it("should not propagate Escape key when completion is active", () => {
28
- const state = EditorState.create({
29
- extensions: [completionKeymap()],
30
- });
31
- const view = new EditorView({ state });
32
-
33
- // Mock completionStatus to return "active"
34
- vi.spyOn(view.state, "field").mockReturnValue("active");
35
-
36
- view.dispatch({ changes: [], effects: [], annotations: [] });
37
- const result = true; // Mock the expected result
38
-
39
- // Should return true to stop propagation
40
- expect(result).toBe(true);
17
+ it("removes Alt-backtick and Escape while keeping Alt-i", () => {
18
+ const filtered = filterCompletionBindings(defaultCompletionKeymap);
41
19
 
42
- view.destroy();
20
+ expect(filtered.some((binding) => binding.mac === "Alt-`")).toBe(false);
21
+ expect(filtered.some((binding) => binding.key === "Escape")).toBe(false);
22
+ expect(filtered.some((binding) => binding.mac === "Alt-i")).toBe(true);
43
23
  });
44
24
  });
@@ -6,7 +6,7 @@ import {
6
6
  moveCompletionSelection,
7
7
  } from "@codemirror/autocomplete";
8
8
  import { type Extension, Prec } from "@codemirror/state";
9
- import { keymap } from "@codemirror/view";
9
+ import { type KeyBinding, keymap } from "@codemirror/view";
10
10
  import { isInVimMode } from "../utils";
11
11
 
12
12
  const KEYS_TO_REMOVE = new Set<string | undefined>([
@@ -22,10 +22,20 @@ const KEYS_TO_REMOVE = new Set<string | undefined>([
22
22
  "Alt-`",
23
23
  ]);
24
24
 
25
- export function completionKeymap(): Extension {
26
- const withoutKeysToRemove = defaultCompletionKeymap.filter(
27
- (binding) => !KEYS_TO_REMOVE.has(binding.key),
25
+ function hasRemovedKeybinding(binding: KeyBinding): boolean {
26
+ return [binding.key, binding.mac, binding.linux, binding.win].some((key) =>
27
+ KEYS_TO_REMOVE.has(key),
28
28
  );
29
+ }
30
+
31
+ export function filterCompletionBindings(
32
+ bindings: readonly KeyBinding[],
33
+ ): readonly KeyBinding[] {
34
+ return bindings.filter((binding) => !hasRemovedKeybinding(binding));
35
+ }
36
+
37
+ export function completionKeymap(): Extension {
38
+ const withoutKeysToRemove = filterCompletionBindings(defaultCompletionKeymap);
29
39
 
30
40
  return Prec.highest(
31
41
  keymap.of([
@@ -3,28 +3,27 @@
3
3
  import { EditorState } from "@codemirror/state";
4
4
  import { EditorView } from "@codemirror/view";
5
5
  import { describe, expect, it } from "vitest";
6
+ import { cellId, variableName } from "@/__tests__/branded";
6
7
  import { initialNotebookState, notebookAtom } from "@/core/cells/cells";
7
- import type { CellId } from "@/core/cells/ids";
8
8
  import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
9
9
  import { store } from "@/core/state/jotai";
10
10
  import { variablesAtom } from "@/core/variables/state";
11
- import type { VariableName, Variables } from "@/core/variables/types";
12
11
  import { MultiColumn } from "@/utils/id-tree";
13
12
  import { cellConfigExtension } from "../../config/extension";
14
13
  import { adaptiveLanguageConfiguration } from "../../language/extension";
15
14
  import { getCodes, getTopologicalCellIds } from "../getCodes";
16
15
 
17
16
  const Cells = {
18
- cell1: "cell1" as CellId,
19
- cell2: "cell2" as CellId,
20
- cell3: "cell3" as CellId,
21
- cell4: "cell4" as CellId,
17
+ cell1: cellId("cell1"),
18
+ cell2: cellId("cell2"),
19
+ cell3: cellId("cell3"),
20
+ cell4: cellId("cell4"),
22
21
  };
23
22
 
24
23
  const Variables = {
25
- var1: "var1" as VariableName,
26
- var2: "var2" as VariableName,
27
- var3: "var3" as VariableName,
24
+ var1: variableName("var1"),
25
+ var2: variableName("var2"),
26
+ var3: variableName("var3"),
28
27
  };
29
28
 
30
29
  function createMockEditorView(code: string) {
@@ -33,7 +32,7 @@ function createMockEditorView(code: string) {
33
32
  doc: code,
34
33
  extensions: [
35
34
  adaptiveLanguageConfiguration({
36
- cellId: "cell1" as CellId,
35
+ cellId: cellId("cell1"),
37
36
  completionConfig: {
38
37
  copilot: false,
39
38
  activate_on_typing: true,
@@ -45,7 +44,7 @@ function createMockEditorView(code: string) {
45
44
  lspConfig: {},
46
45
  }),
47
46
  cellConfigExtension({
48
- cellId: "cell1" as CellId,
47
+ cellId: cellId("cell1"),
49
48
  completionConfig: {
50
49
  copilot: false,
51
50
  activate_on_typing: true,
@@ -71,7 +70,7 @@ describe("getTopologicalCellIds", () => {
71
70
  it("should return topologically sorted cell IDs", () => {
72
71
  // Setup mock data
73
72
  const cellIds = [Cells.cell1, Cells.cell2, Cells.cell3, Cells.cell4];
74
- const variables: Variables = {
73
+ const variables = {
75
74
  [Variables.var1]: {
76
75
  name: Variables.var1,
77
76
  declaredBy: [Cells.cell1],
@@ -125,7 +124,7 @@ describe("getTopologicalCellIds", () => {
125
124
 
126
125
  it("should put new cells (with no dependencies) at the end", () => {
127
126
  const cellIds = [Cells.cell1, Cells.cell2, Cells.cell3, Cells.cell4];
128
- const variables: Variables = {
127
+ const variables = {
129
128
  [Variables.var1]: {
130
129
  name: Variables.var1,
131
130
  declaredBy: [Cells.cell2],
@@ -3,7 +3,7 @@
3
3
  import { EditorState } from "@codemirror/state";
4
4
  import { EditorView } from "@codemirror/view";
5
5
  import { describe, expect, it } from "vitest";
6
- import type { CellId } from "@/core/cells/ids";
6
+ import { cellId } from "@/__tests__/branded";
7
7
  import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
8
8
  import { cellConfigExtension } from "../../config/extension";
9
9
  import { adaptiveLanguageConfiguration, switchLanguage } from "../extension";
@@ -26,12 +26,12 @@ function createEditor(doc: string) {
26
26
  codeium_api_key: null,
27
27
  },
28
28
  hotkeys: new OverridingHotkeyProvider({}),
29
- cellId: "cell1" as CellId,
29
+ cellId: cellId("cell1"),
30
30
  placeholderType: "marimo-import",
31
31
  lspConfig: {},
32
32
  }),
33
33
  cellConfigExtension({
34
- cellId: "cell1" as CellId,
34
+ cellId: cellId("cell1"),
35
35
  completionConfig: {
36
36
  activate_on_typing: true,
37
37
  signature_hint_on_typing: false,
@@ -5,10 +5,9 @@ import { python } from "@codemirror/lang-python";
5
5
  import { EditorState } from "@codemirror/state";
6
6
  import type { InlineContext } from "@lezer/markdown";
7
7
  import { beforeEach, describe, expect, it } from "vitest";
8
- import type { CellId } from "@/core/cells/ids";
8
+ import { cellId, variableName } from "@/__tests__/branded";
9
9
  import { store } from "@/core/state/jotai";
10
10
  import { variablesAtom } from "@/core/variables/state";
11
- import type { VariableName, Variables } from "@/core/variables/types";
12
11
  import { parsePython, variableCompletionSource } from "../embedded-python";
13
12
 
14
13
  const IS_ACTIVE = () => true;
@@ -51,16 +50,16 @@ describe("parsePython", () => {
51
50
 
52
51
  describe("variableCompletionSource", () => {
53
52
  beforeEach(() => {
54
- const mockCellId = "cell-1" as CellId;
55
- const mockVariables: Variables = {
56
- ["var1" as VariableName]: {
57
- name: "var1" as VariableName,
53
+ const mockCellId = cellId("cell-1");
54
+ const mockVariables = {
55
+ [variableName("var1")]: {
56
+ name: variableName("var1"),
58
57
  dataType: "int",
59
58
  declaredBy: [mockCellId],
60
59
  usedBy: [mockCellId],
61
60
  },
62
- ["var2" as VariableName]: {
63
- name: "var2" as VariableName,
61
+ [variableName("var2")]: {
62
+ name: variableName("var2"),
64
63
  dataType: "str",
65
64
  declaredBy: [mockCellId],
66
65
  usedBy: [mockCellId],
@@ -69,6 +69,10 @@ const pylspClient = once((lspConfig: LSPConfig) => {
69
69
  "W292", // No newline at end of file
70
70
  // Modules can be imported in any cell
71
71
  "E402", // Module level import not at top of file
72
+ // Blank line rules are not useful in marimo because cells are joined
73
+ // without extra blank lines, which can trigger these rules at cell boundaries
74
+ "E302", // Expected 2 blank lines, found 0
75
+ "E305", // Expected 2 blank lines after class or function definition, found 0
72
76
  ];
73
77
  const ignoredRuffRules = [
74
78
  // Even ruff documentation of this rule explains it is not useful in notebooks
@@ -8,6 +8,7 @@ import {
8
8
  } from "@marimo-team/codemirror-languageserver";
9
9
  import { beforeEach, describe, expect, it, type Mocked, vi } from "vitest";
10
10
  import * as LSP from "vscode-languageserver-protocol";
11
+ import { cellId } from "@/__tests__/branded";
11
12
  import type { CellId } from "@/core/cells/ids";
12
13
  import { store } from "@/core/state/jotai";
13
14
  import { topologicalCodesAtom } from "../../copilot/getCodes";
@@ -19,9 +20,9 @@ import { NotebookLanguageServerClient } from "../notebook-lsp";
19
20
  import { CellDocumentUri, type ILanguageServerClient } from "../types";
20
21
 
21
22
  const Cells = {
22
- cell1: "cell1" as CellId,
23
- cell2: "cell2" as CellId,
24
- cell3: "cell3" as CellId,
23
+ cell1: cellId("cell1"),
24
+ cell2: cellId("cell2"),
25
+ cell3: cellId("cell3"),
25
26
  };
26
27
 
27
28
  describe("createNotebookLens", () => {
@@ -178,6 +178,8 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
178
178
  string,
179
179
  Promise<LSP.CompletionItem>
180
180
  >(10);
181
+ private latestDiagnosticsVersion: number | null = null;
182
+ private forwardedDiagnosticsVersion = 0;
181
183
 
182
184
  constructor(
183
185
  client: ILanguageServerClient,
@@ -270,6 +272,8 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
270
272
 
271
273
  // Get the current document state
272
274
  const { lens, version } = this.snapshotter.snapshot();
275
+ this.latestDiagnosticsVersion = null;
276
+ this.forwardedDiagnosticsVersion = 0;
273
277
 
274
278
  // Re-open the merged document with the LSP server
275
279
  // This sends a textDocument/didOpen for the entire notebook
@@ -768,13 +772,34 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
768
772
  | { method: "other"; params: unknown },
769
773
  ) => {
770
774
  if (notification.method === "textDocument/publishDiagnostics") {
775
+ const incomingVersion = notification.params.version;
776
+ if (incomingVersion != null) {
777
+ const latestVersion = this.latestDiagnosticsVersion;
778
+ if (
779
+ latestVersion !== null &&
780
+ Number.isFinite(incomingVersion) &&
781
+ incomingVersion < latestVersion
782
+ ) {
783
+ Logger.debug(
784
+ "[lsp] dropping stale diagnostics notification",
785
+ notification,
786
+ );
787
+ return;
788
+ }
789
+ this.latestDiagnosticsVersion = incomingVersion;
790
+ }
791
+
771
792
  Logger.debug("[lsp] handling diagnostics", notification);
772
793
  // Use the correct lens by version
773
794
  const payload = this.snapshotter.getLatestSnapshot();
774
795
 
775
796
  const diagnostics = notification.params.diagnostics;
776
797
 
777
- const { lens, version: cellVersion } = payload;
798
+ const { lens } = payload;
799
+ // Forward diagnostics with a strictly increasing version so downstream
800
+ // plugin updates/clears reliably, even when server repeats the same
801
+ // document version across multiple publishDiagnostics notifications.
802
+ const diagnosticsVersion = ++this.forwardedDiagnosticsVersion;
778
803
 
779
804
  // Pre-partition diagnostics by cell
780
805
  const diagnosticsByCellId = new Map<CellId, LSP.Diagnostic[]>();
@@ -817,7 +842,7 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
817
842
  params: {
818
843
  ...notification.params,
819
844
  uri: cellDocumentUri,
820
- version: cellVersion,
845
+ version: diagnosticsVersion,
821
846
  diagnostics: cellDiagnostics,
822
847
  },
823
848
  });
@@ -832,6 +857,7 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
832
857
  method: "textDocument/publishDiagnostics",
833
858
  params: {
834
859
  uri: cellDocumentUri,
860
+ version: diagnosticsVersion,
835
861
  diagnostics: [],
836
862
  },
837
863
  });
@@ -3,8 +3,8 @@
3
3
  import { python } from "@codemirror/lang-python";
4
4
  import { EditorState } from "@codemirror/state";
5
5
  import { describe, expect, test } from "vitest";
6
- import type { CellId } from "@/core/cells/ids";
7
- import type { VariableName, Variables } from "@/core/variables/types";
6
+ import { cellId, variableName } from "@/__tests__/branded";
7
+ import type { Variables } from "@/core/variables/types";
8
8
  import { findReactiveVariables, type ReactiveVariableRange } from "../analyzer";
9
9
 
10
10
  describe("findReactiveVariables - Lexical Scoping", () => {
@@ -1199,16 +1199,17 @@ class Foo:
1199
1199
  function runHighlight(variableNames: string[], code: string): string {
1200
1200
  const variables: Variables = {};
1201
1201
  for (const name of variableNames) {
1202
- variables[name as VariableName] = {
1203
- name: name as VariableName,
1204
- declaredBy: ["other-cell" as CellId],
1202
+ const varName = variableName(name);
1203
+ variables[varName] = {
1204
+ name: varName,
1205
+ declaredBy: [cellId("other-cell")],
1205
1206
  usedBy: [],
1206
1207
  value: "test-value",
1207
1208
  dataType: "str",
1208
1209
  };
1209
1210
  }
1210
1211
  const ranges = findReactiveVariables({
1211
- cellId: "current-cell" as CellId,
1212
+ cellId: cellId("current-cell"),
1212
1213
  state: EditorState.create({
1213
1214
  doc: code,
1214
1215
  extensions: [python()],
@@ -3,7 +3,7 @@
3
3
  import { syntaxTree } from "@codemirror/language";
4
4
  import type { EditorState } from "@codemirror/state";
5
5
  import type { SyntaxNode, Tree, TreeCursor } from "@lezer/common";
6
- import type { CellId } from "@/core/cells/ids";
6
+ import { type CellId, SETUP_CELL_ID } from "@/core/cells/ids";
7
7
  import type { VariableName, Variables } from "@/core/variables/types";
8
8
 
9
9
  export interface ReactiveVariableRange {
@@ -52,7 +52,7 @@ export function findReactiveVariables(options: {
52
52
  const variable = options.variables[name as VariableName];
53
53
  return (
54
54
  variable.dataType !== "module" &&
55
- !variable.declaredBy.includes("setup" as CellId) &&
55
+ !variable.declaredBy.includes(SETUP_CELL_ID) &&
56
56
  !variable.declaredBy.includes(options.cellId)
57
57
  );
58
58
  }),
@@ -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
+ });
@@ -72,6 +72,7 @@ export class LoroSyncPluginValue implements PluginValue {
72
72
  insert: text.toString(),
73
73
  },
74
74
  ],
75
+ annotations: [loroSyncAnnotation.of(this)],
75
76
  });
76
77
  });
77
78
  }
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import { beforeEach, describe, expect, it } from "vitest";
3
+ import { variableName } from "@/__tests__/branded";
3
4
  import type { DataTable } from "@/core/kernel/messages";
4
5
  import type { VariableName } from "@/core/variables/types";
5
6
  import {
@@ -182,7 +183,7 @@ describe("filtering data sources", () => {
182
183
  });
183
184
 
184
185
  it("keeps matching variables and internal engines", () => {
185
- const filtered = filterDataSources(["conn1" as unknown as VariableName]);
186
+ const filtered = filterDataSources([variableName("conn1")]);
186
187
  expect(filtered.connectionsMap.size).toBe(defaultConnSize + 1);
187
188
  expect(filtered.connectionsMap.has("conn1" as ConnectionName)).toBe(true);
188
189
  for (const engine of INTERNAL_SQL_ENGINES) {
@@ -191,16 +192,14 @@ describe("filtering data sources", () => {
191
192
  });
192
193
 
193
194
  it("filters out non-matching variables", () => {
194
- const filtered = filterDataSources([
195
- "non_existent" as unknown as VariableName,
196
- ]);
195
+ const filtered = filterDataSources([variableName("non_existent")]);
197
196
  expect(filtered.connectionsMap.size).toBe(defaultConnSize);
198
197
  });
199
198
 
200
199
  it("handles mix of matching and non-matching variables", () => {
201
200
  const filtered = filterDataSources([
202
- "conn1" as unknown as VariableName,
203
- "non_existent" as unknown as VariableName,
201
+ variableName("conn1"),
202
+ variableName("non_existent"),
204
203
  ]);
205
204
  expect(filtered.connectionsMap.size).toBe(defaultConnSize + 1);
206
205
  expect(filtered.connectionsMap.has("conn1" as ConnectionName)).toBe(true);
@@ -83,7 +83,7 @@ const {
83
83
  if (!table.variable_name) {
84
84
  return true;
85
85
  }
86
- return names.has(table.variable_name as VariableName);
86
+ return names.has(table.variable_name);
87
87
  });
88
88
  return { ...state, tables };
89
89
  },
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import { describe, expect, it } from "vitest";
3
+ import { cellId } from "@/__tests__/branded";
3
4
  import type { MarimoError } from "@/core/kernel/messages";
4
5
  import { getAutoFixes, getImportCode } from "../errors";
5
6
 
@@ -25,7 +26,7 @@ describe("getAutoFixes", () => {
25
26
  const error: MarimoError = {
26
27
  type: "multiple-defs",
27
28
  name: "foo",
28
- cells: ["foo"],
29
+ cells: [cellId("foo")],
29
30
  };
30
31
 
31
32
  const fixes = getAutoFixes(error, opts);