fix(muya): keep the document intact when a cut ends in a table (#5400, #5405, #5399, #5398) by Jocs · Pull Request #5406 · marktext/marktext · GitHub
Skip to content

fix(muya): keep the document intact when a cut ends in a table (#5400, #5405, #5399, #5398) - #5406

Merged
Jocs merged 1 commit into
developfrom
fix/5400-cut-into-table
Sep 16, 2026
Merged

Jocs merged 1 commit into
developfrom
fix/5400-cut-into-table

Conversation

@Jocs

@Jocs Jocs commented Sep 16, 2026

Copy link
Copy Markdown
Member

Closes #5400
Closes #5405
Closes #5399
Closes #5398

Summary

A cross-block cut whose end lands in a table went through removeBlocksIntoTable() in packages/muya/src/clipboard/cut.ts, which removed the top-level blocks between the start's outermost block and the table by walking before.outMostBlock.next until it reached the table. Four problems came out of that:

Both paths now share one span removal:

  • removeSpan(before, end, removeEnd) removes the blocks after the start inside its containers, the blocks between the two branches, and the blocks before end inside its containers. removeEnd says whether end itself (and the containers it empties) goes. The general path passes the end leaf and true.
  • A cut into a table stops the span at the table, then clears the cells the selection covers whole. The end cell keeps the text the selection leaves behind, so nothing moves out of the table.
  • A fully selected table goes with the span, the way it already does when the selection runs past the table. resolveCutEnd() reports that case, since only it knows the offsets.
  • Clearing a cell re-renders it, the way TableRectSelection.emptySelectedCells() already does.

A cut with both ends inside one table still merges the end cell's tail into the start cell, unchanged.

Steps to reproduce

Checked with real mouse, keyboard and menu input in a desktop build of develop @ 0e156b0 and of this branch, using Playwright _electron. Each starts by clicking right after a and pressing Shift+↓ until the selection reaches the cell named below, then Backspace.

# Document develop This PR
#5400 - a + a table in its list item, then after, more, # heading - a1 + an empty table; after, more and # heading deleted - a + the table with an empty header and 1 in its cell; the three blocks kept
#5400 - a, a table in a quote, then after - a1; the quote and after deleted; Cannot destructure property 'path' of 'this.parent' - a, the quote with its table, after; no error
#5399 - a / - b, then a table with head and 12345 (selection ends inside 12345) - a45 / - b + an empty table - a + the table with an empty header and 45 in its cell
#5405 as above 45 moved into the list item 45 stays in its cell
#5405 - a + a table, dragging to the end of the last cell - a + an empty table + tail - a + tail
#5398 any of the above the cleared cells still show head / 12345 the cleared cells are empty on screen

Type of change

  • Bug fix (non-breaking, fixes an issue)
  • New feature (non-breaking, adds functionality)
  • Breaking change (causes existing functionality to change)
  • Documentation update

Test plan

Notes for reviewers


By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WEPLCvFTgbYf35z85XUJop

…#5405, #5399, #5398)

A cross-block cut whose end lands in a table went through
`removeBlocksIntoTable`, which walked the top-level siblings after the start's
outermost block until it met the table. A table inside a list item or a quote
is never one of those siblings, so the walk removed every block after the
start, took the quote holding the table with it, and then threw while emptying
the cells of the detached table (#5400). The blocks after the start inside its
own list were never removed either (#5399), the text after the selection end
was moved out of its cell into the start block and a table the selection
covered whole was left as an empty grid (#5405), and every emptied cell kept
showing its old text (#5398).

Both paths now share one span removal. `removeSpan` takes the node the span
ends at and whether that node itself goes, so a cut into a table stops the span
at the table and then clears only the cells the selection covers whole; the end
cell keeps what the selection leaves behind. When the selection covers every
cell, the table goes with the span, as it already does when the selection runs
past it. Clearing a cell re-renders it.

A cut with both ends in one table still merges the end cell's tail into the
start cell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WEPLCvFTgbYf35z85XUJop
@Jocs
Jocs merged commit 00f15b2 into develop Sep 16, 2026
7 checks passed
@Jocs
Jocs deleted the fix/5400-cut-into-table branch September 16, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment