-
-
Notifications
You must be signed in to change notification settings - Fork 170
Description
We're using comrak to build a markdown document programmatically and output it to a file (as markdown). At some point, we produce a list of items, where each item is a code snippet contained in a NodeValue::Code.
The NodeValue::Code nodes are directly added to the list item's children, which are themselves added to the NodeValue::List node. Then some other content is appended.
When rendered with format_markdown, comrak doesn't properly insert a new line as a separation between the list and the next element. If the next element turns out to be e.g. a Paragraph, then it is rendered as:
- `foo : Number`
- `foo | Even`
restinstead of
- `foo : Number`
- `foo | Even`
restThis is an issue, because the first one is different semantically, being equivalent under the commonmark spec to:
- `foo : Number`
- `foo | Even` restHere is a debug print (in comrak 0.17.0) of the AST being invalidly rendered:
Looking at the rendering code in cm.rs, I found that strange bit:
Lines 407 to 421 in 26ad754
| fn format_list(&mut self, node: &'a AstNode<'a>, entering: bool) { | |
| if !entering | |
| && match node.next_sibling() { | |
| Some(next_sibling) => matches!( | |
| next_sibling.data.borrow().value, | |
| NodeValue::CodeBlock(..) | NodeValue::List(..) | |
| ), | |
| _ => false, | |
| } | |
| { | |
| self.cr(); | |
| write!(self, "<!-- end list -->").unwrap(); | |
| self.blankline(); | |
| } | |
| } |
It turns out the renderer only inserts a newline after a list when the next node is code or another list. I don't really see why: we should always insert a new line I believe (excepted when the list is the last element of the children of a block).
However, the bug above doesn't occur when parsing and re-emitting markdown from a source file, e.g. with the comrak binary. After some investigation, it seemss that comrak always parse list items as NodeValue::Paragraph. Paragraph does insert a new line after itself:
Line 564 in 26ad754
| self.blankline(); |
However, when the list is tight, I think this bunch of code cancels out the newline inserted by paragraphs:
Line 100 in 26ad754
| self.need_cr = 1; |
in_tight_list_item doesn't seem to depend on the position of the item in the list). Or some other mechanism which let the self.need_cr to 2 and properly insert the required line.
In any case, one possible workaround is to always wrap the content of list items in a NodeValue::Paragraph. However, it feels a bit fragile, and I think the renderer should always emit a new line, instead of relying on the unspoken invariant that list items are wrapped in paragraphs to function properly.
If maintainers agree with the baseline, I can tentatively submit a patch.