Skip to content

Fix MarkdownRenderer re-rendering of code spans containing backticks#450

Merged
lepture merged 1 commit into
lepture:mainfrom
gaoflow:fix-markdown-codespan-backticks
Jun 26, 2026
Merged

Fix MarkdownRenderer re-rendering of code spans containing backticks#450
lepture merged 1 commit into
lepture:mainfrom
gaoflow:fix-markdown-codespan-backticks

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Problem

MarkdownRenderer.codespan always wraps the content in a single backtick pair:

return "`" + token["raw"] + "`"

When the code-span content itself contains backticks, re-rendering the AST produces Markdown that no longer round-trips:

  • an inner backtick closes the span early, and
  • a code span whose raw content is a single ` renders as ``` , which re-parses as an empty fenced code block.

This shows up through mistune's own round-trip oracle (to_html(text) vs to_html(reformat(text))):

from mistune import create_markdown
from mistune.renderers.markdown import MarkdownRenderer

to_html = create_markdown(escape=False)
reformat = create_markdown(renderer=MarkdownRenderer())

src = "``code with ` inside``\n"
assert to_html(reformat(src)) == to_html(src)  # fails on main

Fix

Size the delimiter to one more than the longest backtick run inside the content, and add one space of padding on each side when the content begins or ends with a backtick. That matches both CommonMark and mistune's own parse_codespan, which strips a single surrounding space back off (inline_parser.py: if code.startswith(" ") and code.endswith(" "): code = code[1:-1]).

For content with no backticks the delimiter stays a single backtick, so output is byte-for-byte identical to before; only backtick-containing spans change.

Tests

Added test_codespan_containing_backticks to TestMarkdownRendererRoundTrip, exercising single/double inner backticks plus leading, trailing, and surrounding backticks through the existing assert_round_trip helper. It fails before the change and passes after. Full suite: 985 passed; ruff check, ruff format, and mypy all clean.

I used an AI assistant to help investigate this under my direction, and I have reviewed and verified the change myself.

MarkdownRenderer.codespan always wrapped the content in a single backtick
pair, so a code span whose content contains backticks re-parsed wrong: the
inner backtick closed the span early, and a lone backtick rendered as an
empty fenced code block.

Size the delimiter to one more than the longest backtick run in the content,
and pad with a space on each side when the content begins or ends with a
backtick (the parser strips that padding back off), matching parse_codespan
and CommonMark.
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.80%. Comparing base (74608f5) to head (f6827e8).
⚠️ Report is 28 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #450      +/-   ##
==========================================
+ Coverage   91.78%   91.80%   +0.01%     
==========================================
  Files          34       34              
  Lines        2653     2659       +6     
  Branches      433      434       +1     
==========================================
+ Hits         2435     2441       +6     
  Misses        146      146              
  Partials       72       72              
Flag Coverage Δ
unittests 91.76% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@lepture lepture merged commit 10c918d into lepture:main Jun 26, 2026
24 checks passed
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants