markdown: reflow soft line breaks instead of rendering them as hard breaks - #2947
Merged
Conversation
mdast hands the line ending over exactly as the source wrote it, so a CRLF document keeps its carriage return inside the `Node::Text` value. Replacing only the newline left the CR stranded in the middle of the reflowed line, where it reaches the text run — visible to copy, to measurement, and to whatever the shaper makes of a bare control character. Before this arm existed the CR sat against the line break and stayed out of the way, so the reflow is what exposed it. Take the CR with the newline, and cover the arm: - `test_soft_break_reflows_to_space` over LF, CRLF and a lone CR. - `test_soft_break_reflows_while_hard_break_survives`, which pins the invariant the collapse rests on — a hard break arrives as `Node::Break` and never as a newline inside `Node::Text`. Also drop the claim that the swap has to be length-preserving for inline mark offsets. `parse_paragraph`'s return value is discarded at every call site; the offsets are recomputed from `merged_text.len()` in `merge_children_with_mark`. Nothing downstream depends on the length, and saying otherwise would rule out this fix, which turns two bytes into one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AEg8SEHNEgRDcZ9mDj1p6r
huacnlee
enabled auto-merge (squash)
September 4, 2026 11:30
Member
|
Thank you |
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.
A CommonMark soft break lives inside a
Node::Textvalue as a plain\n. Therenderer treats any
\nin a text run as a line break, so a paragraph that ishard-wrapped in the source renders one visual line per source line instead of
reflowing to the available width.
Reproduction
Renders as two lines even with 1 200 px of free width. Expected one wrapped
line.
Measured on a 3 874-note vault: 10.9 % of notes (421) contain hard-wrapped
prose and rendered wrong.
Fix
Collapse
\nto a space in theNode::Textarm. Hard breaks are unaffected:they arrive as their own
Node::Breakand never reach this arm. The swap islength-preserving, so inline mark offsets computed against the text stay valid.
crates/base/src/text/format/markdown.rs, +11 −2. Best reviewed after thehard-break PR, which adds the
Node::Breakarm this one relies on for thedistinction.