feat(elements): into_owned function

This commit is contained in:
PoiScript 2019-08-10 20:17:39 +08:00
parent 9bc260627b
commit f2d0a1dd2d
25 changed files with 475 additions and 131 deletions

View file

@ -12,6 +12,15 @@ pub struct SpecialBlock<'a> {
pub name: Cow<'a, str>, pub name: Cow<'a, str>,
} }
impl SpecialBlock<'_> {
pub fn into_owned(self) -> SpecialBlock<'static> {
SpecialBlock {
name: self.name.into_owned().into(),
parameters: self.parameters.map(Into::into).map(Cow::Owned),
}
}
}
#[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))]
@ -19,6 +28,14 @@ pub struct QuoteBlock<'a> {
pub parameters: Option<Cow<'a, str>>, pub parameters: Option<Cow<'a, str>>,
} }
impl QuoteBlock<'_> {
pub fn into_owned(self) -> QuoteBlock<'static> {
QuoteBlock {
parameters: self.parameters.map(Into::into).map(Cow::Owned),
}
}
}
#[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))]
@ -26,6 +43,14 @@ pub struct CenterBlock<'a> {
pub parameters: Option<Cow<'a, str>>, pub parameters: Option<Cow<'a, str>>,
} }
impl CenterBlock<'_> {
pub fn into_owned(self) -> CenterBlock<'static> {
CenterBlock {
parameters: self.parameters.map(Into::into).map(Cow::Owned),
}
}
}
#[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))]
@ -33,6 +58,14 @@ pub struct VerseBlock<'a> {
pub parameters: Option<Cow<'a, str>>, pub parameters: Option<Cow<'a, str>>,
} }
impl VerseBlock<'_> {
pub fn into_owned(self) -> VerseBlock<'static> {
VerseBlock {
parameters: self.parameters.map(Into::into).map(Cow::Owned),
}
}
}
#[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))]
@ -41,6 +74,15 @@ pub struct CommentBlock<'a> {
pub contents: Cow<'a, str>, pub contents: Cow<'a, str>,
} }
impl CommentBlock<'_> {
pub fn into_owned(self) -> CommentBlock<'static> {
CommentBlock {
data: self.data.map(Into::into).map(Cow::Owned),
contents: self.contents.into_owned().into(),
}
}
}
#[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))]
@ -49,6 +91,15 @@ pub struct ExampleBlock<'a> {
pub contents: Cow<'a, str>, pub contents: Cow<'a, str>,
} }
impl ExampleBlock<'_> {
pub fn into_owned(self) -> ExampleBlock<'static> {
ExampleBlock {
data: self.data.map(Into::into).map(Cow::Owned),
contents: self.contents.into_owned().into(),
}
}
}
#[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))]
@ -57,6 +108,15 @@ pub struct ExportBlock<'a> {
pub contents: Cow<'a, str>, pub contents: Cow<'a, str>,
} }
impl ExportBlock<'_> {
pub fn into_owned(self) -> ExportBlock<'static> {
ExportBlock {
data: self.data.into_owned().into(),
contents: self.contents.into_owned().into(),
}
}
}
#[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))]
@ -66,6 +126,16 @@ pub struct SourceBlock<'a> {
pub arguments: Cow<'a, str>, pub arguments: Cow<'a, str>,
} }
impl SourceBlock<'_> {
pub fn into_owned(self) -> SourceBlock<'static> {
SourceBlock {
language: self.language.into_owned().into(),
arguments: self.arguments.into_owned().into(),
contents: self.contents.into_owned().into(),
}
}
}
pub(crate) fn parse_block_element(input: &str) -> IResult<&str, (&str, Option<&str>, &str)> { pub(crate) fn parse_block_element(input: &str) -> IResult<&str, (&str, Option<&str>, &str)> {
let (input, name) = preceded(tag_no_case("#+BEGIN_"), alpha1)(input)?; let (input, name) = preceded(tag_no_case("#+BEGIN_"), alpha1)(input)?;
let (input, args) = line(input)?; let (input, args) = line(input)?;

View file

@ -90,6 +90,33 @@ impl Clock<'_> {
} }
} }
pub fn into_onwed(self) -> Clock<'static> {
match self {
Clock::Closed {
start,
end,
repeater,
delay,
duration,
} => 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(),
},
Clock::Running {
start,
repeater,
delay,
} => Clock::Running {
start: start.into_owned(),
repeater: repeater.map(Into::into).map(Cow::Owned),
delay: delay.map(Into::into).map(Cow::Owned),
},
}
}
/// returns `true` if the clock is running /// returns `true` if the clock is running
pub fn is_running(&self) -> bool { pub fn is_running(&self) -> bool {
match self { match self {

View file

@ -35,6 +35,12 @@ impl Cookie<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> Cookie<'static> {
Cookie {
value: self.value.into_owned().into(),
}
}
} }
#[test] #[test]

View file

@ -30,6 +30,12 @@ impl Drawer<'_> {
Ok((input, (Drawer { name: name.into() }, contents))) Ok((input, (Drawer { name: name.into() }, contents)))
} }
pub fn into_owned(self) -> Drawer<'static> {
Drawer {
name: self.name.into_owned().into(),
}
}
} }
#[test] #[test]

View file

@ -43,6 +43,13 @@ impl DynBlock<'_> {
), ),
)) ))
} }
pub fn into_owned(self) -> DynBlock<'static> {
DynBlock {
block_name: self.block_name.into_owned().into(),
arguments: self.arguments.map(Into::into).map(Cow::Owned),
}
}
} }
#[test] #[test]

View file

@ -35,6 +35,12 @@ impl FnDef<'_> {
), ),
)) ))
} }
pub fn into_owned(self) -> FnDef<'static> {
FnDef {
label: self.label.into_owned().into(),
}
}
} }
#[test] #[test]

View file

@ -50,6 +50,13 @@ impl FnRef<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> FnRef<'static> {
FnRef {
label: self.label.into_owned().into(),
definition: self.definition.map(Into::into).map(Cow::Owned),
}
}
} }
#[test] #[test]

View file

@ -49,6 +49,15 @@ impl InlineCall<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> InlineCall<'static> {
InlineCall {
name: self.name.into_owned().into(),
arguments: self.arguments.into_owned().into(),
inside_header: self.inside_header.map(Into::into).map(Cow::Owned),
end_header: self.end_header.map(Into::into).map(Cow::Owned),
}
}
} }
#[test] #[test]

View file

@ -40,6 +40,14 @@ impl InlineSrc<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> InlineSrc<'static> {
InlineSrc {
lang: self.lang.into_owned().into(),
options: self.options.map(Into::into).map(Cow::Owned),
body: self.body.into_owned().into(),
}
}
} }
#[test] #[test]

View file

@ -19,6 +19,16 @@ pub struct Keyword<'a> {
pub value: Cow<'a, str>, pub value: Cow<'a, str>,
} }
impl Keyword<'_> {
pub fn into_owned(self) -> Keyword<'static> {
Keyword {
key: self.key.into_owned().into(),
optional: self.optional.map(Into::into).map(Cow::Owned),
value: self.value.into_owned().into(),
}
}
}
#[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)]
@ -26,6 +36,14 @@ pub struct BabelCall<'a> {
pub value: Cow<'a, str>, pub value: Cow<'a, str>,
} }
impl BabelCall<'_> {
pub fn into_owned(self) -> BabelCall<'static> {
BabelCall {
value: self.value.into_owned().into(),
}
}
}
pub(crate) fn parse_keyword(input: &str) -> IResult<&str, (&str, Option<&str>, &str)> { pub(crate) fn parse_keyword(input: &str) -> IResult<&str, (&str, Option<&str>, &str)> {
let (input, _) = tag("#+")(input)?; let (input, _) = tag("#+")(input)?;
let (input, key) = take_till(|c: char| c.is_ascii_whitespace() || c == ':' || c == '[')(input)?; let (input, key) = take_till(|c: char| c.is_ascii_whitespace() || c == ':' || c == '[')(input)?;

View file

@ -38,6 +38,13 @@ impl Link<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> Link<'static> {
Link {
path: self.path.into_owned().into(),
desc: self.desc.map(Into::into).map(Cow::Owned),
}
}
} }
#[test] #[test]

View file

