Skip to content

Fix indent on first list item (#482) - #953

Merged
xoofx merged 3 commits into
xoofx:mainfrom
boxofyellow:users/boxofyellow/2026-09/fix-482_0
Sep 19, 2026
Merged

xoofx merged 3 commits into
xoofx:mainfrom
boxofyellow:users/boxofyellow/2026-09/fix-482_0

Conversation

@boxofyellow

@boxofyellow boxofyellow commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

This PR fixes

In short the Markdig.Renderers.Normalize.ListRenderer would include the text for the "list" part of the list item as text, and then push an Indent on the stack comprised on a string of spaces, and lastly then render all the children items.

This caused a problem when the first child block wanted to add its own Indent on the stack. When that first item was a QuoteBlock, previousWasLine within TextRendererBase would still be false, causing its own indent to be "eaten" on the first line of the QuoteBlock. As reported in the bug

- > p

Would get changed into

- p

At the same time if first child block was a sub list an extra new line would be inserted changing

- - a

Into

- 
  - a

To correct this problem, I used Markdig.Renderers.Roundtrip.ListRenderer as inspiration, and updated the Normalize version to move all of the "List" data into the Indent. This did require creating a new constructor so that we could create Indents that would have a specified "first line", and all subsequent uses of the Indent would yield a string the same width of the "first line", but made of spaces. Additional a new public method was add, PushHangingIndent to allow pushing these new Indents to the stack.

This mostly addressed the problem. However it created a problem for truly empty list items. They had no children, and as a result WriteChildren would effectively be a no-op. Again the Roundtrip version contains a solution, we detect this case and just write the empty string, which will respect the Indent.

There is one caveat with that, as noted in the two new tests ListUnorderedEmpty and ListOrderedEmpty. With this implementation, the trailing space that follow the OrderedDelimiter or BulletType is always included, even if it's not in the input. We could address this within our condition for the empty list, but I was not able to find a good way to detect the case when trailing space was in the input. I assume it's better to add the space that will likely be required instead of eating it. But that can easily be changed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This Null check looks like it might be a copy-paste error of
https://github.com/xoofx/markdig/pull/953/changes#diff-93312f2bb29ede6862c9f8cff9baf84ba584d58bd770d388a84381e3b523af22R183

And it should instead be checking to see if lineSpecific is null. But I'm not sure since this is very much looking out for the case when lineSpecific is null
https://github.com/xoofx/markdig/pull/953/changes#diff-93312f2bb29ede6862c9f8cff9baf84ba584d58bd770d388a84381e3b523af22R109

int index = 0;
if (listBlock.OrderedStart != null)
{
switch (listBlock.BulletType)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Another difference I noticed we might want to drop this limited implication of ordered lists identifiers, and instead just use

var bullet = listItem.SourceBullet.ToString();

@xoofx
xoofx merged commit 209b347 into xoofx:main Sep 19, 2026
4 checks passed
@xoofx xoofx added the bug label Sep 19, 2026
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.

2 participants