feat(elements): wrap up every &str with Cow
This commit is contained in:
parent
54c063f41b
commit
a1af0663b5
|
@ -42,7 +42,7 @@ impl HtmlHandler<MyError> for MyHtmlHandler {
|
||||||
w,
|
w,
|
||||||
"<h{0}><a id=\"{1}\" href=\"#{1}\">",
|
"<h{0}><a id=\"{1}\" href=\"#{1}\">",
|
||||||
title.level,
|
title.level,
|
||||||
slugify!(title.raw),
|
slugify!(&title.raw),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl HtmlHandler<Error> for SyntectHtmlHandler {
|
||||||
Element::InlineSrc(inline_src) => write!(
|
Element::InlineSrc(inline_src) => write!(
|
||||||
w,
|
w,
|
||||||
"<code>{}</code>",
|
"<code>{}</code>",
|
||||||
self.highlight(Some(inline_src.lang), inline_src.body)
|
self.highlight(Some(&inline_src.lang), &inline_src.body)
|
||||||
)?,
|
)?,
|
||||||
Element::SourceBlock(block) => {
|
Element::SourceBlock(block) => {
|
||||||
if block.language.is_empty() {
|
if block.language.is_empty() {
|
||||||
|
@ -56,7 +56,7 @@ impl HtmlHandler<Error> for SyntectHtmlHandler {
|
||||||
w,
|
w,
|
||||||
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
||||||
block.language,
|
block.language,
|
||||||
self.highlight(Some(block.language), block.contents)
|
self.highlight(Some(&block.language), &block.contents)
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ impl HtmlHandler<Error> for SyntectHtmlHandler {
|
||||||
Element::ExampleBlock(block) => write!(
|
Element::ExampleBlock(block) => write!(
|
||||||
w,
|
w,
|
||||||
"<pre class=\"example\">{}</pre>",
|
"<pre class=\"example\">{}</pre>",
|
||||||
self.highlight(None, block.contents)
|
self.highlight(None, &block.contents)
|
||||||
)?,
|
)?,
|
||||||
_ => self.default_hanlder.start(w, element)?,
|
_ => self.default_hanlder.start(w, element)?,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{bytes::complete::tag_no_case, character::complete::alpha1, sequence::preceded, IResult};
|
use nom::{bytes::complete::tag_no_case, character::complete::alpha1, sequence::preceded, IResult};
|
||||||
|
|
||||||
use crate::parsers::{take_lines_till, take_until_eol};
|
use crate::parsers::{take_lines_till, take_until_eol};
|
||||||
|
@ -5,8 +7,8 @@ use crate::parsers::{take_lines_till, take_until_eol};
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block<'a> {
|
pub struct Block<'a> {
|
||||||
pub name: &'a str,
|
pub name: Cow<'a, str>,
|
||||||
pub args: Option<&'a str>,
|
pub args: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block<'_> {
|
impl Block<'_> {
|
||||||
|
@ -22,8 +24,12 @@ impl Block<'_> {
|
||||||
input,
|
input,
|
||||||
(
|
(
|
||||||
Block {
|
Block {
|
||||||
name,
|
name: name.into(),
|
||||||
args: if args.is_empty() { None } else { Some(args) },
|
args: if args.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(args.into())
|
||||||
|
},
|
||||||
},
|
},
|
||||||
contents,
|
contents,
|
||||||
),
|
),
|
||||||
|
@ -39,7 +45,7 @@ fn parse() {
|
||||||
"",
|
"",
|
||||||
(
|
(
|
||||||
Block {
|
Block {
|
||||||
name: "SRC",
|
name: "SRC".into(),
|
||||||
args: None,
|
args: None,
|
||||||
},
|
},
|
||||||
""
|
""
|
||||||
|
@ -52,8 +58,8 @@ fn parse() {
|
||||||
"",
|
"",
|
||||||
(
|
(
|
||||||
Block {
|
Block {
|
||||||
name: "SRC",
|
name: "SRC".into(),
|
||||||
args: Some("javascript"),
|
args: Some("javascript".into()),
|
||||||
},
|
},
|
||||||
"console.log('Hello World!');\n"
|
"console.log('Hello World!');\n"
|
||||||
)
|
)
|
||||||
|
@ -66,60 +72,60 @@ fn parse() {
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct SpecialBlock<'a> {
|
pub struct SpecialBlock<'a> {
|
||||||
pub parameters: Option<&'a str>,
|
pub parameters: Option<Cow<'a, str>>,
|
||||||
pub name: &'a str,
|
pub name: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct QuoteBlock<'a> {
|
pub struct QuoteBlock<'a> {
|
||||||
pub parameters: Option<&'a str>,
|
pub parameters: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct CenterBlock<'a> {
|
pub struct CenterBlock<'a> {
|
||||||
pub parameters: Option<&'a str>,
|
pub parameters: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct VerseBlock<'a> {
|
pub struct VerseBlock<'a> {
|
||||||
pub parameters: Option<&'a str>,
|
pub parameters: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct CommentBlock<'a> {
|
pub struct CommentBlock<'a> {
|
||||||
pub data: Option<&'a str>,
|
pub data: Option<Cow<'a, str>>,
|
||||||
pub contents: &'a str,
|
pub contents: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct ExampleBlock<'a> {
|
pub struct ExampleBlock<'a> {
|
||||||
pub data: Option<&'a str>,
|
pub data: Option<Cow<'a, str>>,
|
||||||
pub contents: &'a str,
|
pub contents: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct ExportBlock<'a> {
|
pub struct ExportBlock<'a> {
|
||||||
pub data: &'a str,
|
pub data: Cow<'a, str>,
|
||||||
pub contents: &'a str,
|
pub contents: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
pub struct SourceBlock<'a> {
|
pub struct SourceBlock<'a> {
|
||||||
pub contents: &'a str,
|
pub contents: Cow<'a, str>,
|
||||||
pub language: &'a str,
|
pub language: Cow<'a, str>,
|
||||||
pub arguments: &'a str,
|
pub arguments: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::tag,
|
bytes::complete::tag,
|
||||||
character::complete::{char, digit1, space0},
|
character::complete::{char, digit1, space0},
|
||||||
combinator::{peek, recognize},
|
combinator::recognize,
|
||||||
sequence::separated_pair,
|
sequence::separated_pair,
|
||||||
IResult,
|
IResult,
|
||||||
};
|
};
|
||||||
|
@ -22,18 +24,18 @@ pub enum Clock<'a> {
|
||||||
start: Datetime<'a>,
|
start: Datetime<'a>,
|
||||||
end: Datetime<'a>,
|
end: Datetime<'a>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
repeater: Option<&'a str>,
|
repeater: Option<Cow<'a, str>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
delay: Option<&'a str>,
|
delay: Option<Cow<'a, str>>,
|
||||||
duration: &'a str,
|
duration: Cow<'a, str>,
|
||||||
},
|
},
|
||||||
/// running Clock
|
/// running Clock
|
||||||
Running {
|
Running {
|
||||||
start: Datetime<'a>,
|
start: Datetime<'a>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
repeater: Option<&'a str>,
|
repeater: Option<Cow<'a, str>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
delay: Option<&'a str>,
|
delay: Option<Cow<'a, str>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +43,6 @@ impl Clock<'_> {
|
||||||
pub(crate) fn parse(input: &str) -> IResult<&str, Element<'_>> {
|
pub(crate) fn parse(input: &str) -> IResult<&str, Element<'_>> {
|
||||||
let (input, _) = tag("CLOCK:")(input)?;
|
let (input, _) = tag("CLOCK:")(input)?;
|
||||||
let (input, _) = space0(input)?;
|
let (input, _) = space0(input)?;
|
||||||
let (input, _) = peek(tag("["))(input)?;
|
|
||||||
let (input, timestamp) = Timestamp::parse_inactive(input)?;
|
let (input, timestamp) = Timestamp::parse_inactive(input)?;
|
||||||
|
|
||||||
match timestamp {
|
match timestamp {
|
||||||
|
@ -64,7 +65,7 @@ impl Clock<'_> {
|
||||||
end,
|
end,
|
||||||
repeater,
|
repeater,
|
||||||
delay,
|
delay,
|
||||||
duration,
|
duration: duration.into(),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -83,7 +84,9 @@ impl Clock<'_> {
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(
|
||||||
|
"`Timestamp::parse_inactive` only returns `Timestamp::InactiveRange` or `Timestamp::Inactive`."
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +153,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(9),
|
hour: Some(9),
|
||||||
minute: Some(39)
|
minute: Some(39)
|
||||||
},
|
},
|
||||||
|
@ -168,7 +171,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(9),
|
hour: Some(9),
|
||||||
minute: Some(39)
|
minute: Some(39)
|
||||||
},
|
},
|
||||||
|
@ -176,13 +179,13 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(10),
|
hour: Some(10),
|
||||||
minute: Some(39)
|
minute: Some(39)
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None,
|
delay: None,
|
||||||
duration: "1:00",
|
duration: "1:00".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
branch::alt,
|
branch::alt,
|
||||||
bytes::complete::tag,
|
bytes::complete::tag,
|
||||||
|
@ -11,7 +13,7 @@ use nom::{
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Cookie<'a> {
|
pub struct Cookie<'a> {
|
||||||
pub value: &'a str,
|
pub value: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cookie<'_> {
|
impl Cookie<'_> {
|
||||||
|
@ -26,7 +28,12 @@ impl Cookie<'_> {
|
||||||
tag("]"),
|
tag("]"),
|
||||||
))(input)?;
|
))(input)?;
|
||||||
|
|
||||||
Ok((input, Cookie { value }))
|
Ok((
|
||||||
|
input,
|
||||||
|
Cookie {
|
||||||
|
value: value.into(),
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,22 +41,66 @@ impl Cookie<'_> {
|
||||||
fn parse() {
|
fn parse() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Cookie::parse("[1/10]"),
|
Cookie::parse("[1/10]"),
|
||||||
Ok(("", Cookie { value: "[1/10]" }))
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[1/10]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Cookie::parse("[1/1000]"),
|
Cookie::parse("[1/1000]"),
|
||||||
Ok(("", Cookie { value: "[1/1000]" }))
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[1/1000]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Cookie::parse("[10%]"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[10%]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Cookie::parse("[%]"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[%]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Cookie::parse("[/]"),
|
||||||
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[/]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(Cookie::parse("[10%]"), Ok(("", Cookie { value: "[10%]" })));
|
|
||||||
assert_eq!(Cookie::parse("[%]"), Ok(("", Cookie { value: "[%]" })));
|
|
||||||
assert_eq!(Cookie::parse("[/]"), Ok(("", Cookie { value: "[/]" })));
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Cookie::parse("[100/]"),
|
Cookie::parse("[100/]"),
|
||||||
Ok(("", Cookie { value: "[100/]" }))
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[100/]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Cookie::parse("[/100]"),
|
Cookie::parse("[/100]"),
|
||||||
Ok(("", Cookie { value: "[/100]" }))
|
Ok((
|
||||||
|
"",
|
||||||
|
Cookie {
|
||||||
|
value: "[/100]".into()
|
||||||
|
}
|
||||||
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Cookie::parse("[10% ]").is_err());
|
assert!(Cookie::parse("[10% ]").is_err());
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::parsers::{eol, take_lines_till};
|
use crate::parsers::{eol, take_lines_till};
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
|
@ -10,7 +12,7 @@ use nom::{
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Drawer<'a> {
|
pub struct Drawer<'a> {
|
||||||
pub name: &'a str,
|
pub name: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drawer<'_> {
|
impl Drawer<'_> {
|
||||||
|
@ -24,7 +26,7 @@ impl Drawer<'_> {
|
||||||
let (input, _) = eol(input)?;
|
let (input, _) = eol(input)?;
|
||||||
let (input, contents) = take_lines_till(|line| line.eq_ignore_ascii_case(":END:"))(input)?;
|
let (input, contents) = take_lines_till(|line| line.eq_ignore_ascii_case(":END:"))(input)?;
|
||||||
|
|
||||||
Ok((input, (Drawer { name }, contents)))
|
Ok((input, (Drawer { name: name.into() }, contents)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +34,14 @@ impl Drawer<'_> {
|
||||||
fn parse() {
|
fn parse() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Drawer::parse(":PROPERTIES:\n :CUSTOM_ID: id\n :END:"),
|
Drawer::parse(":PROPERTIES:\n :CUSTOM_ID: id\n :END:"),
|
||||||
Ok(("", (Drawer { name: "PROPERTIES" }, " :CUSTOM_ID: id\n")))
|
Ok((
|
||||||
|
"",
|
||||||
|
(
|
||||||
|
Drawer {
|
||||||
|
name: "PROPERTIES".into()
|
||||||
|
},
|
||||||
|
" :CUSTOM_ID: id\n"
|
||||||
|
)
|
||||||
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::elements::Element;
|
use crate::elements::Element;
|
||||||
use crate::parsers::{take_lines_till, take_until_eol};
|
use crate::parsers::{take_lines_till, take_until_eol};
|
||||||
|
|
||||||
|
@ -11,9 +13,9 @@ use nom::{
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DynBlock<'a> {
|
pub struct DynBlock<'a> {
|
||||||
pub block_name: &'a str,
|
pub block_name: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub arguments: Option<&'a str>,
|
pub arguments: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynBlock<'_> {
|
impl DynBlock<'_> {
|
||||||
|
@ -30,8 +32,12 @@ impl DynBlock<'_> {
|
||||||
input,
|
input,
|
||||||
(
|
(
|
||||||
Element::DynBlock(DynBlock {
|
Element::DynBlock(DynBlock {
|
||||||
block_name: name,
|
block_name: name.into(),
|
||||||
arguments: if args.is_empty() { None } else { Some(args) },
|
arguments: if args.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(args.into())
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
contents,
|
contents,
|
||||||
),
|
),
|
||||||
|
@ -48,8 +54,8 @@ fn parse() {
|
||||||
"",
|
"",
|
||||||
(
|
(
|
||||||
Element::DynBlock(DynBlock {
|
Element::DynBlock(DynBlock {
|
||||||
block_name: "clocktable",
|
block_name: "clocktable".into(),
|
||||||
arguments: Some(":scope file"),
|
arguments: Some(":scope file".into()),
|
||||||
}),
|
}),
|
||||||
"CONTENTS\n"
|
"CONTENTS\n"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use memchr::memchr;
|
use memchr::memchr;
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_while1},
|
bytes::complete::{tag, take_while1},
|
||||||
|
@ -9,7 +11,7 @@ use nom::{
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FnDef<'a> {
|
pub struct FnDef<'a> {
|
||||||
pub label: &'a str,
|
pub label: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_label(input: &str) -> IResult<&str, &str> {
|
fn parse_label(input: &str) -> IResult<&str, &str> {
|
||||||
|
@ -29,7 +31,13 @@ impl FnDef<'_> {
|
||||||
|
|
||||||
let end = memchr(b'\n', tail.as_bytes()).unwrap_or_else(|| tail.len());
|
let end = memchr(b'\n', tail.as_bytes()).unwrap_or_else(|| tail.len());
|
||||||
|
|
||||||
Some((&tail[end..], FnDef { label }, &tail[0..end]))
|
Some((
|
||||||
|
&tail[end..],
|
||||||
|
FnDef {
|
||||||
|
label: label.into(),
|
||||||
|
},
|
||||||
|
&tail[0..end],
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,19 +45,37 @@ impl FnDef<'_> {
|
||||||
fn parse() {
|
fn parse() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
FnDef::parse("[fn:1] https://orgmode.org"),
|
FnDef::parse("[fn:1] https://orgmode.org"),
|
||||||
Some(("", FnDef { label: "1" }, " https://orgmode.org"))
|
Some(("", FnDef { label: "1".into() }, " https://orgmode.org"))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
FnDef::parse("[fn:word_1] https://orgmode.org"),
|
FnDef::parse("[fn:word_1] https://orgmode.org"),
|
||||||
Some(("", FnDef { label: "word_1" }, " https://orgmode.org"))
|
Some((
|
||||||
|
"",
|
||||||
|
FnDef {
|
||||||
|
label: "word_1".into()
|
||||||
|
},
|
||||||
|
" https://orgmode.org"
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
FnDef::parse("[fn:WORD-1] https://orgmode.org"),
|
FnDef::parse("[fn:WORD-1] https://orgmode.org"),
|
||||||
Some(("", FnDef { label: "WORD-1" }, " https://orgmode.org"))
|
Some((
|
||||||
|
"",
|
||||||
|
FnDef {
|
||||||
|
label: "WORD-1".into()
|
||||||
|
},
|
||||||
|
" https://orgmode.org"
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
FnDef::parse("[fn:WORD]"),
|
FnDef::parse("[fn:WORD]"),
|
||||||
Some(("", FnDef { label: "WORD" }, ""))
|
Some((
|
||||||
|
"",
|
||||||
|
FnDef {
|
||||||
|
label: "WORD".into()
|
||||||
|
},
|
||||||
|
""
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(FnDef::parse("[fn:] https://orgmode.org"), None);
|
assert_eq!(FnDef::parse("[fn:] https://orgmode.org"), None);
|
||||||
assert_eq!(FnDef::parse("[fn:wor d] https://orgmode.org"), None);
|
assert_eq!(FnDef::parse("[fn:wor d] https://orgmode.org"), None);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use memchr::memchr2_iter;
|
use memchr::memchr2_iter;
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_while},
|
bytes::complete::{tag, take_while},
|
||||||
|
@ -12,9 +14,9 @@ use nom::{
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FnRef<'a> {
|
pub struct FnRef<'a> {
|
||||||
pub label: &'a str,
|
pub label: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub definition: Option<&'a str>,
|
pub definition: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balanced_brackets(input: &str) -> IResult<&str, &str> {
|
fn balanced_brackets(input: &str) -> IResult<&str, &str> {
|
||||||
|
@ -40,7 +42,13 @@ impl FnRef<'_> {
|
||||||
let (input, definition) = opt(preceded(tag(":"), balanced_brackets))(input)?;
|
let (input, definition) = opt(preceded(tag(":"), balanced_brackets))(input)?;
|
||||||
let (input, _) = tag("]")(input)?;
|
let (input, _) = tag("]")(input)?;
|
||||||
|
|
||||||
Ok((input, FnRef { label, definition }))
|
Ok((
|
||||||
|
input,
|
||||||
|
FnRef {
|
||||||
|
label: label.into(),
|
||||||
|
definition: definition.map(Into::into),
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +59,7 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
FnRef {
|
FnRef {
|
||||||
label: "1",
|
label: "1".into(),
|
||||||
definition: None
|
definition: None
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -61,8 +69,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
FnRef {
|
FnRef {
|
||||||
label: "1",
|
label: "1".into(),
|
||||||
definition: Some("2")
|
definition: Some("2".into())
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -71,8 +79,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
FnRef {
|
FnRef {
|
||||||
label: "",
|
label: "".into(),
|
||||||
definition: Some("2")
|
definition: Some("2".into())
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -81,8 +89,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
FnRef {
|
FnRef {
|
||||||
label: "",
|
label: "".into(),
|
||||||
definition: Some("[]")
|
definition: Some("[]".into())
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_till},
|
bytes::complete::{tag, take_till},
|
||||||
combinator::opt,
|
combinator::opt,
|
||||||
|
@ -11,12 +13,12 @@ use crate::elements::Element;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InlineCall<'a> {
|
pub struct InlineCall<'a> {
|
||||||
pub name: &'a str,
|
pub name: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub inside_header: Option<&'a str>,
|
pub inside_header: Option<Cow<'a, str>>,
|
||||||
pub arguments: &'a str,
|
pub arguments: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub end_header: Option<&'a str>,
|
pub end_header: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InlineCall<'a> {
|
impl<'a> InlineCall<'a> {
|
||||||
|
@ -42,10 +44,10 @@ impl<'a> InlineCall<'a> {
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
Element::InlineCall(InlineCall {
|
Element::InlineCall(InlineCall {
|
||||||
name,
|
name: name.into(),
|
||||||
arguments,
|
arguments: arguments.into(),
|
||||||
inside_header,
|
inside_header: inside_header.map(Into::into),
|
||||||
end_header,
|
end_header: end_header.map(Into::into),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -58,8 +60,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::InlineCall(InlineCall {
|
Element::InlineCall(InlineCall {
|
||||||
name: "square",
|
name: "square".into(),
|
||||||
arguments: "4",
|
arguments: "4".into(),
|
||||||
inside_header: None,
|
inside_header: None,
|
||||||
end_header: None,
|
end_header: None,
|
||||||
}),
|
}),
|
||||||
|
@ -70,9 +72,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::InlineCall(InlineCall {
|
Element::InlineCall(InlineCall {
|
||||||
name: "square",
|
name: "square".into(),
|
||||||
arguments: "4",
|
arguments: "4".into(),
|
||||||
inside_header: Some(":results output"),
|
inside_header: Some(":results output".into()),
|
||||||
end_header: None,
|
end_header: None,
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
|
@ -82,10 +84,10 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::InlineCall(InlineCall {
|
Element::InlineCall(InlineCall {
|
||||||
name: "square",
|
name: "square".into(),
|
||||||
arguments: "4",
|
arguments: "4".into(),
|
||||||
inside_header: None,
|
inside_header: None,
|
||||||
end_header: Some(":results html"),
|
end_header: Some(":results html".into()),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -94,10 +96,10 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::InlineCall(InlineCall {
|
Element::InlineCall(InlineCall {
|
||||||
name: "square",
|
name: "square".into(),
|
||||||
arguments: "4",
|
arguments: "4".into(),
|
||||||
inside_header: Some(":results output"),
|
inside_header: Some(":results output".into()),
|
||||||
end_header: Some(":results html"),
|
end_header: Some(":results html".into()),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_till, take_while1},
|
bytes::complete::{tag, take_till, take_while1},
|
||||||
combinator::opt,
|
combinator::opt,
|
||||||
|
@ -11,10 +13,10 @@ use crate::elements::Element;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InlineSrc<'a> {
|
pub struct InlineSrc<'a> {
|
||||||
pub lang: &'a str,
|
pub lang: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub options: Option<&'a str>,
|
pub options: Option<Cow<'a, str>>,
|
||||||
pub body: &'a str,
|
pub body: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineSrc<'_> {
|
impl InlineSrc<'_> {
|
||||||
|
@ -34,9 +36,9 @@ impl InlineSrc<'_> {
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
Element::InlineSrc(InlineSrc {
|
Element::InlineSrc(InlineSrc {
|
||||||
lang,
|
lang: lang.into(),
|
||||||
options,
|
options: options.map(Into::into),
|
||||||
body,
|
body: body.into(),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -49,9 +51,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::InlineSrc(InlineSrc {
|
Element::InlineSrc(InlineSrc {
|
||||||
lang: "C",
|
lang: "C".into(),
|
||||||
options: None,
|
options: None,
|
||||||
body: "int a = 0;"
|
body: "int a = 0;".into()
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -60,9 +62,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::InlineSrc(InlineSrc {
|
Element::InlineSrc(InlineSrc {
|
||||||
lang: "xml",
|
lang: "xml".into(),
|
||||||
options: Some(":exports code"),
|
options: Some(":exports code".into()),
|
||||||
body: "<tag>text</tag>",
|
body: "<tag>text</tag>".into(),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_till},
|
bytes::complete::{tag, take_till},
|
||||||
combinator::opt,
|
combinator::opt,
|
||||||
|
@ -12,17 +14,17 @@ use crate::parsers::take_until_eol;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Keyword<'a> {
|
pub struct Keyword<'a> {
|
||||||
pub key: &'a str,
|
pub key: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub optional: Option<&'a str>,
|
pub optional: Option<Cow<'a, str>>,
|
||||||
pub value: &'a str,
|
pub value: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BabelCall<'a> {
|
pub struct BabelCall<'a> {
|
||||||
pub value: &'a str,
|
pub value: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keyword<'_> {
|
impl Keyword<'_> {
|
||||||
|
@ -40,14 +42,19 @@ impl Keyword<'_> {
|
||||||
let (input, value) = take_until_eol(input)?;
|
let (input, value) = take_until_eol(input)?;
|
||||||
|
|
||||||
if key.eq_ignore_ascii_case("CALL") {
|
if key.eq_ignore_ascii_case("CALL") {
|
||||||
Ok((input, Element::BabelCall(BabelCall { value })))
|
Ok((
|
||||||
|
input,
|
||||||
|
Element::BabelCall(BabelCall {
|
||||||
|
value: value.into(),
|
||||||
|
}),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key,
|
key: key.into(),
|
||||||
optional,
|
optional: optional.map(Into::into),
|
||||||
value,
|
value: value.into(),
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -61,9 +68,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "KEY",
|
key: "KEY".into(),
|
||||||
optional: None,
|
optional: None,
|
||||||
value: "",
|
value: "".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -72,9 +79,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "KEY",
|
key: "KEY".into(),
|
||||||
optional: None,
|
optional: None,
|
||||||
value: "VALUE",
|
value: "VALUE".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -83,9 +90,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "K_E_Y",
|
key: "K_E_Y".into(),
|
||||||
optional: None,
|
optional: None,
|
||||||
value: "VALUE",
|
value: "VALUE".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -94,9 +101,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "KEY",
|
key: "KEY".into(),
|
||||||
optional: None,
|
optional: None,
|
||||||
value: "VALUE",
|
value: "VALUE".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -108,9 +115,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "RESULTS",
|
key: "RESULTS".into(),
|
||||||
optional: None,
|
optional: None,
|
||||||
value: "",
|
value: "".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -120,9 +127,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "ATTR_LATEX",
|
key: "ATTR_LATEX".into(),
|
||||||
optional: None,
|
optional: None,
|
||||||
value: ":width 5cm",
|
value: ":width 5cm".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -132,7 +139,7 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::BabelCall(BabelCall {
|
Element::BabelCall(BabelCall {
|
||||||
value: "double(n=4)",
|
value: "double(n=4)".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -142,9 +149,9 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Keyword(Keyword {
|
Element::Keyword(Keyword {
|
||||||
key: "CAPTION",
|
key: "CAPTION".into(),
|
||||||
optional: Some("Short caption"),
|
optional: Some("Short caption".into()),
|
||||||
value: "Longer caption.",
|
value: "Longer caption.".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_while},
|
bytes::complete::{tag, take_while},
|
||||||
combinator::opt,
|
combinator::opt,
|
||||||
|
@ -11,9 +13,9 @@ use crate::elements::Element;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Link<'a> {
|
pub struct Link<'a> {
|
||||||
pub path: &'a str,
|
pub path: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub desc: Option<&'a str>,
|
pub desc: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Link<'_> {
|
impl Link<'_> {
|
||||||
|
@ -30,7 +32,13 @@ impl Link<'_> {
|
||||||
tag("]"),
|
tag("]"),
|
||||||
))(input)?;
|
))(input)?;
|
||||||
let (input, _) = tag("]")(input)?;
|
let (input, _) = tag("]")(input)?;
|
||||||
Ok((input, Element::Link(Link { path, desc })))
|
Ok((
|
||||||
|
input,
|
||||||
|
Element::Link(Link {
|
||||||
|
path: path.into(),
|
||||||
|
desc: desc.map(Into::into),
|
||||||
|
}),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +49,7 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Link(Link {
|
Element::Link(Link {
|
||||||
path: "#id",
|
path: "#id".into(),
|
||||||
desc: None
|
desc: None
|
||||||
},)
|
},)
|
||||||
))
|
))
|
||||||
|
@ -51,8 +59,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Link(Link {
|
Element::Link(Link {
|
||||||
path: "#id",
|
path: "#id".into(),
|
||||||
desc: Some("desc")
|
desc: Some("desc".into())
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use memchr::memchr_iter;
|
use memchr::memchr_iter;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
|
@ -65,7 +67,7 @@ impl List {
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ListItem<'a> {
|
pub struct ListItem<'a> {
|
||||||
pub bullet: &'a str,
|
pub bullet: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListItem<'_> {
|
impl ListItem<'_> {
|
||||||
|
@ -87,7 +89,7 @@ impl ListItem<'_> {
|
||||||
return (
|
return (
|
||||||
&text[pos..],
|
&text[pos..],
|
||||||
ListItem {
|
ListItem {
|
||||||
bullet: &text[indent..off],
|
bullet: text[indent..off].into(),
|
||||||
},
|
},
|
||||||
&text[off..pos],
|
&text[off..pos],
|
||||||
);
|
);
|
||||||
|
@ -99,7 +101,7 @@ impl ListItem<'_> {
|
||||||
(
|
(
|
||||||
"",
|
"",
|
||||||
ListItem {
|
ListItem {
|
||||||
bullet: &text[indent..off],
|
bullet: text[indent..off].into(),
|
||||||
},
|
},
|
||||||
&text[off..],
|
&text[off..],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take, take_until, take_while1},
|
bytes::complete::{tag, take, take_until, take_while1},
|
||||||
combinator::{opt, verify},
|
combinator::{opt, verify},
|
||||||
|
@ -11,9 +13,9 @@ use crate::elements::Element;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Macros<'a> {
|
pub struct Macros<'a> {
|
||||||
pub name: &'a str,
|
pub name: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub arguments: Option<&'a str>,
|
pub arguments: Option<Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Macros<'_> {
|
impl Macros<'_> {
|
||||||
|
@ -27,7 +29,13 @@ impl Macros<'_> {
|
||||||
let (input, arguments) = opt(delimited(tag("("), take_until(")}}}"), take(1usize)))(input)?;
|
let (input, arguments) = opt(delimited(tag("("), take_until(")}}}"), take(1usize)))(input)?;
|
||||||
let (input, _) = tag("}}}")(input)?;
|
let (input, _) = tag("}}}")(input)?;
|
||||||
|
|
||||||
Ok((input, Element::Macros(Macros { name, arguments })))
|
Ok((
|
||||||
|
input,
|
||||||
|
Element::Macros(Macros {
|
||||||
|
name: name.into(),
|
||||||
|
arguments: arguments.map(Into::into),
|
||||||
|
}),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +46,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Macros(Macros {
|
Element::Macros(Macros {
|
||||||
name: "poem",
|
name: "poem".into(),
|
||||||
arguments: Some("red,blue")
|
arguments: Some("red,blue".into())
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -48,8 +56,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Macros(Macros {
|
Element::Macros(Macros {
|
||||||
name: "poem",
|
name: "poem".into(),
|
||||||
arguments: Some(")")
|
arguments: Some(")".into())
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -58,7 +66,7 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Macros(Macros {
|
Element::Macros(Macros {
|
||||||
name: "author",
|
name: "author".into(),
|
||||||
arguments: None
|
arguments: None
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
|
|
|
@ -80,7 +80,7 @@ fn prase() {
|
||||||
year: 2019,
|
year: 2019,
|
||||||
month: 4,
|
month: 4,
|
||||||
day: 8,
|
day: 8,
|
||||||
dayname: "Mon",
|
dayname: "Mon".into(),
|
||||||
hour: None,
|
hour: None,
|
||||||
minute: None
|
minute: None
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_until, take_while1},
|
bytes::complete::{tag, take_until, take_while1},
|
||||||
sequence::{delimited, separated_pair},
|
sequence::{delimited, separated_pair},
|
||||||
|
@ -10,8 +12,8 @@ use crate::elements::Element;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Snippet<'a> {
|
pub struct Snippet<'a> {
|
||||||
pub name: &'a str,
|
pub name: Cow<'a, str>,
|
||||||
pub value: &'a str,
|
pub value: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Snippet<'_> {
|
impl Snippet<'_> {
|
||||||
|
@ -27,7 +29,13 @@ impl Snippet<'_> {
|
||||||
tag("@@"),
|
tag("@@"),
|
||||||
)(input)?;
|
)(input)?;
|
||||||
|
|
||||||
Ok((input, Element::Snippet(Snippet { name, value })))
|
Ok((
|
||||||
|
input,
|
||||||
|
Element::Snippet(Snippet {
|
||||||
|
name: name.into(),
|
||||||
|
value: value.into(),
|
||||||
|
}),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +46,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Snippet(Snippet {
|
Element::Snippet(Snippet {
|
||||||
name: "html",
|
name: "html".into(),
|
||||||
value: "<b>"
|
value: "<b>".into()
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -48,8 +56,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Snippet(Snippet {
|
Element::Snippet(Snippet {
|
||||||
name: "latex",
|
name: "latex".into(),
|
||||||
value: "any arbitrary LaTeX code",
|
value: "any arbitrary LaTeX code".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -58,8 +66,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Snippet(Snippet {
|
Element::Snippet(Snippet {
|
||||||
name: "html",
|
name: "html".into(),
|
||||||
value: "",
|
value: "".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -68,8 +76,8 @@ fn parse() {
|
||||||
Ok((
|
Ok((
|
||||||
"",
|
"",
|
||||||
Element::Snippet(Snippet {
|
Element::Snippet(Snippet {
|
||||||
name: "html",
|
name: "html".into(),
|
||||||
value: "<p>@</p>",
|
value: "<p>@</p>".into(),
|
||||||
})
|
})
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[cfg_attr(feature = "ser", serde(tag = "table_type"))]
|
#[cfg_attr(feature = "ser", serde(tag = "table_type"))]
|
||||||
pub enum Table<'a> {
|
pub enum Table<'a> {
|
||||||
#[cfg_attr(feature = "ser", serde(rename = "org"))]
|
#[cfg_attr(feature = "ser", serde(rename = "org"))]
|
||||||
Org { tblfm: Option<&'a str> },
|
Org { tblfm: Option<Cow<'a, str>> },
|
||||||
#[cfg_attr(feature = "ser", serde(rename = "table.el"))]
|
#[cfg_attr(feature = "ser", serde(rename = "table.el"))]
|
||||||
TableEl { value: &'a str },
|
TableEl { value: Cow<'a, str> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_while},
|
bytes::complete::{tag, take_while},
|
||||||
combinator::verify,
|
combinator::verify,
|
||||||
|
@ -11,7 +13,7 @@ use crate::elements::Element;
|
||||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Target<'a> {
|
pub struct Target<'a> {
|
||||||
pub target: &'a str,
|
pub target: Cow<'a, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target<'_> {
|
impl Target<'_> {
|
||||||
|
@ -26,7 +28,12 @@ impl Target<'_> {
|
||||||
tag(">>"),
|
tag(">>"),
|
||||||
)(input)?;
|
)(input)?;
|
||||||
|
|
||||||
Ok((input, Element::Target(Target { target })))
|
Ok((
|
||||||
|
input,
|
||||||
|
Element::Target(Target {
|
||||||
|
target: target.into(),
|
||||||
|
}),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,11 +41,21 @@ impl Target<'_> {
|
||||||
fn parse() {
|
fn parse() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Target::parse("<<target>>"),
|
Target::parse("<<target>>"),
|
||||||
Ok(("", Element::Target(Target { target: "target" })))
|
Ok((
|
||||||
|
"",
|
||||||
|
Element::Target(Target {
|
||||||
|
target: "target".into()
|
||||||
|
})
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Target::parse("<<tar get>>"),
|
Target::parse("<<tar get>>"),
|
||||||
Ok(("", Element::Target(Target { target: "tar get" })))
|
Ok((
|
||||||
|
"",
|
||||||
|
Element::Target(Target {
|
||||||
|
target: "tar get".into()
|
||||||
|
})
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert!(Target::parse("<<target >>").is_err());
|
assert!(Target::parse("<<target >>").is_err());
|
||||||
assert!(Target::parse("<< target>>").is_err());
|
assert!(Target::parse("<< target>>").is_err());
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take, take_till, take_while, take_while_m_n},
|
bytes::complete::{tag, take, take_till, take_while, take_while_m_n},
|
||||||
character::complete::{space0, space1},
|
character::complete::{space0, space1},
|
||||||
|
@ -21,7 +23,7 @@ pub struct Datetime<'a> {
|
||||||
pub year: u16,
|
pub year: u16,
|
||||||
pub month: u8,
|
pub month: u8,
|
||||||
pub day: u8,
|
pub day: u8,
|
||||||
pub dayname: &'a str,
|
pub dayname: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub hour: Option<u8>,
|
pub hour: Option<u8>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
@ -64,7 +66,7 @@ fn parse_datetime(input: &str) -> IResult<&str, Datetime<'_>> {
|
||||||
year,
|
year,
|
||||||
month,
|
month,
|
||||||
day,
|
day,
|
||||||
dayname,
|
dayname: dayname.into(),
|
||||||
hour,
|
hour,
|
||||||
minute,
|
minute,
|
||||||
},
|
},
|
||||||
|
@ -114,35 +116,35 @@ pub enum Timestamp<'a> {
|
||||||
Active {
|
Active {
|
||||||
start: Datetime<'a>,
|
start: Datetime<'a>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
repeater: Option<&'a str>,
|
repeater: Option<Cow<'a, str>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
delay: Option<&'a str>,
|
delay: Option<Cow<'a, str>>,
|
||||||
},
|
},
|
||||||
Inactive {
|
Inactive {
|
||||||
start: Datetime<'a>,
|
start: Datetime<'a>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
repeater: Option<&'a str>,
|
repeater: Option<Cow<'a, str>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
delay: Option<&'a str>,
|
delay: Option<Cow<'a, str>>,
|
||||||
},
|
},
|
||||||
ActiveRange {
|
ActiveRange {
|
||||||
start: Datetime<'a>,
|
start: Datetime<'a>,
|
||||||
end: Datetime<'a>,
|
end: Datetime<'a>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
repeater: Option<&'a str>,
|
repeater: Option<Cow<'a, str>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
delay: Option<&'a str>,
|
delay: Option<Cow<'a, str>>,
|
||||||
},
|
},
|
||||||
InactiveRange {
|
InactiveRange {
|
||||||
start: Datetime<'a>,
|
start: Datetime<'a>,
|
||||||
end: Datetime<'a>,
|
end: Datetime<'a>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
repeater: Option<&'a str>,
|
repeater: Option<Cow<'a, str>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
delay: Option<&'a str>,
|
delay: Option<Cow<'a, str>>,
|
||||||
},
|
},
|
||||||
Diary {
|
Diary {
|
||||||
value: &'a str,
|
value: Cow<'a, str>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +260,12 @@ impl Timestamp<'_> {
|
||||||
let (input, value) = take_till(|c| c == ')' || c == '>' || c == '\n')(input)?;
|
let (input, value) = take_till(|c| c == ')' || c == '>' || c == '\n')(input)?;
|
||||||
let (input, _) = tag(")>")(input)?;
|
let (input, _) = tag(")>")(input)?;
|
||||||
|
|
||||||
Ok((input, Timestamp::Diary { value }))
|
Ok((
|
||||||
|
input,
|
||||||
|
Timestamp::Diary {
|
||||||
|
value: value.into(),
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +327,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: None,
|
hour: None,
|
||||||
minute: None
|
minute: None
|
||||||
},
|
},
|
||||||
|
@ -338,7 +345,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(9),
|
hour: Some(9),
|
||||||
minute: Some(39)
|
minute: Some(39)
|
||||||
},
|
},
|
||||||
|
@ -346,7 +353,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(10),
|
hour: Some(10),
|
||||||
minute: Some(39),
|
minute: Some(39),
|
||||||
},
|
},
|
||||||
|
@ -364,7 +371,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(9),
|
hour: Some(9),
|
||||||
minute: Some(39),
|
minute: Some(39),
|
||||||
},
|
},
|
||||||
|
@ -372,7 +379,7 @@ fn parse() {
|
||||||
year: 2003,
|
year: 2003,
|
||||||
month: 9,
|
month: 9,
|
||||||
day: 16,
|
day: 16,
|
||||||
dayname: "Tue",
|
dayname: "Tue".into(),
|
||||||
hour: Some(10),
|
hour: Some(10),
|
||||||
minute: Some(39),
|
minute: Some(39),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
//! Headline Title
|
//! Headline Title
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use memchr::memrchr;
|
use memchr::memrchr;
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_until, take_while},
|
bytes::complete::{tag, take_until, take_while},
|
||||||
character::complete::{anychar, space1},
|
character::complete::{anychar, space1},
|
||||||
combinator::{map, map_parser, opt, verify},
|
combinator::{map, map_parser, opt, verify},
|
||||||
|
error::ErrorKind,
|
||||||
|
error_position,
|
||||||
multi::fold_many0,
|
multi::fold_many0,
|
||||||
sequence::delimited,
|
sequence::{delimited, preceded},
|
||||||
sequence::preceded,
|
Err, IResult,
|
||||||
IResult,
|
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -27,20 +30,23 @@ pub struct Title<'a> {
|
||||||
pub priority: Option<char>,
|
pub priority: Option<char>,
|
||||||
/// headline tags, including the sparated colons
|
/// headline tags, including the sparated colons
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Vec::is_empty"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Vec::is_empty"))]
|
||||||
pub tags: Vec<&'a str>,
|
pub tags: Vec<Cow<'a, str>>,
|
||||||
/// headline keyword
|
/// headline keyword
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub keyword: Option<&'a str>,
|
pub keyword: Option<Cow<'a, str>>,
|
||||||
pub raw: &'a str,
|
pub raw: Cow<'a, str>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub planning: Option<Box<Planning<'a>>>,
|
pub planning: Option<Box<Planning<'a>>>,
|
||||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "HashMap::is_empty"))]
|
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "HashMap::is_empty"))]
|
||||||
pub properties: HashMap<&'a str, &'a str>,
|
pub properties: HashMap<Cow<'a, str>, Cow<'a, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Title<'_> {
|
impl Title<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn parse<'a>(input: &'a str, config: &ParseConfig) -> IResult<&'a str, Title<'a>> {
|
pub(crate) fn parse<'a>(
|
||||||
|
input: &'a str,
|
||||||
|
config: &ParseConfig,
|
||||||
|
) -> IResult<&'a str, (Title<'a>, &'a str)> {
|
||||||
let (input, (level, keyword, priority, raw, tags)) = parse_headline(input, config)?;
|
let (input, (level, keyword, priority, raw, tags)) = parse_headline(input, config)?;
|
||||||
|
|
||||||
let (input, planning) = Planning::parse(input)
|
let (input, planning) = Planning::parse(input)
|
||||||
|
@ -51,15 +57,18 @@ impl Title<'_> {
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
Title {
|
(
|
||||||
properties: properties.unwrap_or_default(),
|
Title {
|
||||||
level,
|
properties: properties.unwrap_or_default(),
|
||||||
keyword,
|
level,
|
||||||
priority,
|
keyword: keyword.map(Into::into),
|
||||||
tags,
|
priority,
|
||||||
|
tags,
|
||||||
|
raw: raw.into(),
|
||||||
|
planning,
|
||||||
|
},
|
||||||
raw,
|
raw,
|
||||||
planning,
|
),
|
||||||
},
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +76,16 @@ impl Title<'_> {
|
||||||
fn parse_headline<'a>(
|
fn parse_headline<'a>(
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
config: &ParseConfig,
|
config: &ParseConfig,
|
||||||
) -> IResult<&'a str, (usize, Option<&'a str>, Option<char>, &'a str, Vec<&'a str>)> {
|
) -> IResult<
|
||||||
|
&'a str,
|
||||||
|
(
|
||||||
|
usize,
|
||||||
|
Option<&'a str>,
|
||||||
|
Option<char>,
|
||||||
|
&'a str,
|
||||||
|
Vec<Cow<'a, str>>,
|
||||||
|
),
|
||||||
|
> {
|
||||||
let (input, level) = map(take_while(|c: char| c == '*'), |s: &str| s.len())(input)?;
|
let (input, level) = map(take_while(|c: char| c == '*'), |s: &str| s.len())(input)?;
|
||||||
|
|
||||||
debug_assert!(level > 0);
|
debug_assert!(level > 0);
|
||||||
|
@ -103,19 +121,24 @@ fn parse_headline<'a>(
|
||||||
keyword,
|
keyword,
|
||||||
priority,
|
priority,
|
||||||
raw,
|
raw,
|
||||||
tags.split(':').filter(|s| !s.is_empty()).collect(),
|
tags.split(':')
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map(Into::into)
|
||||||
|
.collect(),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_properties_drawer(input: &str) -> IResult<&str, HashMap<&str, &str>> {
|
fn parse_properties_drawer(input: &str) -> IResult<&str, HashMap<Cow<'_, str>, Cow<'_, str>>> {
|
||||||
let (input, (drawer, content)) = Drawer::parse(input)?;
|
let (input, (drawer, content)) = Drawer::parse(input)?;
|
||||||
let _ = tag("PROPERTIES")(drawer.name)?;
|
if drawer.name != "PROPERTIES" {
|
||||||
|
return Err(Err::Error(error_position!(input, ErrorKind::Tag)));
|
||||||
|
}
|
||||||
let (_, map) = fold_many0(
|
let (_, map) = fold_many0(
|
||||||
parse_node_property,
|
parse_node_property,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
|mut acc: HashMap<_, _>, (name, value)| {
|
|mut acc: HashMap<_, _>, (name, value)| {
|
||||||
acc.insert(name, value);
|
acc.insert(name.into(), value.into());
|
||||||
acc
|
acc
|
||||||
},
|
},
|
||||||
)(content)?;
|
)(content)?;
|
||||||
|
@ -134,7 +157,7 @@ fn parse_node_property(input: &str) -> IResult<&str, (&str, &str)> {
|
||||||
impl Title<'_> {
|
impl Title<'_> {
|
||||||
/// checks if this headline is "archived"
|
/// checks if this headline is "archived"
|
||||||
pub fn is_archived(&self) -> bool {
|
pub fn is_archived(&self) -> bool {
|
||||||
self.tags.contains(&"ARCHIVE")
|
self.tags.iter().any(|tag| tag == "ARCHIVE")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +177,7 @@ fn parse_headline_() {
|
||||||
Some("DONE"),
|
Some("DONE"),
|
||||||
Some('A'),
|
Some('A'),
|
||||||
"COMMENT Title",
|
"COMMENT Title",
|
||||||
vec!["tag", "a2%"]
|
vec!["tag".into(), "a2%".into()]
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,14 +3,14 @@ use jetscii::bytes;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{Error, Write};
|
use std::io::{Error, Write};
|
||||||
|
|
||||||
pub struct Escape<'a>(pub &'a str);
|
pub struct Escape<S: AsRef<str>>(pub S);
|
||||||
|
|
||||||
impl fmt::Display for Escape<'_> {
|
impl<S: AsRef<str>> fmt::Display for Escape<S> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let bytes = self.0.as_bytes();
|
let bytes = self.0.as_ref().as_bytes();
|
||||||
while let Some(off) = bytes!(b'<', b'>', b'&', b'\'', b'"').find(&bytes[pos..]) {
|
while let Some(off) = bytes!(b'<', b'>', b'&', b'\'', b'"').find(&bytes[pos..]) {
|
||||||
write!(f, "{}", &self.0[pos..pos + off])?;
|
write!(f, "{}", &self.0.as_ref()[pos..pos + off])?;
|
||||||
|
|
||||||
pos += off + 1;
|
pos += off + 1;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ impl fmt::Display for Escape<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "{}", &self.0[pos..])
|
write!(f, "{}", &self.0.as_ref()[pos..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,9 +57,11 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
Underline => write!(w, "<u>")?,
|
Underline => write!(w, "<u>")?,
|
||||||
// non-container elements
|
// non-container elements
|
||||||
CommentBlock(_) => (),
|
CommentBlock(_) => (),
|
||||||
ExampleBlock(block) => {
|
ExampleBlock(block) => write!(
|
||||||
write!(w, "<pre class=\"example\">{}</pre>", Escape(block.contents))?
|
w,
|
||||||
}
|
"<pre class=\"example\">{}</pre>",
|
||||||
|
Escape(&block.contents)
|
||||||
|
)?,
|
||||||
ExportBlock(block) => {
|
ExportBlock(block) => {
|
||||||
if block.data.eq_ignore_ascii_case("HTML") {
|
if block.data.eq_ignore_ascii_case("HTML") {
|
||||||
write!(w, "{}", block.contents)?
|
write!(w, "{}", block.contents)?
|
||||||
|
@ -67,13 +69,17 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
}
|
}
|
||||||
SourceBlock(block) => {
|
SourceBlock(block) => {
|
||||||
if block.language.is_empty() {
|
if block.language.is_empty() {
|
||||||
write!(w, "<pre class=\"example\">{}</pre>", Escape(block.contents))?;
|
write!(
|
||||||
|
w,
|
||||||
|
"<pre class=\"example\">{}</pre>",
|
||||||
|
Escape(&block.contents)
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
w,
|
w,
|
||||||
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
"<div class=\"org-src-container\"><pre class=\"src src-{}\">{}</pre></div>",
|
||||||
block.language,
|
block.language,
|
||||||
Escape(block.contents)
|
Escape(&block.contents)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +88,7 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
w,
|
w,
|
||||||
"<code class=\"src src-{}\">{}</code>",
|
"<code class=\"src src-{}\">{}</code>",
|
||||||
inline_src.lang,
|
inline_src.lang,
|
||||||
Escape(inline_src.body)
|
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) => (),
|
||||||
|
@ -90,8 +96,8 @@ pub trait HtmlHandler<E: From<Error>> {
|
||||||
Link(link) => write!(
|
Link(link) => write!(
|
||||||
w,
|
w,
|
||||||
"<a href=\"{}\">{}</a>",
|
"<a href=\"{}\">{}</a>",
|
||||||
Escape(link.path),
|
Escape(&link.path),
|
||||||
Escape(link.desc.unwrap_or(link.path)),
|
Escape(link.desc.as_ref().unwrap_or(&link.path)),
|
||||||
)?,
|
)?,
|
||||||
Macros(_macros) => (),
|
Macros(_macros) => (),
|
||||||
RadioTarget(_radio_target) => (),
|
RadioTarget(_radio_target) => (),
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
Document => (),
|
Document => (),
|
||||||
DynBlock(dyn_block) => {
|
DynBlock(dyn_block) => {
|
||||||
write!(&mut w, "#+BEGIN: {}", dyn_block.block_name)?;
|
write!(&mut w, "#+BEGIN: {}", dyn_block.block_name)?;
|
||||||
if let Some(parameters) = dyn_block.arguments {
|
if let Some(parameters) = &dyn_block.arguments {
|
||||||
write!(&mut w, " {}", parameters)?;
|
write!(&mut w, " {}", parameters)?;
|
||||||
}
|
}
|
||||||
writeln!(&mut w)?;
|
writeln!(&mut w)?;
|
||||||
|
@ -49,7 +49,7 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
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)?;
|
||||||
if let Some(options) = inline_src.options {
|
if let Some(options) = &inline_src.options {
|
||||||
write!(&mut w, "[{}]", options)?;
|
write!(&mut w, "[{}]", options)?;
|
||||||
}
|
}
|
||||||
write!(&mut w, "{{{}}}", inline_src.body)?;
|
write!(&mut w, "{{{}}}", inline_src.body)?;
|
||||||
|
@ -57,24 +57,24 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
Code { value } => write!(w, "~{}~", value)?,
|
Code { value } => write!(w, "~{}~", value)?,
|
||||||
FnRef(fn_ref) => {
|
FnRef(fn_ref) => {
|
||||||
write!(&mut w, "[fn:{}", fn_ref.label)?;
|
write!(&mut w, "[fn:{}", fn_ref.label)?;
|
||||||
if let Some(definition) = fn_ref.definition {
|
if let Some(definition) = &fn_ref.definition {
|
||||||
write!(&mut w, ":{}", definition)?;
|
write!(&mut w, ":{}", definition)?;
|
||||||
}
|
}
|
||||||
write!(&mut w, "]")?;
|
write!(&mut w, "]")?;
|
||||||
}
|
}
|
||||||
InlineCall(inline_call) => {
|
InlineCall(inline_call) => {
|
||||||
write!(&mut w, "call_{}", inline_call.name)?;
|
write!(&mut w, "call_{}", inline_call.name)?;
|
||||||
if let Some(header) = inline_call.inside_header {
|
if let Some(header) = &inline_call.inside_header {
|
||||||
write!(&mut w, "[{}]", header)?;
|
write!(&mut w, "[{}]", header)?;
|
||||||
}
|
}
|
||||||
write!(&mut w, "({})", inline_call.arguments)?;
|
write!(&mut w, "({})", inline_call.arguments)?;
|
||||||
if let Some(header) = inline_call.end_header {
|
if let Some(header) = &inline_call.end_header {
|
||||||
write!(&mut w, "[{}]", header)?;
|
write!(&mut w, "[{}]", header)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Link(link) => {
|
Link(link) => {
|
||||||
write!(&mut w, "[[{}]", link.path)?;
|
write!(&mut w, "[[{}]", link.path)?;
|
||||||
if let Some(desc) = link.desc {
|
if let Some(desc) = &link.desc {
|
||||||
write!(&mut w, "[{}]", desc)?;
|
write!(&mut w, "[{}]", desc)?;
|
||||||
}
|
}
|
||||||
write!(&mut w, "]")?;
|
write!(&mut w, "]")?;
|
||||||
|
@ -130,7 +130,7 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
FixedWidth { value } => write!(w, "{}", value)?,
|
FixedWidth { value } => write!(w, "{}", value)?,
|
||||||
Keyword(keyword) => {
|
Keyword(keyword) => {
|
||||||
write!(&mut w, "#+{}", keyword.key)?;
|
write!(&mut w, "#+{}", keyword.key)?;
|
||||||
if let Some(optional) = keyword.optional {
|
if let Some(optional) = &keyword.optional {
|
||||||
write!(&mut w, "[{}]", optional)?;
|
write!(&mut w, "[{}]", optional)?;
|
||||||
}
|
}
|
||||||
writeln!(&mut w, ": {}", keyword.value)?;
|
writeln!(&mut w, ": {}", keyword.value)?;
|
||||||
|
@ -141,7 +141,7 @@ pub trait OrgHandler<E: From<Error>> {
|
||||||
for _ in 0..title.level {
|
for _ in 0..title.level {
|
||||||
write!(&mut w, "*")?;
|
write!(&mut w, "*")?;
|
||||||
}
|
}
|
||||||
if let Some(keyword) = title.keyword {
|
if let Some(keyword) = &title.keyword {
|
||||||
write!(&mut w, " {}", keyword)?;
|
write!(&mut w, " {}", keyword)?;
|
||||||
}
|
}
|
||||||
if let Some(priority) = title.priority {
|
if let Some(priority) = title.priority {
|
||||||
|
|
|
@ -125,7 +125,7 @@
|
||||||
//! w,
|
//! w,
|
||||||
//! "<h{0}><a id=\"{1}\" href=\"#{1}\">",
|
//! "<h{0}><a id=\"{1}\" href=\"#{1}\">",
|
||||||
//! title.level,
|
//! title.level,
|
||||||
//! slugify!(title.raw),
|
//! slugify!(&title.raw),
|
||||||
//! )?;
|
//! )?;
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
|
|
|
@ -10,6 +10,7 @@ use nom::{
|
||||||
error::ErrorKind,
|
error::ErrorKind,
|
||||||
error_position, Err, IResult,
|
error_position, Err, IResult,
|
||||||
};
|
};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::config::ParseConfig;
|
use crate::config::ParseConfig;
|
||||||
use crate::elements::*;
|
use crate::elements::*;
|
||||||
|
@ -50,8 +51,7 @@ pub fn parse_title<'a>(
|
||||||
containers: &mut Vec<Container<'a>>,
|
containers: &mut Vec<Container<'a>>,
|
||||||
config: &ParseConfig,
|
config: &ParseConfig,
|
||||||
) -> &'a str {
|
) -> &'a str {
|
||||||
let (tail, title) = Title::parse(content, config).unwrap();
|
let (tail, (title, content)) = Title::parse(content, config).unwrap();
|
||||||
let content = title.raw;
|
|
||||||
let node = arena.new_node(Element::Title(title));
|
let node = arena.new_node(Element::Title(title));
|
||||||
parent.append(node, arena);
|
parent.append(node, arena);
|
||||||
containers.push(Container::Inline { content, node });
|
containers.push(Container::Inline { content, node });
|
||||||
|
@ -294,33 +294,42 @@ pub fn parse_block<'a>(
|
||||||
"COMMENT" => {
|
"COMMENT" => {
|
||||||
let node = arena.new_node(Element::CommentBlock(CommentBlock {
|
let node = arena.new_node(Element::CommentBlock(CommentBlock {
|
||||||
data: block.args,
|
data: block.args,
|
||||||
contents: content,
|
contents: content.into(),
|
||||||
}));
|
}));
|
||||||
Some((tail, node))
|
Some((tail, node))
|
||||||
}
|
}
|
||||||
"EXAMPLE" => {
|
"EXAMPLE" => {
|
||||||
let node = arena.new_node(Element::ExampleBlock(ExampleBlock {
|
let node = arena.new_node(Element::ExampleBlock(ExampleBlock {
|
||||||
data: block.args,
|
data: block.args,
|
||||||
contents: content,
|
contents: content.into(),
|
||||||
}));
|
}));
|
||||||
Some((tail, node))
|
Some((tail, node))
|
||||||
}
|
}
|
||||||
"EXPORT" => {
|
"EXPORT" => {
|
||||||
let node = arena.new_node(Element::ExportBlock(ExportBlock {
|
let node = arena.new_node(Element::ExportBlock(ExportBlock {
|
||||||
data: block.args.unwrap_or(""),
|
data: block.args.unwrap_or_default(),
|
||||||
contents: content,
|
contents: content.into(),
|
||||||
}));
|
}));
|
||||||
Some((tail, node))
|
Some((tail, node))
|
||||||
}
|
}
|
||||||
"SRC" => {
|
"SRC" => {
|
||||||
let (language, arguments) = block
|
let (language, arguments) = match &block.args {
|
||||||
.args
|
Some(Cow::Borrowed(args)) => {
|
||||||
.map(|args| args.split_at(args.find(' ').unwrap_or_else(|| args.len())))
|
let (language, arguments) =
|
||||||
.unwrap_or(("", ""));
|
args.split_at(args.find(' ').unwrap_or_else(|| args.len()));
|
||||||
|
(Cow::Borrowed(language), Cow::Borrowed(arguments))
|
||||||
|
}
|
||||||
|
Some(Cow::Owned(args)) => {
|
||||||
|
let (language, arguments) =
|
||||||
|
args.split_at(args.find(' ').unwrap_or_else(|| args.len()));
|
||||||
|
(Cow::Owned(language.into()), Cow::Owned(arguments.into()))
|
||||||
|
}
|
||||||
|
None => (Cow::Borrowed(""), Cow::Borrowed("")),
|
||||||
|
};
|
||||||
let node = arena.new_node(Element::SourceBlock(SourceBlock {
|
let node = arena.new_node(Element::SourceBlock(SourceBlock {
|
||||||
arguments,
|
arguments,
|
||||||
language,
|
language,
|
||||||
contents: content,
|
contents: content.into(),
|
||||||
}));
|
}));
|
||||||
Some((tail, node))
|
Some((tail, node))
|
||||||
}
|
}
|
||||||
|
@ -605,7 +614,7 @@ pub fn prase_table<'a>(
|
||||||
Some((
|
Some((
|
||||||
&contents[last_end..],
|
&contents[last_end..],
|
||||||
arena.new_node(Element::Table(Table::TableEl {
|
arena.new_node(Element::Table(Table::TableEl {
|
||||||
value: &contents[0..last_end],
|
value: contents[0..last_end].into(),
|
||||||
})),
|
})),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
@ -615,7 +624,9 @@ pub fn prase_table<'a>(
|
||||||
|
|
||||||
Some((
|
Some((
|
||||||
"",
|
"",
|
||||||
arena.new_node(Element::Table(Table::TableEl { value: contents })),
|
arena.new_node(Element::Table(Table::TableEl {
|
||||||
|
value: contents.into(),
|
||||||
|
})),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
Loading…
Reference in a new issue