Skip to content

Keep Unicode whitespace other than spaces and tabs when trimming paragraphs, headings and info strings - #966

Merged
xoofx merged 1 commit into
xoofx:mainfrom
HuzaifaChaudary:fix/keep-unicode-spaces-when-trimming
Oct 23, 2026
Merged

xoofx merged 1 commit into
xoofx:mainfrom
HuzaifaChaudary:fix/keep-unicode-spaces-when-trimming

Conversation

@HuzaifaChaudary

@HuzaifaChaudary HuzaifaChaudary commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

paragraphs , headings and fenced code info strings were trimmed with StringSlice.Trim* , which uses IsWhitespace , the whole Unicode Zs category . the spec only strips spaces or tabs there , so a trailing no-break space , em space or ideographic space was lost :

markdown cmark before after
a  <p>a </p> <p>a</p> <p>a </p>
 a <p> a</p> <p>a</p> <p> a</p>
a  <p>a </p> <p>a</p> <p>a </p>
# h  <h1>h </h1> <h1>h</h1> <h1>h </h1>
- a  <li>a </li> <li>a</li> <li>a </li>
``` py  class="language- py " class="language-py" same as cmark

the wording in the spec is removing initial and final spaces or tabs for paragraphs , stripped of leading and trailing space or tab characters for headings and trimmed of leading and trailing spaces or tabs for the info string , the same distinction #675 relied on for ## foo . a no-break space at the end of a line is common in text pasted from word processors , and U+3000 in CJK text .

StringSlice gets internal TrimStartSpaceOrTab , TrimEndSpaceOrTab and TrimSpaceOrTab , used only by the paragraph and setext lines , the ATX heading content and the fenced info string and arguments . the existing public Trim* methods are unchanged . the comment above the fence line.TrimStart () already said use space and tab for this case .

found by rendering 19200 random documents with Markdig and cmark-gfm ( CommonMark only , unsafe html ) and comparing : 1139 differed before , 531 now , 608 fixed and none new . the rest is emphasis next to entity references and </pre> after a list item , separate questions .

tests : TestUnicodeWhitespaceTrimming compares Markdown.ToHtml exactly , because TestParser.TestSpec removes whitespace before </li> and applies NFKD , which turns U+00A0 into a space . two info string cases are added to TestInfoAndArguments . the 11 new or changed cases fail before the change . UnpairedCodeInlineWithTrailingChars from #900 expected the trailing form feed to be trimmed , it now expects <p>*\n\f

, which is what cmark gives , the test is about the exception and that is unchanged .dotnet test -c Release` : 7383 passed on net8.0 and net10.0 .

…graphs, headings and info strings

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Copilot AI balanced review requested due to automatic review settings October 22, 2026 21:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@xoofx xoofx added the bug label Oct 23, 2026
@xoofx
xoofx merged commit 96a7f45 into xoofx:main Oct 23, 2026
3 checks passed
@xoofx

xoofx commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Thank you @HuzaifaChaudary for this fix and for the thorough comparison against cmark-gfm! 🙏

I checked the new behavior against the spec wording ("spaces or tabs" for paragraphs, headings and info strings) and against cmark-gfm. The NBSP, U+3000 and form feed cases all match now. IsSpaceOrTab is also cheaper than the full Unicode whitespace check, so there is no performance cost. Squash-merged.

Reviewed by CodeAlta + Opus 5.5/Low

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants