refactor(iter): use indextree::Traverse for iterating nodes

This commit is contained in:
PoiScript 2019-06-27 20:05:54 +08:00
parent 275fbfad34
commit 21aba13d71
7 changed files with 124 additions and 552 deletions

View file

@ -1,171 +1,127 @@
#![allow(unused_variables)]
#![allow(unused_mut)]
use crate::elements::*;
use crate::iter::Container;
use crate::elements::Element;
use jetscii::bytes;
use std::fmt;
use std::io::{Error, Write};
pub trait HtmlHandler<E: From<Error>> {
fn escape<W: Write>(&mut self, mut w: W, text: &str) -> Result<(), E> {
pub struct Escape<'a>(pub &'a str);
impl fmt::Display for Escape<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut pos = 0;
let bytes = text.as_bytes();
let bytes = self.0.as_bytes();
while let Some(off) = bytes!(b'<', b'>', b'&', b'\'', b'"').find(&bytes[pos..]) {
w.write_all(&bytes[pos..pos + off])?;
write!(f, "{}", &self.0[pos..pos + off])?;
pos += off + 1;
match text.as_bytes()[pos - 1] {
b'<' => w.write_all(b"&lt;")?,
b'>' => w.write_all(b"&gt;")?,
b'&' => w.write_all(b"&amp;")?,
b'\'' => w.write_all(b"&#39;")?,
b'"' => w.write_all(b"&quot;")?,
match bytes[pos - 1] {
b'<' => write!(f, "&lt;")?,
b'>' => write!(f, "&gt;")?,
b'&' => write!(f, "&amp;")?,
b'\'' => write!(f, "&#39;")?,
b'"' => write!(f, "&quot;")?,
_ => unreachable!(),
}
}
Ok(w.write_all(&bytes[pos..])?)
write!(f, "{}", &self.0[pos..])
}
fn start<W: Write>(&mut self, mut w: W, container: Container) -> Result<(), E> {
match container {
Container::Block(block) => write!(w, "<div>")?,
Container::Bold => write!(w, "<b>")?,
Container::Document => write!(w, "<main>")?,
Container::DynBlock(_) => (),
Container::Headline(hdl) => {
let level = if hdl.level <= 6 { hdl.level } else { 6 };
write!(&mut w, "<h{}>", level)?;
self.text(&mut w, hdl.title)?;
write!(&mut w, "</h{}>", level)?;
}
pub trait HtmlHandler<E: From<Error>> {
fn start<W: Write>(&mut self, mut w: W, element: &Element) -> Result<(), E> {
use Element::*;
match element {
// container elements
Block { .. } => write!(w, "<div>")?,
Bold { .. } => write!(w, "<b>")?,
Document { .. } => write!(w, "<main>")?,
DynBlock { .. } => (),
Headline { headline, .. } => {
let level = if headline.level <= 6 {
headline.level
} else {
6
};
write!(w, "<h{0}>{1}</h{0}>", level, Escape(headline.title))?;
}
Container::Italic => write!(w, "<i>")?,
Container::List(list) => {
List { list, .. } => {
if list.ordered {
write!(w, "<ol>")?;
} else {
write!(w, "<ul>")?;
}
}
Container::ListItem(_) => write!(w, "<li>")?,
Container::Paragraph => write!(w, "<p>")?,
Container::Section => write!(w, "<section>")?,
Container::Strike => write!(w, "<s>")?,
Container::Underline => write!(w, "<u>")?,
Italic { .. } => write!(w, "<i>")?,
ListItem { .. } => write!(w, "<li>")?,
Paragraph { .. } => write!(w, "<p>")?,
Section { .. } => write!(w, "<section>")?,
Strike { .. } => write!(w, "<s>")?,
Underline { .. } => write!(w, "<u>")?,
// non-container elements
BabelCall { .. } => (),
InlineSrc { inline_src, .. } => write!(w, "<code>{}</code>", Escape(inline_src.body))?,
Code { value, .. } => write!(w, "<code>{}</code>", Escape(value))?,
FnRef { .. } => (),
InlineCall { .. } => (),
Link { link, .. } => write!(
w,
"<a href=\"{}\">{}</a>",
Escape(link.path),
Escape(link.desc.unwrap_or(link.path)),
)?,
Macros { .. } => (),
Planning { .. } => (),
RadioTarget { .. } => (),
Snippet { snippet, .. } => {
if snippet.name.eq_ignore_ascii_case("HTML") {
write!(w, "{}", snippet.value)?;
}
}
Target { .. } => (),
Text { value, .. } => write!(w, "{}", Escape(value))?,
Timestamp { .. } => (),
Verbatim { value, .. } => write!(&mut w, "<code>{}</code>", Escape(value))?,
FnDef { .. } => (),
Clock { .. } => (),
Comment { value, .. } => write!(w, "<!--\n{}\n-->", Escape(value))?,
FixedWidth { value, .. } => write!(w, "<pre>{}</pre>", Escape(value))?,
Keyword { .. } => (),
Drawer { .. } => (),
Rule { .. } => write!(w, "<hr>")?,
Cookie { .. } => (),
}
Ok(())
}
fn end<W: Write>(&mut self, mut w: W, container: Container) -> Result<(), E> {
match container {
Container::Block(block) => write!(w, "</div>")?,
Container::Bold => write!(w, "</b>")?,
Container::Document => write!(w, "</main>")?,
Container::DynBlock(_) => (),
Container::Headline(_) => (),
Container::Italic => write!(w, "</i>")?,
Container::List(list) => {
fn end<W: Write>(&mut self, mut w: W, element: &Element) -> Result<(), E> {
use Element::*;
match element {
// container elements
Block { .. } => write!(w, "</div>")?,
Bold { .. } => write!(w, "</b>")?,
Document { .. } => write!(w, "</main>")?,
DynBlock { .. } => (),
Headline { .. } => (),
List { list, .. } => {
if list.ordered {
write!(w, "</ol>")?;
} else {
write!(w, "</ul>")?;
}
}
Container::ListItem(_) => write!(w, "</li>")?,
Container::Paragraph => write!(w, "</p>")?,
Container::Section => write!(w, "</section>")?,
Container::Strike => write!(w, "</s>")?,
Container::Underline => write!(w, "</u>")?,
Italic { .. } => write!(w, "</i>")?,
ListItem { .. } => write!(w, "</li>")?,
Paragraph { .. } => write!(w, "</p>")?,
Section { .. } => write!(w, "</section>")?,
Strike { .. } => write!(w, "</s>")?,
Underline { .. } => write!(w, "</u>")?,
// non-container elements
_ => (),
}
Ok(())
}
fn keyword<W: Write>(&mut self, mut w: W, keyword: &Keyword<'_>) -> Result<(), E> {
Ok(())
}
fn drawer<W: Write>(&mut self, mut w: W, drawer: &Drawer<'_>) -> Result<(), E> {
Ok(())
}
fn rule<W: Write>(&mut self, mut w: W) -> Result<(), E> {
Ok(write!(w, "<hr>")?)
}
fn cookie<W: Write>(&mut self, mut w: W, cookie: &Cookie) -> Result<(), E> {
Ok(())
}
fn fn_ref<W: Write>(&mut self, mut w: W, fn_ref: &FnRef<'_>) -> Result<(), E> {
Ok(())
}
fn babel_call<W: Write>(&mut self, mut w: W, call: &BabelCall<'_>) -> Result<(), E> {
Ok(())
}
fn inline_call<W: Write>(&mut self, mut w: W, call: &InlineCall<'_>) -> Result<(), E> {
Ok(())
}
fn inline_src<W: Write>(&mut self, mut w: W, src: &InlineSrc<'_>) -> Result<(), E> {
write!(&mut w, "<code>")?;
self.text(&mut w, src.body)?;
write!(&mut w, "</code>")?;
Ok(())
}
fn link<W: Write>(&mut self, mut w: W, link: &Link<'_>) -> Result<(), E> {
write!(&mut w, r#"<a href=""#)?;
self.text(&mut w, link.path)?;
write!(&mut w, r#"">"#)?;
self.text(&mut w, link.desc.unwrap_or(link.path))?;
write!(&mut w, "</a>")?;
Ok(())
}
fn macros<W: Write>(&mut self, mut w: W, macros: &Macros<'_>) -> Result<(), E> {
Ok(())
}
fn radio_target<W: Write>(&mut self, mut w: W, target: &RadioTarget<'_>) -> Result<(), E> {
Ok(())
}
fn snippet<W: Write>(&mut self, mut w: W, snippet: &Snippet<'_>) -> Result<(), E> {
if snippet.name.eq_ignore_ascii_case("HTML") {
write!(w, "{}", snippet.value)?;
}
Ok(())
}
fn target<W: Write>(&mut self, mut w: W, target: &Target<'_>) -> Result<(), E> {
Ok(())
}
fn timestamp<W: Write>(&mut self, mut w: W, timestamp: &Timestamp) -> Result<(), E> {
Ok(())
}
fn verbatim<W: Write>(&mut self, mut w: W, cont: &str) -> Result<(), E> {
write!(&mut w, "<code>")?;
self.text(&mut w, cont)?;
write!(&mut w, "</code>")?;
Ok(())
}
fn code<W: Write>(&mut self, mut w: W, cont: &str) -> Result<(), E> {
write!(&mut w, "<code>")?;
self.text(&mut w, cont)?;
write!(&mut w, "</code>")?;
Ok(())
}
fn text<W: Write>(&mut self, mut w: W, cont: &str) -> Result<(), E> {
self.escape(w, cont)?;
Ok(())
}
fn planning<W: Write>(&mut self, mut w: W, planning: &Planning) -> Result<(), E> {
Ok(())
}
fn clock<W: Write>(&mut self, mut w: W, clock: &Clock<'_>) -> Result<(), E> {
Ok(())
}
fn fn_def<W: Write>(&mut self, mut w: W, fn_def: &FnDef<'_>) -> Result<(), E> {
Ok(())
}
fn comment<W: Write>(&mut self, mut w: W, value: &str) -> Result<(), E> {
write!(&mut w, "<!--\n")?;
self.text(&mut w, value)?;
write!(&mut w, "\n-->")?;
Ok(())
}
fn fixed_width<W: Write>(&mut self, mut w: W, value: &str) -> Result<(), E> {
write!(&mut w, "<pre>")?;
self.text(&mut w, value)?;
write!(&mut w, "</pre>")?;
Ok(())
}
}