diff --git a/devel-common/src/sphinx_exts/substitution_extensions.py b/devel-common/src/sphinx_exts/substitution_extensions.py index 699dbffa30f46..16ae5d128e51d 100644 --- a/devel-common/src/sphinx_exts/substitution_extensions.py +++ b/devel-common/src/sphinx_exts/substitution_extensions.py @@ -61,7 +61,8 @@ def condition(node): return isinstance(node, (nodes.literal_block, nodes.literal)) for node in self.document.traverse(condition): - if not node.get(_SUBSTITUTION_OPTION_NAME): + # Guard: Only process Element nodes with a truthy substitution option + if not (isinstance(node, nodes.Element) and node.attributes.get(_SUBSTITUTION_OPTION_NAME)): continue # Some nodes don't have a direct document property, so walk up until we find it @@ -74,15 +75,20 @@ def condition(node): substitution_defs = document.substitution_defs for child in node.children: old_child = child - for name, value in substitution_defs.items(): - replacement = value.astext() - if isinstance(child, nodes.Text): - child = nodes.Text(child.replace(f"|{name}|", replacement)) - if isinstance(node, nodes.Element): - node.replace(old_child, child) + # Only substitute for Text nodes + if isinstance(child, nodes.Text): + new_text = str(child) + for name, value in substitution_defs.items(): + replacement = value.astext() + new_text = new_text.replace(f"|{name}|", replacement) + # Only replace if the text actually changed + if new_text != str(child): + child = nodes.Text(new_text) + node.replace(old_child, child) + # For non-Text nodes, do not replace # The highlighter checks this -- without this, it will refuse to apply highlighting - node.rawsource = node.astext() # type: ignore[attr-defined] + node.rawsource = node.astext() def substitution_code_role(*args, **kwargs) -> tuple[list, list[Any]]: