use pulldown_cmark::{CowStr, Event, Tag}; use std::iter::Peekable; pub struct FootnoteBackrefs<'a, I: Iterator>> { iter: Peekable, next: Option>, } pub fn new<'a, I: Iterator>>(iter: I) -> FootnoteBackrefs<'a, I> { FootnoteBackrefs { iter: iter.peekable(), next: None, } } impl<'a, I: Iterator>> Iterator for FootnoteBackrefs<'a, I> { type Item = Event<'a>; fn next(&mut self) -> Option { if let Some(e) = self.next.take() { return Some(e); } match self.iter.next() { Some(Event::FootnoteReference(label)) => { let html = format!( r##"[{}]"##, label, label, label ); Some(Event::Html(CowStr::Boxed(html.into_boxed_str()))) } Some(Event::End(Tag::Paragraph)) => { if let Some(Event::End(Tag::FootnoteDefinition(label))) = self.iter.peek() { assert!(self.next.is_none()); self.next = Some(Event::End(Tag::Paragraph)); let html = format!( r##" "##, label ); Some(Event::Html(CowStr::Boxed(html.into_boxed_str()))) } else { Some(Event::End(Tag::Paragraph)) } } e => e, } } } #[cfg(test)] mod tests { use pulldown_cmark::{html, Options, Parser}; fn render(s: &str) -> String { let mut out = String::new(); let parser = Parser::new_ext(s, Options::ENABLE_FOOTNOTES); let footnote_backrefs = super::new(parser); html::push_html(&mut out, footnote_backrefs); out } #[test] fn test_footnote_backrefs() { assert_eq!( render("foo[^1]\n\n[^1]: bar"), r##"

foo[1]

1

bar

"## ); } }