Skip to content

fix: edge cases for parsing pasted notebooks#10033

Merged
akshayka merged 2 commits into
mainfrom
aka/fix-notebook-copy-paste
Jul 1, 2026
Merged

fix: edge cases for parsing pasted notebooks#10033
akshayka merged 2 commits into
mainfrom
aka/fix-notebook-copy-paste

Conversation

@akshayka

@akshayka akshayka commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

This PR replaces the line-based heuristics with lezer's Python parser, adding support for setup cells and app.function's in the process.

Previously, pasting a marimo notebook into a cell used line-based heuristics to strip the file boilerplate, which mangled several valid constructs. Because the parser models block structure directly, nested-function returns, decorators, async def, and multi-line returns of any bracket type are all handled structurally rather than by ad-hoc string matching.

This feature remains not very discoverable, but I do really like it ...

Review in cubic

Pasting a marimo app into a cell used line-based heuristics to strip the
file boilerplate, which mangled several valid constructs. This PR
replaces the line-based heuristics with lezer's Python parser, adding
support for setup cells and app.function's in the process.

Fixes the following, each covered by a test:
- Decorators inside a cell (`@functools.cache`, `@property`, ...) were
  dropped and could split the cell in two.
- `async def` cells with multi-line args leaked the argument list into
  the body.
- Multi-line returns using `[` or `{` (rather than `(`) leaked their
  contents into the cell.
- Cross-cell parser state could corrupt a following cell.
- `with app.setup(...)` blocks and top-level `@app.function`
  definitions were not extracted at all.

Because the parser models block structure directly, nested-function
returns, decorators, `async def`, and multi-line returns of any bracket
type are all handled structurally rather than by ad-hoc string matching.
@akshayka
akshayka requested review from Copilot and mscolnick June 30, 2026 23:53
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jun 30, 2026 11:56pm

Request Review

@akshayka akshayka added the bug Something isn't working label Jun 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the “paste a marimo app into a cell” workflow by replacing fragile line-based parsing with Lezer’s Python parser, enabling structurally-correct extraction of pasted marimo source (including setup blocks and @app.function).

Changes:

  • Replace heuristic cell extraction with syntax-tree-based parsing via @lezer/python, adding support for with app.setup... and @app.function.
  • Route extracted setup code into the notebook’s dedicated setup cell (create it or append to it).
  • Expand test coverage for previously-mangled edge cases (nested decorators, async defs, multiline returns, setup/function extraction).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
frontend/src/core/codemirror/misc/paste.ts Switches pasted-app parsing to Lezer AST; extracts setup blocks, cells, and @app.function definitions.
frontend/src/core/codemirror/misc/__tests__/paste.test.ts Adds regression tests for parsing edge cases and setup-cell routing behavior.
frontend/src/core/codemirror/cells/state.ts Extends CodemirrorCellActions with addOrAppendSetupCell.
frontend/src/components/editor/cell/code/cell-editor.tsx Implements addOrAppendSetupCell by creating/appending to the setup cell and syncing editor/state.

Comment thread frontend/src/core/codemirror/misc/paste.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/core/codemirror/misc/paste.ts">

<violation number="1" location="frontend/src/core/codemirror/misc/paste.ts:123">
P2: `return false` is unconditional here, so *every* `WithStatement` (not just `app.setup`) stops tree descent into its children. If a decorated `@app.cell` or `@app.function` is nested inside a non-setup `with` block, it will be silently missed. Consider only returning `false` when the node is actually an `app.setup` block, and continuing traversal otherwise. Also, the `.includes("app.setup")` check could match unrelated identifiers (e.g. `my_app.setup_data`) — use a word-boundary–aware check consistent with `looksLikeMarimoApp`'s `\bapp\.setup\b` pattern.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

setupBlocks.push(setup);
}
}
return false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: return false is unconditional here, so every WithStatement (not just app.setup) stops tree descent into its children. If a decorated @app.cell or @app.function is nested inside a non-setup with block, it will be silently missed. Consider only returning false when the node is actually an app.setup block, and continuing traversal otherwise. Also, the .includes("app.setup") check could match unrelated identifiers (e.g. my_app.setup_data) — use a word-boundary–aware check consistent with looksLikeMarimoApp's \bapp\.setup\b pattern.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/core/codemirror/misc/paste.ts, line 123:

<comment>`return false` is unconditional here, so *every* `WithStatement` (not just `app.setup`) stops tree descent into its children. If a decorated `@app.cell` or `@app.function` is nested inside a non-setup `with` block, it will be silently missed. Consider only returning `false` when the node is actually an `app.setup` block, and continuing traversal otherwise. Also, the `.includes("app.setup")` check could match unrelated identifiers (e.g. `my_app.setup_data`) — use a word-boundary–aware check consistent with `looksLikeMarimoApp`'s `\bapp\.setup\b` pattern.</comment>

<file context>
@@ -1,159 +1,175 @@
+            setupBlocks.push(setup);
+          }
+        }
+        return false;
       }
-      skipLines--;
</file context>

@akshayka
akshayka merged commit bcb063b into main Jul 1, 2026
35 checks passed
@akshayka
akshayka deleted the aka/fix-notebook-copy-paste branch July 1, 2026 14:57
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.13-dev1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants