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
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- [pull #737] Fix XSS from code spans that the span gamut doesn't treat as code spans in safe mode (#726)
- [pull #743] Add a `strip-syntax` option to the `header-ids` extra that leaves link URLs, image paths, inline HTML tags and emphasis markers out of header ids (#192)
- [pull #747] Fix `link-patterns` extra linking text inside Markdown links and images whose label wraps onto another line
- [pull #755] Fix hard breaks and the `breaks` extra inserting `<br />` inside inline HTML tags and link titles that span several lines


## python-markdown2 2.5.5
Expand Down
32 changes: 27 additions & 5 deletions lib/markdown2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1357,7 +1357,32 @@ def _run_span_gamut(self, text: str) -> str:
text = self._do_italics_and_bold(text)

# Do hard breaks
text = re.sub(r" {2,}\n(?!\<(?:\/?(ul|ol|li))\>)", "<br%s\n" % self.empty_element_suffix, text)
text = self._do_hard_breaks(text)

return text

def _do_hard_breaks(self, text: str, pattern: str = r' {2,}') -> str:
'''
Replace line endings matching `pattern` with `<br>` tags. Line endings
inside a multi-line HTML tag (eg: an `<img>` with its attributes on
separate lines) are left alone, as a `<br>` there would break the tag.
'''
tags = {}

def hash_tag(match: re.Match[str]) -> str:
if '\n' not in match.group(0):
return match.group(0)
key = _hash_text(match.group(0))
tags[key] = match.group(0)
return key

if '<' in text and '\n' in text: # guard for perf
text = self._sorta_html_tokenize_re.sub(hash_tag, text)

text = re.sub(pattern + r"\n(?!\<(?:\/?(ul|ol|li))\>)", "<br%s\n" % self.empty_element_suffix, text)

for key, tag in tags.items():
text = text.replace(key, tag)

return text

Expand Down Expand Up @@ -3575,10 +3600,7 @@ def run(self, text: str):
else:
pattern = r' {2,}'

break_tag = "<br%s\n" % self.md.empty_element_suffix
text = re.sub(pattern + r"\n(?!\<(?:\/?(ul|ol|li))\>)", break_tag, text)

return text
return self.md._do_hard_breaks(text, pattern)


class CodeFriendly(GFMItalicAndBoldProcessor):
Expand Down
7 changes: 7 additions & 0 deletions test/tm-cases/break_on_newline_html_tags.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<p>An image <img src="/path/to/cat.png"
alt="A cat"> sits on this line,<br />
and this line still gets a break.</p>

<p>A raw <a href="https://example.com/"
title="Example">link</a> and a <a href="https://example.com/" title="A title
that wraps">Markdown link</a> keep their attributes.</p>
1 change: 1 addition & 0 deletions test/tm-cases/break_on_newline_html_tags.opts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"extras": ["break-on-newline"]}
7 changes: 7 additions & 0 deletions test/tm-cases/break_on_newline_html_tags.text
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
An image <img src="/path/to/cat.png"
alt="A cat"> sits on this line,
and this line still gets a break.

A raw <a href="https://example.com/"
title="Example">link</a> and a [Markdown link](https://example.com/ "A title
that wraps") keep their attributes.
3 changes: 3 additions & 0 deletions test/tm-cases/hard_break_html_tags.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<p>An image <img src="/path/to/cat.png"
alt="A cat"> with trailing spaces inside the tag,<br />
and a hard break after it.</p>
3 changes: 3 additions & 0 deletions test/tm-cases/hard_break_html_tags.text
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
An image <img src="/path/to/cat.png"
alt="A cat"> with trailing spaces inside the tag,
and a hard break after it.