use std::fmt::{Result, Write};
use pulldown_cmark::{Event, Tag};
use writer::{Frame, Writer};
pub struct PrettyPrinter<W = String> {
writer: Writer<W>,
needs_break: bool
}
impl<W: Write> PrettyPrinter<W> {
pub fn new(write: W) -> PrettyPrinter<W> {
PrettyPrinter::new_with_prefix(write, "")
}
pub fn new_with_prefix(write: W, prefix: &str) -> PrettyPrinter<W> {
PrettyPrinter {
writer: Writer::new(write, prefix.to_string()),
needs_break: false
}
}
pub fn push_event<'a>(&mut self, event: Event<'a>) -> Result {
match event {
Event::Start(tag) => {
match tag {
Tag::Paragraph => {
self.flush_break()?;
},
Tag::Rule => {
self.flush_break()?;
self.writer.write_text("---")?;
},
Tag::Header(indent) => {
self.flush_break()?;
self.writer.write_text(&"#".repeat(indent as usize))?;
self.writer.write_non_breaking_space()?;
},
Tag::List(start) => {
self.flush_break()?;
self.writer.push_frame(Frame::ListItem(start));
},
Tag::Item => {
match self.writer.pop_frame() {
Some(Frame::ListItem(None)) => {
self.flush_break()?;
self.writer.write_text("-")?;
self.writer.write_non_breaking_space()?;
self.writer.push_frame(Frame::ListItem(None));
},
Some(Frame::ListItem(Some(index))) => {
self.flush_break()?;
write!(self.writer, "{}.", index)?;
self.writer.write_non_breaking_space()?;
self.writer.push_frame(Frame::ListItem(Some(index + 1)));
},
_ => {}
}
},
Tag::BlockQuote => {
self.flush_break()?;
self.writer.write_text(">")?;
self.writer.write_non_breaking_space()?;
self.writer.push_frame(Frame::BlockQuote);
},
Tag::CodeBlock(note) => {
self.flush_break()?;
write!(self.writer, "```{}", note)?;
self.writer.write_hard_break()?;
self.writer.write_indent()?;
},
Tag::Emphasis => {
self.writer.write_text("*")?;
},
Tag::Strong => {
self.writer.write_text("**")?;
},
Tag::Code => {
self.writer.write_text("`")?;
},
Tag::Link(_, _) => {
self.writer.write_text("[")?;
},
Tag::Image(_, _) => {
self.writer.write_text("", url)?;
} else {
write!(self.writer, "]({} \"{}\")", url, title)?;
}
},
Tag::FootnoteDefinition(_) => { },
Tag::Table(_) => { },
Tag::TableHead => { },
Tag::TableRow => { },
Tag::TableCell => { }
}
},
Event::Text(text) => {
for (i, line) in text.split('\n').enumerate() {
if i > 0 {
self.writer.write_hard_break()?;
self.writer.write_indent()?;
}
self.writer.write_text(line)?;
}
},
Event::Html(_html) => {
},
Event::InlineHtml(html) => {
self.writer.write_text(html.as_ref())?
},
Event::FootnoteReference(_) => {
},
Event::SoftBreak => {
self.writer.write_soft_break()?
},
Event::HardBreak => {
self.writer.write_text("\\")?;
self.writer.write_hard_break()?;
self.writer.write_indent()?;
}
};
Ok(())
}
pub fn push_events<'a, I>(&mut self, events: I) -> Result
where I: IntoIterator<Item=Event<'a>>
{
for event in events {
self.push_event(event)?;
}
Ok(())
}
pub fn into_inner(self) -> W {
self.writer.into_inner()
}
fn flush_break(&mut self) -> Result {
if self.needs_break {
self.writer.write_hard_break()?;
self.writer.write_indent()?;
self.writer.write_hard_break()?;
self.writer.write_indent()?;
}
self.needs_break = false;
Ok(())
}
}
impl Default for PrettyPrinter {
fn default() -> PrettyPrinter {
PrettyPrinter::new(String::new())
}
}