@ -106,6 +106,12 @@ impl ListItem<'_> {
&text[off..], &text[off..],
) )
} }
pub fn into_owned(self) -> ListItem<'static> {
ListItem {
bullet: self.bullet.into_owned().into(),
}
}
} }
#[inline] #[inline]

View file

@ -35,6 +35,13 @@ impl Macros<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> Macros<'static> {
Macros {
name: self.name.into_owned().into(),
arguments: self.arguments.map(Into::into).map(Cow::Owned),
}
}
} }
#[test] #[test]

View file

@ -24,8 +24,8 @@ mod timestamp;
mod title; mod title;
pub(crate) use self::{ pub(crate) use self::{
block::parse_block_element, emphasis::parse_emphasis, keyword::parse_keyword, rule::parse_rule, block::parse_block_element, emphasis::parse_emphasis, keyword::parse_keyword,
table::parse_table_el, radio_target::parse_radio_target, rule::parse_rule, table::parse_table_el,
}; };
pub use self::{ pub use self::{
@ -46,7 +46,6 @@ pub use self::{
list::{List, ListItem}, list::{List, ListItem},
macros::Macros, macros::Macros,
planning::Planning, planning::Planning,
radio_target::RadioTarget,
snippet::Snippet, snippet::Snippet,
table::{Table, TableRow}, table::{Table, TableRow},
target::Target, target::Target,
@ -74,7 +73,7 @@ pub enum Element<'a> {
Section, Section,
Clock(Clock<'a>), Clock(Clock<'a>),
Cookie(Cookie<'a>), Cookie(Cookie<'a>),
RadioTarget(RadioTarget), RadioTarget,
Drawer(Drawer<'a>), Drawer(Drawer<'a>),
Document, Document,
DynBlock(DynBlock<'a>), DynBlock(DynBlock<'a>),
@ -89,7 +88,7 @@ pub enum Element<'a> {
ListItem(ListItem<'a>), ListItem(ListItem<'a>),
Macros(Macros<'a>), Macros(Macros<'a>),
Snippet(Snippet<'a>), Snippet(Snippet<'a>),
Text { value: &'a str }, Text { value: Cow<'a, str> },
Paragraph, Paragraph,
Rule, Rule,
Timestamp(Timestamp<'a>), Timestamp(Timestamp<'a>),
@ -110,29 +109,76 @@ pub enum Element<'a> {
impl Element<'_> { impl Element<'_> {
pub fn is_container(&self) -> bool { pub fn is_container(&self) -> bool {
use Element::*;
match self { match self {
Element::SpecialBlock(_) SpecialBlock(_) | QuoteBlock(_) | CenterBlock(_) | VerseBlock(_) | Bold | Document
| Element::QuoteBlock(_) | DynBlock(_) | Headline | Italic | List(_) | ListItem(_) | Paragraph | Section
| Element::CenterBlock(_) | Strike | Underline | Title(_) | Table(_) | TableRow(_) | TableCell => true,
| Element::VerseBlock(_)
| Element::Bold
| Element::Document
| Element::DynBlock(_)
| Element::Headline
| Element::Italic
| Element::List(_)
| Element::ListItem(_)
| Element::Paragraph
| Element::Section
| Element::Strike
| Element::Underline
| Element::Title(_)
| Element::Table(_)
| Element::TableRow(_)
| Element::TableCell => true,
_ => false, _ => false,
} }
} }
pub fn into_owned(self) -> Element<'static> {
use Element::*;
match self {
SpecialBlock(e) => SpecialBlock(e.into_owned()),
QuoteBlock(e) => QuoteBlock(e.into_owned()),
CenterBlock(e) => CenterBlock(e.into_owned()),
VerseBlock(e) => VerseBlock(e.into_owned()),
CommentBlock(e) => CommentBlock(e.into_owned()),
ExampleBlock(e) => ExampleBlock(e.into_owned()),
ExportBlock(e) => ExportBlock(e.into_owned()),
SourceBlock(e) => SourceBlock(e.into_owned()),
BabelCall(e) => BabelCall(e.into_owned()),
Section => Section,
Clock(e) => Clock(e.into_onwed()),
Cookie(e) => Cookie(e.into_owned()),
RadioTarget => RadioTarget,
Drawer(e) => Drawer(e.into_owned()),
Document => Document,
DynBlock(e) => DynBlock(e.into_owned()),
FnDef(e) => FnDef(e.into_owned()),
FnRef(e) => FnRef(e.into_owned()),
Headline => Headline,
InlineCall(e) => InlineCall(e.into_owned()),
InlineSrc(e) => InlineSrc(e.into_owned()),
Keyword(e) => Keyword(e.into_owned()),
Link(e) => Link(e.into_owned()),
List(e) => List(e),
ListItem(e) => ListItem(e.into_owned()),
Macros(e) => Macros(e.into_owned()),
Snippet(e) => Snippet(e.into_owned()),
Text { value } => Text {
value: value.into_owned().into(),
},
Paragraph => Paragraph,
Rule => Rule,
Timestamp(e) => Timestamp(e.into_owned()),
Target(e) => Target(e.into_owned()),
Bold => Bold,
Strike => Strike,
Italic => Italic,
Underline => Underline,
Verbatim { value } => Verbatim {
value: value.into_owned().into(),
},
Code { value } => Code {
value: value.into_owned().into(),
},
Comment { value } => Comment {
value: value.into_owned().into(),
},
FixedWidth { value } => FixedWidth {
value: value.into_owned().into(),
},
Title(e) => Title(e.into_owned()),
Table(e) => Table(e.into_owned()),
TableRow(e) => TableRow(e),
TableCell => TableCell,
}
}
} }
macro_rules! impl_from { macro_rules! impl_from {
@ -181,7 +227,6 @@ impl_from!(
Table, Table,
Title, Title,
VerseBlock; VerseBlock;
RadioTarget,
List, List,
TableRow TableRow
); );

View file

@ -64,6 +64,14 @@ impl Planning<'_> {
)) ))
} }
} }
pub fn into_owned(self) -> Planning<'static> {
Planning {
deadline: self.deadline.map(|x| x.into_owned()),
scheduled: self.scheduled.map(|x| x.into_owned()),
closed: self.closed.map(|x| x.into_owned()),
}
}
} }
#[test] #[test]

View file

@ -5,17 +5,10 @@ use nom::{
IResult, IResult,
}; };
use crate::elements::Element;
// TODO: text-markup, entities, latex-fragments, subscript and superscript // TODO: text-markup, entities, latex-fragments, subscript and superscript
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
#[derive(Debug)]
pub struct RadioTarget;
impl RadioTarget { #[inline]
#[inline] pub(crate) fn parse_radio_target(input: &str) -> IResult<&str, &str> {
pub(crate) fn parse(input: &str) -> IResult<&str, (Element, &str)> {
let (input, contents) = delimited( let (input, contents) = delimited(
tag("<<<"), tag("<<<"),
verify( verify(
@ -25,24 +18,17 @@ impl RadioTarget {
tag(">>>"), tag(">>>"),
)(input)?; )(input)?;
Ok((input, (Element::RadioTarget(RadioTarget), contents))) Ok((input, contents))
}
} }
#[test] #[test]
fn parse() { fn parse() {
assert_eq!( assert_eq!(parse_radio_target("<<<target>>>"), Ok(("", "target")));
RadioTarget::parse("<<<target>>>"), assert_eq!(parse_radio_target("<<<tar get>>>"), Ok(("", "tar get")));
Ok(("", (Element::RadioTarget(RadioTarget), "target"))) assert!(parse_radio_target("<<<target >>>").is_err());
); assert!(parse_radio_target("<<< target>>>").is_err());
assert_eq!( assert!(parse_radio_target("<<<ta<get>>>").is_err());
RadioTarget::parse("<<<tar get>>>"), assert!(parse_radio_target("<<<ta>get>>>").is_err());
Ok(("", (Element::RadioTarget(RadioTarget), "tar get"))) assert!(parse_radio_target("<<<ta\nget>>>").is_err());
); assert!(parse_radio_target("<<<target>>").is_err());
assert!(RadioTarget::parse("<<<target >>>").is_err());
assert!(RadioTarget::parse("<<< target>>>").is_err());
assert!(RadioTarget::parse("<<<ta<get>>>").is_err());
assert!(RadioTarget::parse("<<<ta>get>>>").is_err());
assert!(RadioTarget::parse("<<<ta\nget>>>").is_err());
assert!(RadioTarget::parse("<<<target>>").is_err());
} }

View file

@ -35,6 +35,13 @@ impl Snippet<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> Snippet<'static> {
Snippet {
name: self.name.into_owned().into(),
value: self.value.into_owned().into(),
}
}
} }
#[test] #[test]

