Problem
Markdown prettifiers which don't support mdBook's implementation of GFM-style admonitions will mangle them by removing the newline after the admonition header unless you use two newlines... which mdBook doesn't recognize as an admonition.
This markup...
...gets reformatted into:
[!NOTE] Lorem ipsum
Even if it's not formatted automatically, this is a huge footgun, since any contributor might trigger that change without noticing.
Proposed Solution
Support this relaxation of the syntax which passes through the prettifier unaltered and is consistent with what prettifiers generally do to ATX headings without a blank line after them:
> [!NOTE]
>
> Lorem ipsum
(Note that GitHub itself accepts this syntax.)
pulldown-cmark already WONTFIX'd my request for this change, so I'd like to offer this filter I wrote for my own pulldown-cmark-based Markdown processor:
Rust Source Code: Iterator Adapter
/// An iterator adapter to collapse together the incorrectly split BlockQuote elements produced by
/// pulldown-cmark when using blockquote type tags/admonitions with an extra blank line to keep
/// them from being mangled by Markdown formatters which aren't aware of that extension.
pub struct FixPulldownCmarkIssue890<'a, T: Iterator> {
inner: std::iter::Peekable<T>,
buffer: Vec<Option<Event<'a>>>,
}
impl<'a, T> FixPulldownCmarkIssue890<'a, T>
where
T: Iterator<Item = Event<'a>>,
{
pub fn new(iterator: T) -> Self {
Self { inner: iterator.peekable(), buffer: Vec::new() }
}
}
impl<'a, T> Iterator for FixPulldownCmarkIssue890<'a, T>
where
T: Iterator<Item = Event<'a>>,
{
type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match (self.inner.peek(), self.buffer.as_slice()) {
// If we see 3 after accumulating 1&2, drop 2&3 and return 1.
(
Some(Event::Start(Tag::BlockQuote(None))),
[Some(Event::Start(Tag::BlockQuote(Some(_)))), Some(Event::End(TagEnd::BlockQuote(_)))],
) => {
let _ = self.inner.next();
let e = self.buffer.swap_remove(0);
self.buffer.clear();
return e;
},
// If we see 2 and we've accumulated 1, buffer it and go around again
(
Some(Event::End(TagEnd::BlockQuote(_))),
[Some(Event::Start(Tag::BlockQuote(Some(_))))],
) => {
self.buffer.push(self.inner.next());
},
// If we see 1 and the buffer is empty, buffer it and go around again
(Some(Event::Start(Tag::BlockQuote(Some(_)))), []) => {
self.buffer.push(self.inner.next());
},
// Otherwise, if the buffer is empty, just pass it through
(_, []) => return self.inner.next(),
// Otherwise, drain the buffer
(_, [_, ..]) => return self.buffer.remove(0),
}
}
}
}
Notes
To repeat my earlier observation, this would bring mdBook more into line with how GitHub parses GFM admonitions.
Problem
Markdown prettifiers which don't support mdBook's implementation of GFM-style admonitions will mangle them by removing the newline after the admonition header unless you use two newlines... which mdBook doesn't recognize as an admonition.
This markup...
Note
Lorem ipsum
...gets reformatted into:
> [!NOTE] Lorem ipsumEven if it's not formatted automatically, this is a huge footgun, since any contributor might trigger that change without noticing.
Proposed Solution
Support this relaxation of the syntax which passes through the prettifier unaltered and is consistent with what prettifiers generally do to ATX headings without a blank line after them:
Note
Lorem ipsum
(Note that GitHub itself accepts this syntax.)
pulldown-cmark already WONTFIX'd my request for this change, so I'd like to offer this filter I wrote for my own
pulldown-cmark-based Markdown processor:Rust Source Code: Iterator Adapter
Notes
To repeat my earlier observation, this would bring mdBook more into line with how GitHub parses GFM admonitions.