use core::fmt;
use std::fmt::Write;
use jotdown::{Container, Event, Render};
#[derive(Default)]
pub struct TitleRenderer {
in_title: bool,
title: String,
checked_section: bool,
done: bool,
}
impl<'s> Render<'s> for TitleRenderer {
fn push_events<I, W>(&mut self, mut events: I, mut out: W) -> std::fmt::Result
where
I: Iterator<Item = Event<'s>>,
W: Write,
{
events.try_for_each(|e| self.push_event(e, &mut out))?;
if !self.done {
Err(fmt::Error)
} else {
Ok(())
}
}
fn push_event<W>(&mut self, event: Event<'_>, out: W) -> std::fmt::Result
where
W: std::fmt::Write,
{
self.render_event(event, out)
}
}
impl TitleRenderer {
fn render_event<W>(&mut self, e: Event<'_>, mut out: W) -> std::fmt::Result
where
W: std::fmt::Write,
{
match e {
Event::Start(Container::Section { id: _ }, attr) => {
if !self.checked_section {
self.checked_section = true;
if let Some(t) = attr.get_value("dmos:title") {
out.write_str(&t.to_string())?;
out.write_char('\n')?;
self.done = true;
}
}
}
Event::Start(
Container::Heading {
level,
has_section: _,
id: _,
},
_,
) => {
if !self.done && level == 1 {
self.in_title = true;
}
}
Event::End(Container::Heading {
level: _,
has_section: _,
id: _,
}) => {
if !self.done && self.in_title {
out.write_str(&self.title)?;
out.write_char('\n')?;
self.done = true;
}
}
Event::Str(s) => {
if !self.done && self.in_title {
self.title.push_str(&s);
}
}
Event::Blankline => (),
Event::Start(Container::Document, _) => (),
_ => {
if !self.done && !self.in_title {
return Err(fmt::Error);
}
}
}
Ok(())
}
}