diff --git a/lib/markdown2.py b/lib/markdown2.py index 3632a54e..1ac1160d 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -3861,11 +3861,27 @@ class LinkPatterns(Extra): def run(self, text: str): link_from_hash = {} for regex, repl in self.options: + # Spans of inline HTML markup in the current text: tags, + # comments, processing instructions and `<...>` auto-link + # tokens (as recognized by the same tokenizer that + # `_escape_special_chars` uses). Matches inside them must + # not be linkified: that is markup, not prose, and replacing + # inside it corrupts attributes and destroys auto-links + # (e.g. ``, `word`). + markup_spans = [ + m.span(1) + for m in self.md._sorta_html_tokenize_re.finditer(text) + if self.md._is_unescaped_re.match(m.group(1)) + ] replacements = [] for match in regex.finditer(text): if any(self.md._match_overlaps_substr(text, match, h) for h in link_from_hash): continue + # Do not match inside inline HTML markup. + if any(s <= match.start() and match.end() <= e for s, e in markup_spans): + continue + if callable(repl): href = repl(match) else: diff --git a/test/tm-cases/link_patterns_email_autolink.html b/test/tm-cases/link_patterns_email_autolink.html new file mode 100644 index 00000000..1747d494 --- /dev/null +++ b/test/tm-cases/link_patterns_email_autolink.html @@ -0,0 +1 @@ +

foo@example.com is an auto-linked email, but plain foo is still linkified.

diff --git a/test/tm-cases/link_patterns_email_autolink.opts b/test/tm-cases/link_patterns_email_autolink.opts new file mode 100644 index 00000000..02c491dc --- /dev/null +++ b/test/tm-cases/link_patterns_email_autolink.opts @@ -0,0 +1,4 @@ +{"extras": ["link-patterns"], + "link_patterns": [ + (re.compile(r"\b(foo)\b"), r"/w/\1"), + ]} diff --git a/test/tm-cases/link_patterns_email_autolink.tags b/test/tm-cases/link_patterns_email_autolink.tags new file mode 100644 index 00000000..9e0524dd --- /dev/null +++ b/test/tm-cases/link_patterns_email_autolink.tags @@ -0,0 +1 @@ +link_patterns diff --git a/test/tm-cases/link_patterns_email_autolink.text b/test/tm-cases/link_patterns_email_autolink.text new file mode 100644 index 00000000..2ea48b35 --- /dev/null +++ b/test/tm-cases/link_patterns_email_autolink.text @@ -0,0 +1 @@ + is an auto-linked email, but plain foo is still linkified. diff --git a/test/tm-cases/link_patterns_html_tags.html b/test/tm-cases/link_patterns_html_tags.html new file mode 100644 index 00000000..1d6760e7 --- /dev/null +++ b/test/tm-cases/link_patterns_html_tags.html @@ -0,0 +1,7 @@ +

Inline HTML attributes must not be linkified:

+ +

baz

+ +

foo

+ +

But plain foo in prose is linkified.

diff --git a/test/tm-cases/link_patterns_html_tags.opts b/test/tm-cases/link_patterns_html_tags.opts new file mode 100644 index 00000000..02c491dc --- /dev/null +++ b/test/tm-cases/link_patterns_html_tags.opts @@ -0,0 +1,4 @@ +{"extras": ["link-patterns"], + "link_patterns": [ + (re.compile(r"\b(foo)\b"), r"/w/\1"), + ]} diff --git a/test/tm-cases/link_patterns_html_tags.tags b/test/tm-cases/link_patterns_html_tags.tags new file mode 100644 index 00000000..9e0524dd --- /dev/null +++ b/test/tm-cases/link_patterns_html_tags.tags @@ -0,0 +1 @@ +link_patterns diff --git a/test/tm-cases/link_patterns_html_tags.text b/test/tm-cases/link_patterns_html_tags.text new file mode 100644 index 00000000..326906e8 --- /dev/null +++ b/test/tm-cases/link_patterns_html_tags.text @@ -0,0 +1,7 @@ +Inline HTML attributes must not be linkified: + +baz + +foo + +But plain foo in prose is linkified.