feat(element): distinguish block by its name
This commit is contained in:
parent
5b9ceebea4
commit
da18d87aeb
|
@ -1,19 +1,15 @@
|
||||||
use memchr::{memchr, memchr_iter};
|
use memchr::{memchr, memchr_iter};
|
||||||
|
|
||||||
use crate::elements::Element;
|
|
||||||
|
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block<'a> {
|
pub struct Block<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
||||||
pub args: Option<&'a str>,
|
pub args: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block<'_> {
|
impl Block<'_> {
|
||||||
#[inline]
|
#[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("#+"));
|
debug_assert!(text.starts_with("#+"));
|
||||||
|
|
||||||
if text.len() <= 8 || text[2..8].to_uppercase() != "BEGIN_" {
|
if text.len() <= 8 || text[2..8].to_uppercase() != "BEGIN_" {
|
||||||
|
@ -36,18 +32,14 @@ impl Block<'_> {
|
||||||
|
|
||||||
for i in lines {
|
for i in lines {
|
||||||
if text[pos..i].trim().eq_ignore_ascii_case(&end) {
|
if text[pos..i].trim().eq_ignore_ascii_case(&end) {
|
||||||
return Some((
|
return Some((&text[i + 1..], Block { name, args }, &text[off..pos]));
|
||||||
&text[i + 1..],
|
|
||||||
Element::Block(Block { name, args }),
|
|
||||||
&text[off..pos],
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = i + 1;
|
pos = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if text[pos..].trim().eq_ignore_ascii_case(&end) {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -60,10 +52,10 @@ fn parse() {
|
||||||
Block::parse("#+BEGIN_SRC\n#+END_SRC"),
|
Block::parse("#+BEGIN_SRC\n#+END_SRC"),
|
||||||
Some((
|
Some((
|
||||||
"",
|
"",
|
||||||
Element::Block(Block {
|
Block {
|
||||||
name: "SRC",
|
name: "SRC",
|
||||||
args: None,
|
args: None,
|
||||||
}),
|
},
|
||||||
""
|
""
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -71,12 +63,74 @@ fn parse() {
|
||||||
Block::parse("#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n#+END_SRC\n"),
|
Block::parse("#+BEGIN_SRC javascript \nconsole.log('Hello World!');\n#+END_SRC\n"),
|
||||||
Some((
|
Some((
|
||||||
"",
|
"",
|
||||||
Element::Block(Block {
|
Block {
|
||||||
name: "SRC",
|
name: "SRC",
|
||||||
args: Some("javascript"),
|
args: Some("javascript"),
|
||||||
}),
|
},
|
||||||
"console.log('Hello World!');\n"
|
"console.log('Hello World!');\n"
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
// TODO: more testing
|
// 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,
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use memchr::{memchr, memchr2};
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Cookie<'a> {
|
pub struct Cookie<'a> {
|
||||||
value: &'a str,
|
pub value: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cookie<'_> {
|
impl Cookie<'_> {
|
||||||
|
|
|
@ -23,9 +23,13 @@ mod timestamp;
|
||||||
mod title;
|
mod title;
|
||||||
|
|
||||||
pub(crate) use emphasis::parse as parse_emphasis;
|
pub(crate) use emphasis::parse as parse_emphasis;
|
||||||
|
pub(crate) use block::Block;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
block::Block,
|
block::{
|
||||||
|
CenterBlock, CommentBlock, ExampleBlock, ExportBlock, QuoteBlock, SourceBlock,
|
||||||
|
SpecialBlock, VerseBlock,
|
||||||
|
},
|
||||||
clock::Clock,
|
clock::Clock,
|
||||||
cookie::Cookie,
|
cookie::Cookie,
|
||||||
drawer::Drawer,
|
drawer::Drawer,
|
||||||
|
@ -53,7 +57,14 @@ pub use self::{
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
|
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
|
||||||
pub enum Element<'a> {
|
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>),
|
BabelCall(BabelCall<'a>),
|
||||||
Section,
|
Section,
|
||||||
Clock(Clock<'a>),
|
Clock(Clock<'a>),
|
||||||
|
@ -93,7 +104,10 @@ pub enum Element<'a> {
|
||||||
impl Element<'_> {
|
impl Element<'_> {
|
||||||
pub fn is_container(&self) -> bool {
|
pub fn is_container(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Element::Block(_)
|
Element::SpecialBlock(_)
|
||||||
|
| Element::QuoteBlock(_)
|
||||||
|
| Element::CenterBlock(_)
|
||||||
|
| Element::VerseBlock(_)
|
||||||
| Element::Bold
|
| Element::Bold
|
||||||
| Element::Document
|
| Element::Document
|
||||||
| Element::DynBlock(_)
|
| Element::DynBlock(_)
|
||||||
|
@ -112,30 +126,50 @@ impl Element<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_from {
|
macro_rules! impl_from {
|
||||||
($ident:ident) => {
|
($($ele0:ident),*; $($ele1:ident),*) => {
|
||||||
impl<'a> From<$ident<'a>> for Element<'a> {
|
$(
|
||||||
fn from(ele: $ident<'a>) -> Element<'a> {
|
impl<'a> From<$ele0<'a>> for Element<'a> {
|
||||||
Element::$ident(ele)
|
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!(
|
||||||
impl_from!(BabelCall);
|
BabelCall,
|
||||||
impl_from!(Clock);
|
CenterBlock,
|
||||||
impl_from!(Cookie);
|
Clock,
|
||||||
impl_from!(Drawer);
|
CommentBlock,
|
||||||
impl_from!(DynBlock);
|
Cookie,
|
||||||
impl_from!(FnDef);
|
Drawer,
|
||||||
impl_from!(FnRef);
|
DynBlock,
|
||||||
impl_from!(InlineCall);
|
ExampleBlock,
|
||||||
impl_from!(InlineSrc);
|
ExportBlock,
|
||||||
impl_from!(Keyword);
|
FnDef,
|
||||||
impl_from!(Link);
|
FnRef,
|
||||||
impl_from!(ListItem);
|
InlineCall,
|
||||||
impl_from!(Macros);
|
InlineSrc,
|
||||||
impl_from!(Planning);
|
Keyword,
|
||||||
impl_from!(Snippet);
|
Link,
|
||||||
impl_from!(Timestamp);
|
ListItem,
|
||||||
impl_from!(Target);
|
Macros,
|
||||||
|
Planning,
|
||||||
|
QuoteBlock,
|
||||||
|
Snippet,
|
||||||
|
SourceBlock,
|
||||||
|
SpecialBlock,
|
||||||
|
Target,
|
||||||
|
Timestamp,
|
||||||
|
VerseBlock;
|
||||||
|
RadioTarget,
|
||||||
|
List
|
||||||
|
);
|
||||||
|
|
|
@ -34,7 +34,10 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
|
|
||||||
match element {
|
match element {
|
||||||
// container elements
|
// container elements
|
||||||
Block(_block) => write!(w, "<div>")?,
|
SpecialBlock(_) => (),
|
||||||
|
QuoteBlock(_) => write!(w, "<blockquote>")?,
|
||||||
|
CenterBlock(_) => write!(w, "<div class=\"center\">")?,
|
||||||
|
VerseBlock(_) => write!(w, "<p class=\"verse\">")?,
|
||||||
Bold => write!(w, "<b>")?,
|
Bold => write!(w, "<b>")?,
|
||||||
Document => write!(w, "<main>")?,
|
Document => write!(w, "<main>")?,
|
||||||
DynBlock(_dyn_block) => (),
|
DynBlock(_dyn_block) => (),
|
||||||
|
@ -53,11 +56,37 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
Strike => write!(w, "<s>")?,
|
Strike => write!(w, "<s>")?,
|
||||||
Underline => write!(w, "<u>")?,
|
Underline => write!(w, "<u>")?,
|
||||||
// non-container elements
|
// non-container elements
|
||||||
BabelCall(_babel_call) => (),
|
CommentBlock(_) => (),
|
||||||
InlineSrc(inline_src) => write!(w, "<code>{}</code>", Escape(inline_src.body))?,
|
ExampleBlock(block) => {
|
||||||
|
write!(w, "<pre class=\"example\">{}</pre>", 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, "<pre class=\"example\">{}</pre>", Escape(block.contents))?;
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
w,
|
||||||
|
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
||||||
|
block.language,
|
||||||
|
Escape(block.contents)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BabelCall(_) => (),
|
||||||
|
InlineSrc(inline_src) => write!(
|
||||||
|
w,
|
||||||
|
"<code class=\"src src-{}\">{}</code>",
|
||||||
|
inline_src.lang,
|
||||||
|
Escape(inline_src.body)
|
||||||
|
)?,
|
||||||
Code { value } => write!(w, "<code>{}</code>", Escape(value))?,
|
Code { value } => write!(w, "<code>{}</code>", Escape(value))?,
|
||||||
FnRef(_fn_ref) => (),
|
FnRef(_fn_ref) => (),
|
||||||
InlineCall(_inline_call) => (),
|
InlineCall(_) => (),
|
||||||
Link(link) => write!(
|
Link(link) => write!(
|
||||||
w,
|
w,
|
||||||
"<a href=\"{}\">{}</a>",
|
"<a href=\"{}\">{}</a>",
|
||||||
|
@ -74,16 +103,85 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
}
|
}
|
||||||
Target(_target) => (),
|
Target(_target) => (),
|
||||||
Text { value } => write!(w, "{}", Escape(value))?,
|
Text { value } => write!(w, "{}", Escape(value))?,
|
||||||
Timestamp(_timestamp) => (),
|
Timestamp(timestamp) => {
|
||||||
|
use crate::elements::{Date, Time, Timestamp::*};
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut w,
|
||||||
|
"<span class=\"timestamp-wrapper\"><span class=\"timestamp\">"
|
||||||
|
)?;
|
||||||
|
|
||||||
|
fn write_datetime<W: Write>(
|
||||||
|
mut w: W,
|
||||||
|
start: &str,
|
||||||
|
date: &Date,
|
||||||
|
time: &Option<Time>,
|
||||||
|
end: &str,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
write!(w, "{}", start)?;
|
||||||
|
write!(
|
||||||
|
w,
|
||||||
|
"{}-{}-{} {}",
|
||||||
|
date.year,
|
||||||
|
date.month,
|
||||||
|
date.day,
|
||||||
|
Escape(date.dayname)
|
||||||
|
)?;
|
||||||
|
if let Some(time) = time {
|
||||||
|
write!(w, " {}:{}", time.hour, time.minute)?;
|
||||||
|
}
|
||||||
|
write!(w, "{}", end)
|
||||||
|
}
|
||||||
|
|
||||||
|
match timestamp {
|
||||||
|
Active {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write_datetime(&mut w, "<", start_date, start_time, ">")?;
|
||||||
|
}
|
||||||
|
Inactive {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write_datetime(&mut w, "[", start_date, start_time, "]")?;
|
||||||
|
}
|
||||||
|
ActiveRange {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
end_date,
|
||||||
|
end_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write_datetime(&mut w, "<", start_date, start_time, ">–")?;
|
||||||
|
write_datetime(&mut w, "<", end_date, end_time, ">")?;
|
||||||
|
}
|
||||||
|
InactiveRange {
|
||||||
|
start_date,
|
||||||
|
start_time,
|
||||||
|
end_date,
|
||||||
|
end_time,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
write_datetime(&mut w, "[", start_date, start_time, "]–")?;
|
||||||
|
write_datetime(&mut w, "[", end_date, end_time, "]")?;
|
||||||
|
}
|
||||||
|
Diary(value) => write!(&mut w, "<%%({})>", Escape(value))?,
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(&mut w, "</span></span>")?;
|
||||||
|
}
|
||||||
Verbatim { value } => write!(&mut w, "<code>{}</code>", Escape(value))?,
|
Verbatim { value } => write!(&mut w, "<code>{}</code>", Escape(value))?,
|
||||||
FnDef(_fn_def) => (),
|
FnDef(_fn_def) => (),
|
||||||
Clock(_clock) => (),
|
Clock(_clock) => (),
|
||||||
Comment { value } => write!(w, "<!--\n{}\n-->", Escape(value))?,
|
Comment { .. } => (),
|
||||||
FixedWidth { value } => write!(w, "<pre>{}</pre>", Escape(value))?,
|
FixedWidth { value } => write!(w, "<pre class=\"example\">{}</pre>", Escape(value))?,
|
||||||
Keyword(_keyword) => (),
|
Keyword(_keyword) => (),
|
||||||
Drawer(_drawer) => (),
|
Drawer(_drawer) => (),
|
||||||
Rule => write!(w, "<hr>")?,
|
Rule => write!(w, "<hr>")?,
|
||||||
Cookie(_cookie) => (),
|
Cookie(cookie) => write!(w, "<code>{}</code>", cookie.value)?,
|
||||||
Title(title) => write!(w, "<h{}>", if title.level <= 6 { title.level } else { 6 })?,
|
Title(title) => write!(w, "<h{}>", if title.level <= 6 { title.level } else { 6 })?,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +192,10 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
|
|
||||||
match element {
|
match element {
|
||||||
// container elements
|
// container elements
|
||||||
Block(_block) => write!(w, "</div>")?,
|
SpecialBlock(_) => (),
|
||||||
|
QuoteBlock(_) => write!(w, "</blockquote>")?,
|
||||||
|
CenterBlock(_) => write!(w, "</div>")?,
|
||||||
|
VerseBlock(_) => write!(w, "</p>")?,
|
||||||
Bold => write!(w, "</b>")?,
|
Bold => write!(w, "</b>")?,
|
||||||
Document => write!(w, "</main>")?,
|
Document => write!(w, "</main>")?,
|
||||||
DynBlock(_dyn_block) => (),
|
DynBlock(_dyn_block) => (),
|
||||||
|
|
|
@ -7,13 +7,10 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
|
|
||||||
match element {
|
match element {
|
||||||
// container elements
|
// container elements
|
||||||
Block(block) => {
|
SpecialBlock(block) => writeln!(w, "#+BEGIN_{}", block.name)?,
|
||||||
write!(&mut w, "#+BEGIN_{}", block.name)?;
|
QuoteBlock(_) => write!(w, "#+BEGIN_QUOTE")?,
|
||||||
if let Some(parameters) = block.args {
|
CenterBlock(_) => write!(w, "#+BEGIN_CENTER")?,
|
||||||
write!(&mut w, " {}", parameters)?;
|
VerseBlock(_) => write!(w, "#+BEGIN_VERSE")?,
|
||||||
}
|
|
||||||
writeln!(&mut w)?;
|
|
||||||
}
|
|
||||||
Bold => write!(w, "*")?,
|
Bold => write!(w, "*")?,
|
||||||
Document => (),
|
Document => (),
|
||||||
DynBlock(dyn_block) => {
|
DynBlock(dyn_block) => {
|
||||||
|
@ -33,6 +30,22 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
Underline => write!(w, "_")?,
|
Underline => write!(w, "_")?,
|
||||||
Drawer(drawer) => writeln!(w, ":{}:", drawer.name)?,
|
Drawer(drawer) => writeln!(w, ":{}:", drawer.name)?,
|
||||||
// non-container elements
|
// 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) => (),
|
BabelCall(_babel_call) => (),
|
||||||
InlineSrc(inline_src) => {
|
InlineSrc(inline_src) => {
|
||||||
write!(&mut w, "src_{}", inline_src.lang)?;
|
write!(&mut w, "src_{}", inline_src.lang)?;
|
||||||
|
@ -78,20 +91,23 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
Timestamp(timestamp) => {
|
Timestamp(timestamp) => {
|
||||||
use crate::elements::{Date, Time, Timestamp::*};
|
use crate::elements::{Date, Time, Timestamp::*};
|
||||||
|
|
||||||
fn write_date<W: Write>(mut w: W, date: &Date) -> Result<(), Error> {
|
fn write_datetime<W: Write>(
|
||||||
|
mut w: W,
|
||||||
|
start: &str,
|
||||||
|
date: &Date,
|
||||||
|
time: &Option<Time>,
|
||||||
|
end: &str,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
write!(w, "{}", start)?;
|
||||||
write!(
|
write!(
|
||||||
w,
|
w,
|
||||||
"{}-{}-{} {}",
|
"{}-{}-{} {}",
|
||||||
date.year, date.month, date.day, date.dayname
|
date.year, date.month, date.day, date.dayname
|
||||||
)
|
)?;
|
||||||
}
|
|
||||||
|
|
||||||
fn write_time<W: Write>(mut w: W, time: &Option<Time>) -> Result<(), Error> {
|
|
||||||
if let Some(time) = time {
|
if let Some(time) = time {
|
||||||
write!(w, " {}:{}", time.hour, time.minute)
|
write!(w, " {}:{}", time.hour, time.minute,)?;
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
write!(w, "{}", end)
|
||||||
}
|
}
|
||||||
|
|
||||||
match timestamp {
|
match timestamp {
|
||||||
|
@ -100,20 +116,14 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
start_time,
|
start_time,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
write!(&mut w, "<")?;
|
write_datetime(&mut w, "<", start_date, start_time, ">")?;
|
||||||
write_date(&mut w, start_date)?;
|
|
||||||
write_time(&mut w, start_time)?;
|
|
||||||
write!(&mut w, ">")?;
|
|
||||||
}
|
}
|
||||||
Inactive {
|
Inactive {
|
||||||
start_date,
|
start_date,
|
||||||
start_time,
|
start_time,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
write!(&mut w, "[")?;
|
write_datetime(&mut w, "[", start_date, start_time, "]")?;
|
||||||
write_date(&mut w, start_date)?;
|
|
||||||
write_time(&mut w, start_time)?;
|
|
||||||
write!(&mut w, "]")?;
|
|
||||||
}
|
}
|
||||||
ActiveRange {
|
ActiveRange {
|
||||||
start_date,
|
start_date,
|
||||||
|
@ -122,13 +132,8 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
end_time,
|
end_time,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
write!(&mut w, "<")?;
|
write_datetime(&mut w, "<", start_date, start_time, ">--")?;
|
||||||
write_date(&mut w, start_date)?;
|
write_datetime(&mut w, "<", end_date, end_time, ">")?;
|
||||||
write_time(&mut w, start_time)?;
|
|
||||||
write!(&mut w, ">--<")?;
|
|
||||||
write_date(&mut w, end_date)?;
|
|
||||||
write_time(&mut w, end_time)?;
|
|
||||||
write!(&mut w, ">")?;
|
|
||||||
}
|
}
|
||||||
InactiveRange {
|
InactiveRange {
|
||||||
start_date,
|
start_date,
|
||||||
|
@ -137,13 +142,8 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
end_time,
|
end_time,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
write!(&mut w, "[")?;
|
write_datetime(&mut w, "[", start_date, start_time, "]--")?;
|
||||||
write_date(&mut w, start_date)?;
|
write_datetime(&mut w, "[", end_date, end_time, "]")?;
|
||||||
write_time(&mut w, start_time)?;
|
|
||||||
write!(&mut w, "]--[")?;
|
|
||||||
write_date(&mut w, end_date)?;
|
|
||||||
write_time(&mut w, end_time)?;
|
|
||||||
write!(&mut w, "]")?;
|
|
||||||
}
|
}
|
||||||
Diary(value) => write!(w, "<%%({})>", value)?,
|
Diary(value) => write!(w, "<%%({})>", value)?,
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,10 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
|
|
||||||
match element {
|
match element {
|
||||||
// container elements
|
// container elements
|
||||||
Block(block) => writeln!(w, "#+END_{}", block.name)?,
|
SpecialBlock(block) => writeln!(w, "#+END_{}", block.name)?,
|
||||||
|
QuoteBlock(_) => writeln!(w, "#+END_QUOTE")?,
|
||||||
|
CenterBlock(_) => writeln!(w, "#+END_CENTER")?,
|
||||||
|
VerseBlock(_) => writeln!(w, "#+END_VERSE")?,
|
||||||
Bold => write!(w, "*")?,
|
Bold => write!(w, "*")?,
|
||||||
Document => (),
|
Document => (),
|
||||||
DynBlock(_dyn_block) => writeln!(w, "#+END:")?,
|
DynBlock(_dyn_block) => writeln!(w, "#+END:")?,
|
||||||
|
|
77
src/org.rs
77
src/org.rs
|
@ -315,12 +315,12 @@ fn parse_block<'a>(
|
||||||
let mut last_end = 1; // ":"
|
let mut last_end = 1; // ":"
|
||||||
for i in memchr_iter(b'\n', contents.as_bytes()) {
|
for i in memchr_iter(b'\n', contents.as_bytes()) {
|
||||||
last_end = i + 1;
|
last_end = i + 1;
|
||||||
let line = &contents[last_end..];
|
let tail = contents[last_end..].trim_start();
|
||||||
if !(line == ":" || line.starts_with(": ") || line.starts_with(":\n")) {
|
if !(tail == ":" || tail.starts_with(": ") || tail.starts_with(":\n")) {
|
||||||
let fixed_width = arena.new_node(Element::FixedWidth {
|
let fixed_width = arena.new_node(Element::FixedWidth {
|
||||||
value: &contents[0..i + 1],
|
value: &contents[0..last_end],
|
||||||
});
|
});
|
||||||
return Some((&contents[i + 1..], fixed_width));
|
return Some((&contents[last_end..], fixed_width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let fixed_width = arena.new_node(Element::FixedWidth {
|
let fixed_width = arena.new_node(Element::FixedWidth {
|
||||||
|
@ -334,12 +334,12 @@ fn parse_block<'a>(
|
||||||
let mut last_end = 1; // "#"
|
let mut last_end = 1; // "#"
|
||||||
for i in memchr_iter(b'\n', contents.as_bytes()) {
|
for i in memchr_iter(b'\n', contents.as_bytes()) {
|
||||||
last_end = i + 1;
|
last_end = i + 1;
|
||||||
let line = &contents[last_end..];
|
let line = contents[last_end..].trim_start();
|
||||||
if !(line == "#" || line.starts_with("# ") || line.starts_with("#\n")) {
|
if !(line == "#" || line.starts_with("# ") || line.starts_with("#\n")) {
|
||||||
let comment = arena.new_node(Element::Comment {
|
let comment = arena.new_node(Element::Comment {
|
||||||
value: &contents[0..i + 1],
|
value: &contents[0..last_end],
|
||||||
});
|
});
|
||||||
return Some((&contents[i + 1..], comment));
|
return Some((&contents[last_end..], comment));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let comment = arena.new_node(Element::Comment {
|
let comment = arena.new_node(Element::Comment {
|
||||||
|
@ -350,9 +350,70 @@ fn parse_block<'a>(
|
||||||
|
|
||||||
if tail.starts_with("#+") {
|
if tail.starts_with("#+") {
|
||||||
if let Some((tail, block, content)) = Block::parse(tail) {
|
if let Some((tail, block, content)) = Block::parse(tail) {
|
||||||
let node = arena.new_node(block);
|
match &*block.name.to_uppercase() {
|
||||||
|
"CENTER" => {
|
||||||
|
let node = arena.new_node(Element::CenterBlock(CenterBlock {
|
||||||
|
parameters: block.args,
|
||||||
|
}));
|
||||||
containers.push(Container::Block { content, node });
|
containers.push(Container::Block { content, node });
|
||||||
Some((tail, node))
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
"QUOTE" => {
|
||||||
|
let node = arena.new_node(Element::QuoteBlock(QuoteBlock {
|
||||||
|
parameters: block.args,
|
||||||
|
}));
|
||||||
|
containers.push(Container::Block { content, node });
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
"COMMENT" => {
|
||||||
|
let node = arena.new_node(Element::CommentBlock(CommentBlock {
|
||||||
|
data: block.args,
|
||||||
|
contents: content,
|
||||||
|
}));
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
"EXAMPLE" => {
|
||||||
|
let node = arena.new_node(Element::ExampleBlock(ExampleBlock {
|
||||||
|
data: block.args,
|
||||||
|
contents: content,
|
||||||
|
}));
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
"EXPORT" => {
|
||||||
|
let node = arena.new_node(Element::ExportBlock(ExportBlock {
|
||||||
|
data: block.args.unwrap_or(""),
|
||||||
|
contents: content,
|
||||||
|
}));
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
"SRC" => {
|
||||||
|
let (language, arguments) = block
|
||||||
|
.args
|
||||||
|
.map(|args| args.split_at(args.find(' ').unwrap_or_else(|| args.len())))
|
||||||
|
.unwrap_or(("", ""));
|
||||||
|
let node = arena.new_node(Element::SourceBlock(SourceBlock {
|
||||||
|
arguments,
|
||||||
|
language,
|
||||||
|
contents: content,
|
||||||
|
}));
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
"VERSE" => {
|
||||||
|
let node = arena.new_node(Element::VerseBlock(VerseBlock {
|
||||||
|
parameters: block.args,
|
||||||
|
}));
|
||||||
|
containers.push(Container::Block { content, node });
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let node = arena.new_node(Element::SpecialBlock(SpecialBlock {
|
||||||
|
parameters: block.args,
|
||||||
|
name: block.name,
|
||||||
|
}));
|
||||||
|
containers.push(Container::Block { content, node });
|
||||||
|
Some((tail, node))
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if let Some((tail, dyn_block, content)) = DynBlock::parse(tail) {
|
} else if let Some((tail, dyn_block, content)) = DynBlock::parse(tail) {
|
||||||
let node = arena.new_node(dyn_block);
|
let node = arena.new_node(dyn_block);
|
||||||
containers.push(Container::Block { content, node });
|
containers.push(Container::Block { content, node });
|
||||||
|
|
Loading…
Reference in a new issue