74 lines
2.3 KiB
Rust
74 lines
2.3 KiB
Rust
|
use pulldown_cmark::{CowStr, Event, Tag};
|
||
|
use std::iter::Peekable;
|
||
|
|
||
|
pub struct FootnoteBackrefs<'a, I: Iterator<Item = Event<'a>>> {
|
||
|
iter: Peekable<I>,
|
||
|
next: Option<Event<'a>>,
|
||
|
}
|
||
|
|
||
|
pub fn new<'a, I: Iterator<Item = Event<'a>>>(iter: I) -> FootnoteBackrefs<'a, I> {
|
||
|
FootnoteBackrefs {
|
||
|
iter: iter.peekable(),
|
||
|
next: None,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a, I: Iterator<Item = Event<'a>>> Iterator for FootnoteBackrefs<'a, I> {
|
||
|
type Item = Event<'a>;
|
||
|
|
||
|
fn next(&mut self) -> Option<Self::Item> {
|
||
|
if let Some(e) = self.next.take() {
|
||
|
return Some(e);
|
||
|
}
|
||
|
|
||
|
match self.iter.next() {
|
||
|
Some(Event::FootnoteReference(label)) => {
|
||
|
let html = format!(
|
||
|
r##"<sup class="footnote-reference" id="fnref{}"><a href="#{}">[{}]</a></sup>"##,
|
||
|
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##" <a href="#fnref{}" class="footnote-backref">↩</a>"##,
|
||
|
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##"<p>foo<sup class="footnote-reference" id="fnref1"><a href="#1">[1]</a></sup></p>
|
||
|
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
|
||
|
<p>bar <a href="#fnref1" class="footnote-backref">↩</a></p>
|
||
|
</div>
|
||
|
"##
|
||
|
);
|
||
|
}
|
||
|
}
|