Problem
When a block sits directly below a code block or quote block, pressing backspace at position 0 merges that block's content into the container via mergeBlockUp(). This is almost never what the user wants — the text becomes trapped inside the code/quote block with no way to extract it (until #164 undo/redo lands).
Other block editors (Notion, VS Code notebooks) treat container blocks as hard boundaries that resist absorbing adjacent content on backspace.
Context
handleBackspace() in editor.go:642–655 handles the merge path. After the list-unwrap logic (line 630–640) and divider-delete (line 648–651), the code falls through to mergeBlockUp() unconditionally at line 654. There is no check on the target block's type.
The fix is a guard before mergeBlockUp(): if the previous block is a CodeBlock or Quote, skip the merge.
Key file: internal/editor/editor.go — handleBackspace() (line 642–655)
Proposed approach
Add a guard clause after line 647 (before the divider check or merged with it):
// Don't merge into container blocks — content gets trapped.
if m.blocks[m.active-1].Type == block.CodeBlock || m.blocks[m.active-1].Type == block.Quote {
return false
}
This prevents the merge entirely. The cursor stays put, the content stays in its own block.
Tasks
Test plan
References
Scope
Type: bug
Size: small
Problem
When a block sits directly below a code block or quote block, pressing backspace at position 0 merges that block's content into the container via
mergeBlockUp(). This is almost never what the user wants — the text becomes trapped inside the code/quote block with no way to extract it (until #164 undo/redo lands).Other block editors (Notion, VS Code notebooks) treat container blocks as hard boundaries that resist absorbing adjacent content on backspace.
Context
handleBackspace()ineditor.go:642–655handles the merge path. After the list-unwrap logic (line 630–640) and divider-delete (line 648–651), the code falls through tomergeBlockUp()unconditionally at line 654. There is no check on the target block's type.The fix is a guard before
mergeBlockUp(): if the previous block is aCodeBlockorQuote, skip the merge.Key file:
internal/editor/editor.go—handleBackspace()(line 642–655)Proposed approach
Add a guard clause after line 647 (before the divider check or merged with it):
This prevents the merge entirely. The cursor stays put, the content stays in its own block.
Tasks
handleBackspace()beforemergeBlockUp()callTest plan
References
Scope
Type: bug
Size: small