Repository navigation
🐛 fix(markdown): preserve links after bangs - #1289
Merged
Merged
Conversation
CommonMark treats a literal ! beside a link bracket as an image. Escape that bang when it is still live, retaining both the link and the text. Append one-byte markers in one step to offset the check on the normal rendering path.
gaborbernat
force-pushed
the
fix/markdown-bang-link
branch
from
October 10, 2026 17:29
4d356b4 to
38cf8ed
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
to_markdown()turns!<a href="/x">x</a>into, which CommonMark reads as an image instead of a literal!followed by a link. CommonMark 6.4, Example 593 gives\for this case.Fix
Escape a live
!only when the next emitted marker opens a link. This also covers empty and reference-style links while leaving spaces and already escaped punctuation alone. Escaping only!keeps the link in ordinary Markdown and avoids a raw HTML fallback for valid link syntax. Single-byte marker opens use a direct append, keeping normal Markdown rendering below the prior instruction count.Turbohtml: literal
!and link preserved. The before and after files below contain the exactto_markdown()output for the same input. This hunk comes fromgit diff --no-index --unified=0:Competitors
markdownify 1.2.3 and html2text 2025.4.15: image instead of link
markdownify output:
markdownify emits
, which md4c and markdown-it-py parse as an image. The source has a literal exclamation mark followed by a link, so we escape!.html2text output:
html2text produces the same image syntax with an extra blank line. The blank line does not change the parse; the escaped
!form preserves the source structure and follows CommonMark Example 593.Performance
On CPython 3.15.0 with GCC 16.2.1, Valgrind Callgrind 3.27.1, and a fixed hash seed, 20,000 representative Markdown renders changed from 221,941,063 to 221,561,063 instructions (−0.17%). A five-link paragraph changed from 255,841,056 to 253,921,056 (−0.75%).