Skip to content

fix: use split('\n') instead of splitlines() in blockquote renderer#581

Open
gaoflow wants to merge 1 commit into
hukkin:masterfrom
gaoflow:fix/blockquote-splitlines-unicode-line-separators
Open

fix: use split('\n') instead of splitlines() in blockquote renderer#581
gaoflow wants to merge 1 commit into
hukkin:masterfrom
gaoflow:fix/blockquote-splitlines-unicode-line-separators

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 24, 2026

Copy link
Copy Markdown

Blockquote rendering in mdformat is non-idempotent when the content
contains Unicode whitespace characters like form feed (\x0c),
vertical tab (\x0b), or Unicode line separators.

f(f(x)) != f(x) — the first format pass produces semantically
different output from the input. The second pass normalizes it.

Minimal reproduction:

import mdformat
pass1 = mdformat.text('>a\x0c\t6')
pass2 = mdformat.text(pass1)
assert pass1 == pass2  # FAILS

Root cause: blockquote() in _context.py uses
text.splitlines() which splits on Unicode line separators that
CommonMark does not recognize. The other renderers (paragraph,
list_item) correctly use text.split("\n").

Fix (+1/-1): text.splitlines()text.split("\n") — brings
blockquote in line with paragraph and list_item.

4282/4282 tests pass (5 skipped pre-existing).
211/211 idempotence fuzz tests pass.

This pull request was prepared with the assistance of AI, under my
direction and review.

The blockquote renderer used str.splitlines() to split rendered text
into lines, but splitlines() treats Unicode line separators (form feed
\x0c, vertical tab \x0b, file/group/record separators, NEL \x85,
line/paragraph separator) as line breaks.

CommonMark only recognizes \n, \r\n, and \r as line endings. Other
renderers (paragraph, list_item) correctly use split('\n').

When blockquote content contained Unicode whitespace like form feed,
the renderer would split on it and prepend spurious '> ' markers,
creating semantically different output on the first format pass. The
second pass then normalized this, breaking idempotence.
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.

1 participant