Skip to content

Commit cf09e08

Browse files
committed
Allow reference links with backticks
1 parent 89112c2 commit cf09e08

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

markdown/inlinepatterns.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def build_inlinepatterns(md: Markdown, **kwargs: Any) -> util.Registry[InlinePro
7070
7171
"""
7272
inlinePatterns = util.Registry()
73-
inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE), 'backtick', 190)
73+
inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE, md), 'backtick', 190)
7474
inlinePatterns.register(EscapeInlineProcessor(ESCAPE_RE, md), 'escape', 180)
7575
inlinePatterns.register(ReferenceInlineProcessor(REFERENCE_RE, md), 'reference', 170)
7676
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,
435435

436436
class BacktickInlineProcessor(InlineProcessor):
437437
""" Return a `<code>` element containing the escaped matching text. """
438-
def __init__(self, pattern: str):
438+
def __init__(self, pattern: str, md: Markdown):
439439
InlineProcessor.__init__(self, pattern)
440440
self.ESCAPED_BSLASH = '{}{}{}'.format(util.STX, ord('\\'), util.ETX)
441441
self.tag = 'code'
442442
""" The tag of the rendered element. """
443443

444+
self.md = md
445+
444446
def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | str, int, int]:
445447
"""
446448
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,
451453
452454
"""
453455
if m.group(3):
456+
if data.lstrip('[').rstrip(']').lower() in self.md.references: # ignore known references
457+
return None, None, None
454458
el = etree.Element(self.tag)
455459
el.text = util.AtomicString(util.code_escape(m.group(3).strip()))
456460
return el, m.start(0), m.end(0)
@@ -879,6 +883,8 @@ class ReferenceInlineProcessor(LinkInlineProcessor):
879883

880884
RE_LINK = re.compile(r'\s?\[([^\]]*)\]', re.DOTALL | re.UNICODE)
881885

886+
RE_BACKTICK = re.compile(BACKTICK_RE, re.DOTALL | re.UNICODE)
887+
882888
def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | None, int | None, int | None]:
883889
"""
884890
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:
925931
if title:
926932
el.set('title', title)
927933

928-
el.text = text
934+
if '`' in text: # Process possible backtick within text
935+
m = self.RE_BACKTICK.search(text)
936+
if m and m.group(3):
937+
el2 = etree.Element('code')
938+
el2.text = util.AtomicString(util.code_escape(m.group(3).strip()))
939+
el.append(el2)
940+
el.text = text[0:m.start(0)]
941+
el2.tail = text[m.end(0):]
942+
else:
943+
el.text = text
944+
else:
945+
el.text = text
946+
929947
return el
930948

931949

tests/test_syntax/inline/test_links.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,23 @@ def test_angles_and_nonsense_url(self):
164164
'<p><a href="?}]*+|&amp;)">test nonsense</a>.</p>'
165165
)
166166

167+
def test_monospaced_title(self):
168+
self.assertMarkdownRenders(
169+
"""[`test`](link)""",
170+
"""<p><a href="link"><code>test</code></a></p>"""
171+
)
172+
173+
def test_title_containing_monospaced_title(self):
174+
self.assertMarkdownRenders(
175+
"""[some `test`](link)""",
176+
"""<p><a href="link">some <code>test</code></a></p>"""
177+
)
178+
179+
def test_title_containing_single_backtick(self):
180+
self.assertMarkdownRenders(
181+
"""[some `test](link)""",
182+
"""<p><a href="link">some `test</a></p>"""
183+
)
167184

168185
class TestReferenceLinks(TestCase):
169186

@@ -434,3 +451,51 @@ def test_ref_round_brackets(self):
434451
"""
435452
)
436453
)
454+
455+
def test_ref_link_monospaced_text(self):
456+
self.assertMarkdownRenders(
457+
self.dedent(
458+
"""
459+
[`Text`]
460+
461+
[`Text`]: http://example.com
462+
"""
463+
),
464+
"""<p><a href="http://example.com"><code>Text</code></a></p>"""
465+
)
466+
467+
def test_ref_link_with_containing_monospaced_text(self):
468+
self.assertMarkdownRenders(
469+
self.dedent(
470+
"""
471+
[some `Text`]
472+
473+
[some `Text`]: http://example.com
474+
"""
475+
),
476+
"""<p><a href="http://example.com">some <code>Text</code></a></p>"""
477+
)
478+
479+
self.assertMarkdownRenders(
480+
self.dedent(
481+
"""
482+
[`Text` after]
483+
484+
[`Text` after]: http://example.com
485+
"""
486+
),
487+
"""<p><a href="http://example.com"><code>Text</code> after</a></p>"""
488+
)
489+
490+
491+
def test_ref_link_with_single_backtick(self):
492+
self.assertMarkdownRenders(
493+
self.dedent(
494+
"""
495+
[some `Text]
496+
497+
[some `Text]: http://example.com
498+
"""
499+
),
500+
"""<p><a href="http://example.com">some `Text</a></p>"""
501+
)

0 commit comments

Comments
 (0)