feat(elements): into_owned
function
This commit is contained in:
parent
9bc260627b
commit
f2d0a1dd2d
|
@ -12,6 +12,15 @@ pub struct SpecialBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -19,6 +28,14 @@ pub struct QuoteBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -26,6 +43,14 @@ pub struct CenterBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -33,6 +58,14 @@ pub struct VerseBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -41,6 +74,15 @@ pub struct CommentBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -49,6 +91,15 @@ pub struct ExampleBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -57,6 +108,15 @@ pub struct ExportBlock<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
@ -66,6 +126,16 @@ pub struct SourceBlock<'a> {
|
|||
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)> {
|
||||
let (input, name) = preceded(tag_no_case("#+BEGIN_"), alpha1)(input)?;
|
||||
let (input, args) = line(input)?;
|
||||
|
|
|
@ -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
|
||||
pub fn is_running(&self) -> bool {
|
||||
match self {
|
||||
|
|
|
@ -35,6 +35,12 @@ impl Cookie<'_> {
|
|||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> Cookie<'static> {
|
||||
Cookie {
|
||||
value: self.value.into_owned().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -30,6 +30,12 @@ impl Drawer<'_> {
|
|||
|
||||
Ok((input, (Drawer { name: name.into() }, contents)))
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> Drawer<'static> {
|
||||
Drawer {
|
||||
name: self.name.into_owned().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -35,6 +35,12 @@ impl FnDef<'_> {
|
|||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> FnDef<'static> {
|
||||
FnDef {
|
||||
label: self.label.into_owned().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -19,6 +19,16 @@ pub struct Keyword<'a> {
|
|||
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(feature = "ser", derive(serde::Serialize))]
|
||||
#[derive(Debug)]
|
||||
|
@ -26,6 +36,14 @@ pub struct BabelCall<'a> {
|
|||
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)> {
|
||||
let (input, _) = tag("#+")(input)?;
|
||||
let (input, key) = take_till(|c: char| c.is_ascii_whitespace() || c == ':' || c == '[')(input)?;
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -106,6 +106,12 @@ impl ListItem<'_> {
|
|||
&text[off..],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> ListItem<'static> {
|
||||
ListItem {
|
||||
bullet: self.bullet.into_owned().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -24,8 +24,8 @@ mod timestamp;
|
|||
mod title;
|
||||
|
||||
pub(crate) use self::{
|
||||
block::parse_block_element, emphasis::parse_emphasis, keyword::parse_keyword, rule::parse_rule,
|
||||
table::parse_table_el,
|
||||
block::parse_block_element, emphasis::parse_emphasis, keyword::parse_keyword,
|
||||
radio_target::parse_radio_target, rule::parse_rule, table::parse_table_el,
|
||||
};
|
||||
|
||||
pub use self::{
|
||||
|
@ -46,7 +46,6 @@ pub use self::{
|
|||
list::{List, ListItem},
|
||||
macros::Macros,
|
||||
planning::Planning,
|
||||
radio_target::RadioTarget,
|
||||
snippet::Snippet,
|
||||
table::{Table, TableRow},
|
||||
target::Target,
|
||||
|
@ -74,7 +73,7 @@ pub enum Element<'a> {
|
|||
Section,
|
||||
Clock(Clock<'a>),
|
||||
Cookie(Cookie<'a>),
|
||||
RadioTarget(RadioTarget),
|
||||
RadioTarget,
|
||||
Drawer(Drawer<'a>),
|
||||
Document,
|
||||
DynBlock(DynBlock<'a>),
|
||||
|
@ -89,7 +88,7 @@ pub enum Element<'a> {
|
|||
ListItem(ListItem<'a>),
|
||||
Macros(Macros<'a>),
|
||||
Snippet(Snippet<'a>),
|
||||
Text { value: &'a str },
|
||||
Text { value: Cow<'a, str> },
|
||||
Paragraph,
|
||||
Rule,
|
||||
Timestamp(Timestamp<'a>),
|
||||
|
@ -110,29 +109,76 @@ pub enum Element<'a> {
|
|||
|
||||
impl Element<'_> {
|
||||
pub fn is_container(&self) -> bool {
|
||||
use Element::*;
|
||||
|
||||
match self {
|
||||
Element::SpecialBlock(_)
|
||||
| Element::QuoteBlock(_)
|
||||
| Element::CenterBlock(_)
|
||||
| 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,
|
||||
SpecialBlock(_) | QuoteBlock(_) | CenterBlock(_) | VerseBlock(_) | Bold | Document
|
||||
| DynBlock(_) | Headline | Italic | List(_) | ListItem(_) | Paragraph | Section
|
||||
| Strike | Underline | Title(_) | Table(_) | TableRow(_) | TableCell => true,
|
||||
_ => 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 {
|
||||
|
@ -181,7 +227,6 @@ impl_from!(
|
|||
Table,
|
||||
Title,
|
||||
VerseBlock;
|
||||
RadioTarget,
|
||||
List,
|
||||
TableRow
|
||||
);
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -5,44 +5,30 @@ use nom::{
|
|||
IResult,
|
||||
};
|
||||
|
||||
use crate::elements::Element;
|
||||
|
||||
// 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]
|
||||
pub(crate) fn parse(input: &str) -> IResult<&str, (Element, &str)> {
|
||||
let (input, contents) = delimited(
|
||||
tag("<<<"),
|
||||
verify(
|
||||
take_while(|c: char| c != '<' && c != '\n' && c != '>'),
|
||||
|s: &str| s.starts_with(|c| c != ' ') && s.ends_with(|c| c != ' '),
|
||||
),
|
||||
tag(">>>"),
|
||||
)(input)?;
|
||||
#[inline]
|
||||
pub(crate) fn parse_radio_target(input: &str) -> IResult<&str, &str> {
|
||||
let (input, contents) = delimited(
|
||||
tag("<<<"),
|
||||
verify(
|
||||
take_while(|c: char| c != '<' && c != '\n' && c != '>'),
|
||||
|s: &str| s.starts_with(|c| c != ' ') && s.ends_with(|c| c != ' '),
|
||||
),
|
||||
tag(">>>"),
|
||||
)(input)?;
|
||||
|
||||
Ok((input, (Element::RadioTarget(RadioTarget), contents)))
|
||||
}
|
||||
Ok((input, contents))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
assert_eq!(
|
||||
RadioTarget::parse("<<<target>>>"),
|
||||
Ok(("", (Element::RadioTarget(RadioTarget), "target")))
|
||||
);
|
||||
assert_eq!(
|
||||
RadioTarget::parse("<<<tar get>>>"),
|
||||
Ok(("", (Element::RadioTarget(RadioTarget), "tar get")))
|
||||
);
|
||||
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());
|
||||
assert_eq!(parse_radio_target("<<<target>>>"), Ok(("", "target")));
|
||||
assert_eq!(parse_radio_target("<<<tar get>>>"), Ok(("", "tar get")));
|
||||
assert!(parse_radio_target("<<<target >>>").is_err());
|
||||
assert!(parse_radio_target("<<< target>>>").is_err());
|
||||
assert!(parse_radio_target("<<<ta<get>>>").is_err());
|
||||
assert!(parse_radio_target("<<<ta>get>>>").is_err());
|
||||
assert!(parse_radio_target("<<<ta\nget>>>").is_err());
|
||||
assert!(parse_radio_target("<<<target>>").is_err());
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -18,6 +18,19 @@ pub enum Table<'a> {
|
|||
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)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
|
||||
|
|
|
@ -33,6 +33,12 @@ impl Target<'_> {
|
|||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> Target<'static> {
|
||||
Target {
|
||||
target: self.target.into_owned().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -30,47 +30,17 @@ pub struct Datetime<'a> {
|
|||
pub minute: Option<u8>,
|
||||
}
|
||||
|
||||
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,
|
||||
impl Datetime<'_> {
|
||||
pub fn into_owned(self) -> Datetime<'static> {
|
||||
Datetime {
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
dayname: dayname.into(),
|
||||
hour,
|
||||
minute,
|
||||
},
|
||||
))
|
||||
year: self.year,
|
||||
month: self.month,
|
||||
day: self.day,
|
||||
dayname: self.dayname.into_owned().into(),
|
||||
hour: self.hour,
|
||||
minute: self.minute,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -101,7 +101,7 @@ pub trait HtmlHandler<E: From<Error>> {
|
|||
Escape(link.desc.as_ref().unwrap_or(&link.path)),
|
||||
)?,
|
||||
Macros(_macros) => (),
|
||||
RadioTarget(_radio_target) => (),
|
||||
RadioTarget => (),
|
||||
Snippet(snippet) => {
|
||||
if snippet.name.eq_ignore_ascii_case("HTML") {
|
||||
write!(w, "{}", snippet.value)?;
|
||||
|
|
|
@ -81,7 +81,7 @@ pub trait OrgHandler<E: From<Error>> {
|
|||
write!(&mut w, "]")?;
|
||||
}
|
||||
Macros(_macros) => (),
|
||||
RadioTarget(_radio_target) => (),
|
||||
RadioTarget => (),
|
||||
Snippet(snippet) => write!(w, "@@{}:{}@@", snippet.name, snippet.value)?,
|
||||
Target(_target) => (),
|
||||
Text { value } => write!(w, "{}", value)?,
|
||||
|
|
28
src/org.rs
28
src/org.rs
|
@ -5,7 +5,7 @@ use crate::config::ParseConfig;
|
|||
use crate::elements::Element;
|
||||
use crate::export::*;
|
||||
use crate::node::HeadlineNode;
|
||||
use crate::parsers::*;
|
||||
use crate::parsers::{parse_container, Container};
|
||||
|
||||
pub struct Org<'a> {
|
||||
pub(crate) arena: Arena<Element<'a>>,
|
||||
|
@ -27,31 +27,7 @@ impl Org<'_> {
|
|||
let mut arena = Arena::new();
|
||||
let node = arena.new_node(Element::Document);
|
||||
|
||||
let containers = &mut vec![Container::Document { content, node }];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_container(&mut arena, Container::Document { content, node }, config);
|
||||
|
||||
Org { arena, root: node }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// parser related functions
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use indextree::{Arena, NodeId};
|
||||
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>>(
|
||||
arena: &mut T,
|
||||
content: &'a str,
|
||||
|
@ -397,7 +430,12 @@ pub fn parse_inlines<'a, T: ElementArena<'a>>(
|
|||
|
||||
macro_rules! insert_text {
|
||||
($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;
|
||||
};
|
||||
}
|
||||
|
@ -449,7 +487,7 @@ pub fn parse_inlines<'a, T: ElementArena<'a>>(
|
|||
}
|
||||
|
||||
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'<' => {
|
||||
if let Ok((tail, (radio, _content))) = RadioTarget::parse(contents) {
|
||||
arena.push_element(radio, parent);
|
||||
if let Ok((tail, _content)) = parse_radio_target(contents) {
|
||||
arena.push_element(Element::RadioTarget, parent);
|
||||
return Some(tail);
|
||||
} else if let Ok((tail, target)) = Target::parse(contents) {
|
||||
arena.push_element(target, parent);
|
||||
|
@ -717,7 +755,7 @@ pub fn take_one_word(input: &str) -> IResult<&str, &str> {
|
|||
}
|
||||
|
||||
#[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(" \nfoo\n"), "foo\n");
|
||||
|
|
Loading…
Reference in a new issue