feat: pre_blank and post_blank
This commit is contained in:
parent
1a0240a747
commit
948b1be2db
19 changed files with 678 additions and 211 deletions
|
|
@ -5,7 +5,7 @@ use nom::{
|
|||
sequence::preceded, IResult,
|
||||
};
|
||||
|
||||
use crate::parsers::{line, take_lines_while};
|
||||
use crate::parsers::{blank_lines, line, take_lines_while};
|
||||
|
||||
/// Special Block Element
|
||||
#[derive(Debug)]
|
||||
|
|
@ -13,9 +13,14 @@ use crate::parsers::{line, take_lines_while};
|
|||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct SpecialBlock<'a> {
|
||||
/// Optional block parameters
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub parameters: Option<Cow<'a, str>>,
|
||||
/// Block name
|
||||
pub name: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub pre_blank: usize,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl SpecialBlock<'_> {
|
||||
|
|
@ -23,6 +28,8 @@ impl SpecialBlock<'_> {
|
|||
SpecialBlock {
|
||||
name: self.name.into_owned().into(),
|
||||
parameters: self.parameters.map(Into::into).map(Cow::Owned),
|
||||
pre_blank: self.pre_blank,
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,13 +40,20 @@ impl SpecialBlock<'_> {
|
|||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct QuoteBlock<'a> {
|
||||
/// Optional block parameters
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub parameters: Option<Cow<'a, str>>,
|
||||
/// Numbers of blank lines
|
||||
pub pre_blank: usize,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl QuoteBlock<'_> {
|
||||
pub fn into_owned(self) -> QuoteBlock<'static> {
|
||||
QuoteBlock {
|
||||
parameters: self.parameters.map(Into::into).map(Cow::Owned),
|
||||
pre_blank: self.pre_blank,
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,13 +64,20 @@ impl QuoteBlock<'_> {
|
|||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct CenterBlock<'a> {
|
||||
/// Optional block parameters
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub parameters: Option<Cow<'a, str>>,
|
||||
/// Numbers of blank lines
|
||||
pub pre_blank: usize,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl CenterBlock<'_> {
|
||||
pub fn into_owned(self) -> CenterBlock<'static> {
|
||||
CenterBlock {
|
||||
parameters: self.parameters.map(Into::into).map(Cow::Owned),
|
||||
pre_blank: self.pre_blank,
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -67,13 +88,20 @@ impl CenterBlock<'_> {
|
|||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct VerseBlock<'a> {
|
||||
/// Optional block parameters
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub parameters: Option<Cow<'a, str>>,
|
||||
/// Numbers of blank lines
|
||||
pub pre_blank: usize,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl VerseBlock<'_> {
|
||||
pub fn into_owned(self) -> VerseBlock<'static> {
|
||||
VerseBlock {
|
||||
parameters: self.parameters.map(Into::into).map(Cow::Owned),
|
||||
pre_blank: self.pre_blank,
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,9 +111,12 @@ impl VerseBlock<'_> {
|
|||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct CommentBlock<'a> {
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub data: Option<Cow<'a, str>>,
|
||||
/// Comment, without block's boundaries
|
||||
pub contents: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl CommentBlock<'_> {
|
||||
|
|
@ -93,6 +124,7 @@ impl CommentBlock<'_> {
|
|||
CommentBlock {
|
||||
data: self.data.map(Into::into).map(Cow::Owned),
|
||||
contents: self.contents.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,9 +134,12 @@ impl CommentBlock<'_> {
|
|||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct ExampleBlock<'a> {
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub data: Option<Cow<'a, str>>,
|
||||
/// Block contents
|
||||
pub contents: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl ExampleBlock<'_> {
|
||||
|
|
@ -112,6 +147,7 @@ impl ExampleBlock<'_> {
|
|||
ExampleBlock {
|
||||
data: self.data.map(Into::into).map(Cow::Owned),
|
||||
contents: self.contents.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -124,6 +160,8 @@ pub struct ExportBlock<'a> {
|
|||
pub data: Cow<'a, str>,
|
||||
/// Block contents
|
||||
pub contents: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl ExportBlock<'_> {
|
||||
|
|
@ -131,12 +169,13 @@ impl ExportBlock<'_> {
|
|||
ExportBlock {
|
||||
data: self.data.into_owned().into(),
|
||||
contents: self.contents.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Src Block Element
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct SourceBlock<'a> {
|
||||
|
|
@ -145,6 +184,8 @@ pub struct SourceBlock<'a> {
|
|||
/// Language of the code in the block
|
||||
pub language: Cow<'a, str>,
|
||||
pub arguments: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl SourceBlock<'_> {
|
||||
|
|
@ -153,6 +194,7 @@ impl SourceBlock<'_> {
|
|||
language: self.language.into_owned().into(),
|
||||
arguments: self.arguments.into_owned().into(),
|
||||
contents: self.contents.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,20 +206,21 @@ impl SourceBlock<'_> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn parse_block_element(input: &str) -> Option<(&str, (&str, Option<&str>, &str))> {
|
||||
pub fn parse_block_element(input: &str) -> Option<(&str, (&str, Option<&str>, &str, usize))> {
|
||||
parse_block_element_internal::<()>(input).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_block_element_internal<'a, E: ParseError<&'a str>>(
|
||||
input: &'a str,
|
||||
) -> IResult<&str, (&str, Option<&str>, &str), E> {
|
||||
) -> IResult<&str, (&str, Option<&str>, &str, usize), E> {
|
||||
let (input, name) = preceded(tag_no_case("#+BEGIN_"), alpha1)(input)?;
|
||||
let (input, args) = line(input)?;
|
||||
let end_line = format!("#+END_{}", name);
|
||||
let (input, contents) =
|
||||
take_lines_while(|line| !line.trim().eq_ignore_ascii_case(&end_line))(input);
|
||||
let (input, _) = line(input)?;
|
||||
let (input, blank) = blank_lines(input);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
|
|
@ -189,6 +232,7 @@ fn parse_block_element_internal<'a, E: ParseError<&'a str>>(
|
|||
Some(args.trim())
|
||||
},
|
||||
contents,
|
||||
blank,
|
||||
),
|
||||
))
|
||||
}
|
||||
|
|
@ -202,20 +246,21 @@ fn parse() {
|
|||
r#"#+BEGIN_SRC
|
||||
#+END_SRC"#
|
||||
),
|
||||
Ok(("", ("SRC".into(), None, "")))
|
||||
Ok(("", ("SRC".into(), None, "", 0)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_block_element_internal::<VerboseError<&str>>(
|
||||
r#"#+begin_src
|
||||
#+end_src"#
|
||||
),
|
||||
Ok(("", ("src".into(), None, "")))
|
||||
Ok(("", ("src".into(), None, "", 0)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_block_element_internal::<VerboseError<&str>>(
|
||||
r#"#+BEGIN_SRC javascript
|
||||
console.log('Hello World!');
|
||||
#+END_SRC
|
||||
|
||||
"#
|
||||
),
|
||||
Ok((
|
||||
|
|
@ -223,7 +268,8 @@ console.log('Hello World!');
|
|||
(
|
||||
"SRC".into(),
|
||||
Some("javascript".into()),
|
||||
"console.log('Hello World!');\n"
|
||||
"console.log('Hello World!');\n",
|
||||
1
|
||||
)
|
||||
))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use nom::{
|
|||
|
||||
use crate::elements::timestamp::{parse_inactive, Datetime, Timestamp};
|
||||
|
||||
use crate::parsers::eol;
|
||||
use crate::parsers::{blank_lines, eol};
|
||||
|
||||
/// Clock Element
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
|
|
@ -31,6 +31,8 @@ pub enum Clock<'a> {
|
|||
delay: Option<Cow<'a, str>>,
|
||||
/// Clock duration
|
||||
duration: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
post_blank: usize,
|
||||
},
|
||||
/// Running Clock
|
||||
Running {
|
||||
|
|
@ -40,6 +42,8 @@ pub enum Clock<'a> {
|
|||
repeater: Option<Cow<'a, str>>,
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
delay: Option<Cow<'a, str>>,
|
||||
/// Numbers of blank lines
|
||||
post_blank: usize,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -56,21 +60,25 @@ impl Clock<'_> {
|
|||
repeater,
|
||||
delay,
|
||||
duration,
|
||||
post_blank,
|
||||
} => Clock::Closed {
|
||||
start: start.into_owned(),
|
||||
end: end.into_owned(),
|
||||
repeater: repeater.map(Into::into).map(Cow::Owned),
|
||||
delay: delay.map(Into::into).map(Cow::Owned),
|
||||
duration: duration.into_owned().into(),
|
||||
post_blank,
|
||||
},
|
||||
Clock::Running {
|
||||
start,
|
||||
repeater,
|
||||
delay,
|
||||
post_blank,
|
||||
} => Clock::Running {
|
||||
start: start.into_owned(),
|
||||
repeater: repeater.map(Into::into).map(Cow::Owned),
|
||||
delay: delay.map(Into::into).map(Cow::Owned),
|
||||
post_blank,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +126,7 @@ impl Clock<'_> {
|
|||
start,
|
||||
repeater,
|
||||
delay,
|
||||
..
|
||||
} => Timestamp::Inactive {
|
||||
start: start.clone(),
|
||||
repeater: repeater.clone(),
|
||||
|
|
@ -144,6 +153,7 @@ fn parse_clock<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Cloc
|
|||
let (input, _) = space0(input)?;
|
||||
let (input, duration) = recognize(separated_pair(digit1, char(':'), digit1))(input)?;
|
||||
let (input, _) = eol(input)?;
|
||||
let (input, blank) = blank_lines(input);
|
||||
Ok((
|
||||
input,
|
||||
Clock::Closed {
|
||||
|
|
@ -152,6 +162,7 @@ fn parse_clock<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Cloc
|
|||
repeater,
|
||||
delay,
|
||||
duration: duration.into(),
|
||||
post_blank: blank,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
@ -161,12 +172,14 @@ fn parse_clock<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Cloc
|
|||
delay,
|
||||
} => {
|
||||
let (input, _) = eol(input)?;
|
||||
let (input, blank) = blank_lines(input);
|
||||
Ok((
|
||||
input,
|
||||
Clock::Running {
|
||||
start,
|
||||
repeater,
|
||||
delay,
|
||||
post_blank: blank,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
@ -195,12 +208,13 @@ fn parse() {
|
|||
},
|
||||
repeater: None,
|
||||
delay: None,
|
||||
post_blank: 0,
|
||||
}
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_clock::<VerboseError<&str>>(
|
||||
"CLOCK: [2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39] => 1:00"
|
||||
"CLOCK: [2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39] => 1:00\n\n"
|
||||
),
|
||||
Ok((
|
||||
"",
|
||||
|
|
@ -224,6 +238,7 @@ fn parse() {
|
|||
repeater: None,
|
||||
delay: None,
|
||||
duration: "1:00".into(),
|
||||
post_blank: 1,
|
||||
}
|
||||
))
|
||||
);
|
||||
|
|
|
|||
36
src/elements/comment.rs
Normal file
36
src/elements/comment.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::parsers::{blank_lines, take_lines_while};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct Comment<'a> {
|
||||
pub value: Cow<'a, str>,
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl Comment<'_> {
|
||||
pub(crate) fn parse(input: &str) -> Option<(&str, Comment<'_>)> {
|
||||
let (input, value) = take_lines_while(|line| line == "#" || line.starts_with("# "))(input);
|
||||
let (input, blank) = blank_lines(input);
|
||||
|
||||
if value.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((
|
||||
input,
|
||||
Comment {
|
||||
value: value.into(),
|
||||
post_blank: blank,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> Comment<'static> {
|
||||
Comment {
|
||||
value: self.value.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,15 +7,19 @@ use nom::{
|
|||
IResult,
|
||||
};
|
||||
|
||||
use crate::parsers::{eol, line, take_lines_while};
|
||||
use crate::parsers::{blank_lines, eol, line, take_lines_while};
|
||||
|
||||
/// Drawer Element
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
#[derive(Debug)]
|
||||
pub struct Drawer<'a> {
|
||||
/// Drawer name
|
||||
pub name: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub pre_blank: usize,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl Drawer<'_> {
|
||||
|
|
@ -26,6 +30,8 @@ impl Drawer<'_> {
|
|||
pub fn into_owned(self) -> Drawer<'static> {
|
||||
Drawer {
|
||||
name: self.name.into_owned().into(),
|
||||
pre_blank: self.pre_blank,
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +39,20 @@ impl Drawer<'_> {
|
|||
#[inline]
|
||||
pub fn parse_drawer<'a, E: ParseError<&'a str>>(
|
||||
input: &'a str,
|
||||
) -> IResult<&str, (Drawer, &str), E> {
|
||||
let (input, (mut drawer, content)) = parse_drawer_without_blank(input)?;
|
||||
|
||||
let (content, blank) = blank_lines(content);
|
||||
drawer.pre_blank = blank;
|
||||
|
||||
let (input, blank) = blank_lines(input);
|
||||
drawer.post_blank = blank;
|
||||
|
||||
Ok((input, (drawer, content)))
|
||||
}
|
||||
|
||||
pub fn parse_drawer_without_blank<'a, E: ParseError<&'a str>>(
|
||||
input: &'a str,
|
||||
) -> IResult<&str, (Drawer, &str), E> {
|
||||
let (input, name) = delimited(
|
||||
tag(":"),
|
||||
|
|
@ -44,7 +64,17 @@ pub fn parse_drawer<'a, E: ParseError<&'a str>>(
|
|||
take_lines_while(|line| !line.trim().eq_ignore_ascii_case(":END:"))(input);
|
||||
let (input, _) = line(input)?;
|
||||
|
||||
Ok((input, (Drawer { name: name.into() }, contents)))
|
||||
Ok((
|
||||
input,
|
||||
(
|
||||
Drawer {
|
||||
name: name.into(),
|
||||
pre_blank: 0,
|
||||
post_blank: 0,
|
||||
},
|
||||
contents,
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -52,24 +82,39 @@ fn parse() {
|
|||
use nom::error::VerboseError;
|
||||
|
||||
assert_eq!(
|
||||
parse_drawer::<VerboseError<&str>>(":PROPERTIES:\n :CUSTOM_ID: id\n :END:"),
|
||||
parse_drawer::<VerboseError<&str>>(
|
||||
r#":PROPERTIES:
|
||||
:CUSTOM_ID: id
|
||||
:END:"#
|
||||
),
|
||||
Ok((
|
||||
"",
|
||||
(
|
||||
Drawer {
|
||||
name: "PROPERTIES".into()
|
||||
name: "PROPERTIES".into(),
|
||||
pre_blank: 0,
|
||||
post_blank: 0
|
||||
},
|
||||
" :CUSTOM_ID: id\n"
|
||||
)
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_drawer::<VerboseError<&str>>(":PROPERTIES:\n :END:"),
|
||||
parse_drawer::<VerboseError<&str>>(
|
||||
r#":PROPERTIES:
|
||||
|
||||
|
||||
:END:
|
||||
|
||||
"#
|
||||
),
|
||||
Ok((
|
||||
"",
|
||||
(
|
||||
Drawer {
|
||||
name: "PROPERTIES".into()
|
||||
name: "PROPERTIES".into(),
|
||||
pre_blank: 2,
|
||||
post_blank: 1,
|
||||
},
|
||||
""
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,18 +7,22 @@ use nom::{
|
|||
IResult,
|
||||
};
|
||||
|
||||
use crate::parsers::{line, take_lines_while};
|
||||
use crate::parsers::{blank_lines, line, take_lines_while};
|
||||
|
||||
/// Dynamic Block Element
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
#[derive(Debug)]
|
||||
pub struct DynBlock<'a> {
|
||||
/// Block name
|
||||
pub block_name: Cow<'a, str>,
|
||||
/// Block argument
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
|
||||
pub arguments: Option<Cow<'a, str>>,
|
||||
/// Numbers of blank lines
|
||||
pub pre_blank: usize,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl DynBlock<'_> {
|
||||
|
|
@ -30,6 +34,8 @@ impl DynBlock<'_> {
|
|||
DynBlock {
|
||||
block_name: self.block_name.into_owned().into(),
|
||||
arguments: self.arguments.map(Into::into).map(Cow::Owned),
|
||||
pre_blank: self.pre_blank,
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,7 +50,9 @@ fn parse_dyn_block<'a, E: ParseError<&'a str>>(
|
|||
let (input, args) = line(input)?;
|
||||
let (input, contents) =
|
||||
take_lines_while(|line| !line.trim().eq_ignore_ascii_case("#+END:"))(input);
|
||||
let (contents, pre_blank) = blank_lines(contents);
|
||||
let (input, _) = line(input)?;
|
||||
let (input, post_blank) = blank_lines(input);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
|
|
@ -56,6 +64,8 @@ fn parse_dyn_block<'a, E: ParseError<&'a str>>(
|
|||
} else {
|
||||
Some(args.trim().into())
|
||||
},
|
||||
pre_blank,
|
||||
post_blank,
|
||||
},
|
||||
contents,
|
||||
),
|
||||
|
|
@ -70,8 +80,11 @@ fn parse() {
|
|||
assert_eq!(
|
||||
parse_dyn_block::<VerboseError<&str>>(
|
||||
r#"#+BEGIN: clocktable :scope file
|
||||
|
||||
|
||||
CONTENTS
|
||||
#+END:
|
||||
|
||||
"#
|
||||
),
|
||||
Ok((
|
||||
|
|
@ -80,6 +93,8 @@ CONTENTS
|
|||
DynBlock {
|
||||
block_name: "clocktable".into(),
|
||||
arguments: Some(":scope file".into()),
|
||||
pre_blank: 2,
|
||||
post_blank: 1,
|
||||
},
|
||||
"CONTENTS\n"
|
||||
)
|
||||
|
|
|
|||
63
src/elements/fixed_width.rs
Normal file
63
src/elements/fixed_width.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::parsers::{blank_lines, take_lines_while};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct FixedWidth<'a> {
|
||||
pub value: Cow<'a, str>,
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl FixedWidth<'_> {
|
||||
pub(crate) fn parse(input: &str) -> Option<(&str, FixedWidth<'_>)> {
|
||||
let (input, value) = take_lines_while(|line| line == ":" || line.starts_with(": "))(input);
|
||||
let (input, blank) = blank_lines(input);
|
||||
|
||||
if value.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((
|
||||
input,
|
||||
FixedWidth {
|
||||
value: value.into(),
|
||||
post_blank: blank,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> FixedWidth<'static> {
|
||||
FixedWidth {
|
||||
value: self.value.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
assert_eq!(
|
||||
FixedWidth::parse(
|
||||
r#": A
|
||||
:
|
||||
: B
|
||||
: C
|
||||
|
||||
"#
|
||||
),
|
||||
Some((
|
||||
"",
|
||||
FixedWidth {
|
||||
value: r#": A
|
||||
:
|
||||
: B
|
||||
: C
|
||||
"#
|
||||
.into(),
|
||||
post_blank: 1
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
|
@ -7,15 +7,17 @@ use nom::{
|
|||
IResult,
|
||||
};
|
||||
|
||||
use crate::parsers::line;
|
||||
use crate::parsers::{blank_lines, line};
|
||||
|
||||
/// Footnote Definition Element
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FnDef<'a> {
|
||||
/// Footnote label, used for refrence
|
||||
pub label: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl FnDef<'_> {
|
||||
|
|
@ -26,6 +28,7 @@ impl FnDef<'_> {
|
|||
pub fn into_owned(self) -> FnDef<'static> {
|
||||
FnDef {
|
||||
label: self.label.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,12 +41,14 @@ fn parse_fn_def<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, (Fn
|
|||
tag("]"),
|
||||
)(input)?;
|
||||
let (input, content) = line(input)?;
|
||||
let (input, blank) = blank_lines(input);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
(
|
||||
FnDef {
|
||||
label: label.into(),
|
||||
post_blank: blank,
|
||||
},
|
||||
content,
|
||||
),
|
||||
|
|
@ -56,7 +61,16 @@ fn parse() {
|
|||
|
||||
assert_eq!(
|
||||
parse_fn_def::<VerboseError<&str>>("[fn:1] https://orgmode.org"),
|
||||
Ok(("", (FnDef { label: "1".into() }, " https://orgmode.org")))
|
||||
Ok((
|
||||
"",
|
||||
(
|
||||
FnDef {
|
||||
label: "1".into(),
|
||||
post_blank: 0
|
||||
},
|
||||
" https://orgmode.org"
|
||||
)
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_fn_def::<VerboseError<&str>>("[fn:word_1] https://orgmode.org"),
|
||||
|
|
@ -64,7 +78,8 @@ fn parse() {
|
|||
"",
|
||||
(
|
||||
FnDef {
|
||||
label: "word_1".into()
|
||||
label: "word_1".into(),
|
||||
post_blank: 0,
|
||||
},
|
||||
" https://orgmode.org"
|
||||
)
|
||||
|
|
@ -76,7 +91,8 @@ fn parse() {
|
|||
"",
|
||||
(
|
||||
FnDef {
|
||||
label: "WORD-1".into()
|
||||
label: "WORD-1".into(),
|
||||
post_blank: 0,
|
||||
},
|
||||
" https://orgmode.org"
|
||||
)
|
||||
|
|
@ -88,7 +104,8 @@ fn parse() {
|
|||
"",
|
||||
(
|
||||
FnDef {
|
||||
label: "WORD".into()
|
||||
label: "WORD".into(),
|
||||
post_blank: 0,
|
||||
},
|
||||
""
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use nom::{
|
|||
IResult,
|
||||
};
|
||||
|
||||
use crate::parsers::line;
|
||||
use crate::parsers::{blank_lines, line};
|
||||
|
||||
/// Keyword Elemenet
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
|
|
@ -21,6 +21,8 @@ pub struct Keyword<'a> {
|
|||
pub optional: Option<Cow<'a, str>>,
|
||||
/// Keyword value
|
||||
pub value: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl Keyword<'_> {
|
||||
|
|
@ -29,6 +31,7 @@ impl Keyword<'_> {
|
|||
key: self.key.into_owned().into(),
|
||||
optional: self.optional.map(Into::into).map(Cow::Owned),
|
||||
value: self.value.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,25 +42,28 @@ impl Keyword<'_> {
|
|||
#[derive(Debug)]
|
||||
pub struct BabelCall<'a> {
|
||||
pub value: Cow<'a, str>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl BabelCall<'_> {
|
||||
pub fn into_owned(self) -> BabelCall<'static> {
|
||||
BabelCall {
|
||||
value: self.value.into_owned().into(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn parse_keyword(input: &str) -> Option<(&str, (&str, Option<&str>, &str))> {
|
||||
pub fn parse_keyword(input: &str) -> Option<(&str, (&str, Option<&str>, &str, usize))> {
|
||||
parse_keyword_internal::<()>(input).ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_keyword_internal<'a, E: ParseError<&'a str>>(
|
||||
input: &'a str,
|
||||
) -> IResult<&str, (&str, Option<&str>, &str), E> {
|
||||
) -> IResult<&str, (&str, Option<&str>, &str, usize), E> {
|
||||
let (input, _) = tag("#+")(input)?;
|
||||
let (input, key) = take_till(|c: char| c.is_ascii_whitespace() || c == ':' || c == '[')(input)?;
|
||||
let (input, optional) = opt(delimited(
|
||||
|
|
@ -67,8 +73,9 @@ fn parse_keyword_internal<'a, E: ParseError<&'a str>>(
|
|||
))(input)?;
|
||||
let (input, _) = tag(":")(input)?;
|
||||
let (input, value) = line(input)?;
|
||||
let (input, blank) = blank_lines(input);
|
||||
|
||||
Ok((input, (key, optional, value.trim())))
|
||||
Ok((input, (key, optional, value.trim(), blank)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -77,40 +84,40 @@ fn parse() {
|
|||
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+KEY:"),
|
||||
Ok(("", ("KEY", None, "")))
|
||||
Ok(("", ("KEY", None, "", 0)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+KEY: VALUE"),
|
||||
Ok(("", ("KEY", None, "VALUE")))
|
||||
Ok(("", ("KEY", None, "VALUE", 0)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+K_E_Y: VALUE"),
|
||||
Ok(("", ("K_E_Y", None, "VALUE")))
|
||||
Ok(("", ("K_E_Y", None, "VALUE", 0)))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+KEY:VALUE\n"),
|
||||
Ok(("", ("KEY", None, "VALUE")))
|
||||
Ok(("", ("KEY", None, "VALUE", 0)))
|
||||
);
|
||||
assert!(parse_keyword_internal::<VerboseError<&str>>("#+KE Y: VALUE").is_err());
|
||||
assert!(parse_keyword_internal::<VerboseError<&str>>("#+ KEY: VALUE").is_err());
|
||||
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+RESULTS:"),
|
||||
Ok(("", ("RESULTS", None, "")))
|
||||
Ok(("", ("RESULTS", None, "", 0)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+ATTR_LATEX: :width 5cm\n"),
|
||||
Ok(("", ("ATTR_LATEX", None, ":width 5cm")))
|
||||
Ok(("", ("ATTR_LATEX", None, ":width 5cm", 0)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+CALL: double(n=4)"),
|
||||
Ok(("", ("CALL", None, "double(n=4)")))
|
||||
Ok(("", ("CALL", None, "double(n=4)", 0)))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
parse_keyword_internal::<VerboseError<&str>>("#+CAPTION[Short caption]: Longer caption."),
|
||||
Ok(("", ("CAPTION", Some("Short caption"), "Longer caption.",)))
|
||||
Ok(("", ("CAPTION", Some("Short caption"), "Longer caption.", 0)))
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
pub(crate) mod block;
|
||||
pub(crate) mod clock;
|
||||
pub(crate) mod comment;
|
||||
pub(crate) mod cookie;
|
||||
pub(crate) mod drawer;
|
||||
pub(crate) mod dyn_block;
|
||||
pub(crate) mod emphasis;
|
||||
pub(crate) mod fixed_width;
|
||||
pub(crate) mod fn_def;
|
||||
pub(crate) mod fn_ref;
|
||||
pub(crate) mod inline_call;
|
||||
|
|
@ -29,9 +31,11 @@ pub use self::{
|
|||
SpecialBlock, VerseBlock,
|
||||
},
|
||||
clock::Clock,
|
||||
comment::Comment,
|
||||
cookie::Cookie,
|
||||
drawer::Drawer,
|
||||
dyn_block::DynBlock,
|
||||
fixed_width::FixedWidth,
|
||||
fn_def::FnDef,
|
||||
fn_ref::FnRef,
|
||||
inline_call::InlineCall,
|
||||
|
|
@ -41,6 +45,7 @@ pub use self::{
|
|||
list::{List, ListItem},
|
||||
macros::Macros,
|
||||
planning::Planning,
|
||||
rule::Rule,
|
||||
snippet::Snippet,
|
||||
table::{Table, TableRow},
|
||||
target::Target,
|
||||
|
|
@ -52,7 +57,6 @@ use std::borrow::Cow;
|
|||
|
||||
/// Element Enum
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "ser", serde(tag = "type", rename_all = "kebab-case"))]
|
||||
pub enum Element<'a> {
|
||||
|
|
@ -70,7 +74,7 @@ pub enum Element<'a> {
|
|||
Cookie(Cookie<'a>),
|
||||
RadioTarget,
|
||||
Drawer(Drawer<'a>),
|
||||
Document,
|
||||
Document { pre_blank: usize },
|
||||
DynBlock(DynBlock<'a>),
|
||||
FnDef(FnDef<'a>),
|
||||
FnRef(FnRef<'a>),
|
||||
|
|
@ -84,8 +88,8 @@ pub enum Element<'a> {
|
|||
Macros(Macros<'a>),
|
||||
Snippet(Snippet<'a>),
|
||||
Text { value: Cow<'a, str> },
|
||||
Paragraph,
|
||||
Rule,
|
||||
Paragraph { post_blank: usize },
|
||||
Rule(Rule),
|
||||
Timestamp(Timestamp<'a>),
|
||||
Target(Target<'a>),
|
||||
Bold,
|
||||
|
|
@ -94,8 +98,8 @@ pub enum Element<'a> {
|
|||
Underline,
|
||||
Verbatim { value: Cow<'a, str> },
|
||||
Code { value: Cow<'a, str> },
|
||||
Comment { value: Cow<'a, str> },
|
||||
FixedWidth { value: Cow<'a, str> },
|
||||
Comment(Comment<'a>),
|
||||
FixedWidth(FixedWidth<'a>),
|
||||
Title(Title<'a>),
|
||||
Table(Table<'a>),
|
||||
TableRow(TableRow),
|
||||
|
|
@ -112,13 +116,13 @@ impl Element<'_> {
|
|||
| CenterBlock(_)
|
||||
| VerseBlock(_)
|
||||
| Bold
|
||||
| Document
|
||||
| Document { .. }
|
||||
| DynBlock(_)
|
||||
| Headline { .. }
|
||||
| Italic
|
||||
| List(_)
|
||||
| ListItem(_)
|
||||
| Paragraph
|
||||
| Paragraph { .. }
|
||||
| Section
|
||||
| Strike
|
||||
| Underline
|
||||
|
|
@ -148,7 +152,7 @@ impl Element<'_> {
|
|||
Cookie(e) => Cookie(e.into_owned()),
|
||||
RadioTarget => RadioTarget,
|
||||
Drawer(e) => Drawer(e.into_owned()),
|
||||
Document => Document,
|
||||
Document { pre_blank } => Document { pre_blank },
|
||||
DynBlock(e) => DynBlock(e.into_owned()),
|
||||
FnDef(e) => FnDef(e.into_owned()),
|
||||
FnRef(e) => FnRef(e.into_owned()),
|
||||
|
|
@ -164,8 +168,8 @@ impl Element<'_> {
|
|||
Text { value } => Text {
|
||||
value: value.into_owned().into(),
|
||||
},
|
||||
Paragraph => Paragraph,
|
||||
Rule => Rule,
|
||||
Paragraph { post_blank } => Paragraph { post_blank },
|
||||
Rule(e) => Rule(e),
|
||||
Timestamp(e) => Timestamp(e.into_owned()),
|
||||
Target(e) => Target(e.into_owned()),
|
||||
Bold => Bold,
|
||||
|
|
@ -178,12 +182,8 @@ impl Element<'_> {
|
|||
Code { value } => Code {
|
||||
value: value.into_owned().into(),
|
||||
},
|
||||
Comment { value } => Comment {
|
||||
value: value.into_owned().into(),
|
||||
},
|
||||
FixedWidth { value } => FixedWidth {
|
||||
value: value.into_owned().into(),
|
||||
},
|
||||
Comment(e) => Comment(e.into_owned()),
|
||||
FixedWidth(e) => FixedWidth(e.into_owned()),
|
||||
Title(e) => Title(e.into_owned()),
|
||||
Table(e) => Table(e.into_owned()),
|
||||
TableRow(e) => TableRow(e),
|
||||
|
|
@ -215,12 +215,14 @@ impl_from!(
|
|||
BabelCall,
|
||||
CenterBlock,
|
||||
Clock,
|
||||
Comment,
|
||||
CommentBlock,
|
||||
Cookie,
|
||||
Drawer,
|
||||
DynBlock,
|
||||
ExampleBlock,
|
||||
ExportBlock,
|
||||
FixedWidth,
|
||||
FnDef,
|
||||
FnRef,
|
||||
InlineCall,
|
||||
|
|
@ -233,11 +235,12 @@ impl_from!(
|
|||
Snippet,
|
||||
SourceBlock,
|
||||
SpecialBlock,
|
||||
Table,
|
||||
Target,
|
||||
Timestamp,
|
||||
Table,
|
||||
Title,
|
||||
VerseBlock;
|
||||
List,
|
||||
Rule,
|
||||
TableRow
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,19 +1,25 @@
|
|||
use std::usize;
|
||||
|
||||
use nom::{bytes::complete::take_while_m_n, error::ParseError, IResult};
|
||||
|
||||
use crate::parsers::eol;
|
||||
use crate::parsers::{blank_lines, eol};
|
||||
|
||||
pub fn parse_rule(input: &str) -> Option<&str> {
|
||||
parse_rule_internal::<()>(input)
|
||||
.ok()
|
||||
.map(|(input, _)| input)
|
||||
#[derive(Debug, Default)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
pub struct Rule {
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
fn parse_rule_internal<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, (), E> {
|
||||
let (input, _) = take_while_m_n(5, usize::MAX, |c| c == '-')(input)?;
|
||||
impl Rule {
|
||||
pub(crate) fn parse(input: &str) -> Option<(&str, Rule)> {
|
||||
parse_rule::<()>(input).ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_rule<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Rule, E> {
|
||||
let (input, _) = take_while_m_n(5, usize::max_value(), |c| c == '-')(input)?;
|
||||
let (input, _) = eol(input)?;
|
||||
Ok((input, ()))
|
||||
let (input, blank) = blank_lines(input);
|
||||
Ok((input, Rule { post_blank: blank }))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -21,29 +27,29 @@ fn parse() {
|
|||
use nom::error::VerboseError;
|
||||
|
||||
assert_eq!(
|
||||
parse_rule_internal::<VerboseError<&str>>("-----"),
|
||||
Ok(("", ()))
|
||||
parse_rule::<VerboseError<&str>>("-----"),
|
||||
Ok(("", Rule { post_blank: 0 }))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_rule_internal::<VerboseError<&str>>("--------"),
|
||||
Ok(("", ()))
|
||||
parse_rule::<VerboseError<&str>>("--------"),
|
||||
Ok(("", Rule { post_blank: 0 }))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_rule_internal::<VerboseError<&str>>("-----\n"),
|
||||
Ok(("", ()))
|
||||
parse_rule::<VerboseError<&str>>("-----\n\n\n"),
|
||||
Ok(("", Rule { post_blank: 2 }))
|
||||
);
|
||||
assert_eq!(
|
||||
parse_rule_internal::<VerboseError<&str>>("----- \n"),
|
||||
Ok(("", ()))
|
||||
parse_rule::<VerboseError<&str>>("----- \n"),
|
||||
Ok(("", Rule { post_blank: 0 }))
|
||||
);
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("----").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("----").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("None----").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("None ----").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("None------").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("----None----").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("\t\t----").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("------None").is_err());
|
||||
assert!(parse_rule_internal::<VerboseError<&str>>("----- None").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("----").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("----").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("None----").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("None ----").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("None------").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("----None----").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("\t\t----").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("------None").is_err());
|
||||
assert!(parse_rule::<VerboseError<&str>>("----- None").is_err());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ impl TableRow {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_table_el(input: &str) -> Option<(&str, &str)> {
|
||||
pub fn parse_table_el(input: &str) -> Option<(&str, &str)> {
|
||||
parse_table_el_internal::<()>(input).ok()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ use nom::{
|
|||
|
||||
use crate::{
|
||||
config::ParseConfig,
|
||||
elements::{drawer::parse_drawer, Planning, Timestamp},
|
||||
parsers::{line, skip_empty_lines, take_one_word},
|
||||
elements::{drawer::parse_drawer_without_blank, Planning, Timestamp},
|
||||
parsers::{blank_lines, line, skip_empty_lines, take_one_word},
|
||||
};
|
||||
|
||||
/// Title Elemenet
|
||||
|
|
@ -44,6 +44,8 @@ pub struct Title<'a> {
|
|||
/// Property drawer associated to this headline
|
||||
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "HashMap::is_empty"))]
|
||||
pub properties: HashMap<Cow<'a, str>, Cow<'a, str>>,
|
||||
/// Numbers of blank lines
|
||||
pub post_blank: usize,
|
||||
}
|
||||
|
||||
impl Title<'_> {
|
||||
|
|
@ -102,6 +104,7 @@ impl Title<'_> {
|
|||
.into_iter()
|
||||
.map(|(k, v)| (k.into_owned().into(), v.into_owned().into()))
|
||||
.collect(),
|
||||
post_blank: self.post_blank,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,6 +119,7 @@ impl Default for Title<'_> {
|
|||
raw: Cow::Borrowed(""),
|
||||
planning: None,
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,6 +170,7 @@ fn parse_title<'a, E: ParseError<&'a str>>(
|
|||
.unwrap_or((input, None));
|
||||
|
||||
let (input, properties) = opt(parse_properties_drawer)(input)?;
|
||||
let (input, blank) = blank_lines(input);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
|
|
@ -178,6 +183,7 @@ fn parse_title<'a, E: ParseError<&'a str>>(
|
|||
tags,
|
||||
raw: raw.into(),
|
||||
planning,
|
||||
post_blank: blank,
|
||||
},
|
||||
raw,
|
||||
),
|
||||
|
|
@ -188,7 +194,7 @@ fn parse_title<'a, E: ParseError<&'a str>>(
|
|||
fn parse_properties_drawer<'a, E: ParseError<&'a str>>(
|
||||
input: &'a str,
|
||||
) -> IResult<&str, HashMap<Cow<'_, str>, Cow<'_, str>>, E> {
|
||||
let (input, (drawer, content)) = parse_drawer(input.trim_start())?;
|
||||
let (input, (drawer, content)) = parse_drawer_without_blank(input.trim_start())?;
|
||||
if drawer.name != "PROPERTIES" {
|
||||
return Err(Err::Error(E::from_error_kind(input, ErrorKind::Tag)));
|
||||
}
|
||||
|
|
@ -236,7 +242,8 @@ fn parse_title_() {
|
|||
raw: "COMMENT Title".into(),
|
||||
tags: vec!["tag".into(), "a2%".into()],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"COMMENT Title"
|
||||
)
|
||||
|
|
@ -254,7 +261,8 @@ fn parse_title_() {
|
|||
raw: "ToDO [#A] COMMENT Title".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"ToDO [#A] COMMENT Title"
|
||||
)
|
||||
|
|
@ -272,7 +280,8 @@ fn parse_title_() {
|
|||
raw: "T0DO [#A] COMMENT Title".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"T0DO [#A] COMMENT Title"
|
||||
)
|
||||
|
|
@ -290,7 +299,8 @@ fn parse_title_() {
|
|||
raw: "[#1] COMMENT Title".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"[#1] COMMENT Title"
|
||||
)
|
||||
|
|
@ -308,7 +318,8 @@ fn parse_title_() {
|
|||
raw: "[#a] COMMENT Title".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"[#a] COMMENT Title"
|
||||
)
|
||||
|
|
@ -326,7 +337,8 @@ fn parse_title_() {
|
|||
raw: "Title :tag:a2%".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"Title :tag:a2%"
|
||||
)
|
||||
|
|
@ -344,7 +356,8 @@ fn parse_title_() {
|
|||
raw: "Title tag:a2%:".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"Title tag:a2%:"
|
||||
)
|
||||
|
|
@ -369,7 +382,8 @@ fn parse_title_() {
|
|||
raw: "DONE Title".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"DONE Title"
|
||||
)
|
||||
|
|
@ -393,7 +407,8 @@ fn parse_title_() {
|
|||
raw: "Title".into(),
|
||||
tags: vec![],
|
||||
planning: None,
|
||||
properties: HashMap::new()
|
||||
properties: HashMap::new(),
|
||||
post_blank: 0,
|
||||
},
|
||||
"Title"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue