From cf09e08f2fae7add1f260cc8b6a8c555f4ca4929 Mon Sep 17 00:00:00 2001 From: Martyn <12006448+martynp@users.noreply.github.com> Date: Mon, 29 Dec 2025 09:59:58 +0000 Subject: [PATCH 1/2] Allow reference links with backticks --- markdown/inlinepatterns.py | 24 ++++++++-- tests/test_syntax/inline/test_links.py | 65 ++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index 9f24512bf..c306c1f6c 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -70,7 +70,7 @@ def build_inlinepatterns(md: Markdown, **kwargs: Any) -> util.Registry[InlinePro """ inlinePatterns = util.Registry() - inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE), 'backtick', 190) + inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE, md), 'backtick', 190) inlinePatterns.register(EscapeInlineProcessor(ESCAPE_RE, md), 'escape', 180) inlinePatterns.register(ReferenceInlineProcessor(REFERENCE_RE, md), 'reference', 170) inlinePatterns.register(LinkInlineProcessor(LINK_RE, md), 'link', 160) @@ -435,12 +435,14 @@ def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element, int, class BacktickInlineProcessor(InlineProcessor): """ Return a `` element containing the escaped matching text. """ - def __init__(self, pattern: str): + def __init__(self, pattern: str, md: Markdown): InlineProcessor.__init__(self, pattern) self.ESCAPED_BSLASH = '{}{}{}'.format(util.STX, ord('\\'), util.ETX) self.tag = 'code' """ The tag of the rendered element. """ + self.md = md + def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | str, int, int]: """ If the match contains `group(3)` of a pattern, then return a `code` @@ -451,6 +453,8 @@ def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | str, """ if m.group(3): + if data.lstrip('[').rstrip(']').lower() in self.md.references: # ignore known references + return None, None, None el = etree.Element(self.tag) el.text = util.AtomicString(util.code_escape(m.group(3).strip())) return el, m.start(0), m.end(0) @@ -879,6 +883,8 @@ class ReferenceInlineProcessor(LinkInlineProcessor): RE_LINK = re.compile(r'\s?\[([^\]]*)\]', re.DOTALL | re.UNICODE) + RE_BACKTICK = re.compile(BACKTICK_RE, re.DOTALL | re.UNICODE) + def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | None, int | None, int | None]: """ Return [`Element`][xml.etree.ElementTree.Element] returned by `makeTag` method or `(None, None, None)`. @@ -925,7 +931,19 @@ def makeTag(self, href: str, title: str, text: str) -> etree.Element: if title: el.set('title', title) - el.text = text + if '`' in text: # Process possible backtick within text + m = self.RE_BACKTICK.search(text) + if m and m.group(3): + el2 = etree.Element('code') + el2.text = util.AtomicString(util.code_escape(m.group(3).strip())) + el.append(el2) + el.text = text[0:m.start(0)] + el2.tail = text[m.end(0):] + else: + el.text = text + else: + el.text = text + return el diff --git a/tests/test_syntax/inline/test_links.py b/tests/test_syntax/inline/test_links.py index e57bd995d..783acb19e 100644 --- a/tests/test_syntax/inline/test_links.py +++ b/tests/test_syntax/inline/test_links.py @@ -164,6 +164,23 @@ def test_angles_and_nonsense_url(self): '

test nonsense.

' ) + def test_monospaced_title(self): + self.assertMarkdownRenders( + """[`test`](link)""", + """

test

""" + ) + + def test_title_containing_monospaced_title(self): + self.assertMarkdownRenders( + """[some `test`](link)""", + """

some test

""" + ) + + def test_title_containing_single_backtick(self): + self.assertMarkdownRenders( + """[some `test](link)""", + """

some `test

""" + ) class TestReferenceLinks(TestCase): @@ -434,3 +451,51 @@ def test_ref_round_brackets(self): """ ) ) + + def test_ref_link_monospaced_text(self): + self.assertMarkdownRenders( + self.dedent( + """ + [`Text`] + + [`Text`]: http://example.com + """ + ), + """

Text

""" + ) + + def test_ref_link_with_containing_monospaced_text(self): + self.assertMarkdownRenders( + self.dedent( + """ + [some `Text`] + + [some `Text`]: http://example.com + """ + ), + """

some Text

""" + ) + + self.assertMarkdownRenders( + self.dedent( + """ + [`Text` after] + + [`Text` after]: http://example.com + """ + ), + """

Text after

""" + ) + + + def test_ref_link_with_single_backtick(self): + self.assertMarkdownRenders( + self.dedent( + """ + [some `Text] + + [some `Text]: http://example.com + """ + ), + """

some `Text

""" + ) From f5c04d7986b6ae8b382a5693a713f52a6c697b00 Mon Sep 17 00:00:00 2001 From: Martyn <12006448+martynp@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:04:07 +0000 Subject: [PATCH 2/2] Flake8 formatting and changelog entry --- docs/changelog.md | 2 ++ markdown/inlinepatterns.py | 2 +- tests/test_syntax/inline/test_links.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 4311353fb..f4c257457 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -16,6 +16,8 @@ See the [Contributing Guide](contributing.md) for details. * Ensure nested elements inside inline comments are properly unescaped (#1571). * Make the docs build successfully with mkdocstrings-python 2.0 (#1575). +* Backtick formatting permitted in reference links to match conventional + links (#495). ## [3.10.0] - 2025-11-03 diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py index c306c1f6c..ee284a619 100644 --- a/markdown/inlinepatterns.py +++ b/markdown/inlinepatterns.py @@ -931,7 +931,7 @@ def makeTag(self, href: str, title: str, text: str) -> etree.Element: if title: el.set('title', title) - if '`' in text: # Process possible backtick within text + if '`' in text: # Process possible backtick within text m = self.RE_BACKTICK.search(text) if m and m.group(3): el2 = etree.Element('code') diff --git a/tests/test_syntax/inline/test_links.py b/tests/test_syntax/inline/test_links.py index 783acb19e..708c980aa 100644 --- a/tests/test_syntax/inline/test_links.py +++ b/tests/test_syntax/inline/test_links.py @@ -182,6 +182,7 @@ def test_title_containing_single_backtick(self): """

some `test

""" ) + class TestReferenceLinks(TestCase): def test_ref_link(self): @@ -487,7 +488,6 @@ def test_ref_link_with_containing_monospaced_text(self): """

Text after

""" ) - def test_ref_link_with_single_backtick(self): self.assertMarkdownRenders( self.dedent(