View file

@ -18,6 +18,19 @@ pub enum Table<'a> {
TableEl { value: Cow<'a, str> }, TableEl { value: Cow<'a, str> },
} }
impl Table<'_> {
pub fn into_owned(self) -> Table<'static> {
match self {
Table::Org { tblfm } => Table::Org {
tblfm: tblfm.map(Into::into).map(Cow::Owned),
},
Table::TableEl { value } => Table::TableEl {
value: value.into_owned().into(),
},
}
}
}
#[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))]

View file

@ -33,6 +33,12 @@ impl Target<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> Target<'static> {
Target {
target: self.target.into_owned().into(),
}
}
} }
#[test] #[test]

View file

@ -30,47 +30,17 @@ pub struct Datetime<'a> {
pub minute: Option<u8>, pub minute: Option<u8>,
} }
fn parse_time(input: &str) -> IResult<&str, (u8, u8)> { impl Datetime<'_> {
let (input, hour) = map_res(take_while_m_n(1, 2, |c: char| c.is_ascii_digit()), |num| { pub fn into_owned(self) -> Datetime<'static> {
u8::from_str_radix(num, 10)
})(input)?;
let (input, _) = tag(":")(input)?;
let (input, minute) = map_res(take(2usize), |num| u8::from_str_radix(num, 10))(input)?;
Ok((input, (hour, minute)))
}
fn parse_datetime(input: &str) -> IResult<&str, Datetime<'_>> {
let parse_u8 = |num| u8::from_str_radix(num, 10);
let (input, year) = map_res(take(4usize), |num| u16::from_str_radix(num, 10))(input)?;
let (input, _) = tag("-")(input)?;
let (input, month) = map_res(take(2usize), parse_u8)(input)?;
let (input, _) = tag("-")(input)?;
let (input, day) = map_res(take(2usize), parse_u8)(input)?;
let (input, _) = space1(input)?;
let (input, dayname) = take_while(|c: char| {
!c.is_ascii_whitespace()
&& !c.is_ascii_digit()
&& c != '+'
&& c != '-'
&& c != ']'
&& c != '>'
})(input)?;
let (input, (hour, minute)) = map(opt(preceded(space1, parse_time)), |time| {
(time.map(|t| t.0), time.map(|t| t.1))
})(input)?;
Ok((
input,
Datetime { Datetime {
year, year: self.year,
month, month: self.month,
day, day: self.day,
dayname: dayname.into(), dayname: self.dayname.into_owned().into(),
hour, hour: self.hour,
minute, minute: self.minute,
}, }
)) }
} }
#[cfg(feature = "chrono")] #[cfg(feature = "chrono")]
@ -281,6 +251,97 @@ impl Timestamp<'_> {
}, },
)) ))
} }
pub fn into_owned(self) -> Timestamp<'static> {
match self {
Timestamp::Active {
start,
repeater,
delay,
} => Timestamp::Active {
start: start.into_owned(),
repeater: repeater.map(Into::into).map(Cow::Owned),
delay: delay.map(Into::into).map(Cow::Owned),
},
Timestamp::Inactive {
start,
repeater,
delay,
} => Timestamp::Inactive {
start: start.into_owned(),
repeater: repeater.map(Into::into).map(Cow::Owned),
delay: delay.map(Into::into).map(Cow::Owned),
},
Timestamp::ActiveRange {
start,
end,
repeater,
delay,
} => Timestamp::ActiveRange {
start: start.into_owned(),
end: end.into_owned(),
repeater: repeater.map(Into::into).map(Cow::Owned),
delay: delay.map(Into::into).map(Cow::Owned),
},
Timestamp::InactiveRange {
start,
end,
repeater,
delay,
} => Timestamp::InactiveRange {
start: start.into_owned(),
end: end.into_owned(),
repeater: repeater.map(Into::into).map(Cow::Owned),
delay: delay.map(Into::into).map(Cow::Owned),
},
Timestamp::Diary { value } => Timestamp::Diary {
value: value.into_owned().into(),
},
}
}
}
fn parse_time(input: &str) -> IResult<&str, (u8, u8)> {
let (input, hour) = map_res(take_while_m_n(1, 2, |c: char| c.is_ascii_digit()), |num| {
u8::from_str_radix(num, 10)
})(input)?;
let (input, _) = tag(":")(input)?;
let (input, minute) = map_res(take(2usize), |num| u8::from_str_radix(num, 10))(input)?;
Ok((input, (hour, minute)))
}
fn parse_datetime(input: &str) -> IResult<&str, Datetime<'_>> {
let parse_u8 = |num| u8::from_str_radix(num, 10);
let (input, year) = map_res(take(4usize), |num| u16::from_str_radix(num, 10))(input)?;
let (input, _) = tag("-")(input)?;
let (input, month) = map_res(take(2usize), parse_u8)(input)?;
let (input, _) = tag("-")(input)?;
let (input, day) = map_res(take(2usize), parse_u8)(input)?;
let (input, _) = space1(input)?;
let (input, dayname) = take_while(|c: char| {
!c.is_ascii_whitespace()
&& !c.is_ascii_digit()
&& c != '+'
&& c != '-'
&& c != ']'
&& c != '>'
})(input)?;
let (input, (hour, minute)) = map(opt(preceded(space1, parse_time)), |time| {
(time.map(|t| t.0), time.map(|t| t.1))
})(input)?;
Ok((
input,
Datetime {
year,
month,
day,
dayname: dayname.into(),
hour,
minute,
},
))
} }
// TODO // TODO

