diff --git a/benches/parse.rs b/benches/parse.rs index 382c53a..0666be2 100644 --- a/benches/parse.rs +++ b/benches/parse.rs @@ -9,7 +9,7 @@ use test::Bencher; fn org_syntax(b: &mut Bencher) { // wget https://orgmode.org/worg/sources/dev/org-syntax.org b.iter(|| { - Org::new(include_str!("org-syntax.org")).parse(); + Org::parse(include_str!("org-syntax.org")); }) } @@ -17,7 +17,7 @@ fn org_syntax(b: &mut Bencher) { fn doc(b: &mut Bencher) { // wget https://orgmode.org/worg/sources/doc.org b.iter(|| { - Org::new(include_str!("doc.org")).parse(); + Org::parse(include_str!("doc.org")); }) } @@ -25,6 +25,6 @@ fn doc(b: &mut Bencher) { fn org_faq(b: &mut Bencher) { // wget https://orgmode.org/worg/sources/org-faq.org b.iter(|| { - Org::new(include_str!("org-faq.org")).parse(); + Org::parse(include_str!("org-faq.org")); }) } diff --git a/examples/custom_handler.rs b/examples/custom_handler.rs index 807919a..2d1959e 100644 --- a/examples/custom_handler.rs +++ b/examples/custom_handler.rs @@ -60,11 +60,9 @@ fn main() -> Result<(), MyError> { eprintln!("Usage: {} ", args[0]); } else { let contents = String::from_utf8(fs::read(&args[1])?)?; - let mut org = Org::new(&contents); - let mut writer = Vec::new(); - org.parse(); - org.html(&mut writer, CustomHtmlHandler)?; + let mut writer = Vec::new(); + Org::parse(&contents).html(&mut writer, CustomHtmlHandler)?; println!("{}", String::from_utf8(writer)?); } diff --git a/examples/json.rs b/examples/json.rs index b44b529..e2ac5cf 100644 --- a/examples/json.rs +++ b/examples/json.rs @@ -11,9 +11,7 @@ fn main() -> Result<()> { eprintln!("Usage: {} ", args[0]); } else { let contents = String::from_utf8(fs::read(&args[1])?).unwrap(); - let mut org = Org::new(&contents); - org.parse(); - println!("{}", to_string(&org).unwrap()); + println!("{}", to_string(&Org::parse(&contents)).unwrap()); } Ok(()) } diff --git a/src/elements/headline.rs b/src/elements/headline.rs index c48f54f..d1523e3 100644 --- a/src/elements/headline.rs +++ b/src/elements/headline.rs @@ -3,7 +3,7 @@ use jetscii::ByteSubstring; use memchr::{memchr, memchr2, memrchr}; -pub(crate) const DEFAULT_TODO_KEYWORDS: &[&str] = +pub const DEFAULT_TODO_KEYWORDS: &[&str] = &["TODO", "DONE", "NEXT", "WAITING", "LATER", "CANCELLED"]; #[cfg_attr(test, derive(PartialEq))] diff --git a/src/elements/mod.rs b/src/elements/mod.rs index d75a7c8..5b474d4 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -30,7 +30,7 @@ pub use self::{ dyn_block::DynBlock, fn_def::FnDef, fn_ref::FnRef, - headline::Headline, + headline::{Headline, DEFAULT_TODO_KEYWORDS}, inline_call::InlineCall, inline_src::InlineSrc, keyword::{BabelCall, Keyword}, @@ -45,6 +45,8 @@ pub use self::{ timestamp::*, }; +use indextree::NodeId; + #[derive(Debug)] pub enum Element<'a> { Root, @@ -91,6 +93,8 @@ pub enum Element<'a> { Document { begin: usize, end: usize, + contents_begin: usize, + contents_end: usize, }, DynBlock { dyn_block: DynBlock<'a>, @@ -157,7 +161,13 @@ pub enum Element<'a> { begin: usize, end: usize, }, - Planning(Planning<'a>), + Planning { + deadline: Option, + scheduled: Option, + closed: Option, + begin: usize, + end: usize, + }, Snippet { begin: usize, end: usize, diff --git a/src/elements/planning.rs b/src/elements/planning.rs index 33fa879..88357c9 100644 --- a/src/elements/planning.rs +++ b/src/elements/planning.rs @@ -6,16 +6,24 @@ use memchr::memchr; #[derive(Debug)] pub struct Planning<'a> { /// the date when the task should be done - pub deadline: Option>, + pub deadline: Option<&'a Timestamp<'a>>, /// the date when you should start working on the task - pub scheduled: Option>, + pub scheduled: Option<&'a Timestamp<'a>>, /// the date when the task is closed - pub closed: Option>, + pub closed: Option<&'a Timestamp<'a>>, } impl Planning<'_> { #[inline] - pub(crate) fn parse(text: &str) -> Option<(Planning<'_>, usize)> { + pub(crate) fn parse( + text: &str, + ) -> Option<( + // TODO: timestamp position + Option<(Timestamp<'_>, usize, usize)>, + Option<(Timestamp<'_>, usize, usize)>, + Option<(Timestamp<'_>, usize, usize)>, + usize, + )> { let (mut deadline, mut scheduled, mut closed) = (None, None, None); let (mut tail, off) = memchr(b'\n', text.as_bytes()) .map(|i| (text[..i].trim(), i + 1)) @@ -28,7 +36,7 @@ impl Planning<'_> { ($timestamp:expr) => { if $timestamp.is_none() { let (timestamp, off) = Timestamp::parse(next)?; - $timestamp = Some(timestamp); + $timestamp = Some((timestamp, 0, 0)); tail = &next[off..].trim_start(); } else { return None; @@ -47,14 +55,7 @@ impl Planning<'_> { if deadline.is_none() && scheduled.is_none() && closed.is_none() { None } else { - Some(( - Planning { - deadline, - scheduled, - closed, - }, - off, - )) + Some((deadline, scheduled, closed, off)) } } } @@ -66,8 +67,9 @@ fn prase() { assert_eq!( Planning::parse("SCHEDULED: <2019-04-08 Mon>\n"), Some(( - Planning { - scheduled: Some(Timestamp::Active { + None, + Some(( + Timestamp::Active { start: Datetime { date: "2019-04-08", time: None, @@ -75,10 +77,11 @@ fn prase() { }, repeater: None, delay: None - }), - closed: None, - deadline: None, - }, + }, + 0, + 0 + )), + None, "SCHEDULED: <2019-04-08 Mon>\n".len() )) ) diff --git a/src/iter.rs b/src/iter.rs index 744a5d6..0e47777 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -32,7 +32,7 @@ pub enum Event<'a> { Keyword(&'a Keyword<'a>), Link(&'a Link<'a>), Macros(&'a Macros<'a>), - Planning(&'a Planning<'a>), + Planning(Planning<'a>), RadioTarget(&'a RadioTarget<'a>), Rule, Snippet(&'a Snippet<'a>), @@ -226,9 +226,36 @@ impl<'a> Iter<'a> { self.state = State::Start; Some(Event::Macros(macros)) } - Element::Planning(planning) => { + Element::Planning { + deadline, + scheduled, + closed, + .. + } => { self.state = State::Start; - Some(Event::Planning(planning)) + 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; @@ -364,9 +391,36 @@ impl<'a> Iter<'a> { self.state = State::End; Some(Event::Macros(macros)) } - Element::Planning(planning) => { + Element::Planning { + deadline, + scheduled, + closed, + .. + } => { self.state = State::End; - Some(Event::Planning(planning)) + 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::End; diff --git a/src/org.rs b/src/org.rs index a5c7bd8..d282c30 100644 --- a/src/org.rs +++ b/src/org.rs @@ -1,12 +1,12 @@ -use crate::elements::*; -use crate::export::{DefaultHtmlHandler, HtmlHandler}; -use crate::iter::Iter; - use indextree::{Arena, NodeId}; use jetscii::bytes; use memchr::{memchr, memchr_iter, memrchr_iter}; use std::io::{Error, Write}; +use crate::elements::*; +use crate::export::{DefaultHtmlHandler, HtmlHandler}; +use crate::iter::Iter; + pub struct Org<'a> { pub(crate) arena: Arena>, pub(crate) document: NodeId, @@ -15,25 +15,26 @@ pub struct Org<'a> { } impl<'a> Org<'a> { - pub fn new(text: &'a str) -> Self { + 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(); - Org { + let mut org = Org { arena, root, document, text, - } - } + }; + org.parse_internal(); - pub fn finish(&self) -> bool { - self.arena[self.document].first_child().is_some() + org } pub fn iter(&'a self) -> Iter<'a> { @@ -62,7 +63,7 @@ impl<'a> Org<'a> { 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)?, + 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)?, @@ -82,15 +83,15 @@ impl<'a> Org<'a> { self.html(wrtier, DefaultHtmlHandler) } - pub fn parse(&mut self) { - if self.finish() { - return; - } - + fn parse_internal(&mut self) { let mut node = self.document; loop { match self.arena[node].data { - Element::Document { begin, end, .. } + Element::Document { + contents_begin: begin, + contents_end: end, + .. + } | Element::Headline { contents_begin: begin, contents_end: end, @@ -131,8 +132,51 @@ impl<'a> Org<'a> { contents_begin, contents_end, .. + } => { + let (mut deadline_node, mut scheduled_node, mut closed_node) = + (None, None, None); + if let Some((deadline, scheduled, closed, off)) = + Planning::parse(&self.text[contents_begin..contents_end]) + { + if let Some((deadline, off, end)) = deadline { + let timestamp = Element::Timestamp { + timestamp: deadline, + begin: contents_begin + off, + end: contents_end + end, + }; + deadline_node = Some(self.arena.new_node(timestamp)); + } + if let Some((scheduled, off, end)) = scheduled { + let timestamp = Element::Timestamp { + timestamp: scheduled, + begin: contents_begin + off, + end: contents_end + end, + }; + scheduled_node = Some(self.arena.new_node(timestamp)); + } + if let Some((closed, off, end)) = closed { + let timestamp = Element::Timestamp { + timestamp: closed, + begin: contents_begin + off, + end: contents_end + end, + }; + closed_node = Some(self.arena.new_node(timestamp)); + } + let planning = Element::Planning { + deadline: deadline_node, + scheduled: scheduled_node, + closed: closed_node, + begin: contents_begin, + end: contents_begin + off, + }; + let new_node = self.arena.new_node(planning); + node.append(new_node, &mut self.arena).unwrap(); + self.parse_elements_children(contents_begin + off, contents_end, node); + } else { + self.parse_elements_children(contents_begin, contents_end, node); + } } - | Element::Block { + Element::Block { contents_begin, contents_end, .. diff --git a/src/serde.rs b/src/serde.rs index f5fbd2a..2475b6f 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -25,19 +25,59 @@ struct ElementNode<'a> { impl Serialize for ElementNode<'_> { #[allow(unused_variables)] fn serialize(&self, serializer: S) -> Result { - let mut state; - match &self.arena[self.node].data { - Element::Root => { - state = serializer.serialize_struct("Element::Root", 2)?; - state.serialize_field("type", "root")?; - } - Element::Document { begin, end } => { - state = serializer.serialize_struct("Element::Document", 2)?; - state.serialize_field("type", "document")?; + let node = &self.arena[self.node]; + + macro_rules! ser { + ($state:ident, $begin:ident, $end:ident) => { if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; + $state.serialize_field("begin", $begin)?; + $state.serialize_field("end", $end)?; } + }; + ($state:ident, $begin:ident, $end:ident, $contents_begin:ident, $contents_end:ident) => { + if cfg!(feature = "extra-serde-info") { + $state.serialize_field("begin", $begin)?; + $state.serialize_field("end", $end)?; + $state.serialize_field("contents_begin", $contents_begin)?; + $state.serialize_field("contents_end", $contents_end)?; + } + if let Some(first) = node.first_child() { + $state.serialize_field( + "children", + &ElementChildrenNode { + first, + arena: self.arena, + }, + )?; + } + }; + } + + match &node.data { + Element::Root => { + let mut state = serializer.serialize_struct("Element::Root", 2)?; + state.serialize_field("type", "root")?; + if let Some(first) = node.first_child() { + state.serialize_field( + "children", + &ElementChildrenNode { + first, + arena: self.arena, + }, + )?; + } + state.end() + } + Element::Document { + begin, + end, + contents_begin, + contents_end, + } => { + let mut state = serializer.serialize_struct("Element::Document", 2)?; + state.serialize_field("type", "document")?; + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Block { block, @@ -46,14 +86,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Block", 2)?; + let mut state = serializer.serialize_struct("Element::Block", 2)?; state.serialize_field("type", "block")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Section { begin, @@ -61,14 +97,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Section", 2)?; + let mut state = serializer.serialize_struct("Element::Section", 2)?; state.serialize_field("type", "section")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Drawer { drawer, @@ -77,14 +109,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Drawer", 2)?; + let mut state = serializer.serialize_struct("Element::Drawer", 2)?; state.serialize_field("type", "drawer")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::DynBlock { dyn_block, @@ -93,14 +121,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::DynBlock", 2)?; + let mut state = serializer.serialize_struct("Element::DynBlock", 2)?; state.serialize_field("type", "dynamic_block")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::FnDef { begin, @@ -109,14 +133,10 @@ impl Serialize for ElementNode<'_> { contents_end, fn_def, } => { - state = serializer.serialize_struct("Element::FnDef", 2)?; + let mut state = serializer.serialize_struct("Element::FnDef", 2)?; state.serialize_field("type", "footnote_definition")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Headline { begin, @@ -125,7 +145,7 @@ impl Serialize for ElementNode<'_> { contents_end, headline, } => { - state = serializer.serialize_struct("Element::Headline", 2)?; + let mut state = serializer.serialize_struct("Element::Headline", 6)?; state.serialize_field("type", "headline")?; state.serialize_field("level", &headline.level)?; state.serialize_field("title", &headline.title)?; @@ -138,12 +158,8 @@ impl Serialize for ElementNode<'_> { if !headline.tags.is_empty() { state.serialize_field("tags", &headline.tags)?; } - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::List { list, @@ -152,14 +168,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::List", 2)?; + let mut state = serializer.serialize_struct("Element::List", 2)?; state.serialize_field("type", "list")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::ListItem { list_item, @@ -168,15 +180,11 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::ListItem", 2)?; + let mut state = serializer.serialize_struct("Element::ListItem", 3)?; state.serialize_field("type", "list_item")?; state.serialize_field("bullet", list_item.bullet)?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Paragraph { begin, @@ -184,152 +192,157 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Paragraph", 2)?; + let mut state = serializer.serialize_struct("Element::Paragraph", 2)?; state.serialize_field("type", "paragraph")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Clock { clock, begin, end } => { - state = serializer.serialize_struct("Element::Clock", 2)?; + let mut state = serializer.serialize_struct("Element::Clock", 1)?; state.serialize_field("type", "clock")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::BabelCall { call, begin, end } => { - state = serializer.serialize_struct("Element::BabelCall", 2)?; + let mut state = serializer.serialize_struct("Element::BabelCall", 1)?; state.serialize_field("type", "babel_call")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Cookie { cookie, begin, end } => { - state = serializer.serialize_struct("Element::Cookie", 2)?; + let mut state = serializer.serialize_struct("Element::Cookie", 1)?; state.serialize_field("type", "cookie")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::FnRef { fn_ref, begin, end } => { - state = serializer.serialize_struct("Element::FnRef", 2)?; + let mut state = serializer.serialize_struct("Element::FnRef", 1)?; state.serialize_field("type", "footnote_reference")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::InlineCall { inline_call, begin, end, } => { - state = serializer.serialize_struct("Element::InlineCall", 2)?; + let mut state = serializer.serialize_struct("Element::InlineCall", 1)?; state.serialize_field("type", "inline_call")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::InlineSrc { inline_src, begin, end, } => { - state = serializer.serialize_struct("Element::InlineSrc", 2)?; + let mut state = serializer.serialize_struct("Element::InlineSrc", 1)?; state.serialize_field("type", "inlne_source_block")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Keyword { keyword, begin, end, } => { - state = serializer.serialize_struct("Element::Keyword", 2)?; + let mut state = serializer.serialize_struct("Element::Keyword", 4)?; state.serialize_field("type", "keyword")?; state.serialize_field("key", keyword.key)?; if let Some(option) = keyword.option { state.serialize_field("option", option)?; } state.serialize_field("value", keyword.value)?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Link { link, begin, end } => { - state = serializer.serialize_struct("Element::Link", 2)?; + let mut state = serializer.serialize_struct("Element::Link", 3)?; state.serialize_field("type", "link")?; state.serialize_field("path", link.path)?; if let Some(desc) = link.desc { state.serialize_field("desc", desc)?; } - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Macros { macros, begin, end } => { - state = serializer.serialize_struct("Element::Macros", 2)?; + let mut state = serializer.serialize_struct("Element::Macros", 1)?; state.serialize_field("type", "macros")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } - Element::Planning(_) => { - state = serializer.serialize_struct("Element::Planning", 2)?; + Element::Planning { + deadline, + scheduled, + closed, + begin, + end, + } => { + let mut state = serializer.serialize_struct("Element::Planning", 4)?; state.serialize_field("type", "planning")?; + if let Some(node) = deadline { + state.serialize_field( + "deadline", + &ElementNode { + node: *node, + arena: &self.arena, + }, + )?; + } + if let Some(node) = closed { + state.serialize_field( + "closed", + &ElementNode { + node: *node, + arena: &self.arena, + }, + )?; + } + if let Some(node) = scheduled { + state.serialize_field( + "scheduled", + &ElementNode { + node: *node, + arena: &self.arena, + }, + )?; + } + ser!(state, begin, end); + state.end() } Element::Snippet { begin, end, snippet, } => { - state = serializer.serialize_struct("Element::Snippet", 2)?; + let mut state = serializer.serialize_struct("Element::Snippet", 2)?; state.serialize_field("type", "snippet")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Text { value, begin, end } => { - state = serializer.serialize_struct("Element::Text", 2)?; + let mut state = serializer.serialize_struct("Element::Text", 2)?; state.serialize_field("type", "text")?; state.serialize_field("value", value)?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Rule { begin, end } => { - state = serializer.serialize_struct("Element::Rule", 2)?; + let mut state = serializer.serialize_struct("Element::Rule", 1)?; state.serialize_field("type", "rule")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Timestamp { begin, end, timestamp, } => { - state = serializer.serialize_struct("Element::Timestamp", 2)?; + let mut state = serializer.serialize_struct("Element::Timestamp", 1)?; state.serialize_field("type", "timestamp")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Bold { begin, @@ -337,14 +350,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Bold", 2)?; + let mut state = serializer.serialize_struct("Element::Bold", 2)?; state.serialize_field("type", "bold")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Strike { begin, @@ -352,14 +361,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Strike", 2)?; + let mut state = serializer.serialize_struct("Element::Strike", 2)?; state.serialize_field("type", "strike")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Italic { begin, @@ -367,14 +372,10 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Italic", 2)?; + let mut state = serializer.serialize_struct("Element::Italic", 2)?; state.serialize_field("type", "italic")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Underline { begin, @@ -382,64 +383,42 @@ impl Serialize for ElementNode<'_> { contents_begin, contents_end, } => { - state = serializer.serialize_struct("Element::Underline", 2)?; + let mut state = serializer.serialize_struct("Element::Underline", 2)?; state.serialize_field("type", "underline")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - state.serialize_field("contents_begin", contents_begin)?; - state.serialize_field("contents_end", contents_end)?; - } + ser!(state, begin, end, contents_begin, contents_end); + state.end() } Element::Code { begin, end, value } => { - state = serializer.serialize_struct("Element::Code", 2)?; + let mut state = serializer.serialize_struct("Element::Code", 2)?; state.serialize_field("type", "code")?; state.serialize_field("value", value)?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Verbatim { begin, end, value } => { - state = serializer.serialize_struct("Element::Verbatim", 2)?; + let mut state = serializer.serialize_struct("Element::Verbatim", 2)?; state.serialize_field("type", "verbatim")?; state.serialize_field("value", value)?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::RadioTarget { radio_target, begin, end, } => { - state = serializer.serialize_struct("Element::RadioTarget", 2)?; + let mut state = serializer.serialize_struct("Element::RadioTarget", 1)?; state.serialize_field("type", "radio_target")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } Element::Target { target, begin, end } => { - state = serializer.serialize_struct("Element::Target", 2)?; + let mut state = serializer.serialize_struct("Element::Target", 1)?; state.serialize_field("type", "target")?; - if cfg!(feature = "extra-serde-info") { - state.serialize_field("begin", begin)?; - state.serialize_field("end", end)?; - } + ser!(state, begin, end); + state.end() } } - if let Some(first) = self.arena[self.node].first_child() { - state.serialize_field( - "children", - &ElementChildrenNode { - first, - arena: self.arena, - }, - )?; - } - state.end() } } diff --git a/tests/html.rs b/tests/html.rs index 8b3a841..cdf73cb 100644 --- a/tests/html.rs +++ b/tests/html.rs @@ -6,8 +6,7 @@ macro_rules! test_suite { #[test] fn $name() { let mut writer = Vec::new(); - let mut org = Org::new($content); - org.parse(); + let org = Org::parse($content); org.html_default(&mut writer).unwrap(); let string = String::from_utf8(writer).unwrap(); assert_eq!(string, $expected);