Skip to content

fix(muya): correct the caret after a native word/line delete, and defer in code blocks (#5239) - #5658

Merged
Jocs merged 1 commit into
developfrom
fix/5239-followup
Oct 8, 2026
Merged

Jocs merged 1 commit into
developfrom
fix/5239-followup

Conversation

@Jocs

@Jocs Jocs commented Oct 8, 2026

Copy link
Copy Markdown
Member

Follow-up to #5657 (merged), which let Ctrl/Alt/Cmd+Backspace reach the browser so it can delete a word or a line.

Summary

That change left two gaps.

1. The caret lands mid-text after a native delete. A native "delete to line start" clears the last line, leaves a trailing <br> and parks the caret on the content element itself. resolveEndpoint read that element's child index as a character offset, so the surviving foo\n resolved to offset 1 and the caret jumped into foo. Fix: translate the child index into a text offset when the anchor is the content element. Endpoints inside a child node keep the legacy mapping, which the inline-image paths already compensate for.

2. Code blocks still trimmed one character. CodeBlockContent.backspaceHandler owns its own Prism token-boundary fix-up and never called super, so at a token boundary it intercepted the chord and removed a single grapheme — const| produced cons x = 1 instead of x = 1. Fix: defer to the browser there too, after the offset-0 branch that converts the block to a paragraph.

Type of change

  • Bug fix (non-breaking, fixes an issue)

Test plan

  • Unit — new elementAnchorEndpoint.spec.ts; the lineAtPoint5389.spec.ts code-block stub corrected from an impossible (content element, character offset) anchor to a realistic (text node, offset) one. Full muya suite: 283 files / 2443 tests pass.
  • E2E — new cmd-backspace-multiline-caret-5239.spec.ts drives a real Meta/Ctrl+Backspace on a multi-line soft-break paragraph and on a highlighted code block; it asserts the caret stays at the end of the surviving text and that a Prism token boundary deletes the whole word. Both fail without these fixes.
  • Targeted e2e (blocks + modifier chords): 113 pass.
  • eslint and tsc --noEmit clean.

Notes for reviewers

  • The caret bug is not macOS-only: Alt+Backspace (delete-word, i.e. what Ctrl+Backspace maps to on Linux/Windows) triggers it too whenever the deletion empties the last line. fix: #5239 let Ctrl+Backspace delete a word at the end of a line #5657 was manually tested on Linux with a single-line case, which is why it slipped through.
  • Scope note: resolveEndpoint only reinterprets the content-element anchor. The nested-element case is deliberately left alone — the inline-image caret paths (_caretOffsetOnInlineImage, the ParagraphContent offset-0 branch) depend on the current value.

Refs #5239, #5657

…in code blocks (#5239)

#5657 let Ctrl/Alt/Cmd+Backspace reach the browser so it can delete a whole
word or line. Two gaps remained.

`resolveEndpoint` read the DOM offset of an element-anchored selection as a
character offset. A native "delete to line start" clears the last line, leaves
a trailing `<br>`, and parks the caret on the content element itself — so the
surviving text `foo\n` resolved to offset 1 and the caret jumped into `foo`.
Translate the child index into a text offset for that anchor. Endpoints inside
a child node keep the legacy mapping, which the inline-image paths compensate
for.

`CodeBlockContent.backspaceHandler` owns its own token-boundary fix-up and
never called `super`, so at a Prism token boundary it still intercepted the
chord and trimmed one character (`const|` -> `cons x = 1` instead of ` x = 1`).
Defer to the browser there too, after the offset-0 branch that converts the
block to a paragraph.
@Jocs
Jocs force-pushed the fix/5239-followup branch from 0b26d7b to 5b1d473 Compare October 8, 2026 11:05
@Jocs
Jocs requested a balanced review from Copilot October 8, 2026 11:18

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.

🟢 Approval recommended

The implementation addresses both reported regressions with focused unit and browser-level coverage.

0 open findings

What changed in this PR

Fixes native modifier-assisted Backspace behavior and caret resolution in Muya.

Changes:

  • Converts element child indexes into text offsets.
  • Defers modified Backspace handling in code blocks to the browser.
  • Adds unit and end-to-end regression coverage.
File Description
packages/​muya/​src/​selection/​dom.ts Corrects element-anchored caret offsets.
packages/​muya/​src/​selection/​__tests__/​lineAtPoint5389.spec.ts Uses a realistic text-node caret anchor.
packages/​muya/​src/​selection/​__tests__/​elementAnchorEndpoint.spec.ts Tests element and text-node endpoint resolution.
packages/​muya/​src/​block/​content/​codeBlockContent/​index.ts Defers modified Backspace operations.
packages/​muya/​e2e/​tests/​editing/​cmd-backspace-multiline-caret-5239.spec.ts Covers multiline and Prism token-boundary deletion.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

@Jocs
Jocs merged commit 45e0516 into develop Oct 8, 2026
8 checks passed
Jocs added a commit that referenced this pull request Oct 8, 2026
The find bar seeds its query from the editor selection. #5658 made
resolveEndpoint translate an element-anchored range's offset into a text
offset (the fix for #5239), so the whole-paragraph selection the e2e helper
installs now reads back as the whole paragraph instead of a single character.

That seeded query matches the paragraph once, so the counter already showed
"1 / 1" and the test's poll returned before the debounced search for the
typed query ran; Escape then restored the cursor onto the seeded
whole-paragraph match instead of the typed one.

Wait for the highlight to be the typed query before pressing Escape.
@Jocs
Jocs deleted the fix/5239-followup branch October 23, 2026 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants