refactor(iter): use indextree::Traverse for iterating nodes
This commit is contained in:
parent
275fbfad34
commit
21aba13d71
|
@ -5,8 +5,8 @@ use std::io::{Error as IOError, Write};
|
|||
use std::result::Result;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use orgize::export::*;
|
||||
use orgize::{Container, Org};
|
||||
use orgize::export::{html::Escape, DefaultHtmlHandler, HtmlHandler};
|
||||
use orgize::{Element, Org};
|
||||
use slugify::slugify;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -32,22 +32,25 @@ impl From<FromUtf8Error> for MyError {
|
|||
struct MyHtmlHandler;
|
||||
|
||||
impl HtmlHandler<MyError> for MyHtmlHandler {
|
||||
fn start<W: Write>(&mut self, mut w: W, container: Container<'_>) -> Result<(), MyError> {
|
||||
fn start<W: Write>(&mut self, mut w: W, element: &Element<'_>) -> Result<(), MyError> {
|
||||
let mut default_handler = DefaultHtmlHandler;
|
||||
match container {
|
||||
Container::Headline(hdl) => {
|
||||
if hdl.level > 6 {
|
||||
match element {
|
||||
Element::Headline { headline, .. } => {
|
||||
if headline.level > 6 {
|
||||
return Err(MyError::Heading);
|
||||
} else {
|
||||
let slugify = slugify!(hdl.title);
|
||||
let slugify = slugify!(headline.title);
|
||||
write!(
|
||||
w,
|
||||
"<h{0}><a id=\"{1}\" href=\"#{1}\">{2}</a></h{0}>",
|
||||
hdl.level, slugify, hdl.title,
|
||||
headline.level,
|
||||
slugify,
|
||||
Escape(headline.title),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
_ => default_handler.start(w, container)?,
|
||||
// fallthrough to default handler
|
||||
_ => default_handler.start(w, element)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ use indextree::NodeId;
|
|||
#[cfg_attr(feature = "serde", serde(tag = "type"))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
pub enum Element<'a> {
|
||||
Root,
|
||||
Block {
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
block: Block<'a>,
|
||||
|
|
|
@ -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"<")?,
|
||||
b'>' => w.write_all(b">")?,
|
||||
b'&' => w.write_all(b"&")?,
|
||||
b'\'' => w.write_all(b"'")?,
|
||||
b'"' => w.write_all(b""")?,
|
||||
match bytes[pos - 1] {
|
||||
b'<' => write!(f, "<")?,
|
||||
b'>' => write!(f, ">")?,
|
||||
b'&' => write!(f, "&")?,
|
||||
b'\'' => write!(f, "'")?,
|
||||
b'"' => write!(f, """)?,
|
||||
_ => 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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
mod html;
|
||||
pub mod html;
|
||||
|
||||
pub use html::*;
|
||||
pub use html::{DefaultHtmlHandler, HtmlHandler};
|
||||
|
|
384
src/iter.rs
384
src/iter.rs
|
@ -1,389 +1,25 @@
|
|||
use indextree::{Arena, NodeId};
|
||||
use indextree::{Arena, NodeEdge, Traverse};
|
||||
|
||||
use crate::elements::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Container<'a> {
|
||||
Block(&'a Block<'a>),
|
||||
Bold,
|
||||
Document,
|
||||
DynBlock(&'a DynBlock<'a>),
|
||||
Headline(&'a Headline<'a>),
|
||||
Italic,
|
||||
List(&'a List),
|
||||
ListItem(&'a ListItem<'a>),
|
||||
Paragraph,
|
||||
Section,
|
||||
Strike,
|
||||
Underline,
|
||||
}
|
||||
use crate::elements::Element;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event<'a> {
|
||||
Start(Container<'a>),
|
||||
End(Container<'a>),
|
||||
Rule,
|
||||
BabelCall(&'a BabelCall<'a>),
|
||||
Clock(&'a Clock<'a>),
|
||||
Cookie(&'a Cookie<'a>),
|
||||
Drawer(&'a Drawer<'a>),
|
||||
FnDef(&'a FnDef<'a>),
|
||||
FnRef(&'a FnRef<'a>),
|
||||
InlineCall(&'a InlineCall<'a>),
|
||||
InlineSrc(&'a InlineSrc<'a>),
|
||||
Keyword(&'a Keyword<'a>),
|
||||
Link(&'a Link<'a>),
|
||||
Macros(&'a Macros<'a>),
|
||||
Planning(Planning<'a>),
|
||||
RadioTarget(&'a RadioTarget<'a>),
|
||||
Snippet(&'a Snippet<'a>),
|
||||
Target(&'a Target<'a>),
|
||||
Timestamp(&'a Timestamp<'a>),
|
||||
Code(&'a str),
|
||||
Comment(&'a str),
|
||||
FixedWidth(&'a str),
|
||||
Text(&'a str),
|
||||
Verbatim(&'a str),
|
||||
}
|
||||
|
||||
enum State {
|
||||
Start,
|
||||
End,
|
||||
Empty,
|
||||
Finished,
|
||||
Start(&'a Element<'a>),
|
||||
End(&'a Element<'a>),
|
||||
}
|
||||
|
||||
pub struct Iter<'a> {
|
||||
arena: &'a Arena<Element<'a>>,
|
||||
node: NodeId,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl<'a> Iter<'a> {
|
||||
pub(crate) fn new(arena: &'a Arena<Element<'a>>, node: NodeId) -> Self {
|
||||
Iter {
|
||||
arena,
|
||||
node,
|
||||
state: State::Start,
|
||||
}
|
||||
}
|
||||
|
||||
fn start_event(&mut self) -> Option<Event<'a>> {
|
||||
let node = &self.arena[self.node];
|
||||
match &node.data {
|
||||
Element::Root => {
|
||||
self.state = State::Finished;
|
||||
None
|
||||
}
|
||||
Element::BabelCall { call, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::BabelCall(call))
|
||||
}
|
||||
Element::Verbatim { value, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Verbatim(value))
|
||||
}
|
||||
Element::Code { value, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Code(value))
|
||||
}
|
||||
Element::Text { value, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Text(value))
|
||||
}
|
||||
Element::Block { block, .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Block(block)))
|
||||
}
|
||||
Element::Bold { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Bold))
|
||||
}
|
||||
Element::Document { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
|
||||
Some(Event::Start(Container::Document))
|
||||
}
|
||||
Element::DynBlock { dyn_block, .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::DynBlock(dyn_block)))
|
||||
}
|
||||
Element::Headline { headline, .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Headline(headline)))
|
||||
}
|
||||
Element::Italic { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Italic))
|
||||
}
|
||||
Element::List { list, .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::List(list)))
|
||||
}
|
||||
Element::ListItem { list_item, .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::ListItem(list_item)))
|
||||
}
|
||||
Element::Paragraph { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Paragraph))
|
||||
}
|
||||
Element::Section { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Section))
|
||||
}
|
||||
Element::Strike { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Strike))
|
||||
}
|
||||
Element::Underline { .. } => {
|
||||
if node.first_child().is_none() {
|
||||
self.state = State::Empty;
|
||||
} else {
|
||||
self.state = State::Start;
|
||||
}
|
||||
Some(Event::Start(Container::Underline))
|
||||
}
|
||||
Element::Clock { clock, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Clock(clock))
|
||||
}
|
||||
Element::Cookie { cookie, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Cookie(cookie))
|
||||
}
|
||||
Element::Drawer { drawer, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Drawer(drawer))
|
||||
}
|
||||
Element::FnDef { fn_def, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::FnDef(fn_def))
|
||||
}
|
||||
Element::FnRef { fn_ref, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::FnRef(fn_ref))
|
||||
}
|
||||
Element::InlineCall { inline_call, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::InlineCall(inline_call))
|
||||
}
|
||||
Element::InlineSrc { inline_src, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::InlineSrc(inline_src))
|
||||
}
|
||||
Element::Keyword { keyword, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Keyword(keyword))
|
||||
}
|
||||
Element::Link { link, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Link(link))
|
||||
}
|
||||
Element::Macros { macros, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Macros(macros))
|
||||
}
|
||||
Element::Planning {
|
||||
deadline,
|
||||
scheduled,
|
||||
closed,
|
||||
..
|
||||
} => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Planning(Planning {
|
||||
deadline: deadline.and_then(|id| {
|
||||
if let Element::Timestamp { timestamp, .. } = &self.arena[id].data {
|
||||
Some(timestamp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
scheduled: scheduled.and_then(|id| {
|
||||
if let Element::Timestamp { timestamp, .. } = &self.arena[id].data {
|
||||
Some(timestamp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
closed: closed.and_then(|id| {
|
||||
if let Element::Timestamp { timestamp, .. } = &self.arena[id].data {
|
||||
Some(timestamp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
}))
|
||||
}
|
||||
Element::RadioTarget { radio_target, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::RadioTarget(radio_target))
|
||||
}
|
||||
Element::Rule { .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Rule)
|
||||
}
|
||||
Element::Snippet { snippet, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Snippet(snippet))
|
||||
}
|
||||
Element::Target { target, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Target(target))
|
||||
}
|
||||
Element::Timestamp { timestamp, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Timestamp(timestamp))
|
||||
}
|
||||
Element::FixedWidth { value, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::FixedWidth(value))
|
||||
}
|
||||
Element::Comment { value, .. } => {
|
||||
self.state = State::Start;
|
||||
Some(Event::Comment(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn end_event(&mut self) -> Option<Event<'a>> {
|
||||
let node = &self.arena[self.node];
|
||||
match &node.data {
|
||||
Element::Root => {
|
||||
self.state = State::Finished;
|
||||
None
|
||||
}
|
||||
Element::Block { block, .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Block(block)))
|
||||
}
|
||||
Element::Bold { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Bold))
|
||||
}
|
||||
Element::Document { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Document))
|
||||
}
|
||||
Element::DynBlock { dyn_block, .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::DynBlock(dyn_block)))
|
||||
}
|
||||
Element::Headline { headline, .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Headline(headline)))
|
||||
}
|
||||
Element::Italic { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Italic))
|
||||
}
|
||||
Element::List { list, .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::List(list)))
|
||||
}
|
||||
Element::ListItem { list_item, .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::ListItem(list_item)))
|
||||
}
|
||||
Element::Paragraph { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Paragraph))
|
||||
}
|
||||
Element::Section { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Section))
|
||||
}
|
||||
Element::Strike { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Strike))
|
||||
}
|
||||
Element::Underline { .. } => {
|
||||
self.state = State::End;
|
||||
Some(Event::End(Container::Underline))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub(crate) arena: &'a Arena<Element<'a>>,
|
||||
pub(crate) traverse: Traverse<'a, Element<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Iter<'a> {
|
||||
type Item = Event<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.state {
|
||||
State::Finished => None,
|
||||
State::End => {
|
||||
let node = &self.arena[self.node];
|
||||
if let Some(sibling_node) = node.next_sibling() {
|
||||
self.node = sibling_node;
|
||||
self.start_event()
|
||||
} else if let Some(parent_node) = node.parent() {
|
||||
self.node = parent_node;
|
||||
self.end_event()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
State::Start => {
|
||||
let node = &self.arena[self.node];
|
||||
if let Some(child_node) = node.first_child() {
|
||||
self.node = child_node;
|
||||
self.start_event()
|
||||
} else if let Some(sibling_node) = node.next_sibling() {
|
||||
self.node = sibling_node;
|
||||
self.start_event()
|
||||
} else if let Some(parent_node) = node.parent() {
|
||||
self.node = parent_node;
|
||||
self.end_event()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
State::Empty => self.end_event(),
|
||||
}
|
||||
self.traverse.next().map(|edge| match edge {
|
||||
NodeEdge::Start(e) => Event::Start(&self.arena[e].data),
|
||||
NodeEdge::End(e) => Event::End(&self.arena[e].data),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,5 +146,6 @@ pub mod org;
|
|||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
|
||||
pub use iter::{Container, Event};
|
||||
pub use elements::Element;
|
||||
pub use iter::{Event, Iter};
|
||||
pub use org::Org;
|
||||
|
|
31
src/org.rs
31
src/org.rs
|
@ -10,25 +10,21 @@ use crate::iter::Iter;
|
|||
pub struct Org<'a> {
|
||||
pub(crate) arena: Arena<Element<'a>>,
|
||||
pub(crate) document: NodeId,
|
||||
root: NodeId,
|
||||
text: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Org<'a> {
|
||||
pub fn parse(text: &'a str) -> Self {
|
||||
let mut arena = Arena::new();
|
||||
let root = arena.new_node(Element::Root);
|
||||
let document = arena.new_node(Element::Document {
|
||||
begin: 0,
|
||||
end: text.len(),
|
||||
contents_begin: 0,
|
||||
contents_end: text.len(),
|
||||
});
|
||||
root.append(document, &mut arena).unwrap();
|
||||
|
||||
let mut org = Org {
|
||||
arena,
|
||||
root,
|
||||
document,
|
||||
text,
|
||||
};
|
||||
|
@ -38,7 +34,10 @@ impl<'a> Org<'a> {
|
|||
}
|
||||
|
||||
pub fn iter(&'a self) -> Iter<'a> {
|
||||
Iter::new(&self.arena, self.root)
|
||||
Iter {
|
||||
arena: &self.arena,
|
||||
traverse: self.document.traverse(&self.arena),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn html<W, H, E>(&self, mut writer: W, mut handler: H) -> Result<(), E>
|
||||
|
@ -53,28 +52,6 @@ impl<'a> Org<'a> {
|
|||
match event {
|
||||
Start(e) => handler.start(&mut writer, e)?,
|
||||
End(e) => handler.end(&mut writer, e)?,
|
||||
Clock(e) => handler.clock(&mut writer, e)?,
|
||||
Cookie(e) => handler.cookie(&mut writer, e)?,
|
||||
Drawer(e) => handler.drawer(&mut writer, e)?,
|
||||
FnDef(e) => handler.fn_def(&mut writer, e)?,
|
||||
FnRef(e) => handler.fn_ref(&mut writer, e)?,
|
||||
InlineCall(e) => handler.inline_call(&mut writer, e)?,
|
||||
InlineSrc(e) => handler.inline_src(&mut writer, e)?,
|
||||
Keyword(e) => handler.keyword(&mut writer, e)?,
|
||||
Link(e) => handler.link(&mut writer, e)?,
|
||||
Macros(e) => handler.macros(&mut writer, e)?,
|
||||
Planning(e) => handler.planning(&mut writer, &e)?,
|
||||
RadioTarget(e) => handler.radio_target(&mut writer, e)?,
|
||||
Snippet(e) => handler.snippet(&mut writer, e)?,
|
||||
Target(e) => handler.target(&mut writer, e)?,
|
||||
Timestamp(e) => handler.timestamp(&mut writer, e)?,
|
||||
Text(e) => handler.text(&mut writer, e)?,
|
||||
Code(e) => handler.code(&mut writer, e)?,
|
||||
Verbatim(e) => handler.verbatim(&mut writer, e)?,
|
||||
BabelCall(e) => handler.babel_call(&mut writer, e)?,
|
||||
Rule => handler.rule(&mut writer)?,
|
||||
Comment(e) => handler.comment(&mut writer, e)?,
|
||||
FixedWidth(e) => handler.fixed_width(&mut writer, e)?,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue