fix: preserve authored line breaks and represent blank paragraphs with blank lines - #198
Merged
Conversation
The commonmark preset couples the two: an empty paragraph serializes to `<br />` only while a parse-time plugin is registered, and that plugin deletes every `<br>` it finds, so an authored one never reaches the document. Removing the plugin settles both halves at once. Raw HTML stays document content, and a blank paragraph is carried by the blank-line run the serializer already writes for it, which renders as nothing in other readers where `<br />` renders a visible line break. The preset wraps block-position raw HTML for root, blockquote, and list items but not footnote definitions, where an unwrapped inline node takes the whole definition out of the document.
The override belongs under the existing GFM preset decision rather than as a new one, which already reserves the case of the specification overriding a preset default.
3 tasks
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.
Summary
An authored
<br>never reached the document, because the commonmark preset deletes every<br>-shapedhtmlnode on parse to support its own empty-paragraph round trip. The two halves are coupled — an empty paragraph serializes to<br />only while that plugin is registered — so this replaces the mechanism instead of narrowing the match.remarkPreserveEmptyLinePluginis removed before the editor is created.<br />, blank lines render as nothing in other Markdown readers, so a Leafdown save no longer changes how a document renders elsewhere.root,blockquote, andlistItem, and an unwrapped inline node in block position takes the whole definition out of the document.The file is the only state, so
a\n\n<br />\n\nbis byte-identical whether the author typed the tag or the editor saved a blank paragraph. No parse-time rule can separate them, which is why the representation changes rather than the match.Related Issue
Closes #193
Closes #196
Verification
Focused tests prove the round trip in both directions.
blockStructure.test.tscovers the transformer as a pure tree function: the blank-line-to-paragraph mapping across 1, 2, 3, 5, and 7 blank lines, nested containers, absent positions, containers that hold no block content, and the footnote wrap.markdownCompatibility.test.tsxcovers 16 authored line-break round trips across every spelling and position — inline, alone in a paragraph, heading, list item, table cell, blockquote, footnote definition, uppercase, code span, fenced block, and raw HTML block — plus an edit cycle, blank-paragraph preservation including inside a blockquote and a footnote definition, blank paragraphs made in the editor surviving a write and reopen for one through three, and an assertion that no<bris written to represent one.Round-tripped
corpus/commonmark/html.mdthrough the editor: the two new sections return byte-identical. Three deviations in that file predate this change and were left alone — an inserted blank line before a block-tag interruption, a type-seven tag folded into the paragraph it cannot interrupt, and escapes added to malformed tag-like text.Not verified: behavior in the WebView. Nothing here depends on layout or hit-testing, but a blank paragraph and a literal
<br>have not been looked at in the running application.Notes
The override is recorded under the existing
Accept Milkdown GFM preset behaviordecision rather than as a new decision, since that entry already reserves the case of the specification overriding a preset default. The Specification states the behavior only; the two-blank-lines convention is an implementation detail and stays out of it.Trailing blank paragraphs are deliberately excluded. Save output trims trailing blank lines by specification, so they cannot survive regardless of representation, and a preserve-trailing-blank-lines option is tracked on the
Output formatting preferencesproject draft.The upstream defects behind this are unreported so far: the unscoped
<br>match, and the missingfootnoteDefinitionin the preset's wrap list. Both are unchanged in 7.22.0. Only the second still affects Leafdown after this change, since the plugin holding the first is no longer loaded.