diff --git a/src/elements/block.rs b/src/elements/block.rs
index 9cf5df0..8963a2e 100644
--- a/src/elements/block.rs
+++ b/src/elements/block.rs
@@ -1,19 +1,15 @@
use memchr::{memchr, memchr_iter};
-use crate::elements::Element;
-
#[cfg_attr(test, derive(PartialEq))]
-#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[derive(Debug)]
pub struct Block<'a> {
pub name: &'a str,
- #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub args: Option<&'a str>,
}
impl Block<'_> {
#[inline]
- pub(crate) fn parse(text: &str) -> Option<(&str, Element<'_>, &str)> {
+ pub(crate) fn parse(text: &str) -> Option<(&str, Block<'_>, &str)> {
debug_assert!(text.starts_with("#+"));
if text.len() <= 8 || text[2..8].to_uppercase() != "BEGIN_" {
@@ -36,18 +32,14 @@ impl Block<'_> {
for i in lines {
if text[pos..i].trim().eq_ignore_ascii_case(&end) {
- return Some((
- &text[i + 1..],
- Element::Block(Block { name, args }),
- &text[off..pos],
- ));
+ return Some((&text[i + 1..], Block { name, args }, &text[off..pos]));
}
pos = i + 1;
}
if text[pos..].trim().eq_ignore_ascii_case(&end) {
- Some(("", Element::Block(Block { name, args }), &text[off..pos]))
+ Some(("", Block { name, args }, &text[off..pos]))
} else {
None
}
@@ -60,10 +52,10 @@ fn parse() {
Block::parse("#+BEGIN_SRC\n#+END_SRC"),
Some((
"",
- Element::Block(Block {
+ Block {
name: "SRC",
args: None,
- }),
+ },
""
))
);
@@ -71,12 +63,74 @@ fn parse() {
Block::parse("#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n#+END_SRC\n"),
Some((
"",
- Element::Block(Block {
+ Block {
name: "SRC",
args: Some("javascript"),
- }),
+ },
"console.log('Hello World!');\n"
))
);
// TODO: more testing
}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct SpecialBlock<'a> {
+ pub parameters: Option<&'a str>,
+ pub name: &'a str,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct QuoteBlock<'a> {
+ pub parameters: Option<&'a str>,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct CenterBlock<'a> {
+ pub parameters: Option<&'a str>,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct VerseBlock<'a> {
+ pub parameters: Option<&'a str>,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct CommentBlock<'a> {
+ pub data: Option<&'a str>,
+ pub contents: &'a str,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct ExampleBlock<'a> {
+ pub data: Option<&'a str>,
+ pub contents: &'a str,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct ExportBlock<'a> {
+ pub data: &'a str,
+ pub contents: &'a str,
+}
+
+#[derive(Debug)]
+#[cfg_attr(test, derive(PartialEq))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize))]
+pub struct SourceBlock<'a> {
+ pub contents: &'a str,
+ pub language: &'a str,
+ pub arguments: &'a str,
+}
diff --git a/src/elements/cookie.rs b/src/elements/cookie.rs
index 1de7e73..be03e9f 100644
--- a/src/elements/cookie.rs
+++ b/src/elements/cookie.rs
@@ -4,7 +4,7 @@ use memchr::{memchr, memchr2};
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[derive(Debug)]
pub struct Cookie<'a> {
- value: &'a str,
+ pub value: &'a str,
}
impl Cookie<'_> {
diff --git a/src/elements/mod.rs b/src/elements/mod.rs
index 2dfe523..14d636f 100644
--- a/src/elements/mod.rs
+++ b/src/elements/mod.rs
@@ -23,9 +23,13 @@ mod timestamp;
mod title;
pub(crate) use emphasis::parse as parse_emphasis;
+pub(crate) use block::Block;
pub use self::{
- block::Block,
+ block::{
+ CenterBlock, CommentBlock, ExampleBlock, ExportBlock, QuoteBlock, SourceBlock,
+ SpecialBlock, VerseBlock,
+ },
clock::Clock,
cookie::Cookie,
drawer::Drawer,
@@ -53,7 +57,14 @@ pub use self::{
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
pub enum Element<'a> {
- Block(Block<'a>),
+ SpecialBlock(SpecialBlock<'a>),
+ QuoteBlock(QuoteBlock<'a>),
+ CenterBlock(CenterBlock<'a>),
+ VerseBlock(VerseBlock<'a>),
+ CommentBlock(CommentBlock<'a>),
+ ExampleBlock(ExampleBlock<'a>),
+ ExportBlock(ExportBlock<'a>),
+ SourceBlock(SourceBlock<'a>),
BabelCall(BabelCall<'a>),
Section,
Clock(Clock<'a>),
@@ -93,7 +104,10 @@ pub enum Element<'a> {
impl Element<'_> {
pub fn is_container(&self) -> bool {
match self {
- Element::Block(_)
+ Element::SpecialBlock(_)
+ | Element::QuoteBlock(_)
+ | Element::CenterBlock(_)
+ | Element::VerseBlock(_)
| Element::Bold
| Element::Document
| Element::DynBlock(_)
@@ -112,30 +126,50 @@ impl Element<'_> {
}
macro_rules! impl_from {
- ($ident:ident) => {
- impl<'a> From<$ident<'a>> for Element<'a> {
- fn from(ele: $ident<'a>) -> Element<'a> {
- Element::$ident(ele)
+ ($($ele0:ident),*; $($ele1:ident),*) => {
+ $(
+ impl<'a> From<$ele0<'a>> for Element<'a> {
+ fn from(ele: $ele0<'a>) -> Element<'a> {
+ Element::$ele0(ele)
+ }
}
- }
+ )*
+ $(
+ impl<'a> From<$ele1> for Element<'a> {
+ fn from(ele: $ele1) -> Element<'a> {
+ Element::$ele1(ele)
+ }
+ }
+ )*
};
}
-impl_from!(Block);
-impl_from!(BabelCall);
-impl_from!(Clock);
-impl_from!(Cookie);
-impl_from!(Drawer);
-impl_from!(DynBlock);
-impl_from!(FnDef);
-impl_from!(FnRef);
-impl_from!(InlineCall);
-impl_from!(InlineSrc);
-impl_from!(Keyword);
-impl_from!(Link);
-impl_from!(ListItem);
-impl_from!(Macros);
-impl_from!(Planning);
-impl_from!(Snippet);
-impl_from!(Timestamp);
-impl_from!(Target);
+impl_from!(
+ BabelCall,
+ CenterBlock,
+ Clock,
+ CommentBlock,
+ Cookie,
+ Drawer,
+ DynBlock,
+ ExampleBlock,
+ ExportBlock,
+ FnDef,
+ FnRef,
+ InlineCall,
+ InlineSrc,
+ Keyword,
+ Link,
+ ListItem,
+ Macros,
+ Planning,
+ QuoteBlock,
+ Snippet,
+ SourceBlock,
+ SpecialBlock,
+ Target,
+ Timestamp,
+ VerseBlock;
+ RadioTarget,
+ List
+);
diff --git a/src/export/html.rs b/src/export/html.rs
index 6ac4b12..1128510 100644
--- a/src/export/html.rs
+++ b/src/export/html.rs
@@ -34,7 +34,10 @@ pub trait HtmlHandler> {
match element {
// container elements
- Block(_block) => write!(w, "")?,
+ SpecialBlock(_) => (),
+ QuoteBlock(_) => write!(w, "
")?,
+ CenterBlock(_) => write!(w, "")?,
+ VerseBlock(_) => write!(w, "
")?,
Bold => write!(w, "")?,
Document => write!(w, "")?,
DynBlock(_dyn_block) => (),
@@ -53,11 +56,37 @@ pub trait HtmlHandler> {
Strike => write!(w, "")?,
Underline => write!(w, "")?,
// non-container elements
- BabelCall(_babel_call) => (),
- InlineSrc(inline_src) => write!(w, "{}
", Escape(inline_src.body))?,
+ CommentBlock(_) => (),
+ ExampleBlock(block) => {
+ write!(w, "{}
", Escape(block.contents))?
+ }
+ ExportBlock(block) => {
+ if block.data.eq_ignore_ascii_case("HTML") {
+ write!(w, "{}", block.contents)?
+ }
+ }
+ SourceBlock(block) => {
+ if block.language.is_empty() {
+ write!(w, "{}
", Escape(block.contents))?;
+ } else {
+ write!(
+ w,
+ "",
+ block.language,
+ Escape(block.contents)
+ )?;
+ }
+ }
+ BabelCall(_) => (),
+ InlineSrc(inline_src) => write!(
+ w,
+ "{}
",
+ inline_src.lang,
+ Escape(inline_src.body)
+ )?,
Code { value } => write!(w, "{}
", Escape(value))?,
FnRef(_fn_ref) => (),
- InlineCall(_inline_call) => (),
+ InlineCall(_) => (),
Link(link) => write!(
w,
"{}",
@@ -74,16 +103,85 @@ pub trait HtmlHandler> {
}
Target(_target) => (),
Text { value } => write!(w, "{}", Escape(value))?,
- Timestamp(_timestamp) => (),
+ Timestamp(timestamp) => {
+ use crate::elements::{Date, Time, Timestamp::*};
+
+ write!(
+ &mut w,
+ ""
+ )?;
+
+ fn write_datetime(
+ mut w: W,
+ start: &str,
+ date: &Date,
+ time: &Option")?;
+ }
Verbatim { value } => write!(&mut w, "{}
", Escape(value))?,
FnDef(_fn_def) => (),
Clock(_clock) => (),
- Comment { value } => write!(w, "", Escape(value))?,
- FixedWidth { value } => write!(w, "{}
", Escape(value))?,
+ Comment { .. } => (),
+ FixedWidth { value } => write!(w, "{}
", Escape(value))?,
Keyword(_keyword) => (),
Drawer(_drawer) => (),
Rule => write!(w, "
")?,
- Cookie(_cookie) => (),
+ Cookie(cookie) => write!(w, "{}
", cookie.value)?,
Title(title) => write!(w, "", if title.level <= 6 { title.level } else { 6 })?,
}
@@ -94,7 +192,10 @@ pub trait HtmlHandler> {
match element {
// container elements
- Block(_block) => write!(w, "
")?,
+ SpecialBlock(_) => (),
+ QuoteBlock(_) => write!(w, "
")?,
+ CenterBlock(_) => write!(w, "
")?,
+ VerseBlock(_) => write!(w, "
")?,
Bold => write!(w, "")?,
Document => write!(w, "")?,
DynBlock(_dyn_block) => (),
diff --git a/src/export/org.rs b/src/export/org.rs
index 9e3e082..c750576 100644
--- a/src/export/org.rs
+++ b/src/export/org.rs
@@ -7,13 +7,10 @@ pub trait OrgHandler> {
match element {
// container elements
- Block(block) => {
- write!(&mut w, "#+BEGIN_{}", block.name)?;
- if let Some(parameters) = block.args {
- write!(&mut w, " {}", parameters)?;
- }
- writeln!(&mut w)?;
- }
+ SpecialBlock(block) => writeln!(w, "#+BEGIN_{}", block.name)?,
+ QuoteBlock(_) => write!(w, "#+BEGIN_QUOTE")?,
+ CenterBlock(_) => write!(w, "#+BEGIN_CENTER")?,
+ VerseBlock(_) => write!(w, "#+BEGIN_VERSE")?,
Bold => write!(w, "*")?,
Document => (),
DynBlock(dyn_block) => {
@@ -33,6 +30,22 @@ pub trait OrgHandler> {
Underline => write!(w, "_")?,
Drawer(drawer) => writeln!(w, ":{}:", drawer.name)?,
// non-container elements
+ CommentBlock(block) => {
+ writeln!(w, "#+BEGIN_COMMENT\n{}\n#+END_COMMENT", block.contents)?
+ }
+ ExampleBlock(block) => {
+ writeln!(w, "#+BEGIN_EXAMPLE\n{}\n#+END_EXAMPLE", block.contents)?
+ }
+ ExportBlock(block) => writeln!(
+ w,
+ "#+BEGIN_EXPORT {}\n{}\n#+END_EXPORT",
+ block.data, block.contents
+ )?,
+ SourceBlock(block) => writeln!(
+ w,
+ "#+BEGIN_SRC {}\n{}\n#+END_SRC",
+ block.language, block.contents
+ )?,
BabelCall(_babel_call) => (),
InlineSrc(inline_src) => {
write!(&mut w, "src_{}", inline_src.lang)?;
@@ -78,20 +91,23 @@ pub trait OrgHandler> {
Timestamp(timestamp) => {
use crate::elements::{Date, Time, Timestamp::*};
- fn write_date(mut w: W, date: &Date) -> Result<(), Error> {
+ fn write_datetime(
+ mut w: W,
+ start: &str,
+ date: &Date,
+ time: &Option