{{ message }}
Repository navigation
fix(muya): keep the code block when a cut ends in its language line (#5371) - #5372
Merged
Merged
Conversation
7 of 10 tasks
…5371) A cross-block cut merges the end leaf's text after the caret into the start block and removes the end leaf's branch. When the selection ends inside a later code block's language line (Shift+Down from a paragraph above lands there), that merged the rest of the language into the start paragraph while the code block kept its full language, and `pruneAfterBranch` removed the language input node itself (a content leaf, so no json op), leaving a code block whose language could not be edited until the document was reopened. Inside a list item, the blocks between the start and the code block were not removed either. Stop such a cut before that code block: nothing from the language joins the start block, the blocks before the code block are removed as usual, and the code block keeps its code and language input and loses only the selected start of its language. The #918 path (a cut that starts in a language line) resolves its end the same way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WEPLCvFTgbYf35z85XUJop
Jocs
force-pushed
the
fix/5371-cut-into-language-input
branch
from
September 15, 2026 15:21
d5adc04 to
2bbca37
Compare
This was referenced Sep 15, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Closes #5371
Summary
Replacing a selection that ends inside a code block's language box (typing, pasting or Backspace) corrupted that code block: the rest of the language was copied into the paragraph where the selection starts while the code block kept its whole language, and the code block lost its language box, so its language could no longer be edited until the document was reopened (undo did not bring it back). Inside a list item, the blocks between the start of the selection and the code block were also left in place. Shift+↓ from a paragraph above lands the end of the selection there.
A cross-block cut merges
endBlock.text.substring(endOffset)into the start block and callsremoveBlocks(startBlock, endBlock). With the language input asendBlock, the merged text is the rest of the language, andpruneAfterBranchremoves the language input node itself (a content leaf, so no json op is sent). muyajs never removed a language input.New
resolveCutEnd()inpackages/muya/src/clipboard/cut.ts: a cut that ends in a language line stops before that code block. Nothing from the language joins the start block, the blocks between the start and the code block are removed as usual (up to the last leaf before the code block), and the code block keeps its code and language input and loses only the selected start of its language. The #918 path (a cut that starts in a language line) resolves its end the same way, so a cut from one language line into another collapses the first code block and trims the second.Steps to reproduce
Checked in the released MarkText 0.20.0-rc.2 (macOS) and in a desktop build of this branch, with real mouse and keyboard input.
inandtro.injs/- item/```jscode/tail—jsduplicated, the selecteditemkeptin/-```jscode/tailTop-level variant (
Intro paragraph/ code block /Outro, selectInt|ro paragraph→j|s, typeX): develop savesIntXswith the code block still```jsand no language box; this PR savesIntXand a code block with languages.Type of change
Test plan
clipboard/__tests__/cutIntoLanguageInput5371.spec.ts(4 cases): end inside the language (top level), end at the start of a nested code block's language (blocks before it removed), whole language selected, and from one language line into another. Each checks the json state against the block tree and that every code block still starts with its language input. All 4 fail ondevelop.editing/cut-into-language-input-5371.spec.ts: Backspace with the real keyboard, then types into the kept language box. Fails ondevelop, passes with the fix (3/3 repeated)._electron, real click + Shift+↓ ×2 + Backspace): the table above, on the packaged 0.20.0-rc.2 and on abuild:unpackof this branch.vitest run237 files / 1675 tests;lint:types, eslint on the changed files andcheck-circularpass; the Unexpected error with message Cannot insert into out of bounds index #4903 / [Bug] Cutting from a nested code block's language box replaces the whole list or quote #5368 / [Bug] Cutting a selection that ends in a code block's language box duplicates text and removes the language box #5371 cut e2e specs pass.Notes for reviewers
Rebased onto #5370 (#5368), which changed the same lines in
collapseLanguageInputCut: the paragraph now replacesstartBlock.getAnchor()(from #5370), and the blocks up to the resolved cut end are removed only when they lie outside that code block (this PR).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