diff --git a/Cargo.toml b/Cargo.toml index 7fab393..56f935f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,8 +26,10 @@ indextree = "3.2.0" jetscii = "0.4.4" memchr = "2.2.0" serde = { version = "1.0.94", optional = true, features = ["derive"] } +nom = "5.0.0" [dev-dependencies] +lazy_static = "1.3.0" pretty_assertions = "0.6.1" serde_json = "1.0.39" slugify = "0.1.0" diff --git a/README.md b/README.md index d8c3837..5bd5c6d 100644 --- a/README.md +++ b/README.md @@ -49,14 +49,14 @@ One as `Event::Start(element)`, one as `Event::End(element)`. ## Render html -You can call the `Org::html_default` function to generate html directly, which +You can call the `Org::html` function to generate html directly, which uses the `DefaultHtmlHandler` internally: ```rust use orgize::Org; let mut writer = Vec::new(); -Org::parse("* title\n*section*").html_default(&mut writer).unwrap(); +Org::parse("* title\n*section*").html(&mut writer).unwrap(); assert_eq!( String::from_utf8(writer).unwrap(), @@ -67,7 +67,7 @@ assert_eq!( ## Render html with custom HtmlHandler To customize html rendering, simply implementing `HtmlHandler` trait and passing -it to the `Org::html` function. +it to the `Org::html_with_handler` function. The following code demonstrates how to add a id for every headline and return own error type while rendering. @@ -107,7 +107,7 @@ impl HtmlHandler for MyHtmlHandler { fn start(&mut self, mut w: W, element: &Element<'_>) -> Result<(), MyError> { let mut default_handler = DefaultHtmlHandler; match element { - Element::Headline { headline, .. } => { + Element::Headline(headline) => { if headline.level > 6 { return Err(MyError::Heading); } else { @@ -130,7 +130,7 @@ impl HtmlHandler for MyHtmlHandler { fn main() -> Result<(), MyError> { let mut writer = Vec::new(); - Org::parse("* title\n*section*").html(&mut writer, MyHtmlHandler)?; + Org::parse("* title\n*section*").html_with_handler(&mut writer, MyHtmlHandler)?; assert_eq!( String::from_utf8(writer)?, diff --git a/examples/custom.rs b/examples/custom.rs index a7a798b..fd304aa 100644 --- a/examples/custom.rs +++ b/examples/custom.rs @@ -35,7 +35,7 @@ impl HtmlHandler for MyHtmlHandler { fn start(&mut self, mut w: W, element: &Element<'_>) -> Result<(), MyError> { let mut default_handler = DefaultHtmlHandler; match element { - Element::Headline { headline, .. } => { + Element::Headline(headline) => { if headline.level > 6 { return Err(MyError::Heading); } else { @@ -65,7 +65,7 @@ fn main() -> Result<(), MyError> { let contents = String::from_utf8(fs::read(&args[1])?)?; let mut writer = Vec::new(); - Org::parse(&contents).html(&mut writer, MyHtmlHandler)?; + Org::parse(&contents).html_with_handler(&mut writer, MyHtmlHandler)?; println!("{}", String::from_utf8(writer)?); } diff --git a/src/elements/block.rs b/src/elements/block.rs index 1f334ac..bf5cd9f 100644 --- a/src/elements/block.rs +++ b/src/elements/block.rs @@ -1,5 +1,7 @@ use memchr::{memchr, memchr_iter}; +use crate::elements::Element; + #[cfg_attr(test, derive(PartialEq))] #[cfg_attr(feature = "serde", derive(serde::Serialize))] #[derive(Debug)] @@ -7,12 +9,13 @@ pub struct Block<'a> { pub name: &'a str, #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub args: Option<&'a str>, + #[cfg_attr(all(feature = "serde", not(feature = "extra-serde-info")), serde(skip))] + pub contents: &'a str, } impl Block<'_> { #[inline] - // return (block, contents-begin, contents-end, end) - pub(crate) fn parse(text: &str) -> Option<(Block<'_>, usize, usize, usize)> { + pub(crate) fn parse(text: &str) -> Option<(&str, Element<'_>)> { debug_assert!(text.starts_with("#+")); if text.len() <= 8 || text[2..8].to_uppercase() != "BEGIN_" { @@ -35,14 +38,28 @@ impl Block<'_> { for i in lines { if text[pos..i].trim().eq_ignore_ascii_case(&end) { - return Some((Block { name, args }, off, pos, i + 1)); + return Some(( + &text[i + 1..], + Element::Block(Block { + name, + args, + contents: &text[off..pos], + }), + )); } pos = i + 1; } if text[pos..].trim().eq_ignore_ascii_case(&end) { - Some((Block { name, args }, off, pos, text.len())) + Some(( + "", + Element::Block(Block { + name, + args, + contents: &text[off..pos], + }), + )) } else { None } @@ -54,25 +71,23 @@ fn parse() { assert_eq!( Block::parse("#+BEGIN_SRC\n#+END_SRC"), Some(( - Block { + "", + Element::Block(Block { name: "SRC", args: None, - }, - "#+BEGIN_SRC\n".len(), - "#+BEGIN_SRC\n".len(), - "#+BEGIN_SRC\n#+END_SRC".len() + contents: "" + }), )) ); assert_eq!( Block::parse("#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n#+END_SRC\n"), Some(( - Block { + "", + Element::Block(Block { name: "SRC", args: Some("javascript"), - }, - "#+BEGIN_SRC javascript \n".len(), - "#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n".len(), - "#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n#+END_SRC\n".len() + contents: "console.log('Hello World!');\n" + }), )) ); // TODO: more testing diff --git a/src/elements/clock.rs b/src/elements/clock.rs index cbf622b..4dfaf3e 100644 --- a/src/elements/clock.rs +++ b/src/elements/clock.rs @@ -1,4 +1,4 @@ -use crate::elements::{Datetime, Timestamp}; +use crate::elements::{Date, Element, Time, Timestamp}; use memchr::memchr; /// clock elements @@ -10,26 +10,25 @@ use memchr::memchr; pub enum Clock<'a> { /// closed Clock Closed { - start: Datetime<'a>, - end: Datetime<'a>, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + start_date: Date<'a>, + start_time: Option