View file

@ -71,6 +71,26 @@ impl Title<'_> {
), ),
)) ))
} }
pub fn into_owned(self) -> Title<'static> {
Title {
level: self.level,
priority: self.priority,
tags: self
.tags
.into_iter()
.map(|s| s.into_owned().into())
.collect(),
keyword: self.keyword.map(Into::into).map(Cow::Owned),
raw: self.raw.into_owned().into(),
planning: self.planning.map(|p| Box::new(p.into_owned())),
properties: self
.properties
.into_iter()
.map(|(k, v)| (k.into_owned().into(), v.into_owned().into()))
.collect(),
}
}
} }
fn parse_headline<'a>( fn parse_headline<'a>(

View file

@ -101,7 +101,7 @@ pub trait HtmlHandler<E: From<Error>> {
Escape(link.desc.as_ref().unwrap_or(&link.path)), Escape(link.desc.as_ref().unwrap_or(&link.path)),
)?, )?,
Macros(_macros) => (), Macros(_macros) => (),
RadioTarget(_radio_target) => (), RadioTarget => (),
Snippet(snippet) => { Snippet(snippet) => {
if snippet.name.eq_ignore_ascii_case("HTML") { if snippet.name.eq_ignore_ascii_case("HTML") {
write!(w, "{}", snippet.value)?; write!(w, "{}", snippet.value)?;

View file

@ -81,7 +81,7 @@ pub trait OrgHandler<E: From<Error>> {
write!(&mut w, "]")?; write!(&mut w, "]")?;
} }
Macros(_macros) => (), Macros(_macros) => (),
RadioTarget(_radio_target) => (), RadioTarget => (),
Snippet(snippet) => write!(w, "@@{}:{}@@", snippet.name, snippet.value)?, Snippet(snippet) => write!(w, "@@{}:{}@@", snippet.name, snippet.value)?,
Target(_target) => (), Target(_target) => (),
Text { value } => write!(w, "{}", value)?, Text { value } => write!(w, "{}", value)?,

View file

@ -5,7 +5,7 @@ use crate::config::ParseConfig;
use crate::elements::Element; use crate::elements::Element;
use crate::export::*; use crate::export::*;
use crate::node::HeadlineNode; use crate::node::HeadlineNode;
use crate::parsers::*; use crate::parsers::{parse_container, Container};
pub struct Org<'a> { pub struct Org<'a> {
pub(crate) arena: Arena<Element<'a>>, pub(crate) arena: Arena<Element<'a>>,
@ -27,31 +27,7 @@ impl Org<'_> {
let mut arena = Arena::new(); let mut arena = Arena::new();
let node = arena.new_node(Element::Document); let node = arena.new_node(Element::Document);
let containers = &mut vec![Container::Document { content, node }]; parse_container(&mut arena, Container::Document { content, node }, config);
while let Some(container) = containers.pop() {
match container {
Container::Document { content, node } => {
parse_section_and_headlines(&mut arena, content, node, containers);
}
Container::Headline { content, node } => {
parse_headline_content(&mut arena, content, node, containers, config);
}
Container::Block { content, node } => {
parse_blocks(&mut arena, content, node, containers);
}
Container::Inline { content, node } => {
parse_inlines(&mut arena, content, node, containers);
}
Container::List {
content,
node,
indent,
} => {
parse_list_items(&mut arena, content, indent, node, containers);
}
}
}
Org { arena, root: node } Org { arena, root: node }
} }

View file

@ -1,6 +1,7 @@
// parser related functions // parser related functions
use std::borrow::Cow; use std::borrow::Cow;
use std::marker::PhantomData;
use indextree::{Arena, NodeId}; use indextree::{Arena, NodeId};
use jetscii::bytes; use jetscii::bytes;
@ -80,6 +81,38 @@ pub enum Container<'a> {
}, },
} }
pub fn parse_container<'a, T: ElementArena<'a>>(
arena: &mut T,
container: Container<'a>,
config: &ParseConfig,
) {
let containers = &mut vec![container];
while let Some(container) = containers.pop() {
match container {
Container::Document { content, node } => {
parse_section_and_headlines(arena, content, node, containers);
}
Container::Headline { content, node } => {
parse_headline_content(arena, content, node, containers, config);
}
Container::Block { content, node } => {
parse_blocks(arena, content, node, containers);
}
Container::Inline { content, node } => {
parse_inlines(arena, content, node, containers);
}
Container::List {
content,
node,
indent,
} => {
parse_list_items(arena, content, indent, node, containers);
}
}
}
}
pub fn parse_headline_content<'a, T: ElementArena<'a>>( pub fn parse_headline_content<'a, T: ElementArena<'a>>(
arena: &mut T, arena: &mut T,
content: &'a str, content: &'a str,
@ -397,7 +430,12 @@ pub fn parse_inlines<'a, T: ElementArena<'a>>(
macro_rules! insert_text { macro_rules! insert_text {
($value:expr) => { ($value:expr) => {
arena.insert_before_last_child(Element::Text { value: $value }, parent); arena.insert_before_last_child(
Element::Text {
value: $value.into(),
},
parent,
);
pos = 0; pos = 0;
}; };
} }
@ -449,7 +487,7 @@ pub fn parse_inlines<'a, T: ElementArena<'a>>(
} }
if !text.is_empty() { if !text.is_empty() {
arena.push_element(Element::Text { value: text }, parent); arena.push_element(Element::Text { value: text.into() }, parent);
} }
} }
@ -478,8 +516,8 @@ pub fn parse_inline<'a, T: ElementArena<'a>>(
} }
} }
b'<' => { b'<' => {
if let Ok((tail, (radio, _content))) = RadioTarget::parse(contents) { if let Ok((tail, _content)) = parse_radio_target(contents) {
arena.push_element(radio, parent); arena.push_element(Element::RadioTarget, parent);
return Some(tail); return Some(tail);
} else if let Ok((tail, target)) = Target::parse(contents) { } else if let Ok((tail, target)) = Target::parse(contents) {
arena.push_element(target, parent); arena.push_element(target, parent);
@ -717,7 +755,7 @@ pub fn take_one_word(input: &str) -> IResult<&str, &str> {
} }
#[test] #[test]
fn test_skip_empty_lines() { pub fn test_skip_empty_lines() {
assert_eq!(skip_empty_lines("foo"), "foo"); assert_eq!(skip_empty_lines("foo"), "foo");
assert_eq!(skip_empty_lines(" foo"), " foo"); assert_eq!(skip_empty_lines(" foo"), " foo");
assert_eq!(skip_empty_lines(" \nfoo\n"), "foo\n"); assert_eq!(skip_empty_lines(" \nfoo\n"), "foo\n");