use crate::Atom; use crate::Container; use crate::Event; /// Generate HTML from parsed events and push it to a unicode-accepting buffer or stream. pub fn push<'s, I: Iterator>, W: std::fmt::Write>(out: W, events: I) { Writer::new(events, out).write().unwrap(); } /// Generate HTML from parsed events and write it to a byte sink, encoded as UTF-8. /// /// NOTE: This performs many small writes, so IO writes should be buffered with e.g. /// [`std::io::BufWriter`]. pub fn write<'s, I: Iterator>, W: std::io::Write>( mut out: W, events: I, ) -> std::io::Result<()> { struct Adapter<'a, T: ?Sized + 'a> { inner: &'a mut T, error: std::io::Result<()>, } impl std::fmt::Write for Adapter<'_, T> { fn write_str(&mut self, s: &str) -> std::fmt::Result { match self.inner.write_all(s.as_bytes()) { Ok(()) => Ok(()), Err(e) => { self.error = Err(e); Err(std::fmt::Error) } } } } let mut output = Adapter { inner: &mut out, error: Ok(()), }; Writer::new(events, &mut output) .write() .map_err(|_| output.error.unwrap_err()) } struct Writer { events: I, out: W, } impl<'s, I: Iterator>, W: std::fmt::Write> Writer { fn new(events: I, out: W) -> Self { Self { events, out } } fn write(&mut self) -> std::fmt::Result { for e in &mut self.events { match e { Event::Start(c, _attrs) => { if c.is_block() { self.out.write_char('\n')?; } match c { Container::Blockquote => self.out.write_str("
")?, Container::List(..) => todo!(), Container::ListItem => self.out.write_str("
  • ")?, Container::DescriptionList => self.out.write_str("
    ")?, Container::DescriptionDetails => self.out.write_str("
    ")?, Container::Footnote { .. } => todo!(), Container::Table => self.out.write_str("")?, Container::TableRow => self.out.write_str("")?, Container::Div { class } => { if let Some(c) = class { write!(self.out, r#"
    "#, c)?; } else { self.out.write_str("
    ")?; } } Container::Span => self.out.write_str("")?, Container::Paragraph => self.out.write_str("

    ")?, Container::Heading { level } => write!(self.out, "", level)?, Container::Link(..) => todo!(), Container::Image(..) => todo!(), Container::TableCell => self.out.write_str("

    ")?, Container::DescriptionTerm => self.out.write_str("
    ")?, Container::RawBlock { .. } => todo!(), Container::CodeBlock { lang } => { if let Some(l) = lang { write!(self.out, r#"
    "#, l)?;
                                } else {
                                    self.out.write_str("
    ")?;
                                }
                            }
                            Container::Subscript => self.out.write_str("")?,
                            Container::Superscript => self.out.write_str("")?,
                            Container::Insert => self.out.write_str("")?,
                            Container::Delete => self.out.write_str("")?,
                            Container::Strong => self.out.write_str("")?,
                            Container::Emphasis => self.out.write_str("")?,
                            Container::Mark => self.out.write_str("")?,
                            Container::SingleQuoted => self.out.write_str("‘")?,
                            Container::DoubleQuoted => self.out.write_str("“")?,
                        }
                    }
                    Event::End(c) => {
                        if c.is_block_container() && !matches!(c, Container::Footnote { .. }) {
                            self.out.write_char('\n')?;
                        }
                        match c {
                            Container::Blockquote => self.out.write_str("")?,
                            Container::List(..) => todo!(),
                            Container::ListItem => self.out.write_str("")?,
                            Container::DescriptionList => self.out.write_str("")?,
                            Container::DescriptionDetails => self.out.write_str("")?,
                            Container::Footnote { .. } => todo!(),
                            Container::Table => self.out.write_str("
    ")?, Container::TableRow => self.out.write_str("")?, Container::Div { .. } => self.out.write_str("")?, Container::Paragraph => self.out.write_str("

    ")?, Container::Heading { level } => write!(self.out, "", level)?, Container::TableCell => self.out.write_str("")?, Container::DescriptionTerm => self.out.write_str("")?, Container::RawBlock { .. } => self.out.write_str("")?, Container::CodeBlock { .. } => self.out.write_str("")?, Container::Span => self.out.write_str("")?, Container::Link(..) => todo!(), Container::Image(..) => todo!(), Container::Subscript => self.out.write_str("")?, Container::Superscript => self.out.write_str("")?, Container::Insert => self.out.write_str("")?, Container::Delete => self.out.write_str("")?, Container::Strong => self.out.write_str("")?, Container::Emphasis => self.out.write_str("")?, Container::Mark => self.out.write_str("")?, Container::SingleQuoted => self.out.write_str("’")?, Container::DoubleQuoted => self.out.write_str("”")?, } } Event::Str(s) => self.out.write_str(s)?, Event::Verbatim(s) => write!(self.out, "{}", s)?, Event::Math { content, display } => { if display { write!( self.out, r#"\[{}\]"#, content, )?; } else { write!( self.out, r#"\({}\)"#, content, )?; } } Event::Atom(a) => match a { Atom::Ellipsis => self.out.write_str("…")?, Atom::EnDash => self.out.write_str("–")?, Atom::EmDash => self.out.write_str("—")?, Atom::ThematicBreak => self.out.write_str("\n
    ")?, Atom::NonBreakingSpace => self.out.write_str(" ")?, Atom::Hardbreak => self.out.write_str("
    \n")?, Atom::Softbreak => self.out.write_char('\n')?, Atom::Blankline | Atom::Escape => {} }, } } Ok(()) } }