2022-11-29 12:34:13 -05:00
|
|
|
use crate::Atom;
|
|
|
|
use crate::Container;
|
2022-11-27 18:53:49 -05:00
|
|
|
use crate::Event;
|
|
|
|
|
2022-11-29 12:34:13 -05:00
|
|
|
/// Generate HTML from parsed events and push it to a unicode-accepting buffer or stream.
|
|
|
|
pub fn push<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write>(out: W, events: I) {
|
|
|
|
Writer::new(events, out).write().unwrap();
|
2022-11-27 18:53:49 -05:00
|
|
|
}
|
|
|
|
|
2022-11-29 12:34:13 -05:00
|
|
|
/// 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<Item = Event<'s>>, W: std::io::Write>(
|
|
|
|
mut out: W,
|
2022-11-27 18:53:49 -05:00
|
|
|
events: I,
|
2022-11-29 12:34:13 -05:00
|
|
|
) -> std::io::Result<()> {
|
|
|
|
struct Adapter<'a, T: ?Sized + 'a> {
|
|
|
|
inner: &'a mut T,
|
|
|
|
error: std::io::Result<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: std::io::Write + ?Sized> 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())
|
2022-11-27 18:53:49 -05:00
|
|
|
}
|
|
|
|
|
2022-11-29 12:34:13 -05:00
|
|
|
struct Writer<I, W> {
|
|
|
|
events: I,
|
|
|
|
out: W,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<I, W> {
|
|
|
|
fn new(events: I, out: W) -> Self {
|
|
|
|
Self { events, out }
|
2022-11-27 18:53:49 -05:00
|
|
|
}
|
|
|
|
|
2022-11-29 12:34:13 -05:00
|
|
|
fn write(&mut self) -> std::fmt::Result {
|
|
|
|
for e in &mut self.events {
|
|
|
|
match e {
|
|
|
|
Event::Start(c, _attrs) => {
|
2022-11-30 13:56:08 -05:00
|
|
|
if c.is_block() {
|
|
|
|
self.out.write_char('\n')?;
|
|
|
|
}
|
2022-11-29 12:34:13 -05:00
|
|
|
match c {
|
|
|
|
Container::Blockquote => self.out.write_str("<blockquote>")?,
|
|
|
|
Container::List(..) => todo!(),
|
|
|
|
Container::ListItem => self.out.write_str("<li>")?,
|
|
|
|
Container::DescriptionList => self.out.write_str("<dl>")?,
|
|
|
|
Container::DescriptionDetails => self.out.write_str("<dd>")?,
|
|
|
|
Container::Footnote { .. } => todo!(),
|
|
|
|
Container::Table => self.out.write_str("<table>")?,
|
|
|
|
Container::TableRow => self.out.write_str("<tr>")?,
|
|
|
|
Container::Div => self.out.write_str("<div>")?,
|
|
|
|
Container::Span => self.out.write_str("<span>")?,
|
|
|
|
Container::Paragraph => self.out.write_str("<p>")?,
|
|
|
|
Container::Heading { level } => write!(self.out, "<h{}>", level)?,
|
|
|
|
Container::Link(..) => todo!(),
|
|
|
|
Container::Image(..) => todo!(),
|
|
|
|
Container::TableCell => self.out.write_str("<td>")?,
|
2022-12-01 14:34:23 -05:00
|
|
|
Container::DescriptionTerm => self.out.write_str("<dt>")?,
|
2022-11-29 12:34:13 -05:00
|
|
|
Container::RawBlock { .. } => todo!(),
|
|
|
|
Container::CodeBlock { .. } => todo!(),
|
|
|
|
Container::Subscript => self.out.write_str("<sub>")?,
|
|
|
|
Container::Superscript => self.out.write_str("<sup>")?,
|
|
|
|
Container::Insert => self.out.write_str("<ins>")?,
|
|
|
|
Container::Delete => self.out.write_str("<del>")?,
|
|
|
|
Container::Strong => self.out.write_str("<strong>")?,
|
|
|
|
Container::Emphasis => self.out.write_str("<em>")?,
|
|
|
|
Container::Mark => self.out.write_str("<mark>")?,
|
|
|
|
Container::SingleQuoted => self.out.write_str("‘")?,
|
|
|
|
Container::DoubleQuoted => self.out.write_str("“")?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Event::End(c) => {
|
2022-11-30 13:56:08 -05:00
|
|
|
if c.is_block_container() && !matches!(c, Container::Footnote { .. }) {
|
|
|
|
self.out.write_char('\n')?;
|
|
|
|
}
|
2022-11-29 12:34:13 -05:00
|
|
|
match c {
|
|
|
|
Container::Blockquote => self.out.write_str("</blockquote>")?,
|
|
|
|
Container::List(..) => todo!(),
|
|
|
|
Container::ListItem => self.out.write_str("</li>")?,
|
|
|
|
Container::DescriptionList => self.out.write_str("</dl>")?,
|
|
|
|
Container::DescriptionDetails => self.out.write_str("</dd>")?,
|
|
|
|
Container::Footnote { .. } => todo!(),
|
|
|
|
Container::Table => self.out.write_str("</table>")?,
|
|
|
|
Container::TableRow => self.out.write_str("</tr>")?,
|
|
|
|
Container::Div => self.out.write_str("</div>")?,
|
|
|
|
Container::Span => self.out.write_str("</span>")?,
|
|
|
|
Container::Paragraph => self.out.write_str("</p>")?,
|
|
|
|
Container::Heading { level } => write!(self.out, "</h{}>", level)?,
|
|
|
|
Container::TableCell => self.out.write_str("</td>")?,
|
2022-12-01 14:34:23 -05:00
|
|
|
Container::DescriptionTerm => self.out.write_str("</dt>")?,
|
2022-11-29 12:34:13 -05:00
|
|
|
Container::RawBlock { .. } => todo!(),
|
|
|
|
Container::CodeBlock { .. } => todo!(),
|
|
|
|
Container::Link(..) => todo!(),
|
|
|
|
Container::Image(..) => todo!(),
|
|
|
|
Container::Subscript => self.out.write_str("</sub>")?,
|
|
|
|
Container::Superscript => self.out.write_str("</sup>")?,
|
|
|
|
Container::Insert => self.out.write_str("</ins>")?,
|
|
|
|
Container::Delete => self.out.write_str("</del>")?,
|
|
|
|
Container::Strong => self.out.write_str("</strong>")?,
|
|
|
|
Container::Emphasis => self.out.write_str("</em>")?,
|
|
|
|
Container::Mark => self.out.write_str("</mark>")?,
|
|
|
|
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, "<code>{}</code>", s)?,
|
|
|
|
Event::Math { content, display } => {
|
|
|
|
if display {
|
|
|
|
write!(
|
|
|
|
self.out,
|
|
|
|
r#"<span class="math display">\[{}\]</span>"#,
|
|
|
|
content,
|
|
|
|
)?;
|
|
|
|
} else {
|
|
|
|
write!(
|
|
|
|
self.out,
|
|
|
|
r#"<span class="math inline">\({}\)</span>"#,
|
|
|
|
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<hr>")?,
|
|
|
|
Atom::NonBreakingSpace => self.out.write_str(" ")?,
|
|
|
|
Atom::Hardbreak => self.out.write_str("<br>\n")?,
|
|
|
|
Atom::Softbreak => self.out.write_char('\n')?,
|
|
|
|
Atom::Blankline | Atom::Escape => {}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-11-27 18:53:49 -05:00
|
|
|
}
|