Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/mistune/block_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ def __init__(

def parse_blank_line(self, m: Match[str], state: BlockState) -> int:
"""Parse token for blank lines."""
state.append_token({"type": "blank_line"})
if state.cursor == 0:
state.append_token({"type": "blank_line", "newlines": m.group(0).count("\n")})
else:
state.append_token({"type": "blank_line"})
return m.end()

def parse_thematic_break(self, m: Match[str], state: BlockState) -> int:
Expand Down
10 changes: 8 additions & 2 deletions src/mistune/renderers/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ class MarkdownRenderer(BaseRenderer):
NAME = "markdown"

def __call__(self, tokens: Iterable[Dict[str, Any]], state: BlockState) -> str:
out = self.render_tokens(tokens, state)
tokens = list(tokens)
leading = ""
i = 0
while i < len(tokens) and tokens[i]["type"] == "blank_line" and "newlines" in tokens[i]:
leading += "\n" * tokens[i]["newlines"]
i += 1
out = self.render_tokens(tokens[i:], state)
# special handle for line breaks
out += "\n\n".join(self.render_referrences(state)) + "\n"
return strip_end(out)
return strip_end(leading + out)

def render_referrences(self, state: BlockState) -> Iterable[str]:
ref_links = state.env["ref_links"]
Expand Down
6 changes: 6 additions & 0 deletions tests/test_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ def test_prose_not_over_escaped(self):
):
self.assert_round_trip(text)

def test_leading_blank_lines_preserved(self):
# blank_line tokens at the start of the document were rendered as
# empty strings, so leading newlines disappeared on reformat
self.assertEqual(self.reformat("\nabc"), "\nabc\n")
self.assertEqual(self.reformat("\n\n\n\nabc"), "\n\n\n\nabc\n")


class TestRendererMethodRegistration(TestCase):
def test_registered_renderer_method(self):
Expand Down