Conversation
GFM accepts both one and two tildes as strike-through delimiters. For input where a lone '~' is used as a shorthand for "approximately", two such tildes in the same block pair up and strike out everything between them. With the new flag, only ~~two tildes~~ delimit a strike-through span and a single tilde is left as literal text. The flag is opt-in, so the default GFM behavior is unchanged. Single tildes claimed by MD_FLAG_SUBSCRIPTS are unaffected, as subscripts are recognized first.
|
I'll come back to review this later, we're now in feature freeze and approaching release. Are we inventing a new syntax rule with this, or is there some notable prior implementation(s) which recognize only the two-char marks? |
Requiring double tilde for strikethrough is how GitHub Flavored Markdown originally worked. When GitHub switched from redcarpet to cmark, they accidently switch strikethrough from two to one tildes. See github/cmark-gfm#71 The GFM spec wasn't updated until 2022 to say,
Before the change in 2022, the spec said,
cmark-gfm includes an option for only parsing strikethroughs if surrounded by exactly 2 tildes. |
|
After some thinking I'm wondering whether this really has to be added into the parser code. Consider this as a workaround:
|
What/Why?
GFM accepts one or two tildes as strike-through delimiters, and MD4C
implements that faithfully. This PR does not change that — it adds an opt-in
flag for callers who need
~~only.The motivating case is LLM-generated text, where a lone
~is very commonlyused as shorthand for "approximately". Two of those in the same block pair up
and strike out everything between them.
A concrete example from a production AI assistant:
renders today as:
79 characters struck out mid-sentence, swallowing the "Mid range:" label, so
the sentence reads as though a figure had been retracted.
Currency amounts are especially prone to this because of the flanking rules:
in
~$1,359the tilde is preceded by whitespace (so it may open) and followedby punctuation (so it may also close), which makes every such tilde eligible
for both roles.
How common this is, measured over 576 full-text responses from one production
assistant surface:
~strike-through
~~…~~spanSo on that surface every strike-through the renderer produced was unintended.
The damage is bounded — pairing is block-scoped, so a span can cross a soft
line break inside a paragraph but not a blank line, heading, or list item —
but within a block it is still disfiguring.
Turning
MD_FLAG_STRIKETHROUGHoff entirely is the only lever available today,and that also gives up deliberate
~~…~~. Hence a flag.The change
MD_FLAG_STRIKETHROUGH_DOUBLE_ONLYmakes length-1 tilde runs inert, so asingle
~is emitted as literal text. It is a one-condition change inmd_collect_marks: the mark is simply never created, somd_analyze_tildeand the pairing logic are untouched.
MD_DIALECT_GITHUB, and the existingspec-strikethrough.txtsuite are all unchanged.MD_FLAG_STRIKETHROUGHis also set.MD_FLAG_SUBSCRIPTSstill claims single tildes when enabled, sincesubscripts are recognized before strike-through.
~text~~,~~~bar~~~) behave as before.md2htmlgains--fstrikethrough-double-only, and README documents the flag.I did not add a CHANGELOG entry, since there is no unreleased section right
now — happy to add one wherever you prefer.
Testing
New
test/spec-strikethrough-double-only.txtwith 8 examples, picked upautomatically by
scripts/run-tests.py. It covers: the real-worldapproximation case both with and without the flag,
~~x~~still striking,~x~not striking, mismatched and over-long runs, the flag being inertwithout
MD_FLAG_STRIKETHROUGH, and theMD_FLAG_SUBSCRIPTSinteraction.Full suite passes, including the 30 pathological-input tests:
Built with
-Wall -Werroron clang (macOS). I compiled the sources directlyrather than through CMake, as CMake was not available in my environment, so
the CMake and Windows build paths are only exercised by CI here.
PR Checklist
md2htmloption and--helpupdated