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
7 changes: 7 additions & 0 deletions markdown/blockprocessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,13 @@ def run(self, parent: etree.Element, blocks: list[str]) -> bool:
link = m.group(2).lstrip('<').rstrip('>')
title = m.group(5) or m.group(6)
self.parser.md.references[id] = (link, title)
# Also store under a backtick-stripped key so that inline
# reference lookups work when the label contains code spans.
# Backtick code spans are processed before reference resolution,
# and the stashed code element does not preserve the backtick count.
id_stripped = id.replace('`', '')
if id_stripped != id:
self.parser.md.references[id_stripped] = (link, title)
if block[m.end():].strip():
# Add any content after match back to blocks as separate block
blocks.insert(0, block[m.end():].lstrip('\n'))
Expand Down
31 changes: 31 additions & 0 deletions markdown/inlinepatterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,35 @@ class ReferenceInlineProcessor(LinkInlineProcessor):

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

def _unescapeId(self, id: str) -> str:
"""Unescape inline placeholders in a reference ID for lookup.

Inline processing (e.g. backtick code spans at priority 190) runs before
reference resolution (priority 170). Code spans are replaced with
placeholders that would not match the raw-text reference definition key.
This method reverses that transformation for reference matching.

Backtick delimiters are stripped during normalization since the backtick
count is not preserved in the stashed element. Reference definitions are
stored under a similarly backtick-stripped key.
"""
try:
stash = self.md.treeprocessors['inline'].stashed_nodes
except (KeyError, AttributeError):
return id

def _replace_placeholder(m: re.Match[str]) -> str:
sid = m.group(1)
if sid in stash:
value = stash.get(sid)
if isinstance(value, str):
return value
else:
return ''.join(value.itertext())
return m.group(0)

return util.INLINE_PLACEHOLDER_RE.sub(_replace_placeholder, id)

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)`.
Expand All @@ -894,6 +923,8 @@ def handleMatch(self, m: re.Match[str], data: str) -> tuple[etree.Element | None

# Clean up line breaks in id
id = self.NEWLINE_CLEANUP_RE.sub(' ', id)
# Unescape inline placeholders (code spans, etc.) for matching
id = self._unescapeId(id)
if id not in self.md.references: # ignore undefined refs
return None, m.start(0), end

Expand Down