docs: some doc comments
This commit is contained in:
parent
2467cb3db3
commit
0101612029
|
@ -1,18 +1,23 @@
|
||||||
use crate::objects::timestamp::{Datetime, Delay, Repeater, Timestamp};
|
use crate::objects::timestamp::{Datetime, Delay, Repeater, Timestamp};
|
||||||
use memchr::memchr;
|
use memchr::memchr;
|
||||||
|
|
||||||
|
/// clock elements
|
||||||
|
///
|
||||||
|
/// there are two types of clock: *closed* clock and *running* clock.
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Clock<'a> {
|
pub enum Clock<'a> {
|
||||||
|
/// closed Clock
|
||||||
Closed {
|
Closed {
|
||||||
start: Datetime,
|
start: Datetime<'a>,
|
||||||
end: Datetime,
|
end: Datetime<'a>,
|
||||||
repeater: Option<Repeater>,
|
repeater: Option<Repeater>,
|
||||||
delay: Option<Delay>,
|
delay: Option<Delay>,
|
||||||
duration: &'a str,
|
duration: &'a str,
|
||||||
},
|
},
|
||||||
|
/// running Clock
|
||||||
Running {
|
Running {
|
||||||
start: Datetime,
|
start: Datetime<'a>,
|
||||||
repeater: Option<Repeater>,
|
repeater: Option<Repeater>,
|
||||||
delay: Option<Delay>,
|
delay: Option<Delay>,
|
||||||
},
|
},
|
||||||
|
@ -88,6 +93,7 @@ impl<'a> Clock<'a> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns `true` if the clock is running
|
||||||
pub fn is_running(&self) -> bool {
|
pub fn is_running(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Clock::Closed { .. } => false,
|
Clock::Closed { .. } => false,
|
||||||
|
@ -95,6 +101,7 @@ impl<'a> Clock<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns `true` if the clock is closed
|
||||||
pub fn is_closed(&self) -> bool {
|
pub fn is_closed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Clock::Closed { .. } => true,
|
Clock::Closed { .. } => true,
|
||||||
|
@ -102,6 +109,7 @@ impl<'a> Clock<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns `Some` if the clock is closed, `None` if running
|
||||||
pub fn duration(&self) -> Option<&'a str> {
|
pub fn duration(&self) -> Option<&'a str> {
|
||||||
match self {
|
match self {
|
||||||
Clock::Closed { duration, .. } => Some(duration),
|
Clock::Closed { duration, .. } => Some(duration),
|
||||||
|
@ -109,6 +117,7 @@ impl<'a> Clock<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// constructs a new timestamp object from the clock
|
||||||
pub fn value(&self) -> Timestamp<'_> {
|
pub fn value(&self) -> Timestamp<'_> {
|
||||||
match *self {
|
match *self {
|
||||||
Clock::Closed {
|
Clock::Closed {
|
||||||
|
@ -150,7 +159,8 @@ mod tests {
|
||||||
Clock::Running {
|
Clock::Running {
|
||||||
start: Datetime {
|
start: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None,
|
delay: None,
|
||||||
|
@ -164,11 +174,13 @@ mod tests {
|
||||||
Clock::Closed {
|
Clock::Closed {
|
||||||
start: Datetime {
|
start: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
end: Datetime {
|
end: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((10, 39))
|
time: Some((10, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None,
|
delay: None,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
/// elements
|
||||||
|
///
|
||||||
|
/// elements means some syntactical parts that have the same level with paragraph.
|
||||||
pub(crate) mod block;
|
pub(crate) mod block;
|
||||||
pub(crate) mod clock;
|
pub(crate) mod clock;
|
||||||
pub(crate) mod drawer;
|
pub(crate) mod drawer;
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use crate::objects::timestamp::Timestamp;
|
use crate::objects::timestamp::Timestamp;
|
||||||
use memchr::memchr;
|
use memchr::memchr;
|
||||||
|
|
||||||
|
/// palnning elements
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Planning<'a> {
|
pub struct Planning<'a> {
|
||||||
|
/// the date when the task should be done
|
||||||
pub deadline: Option<Timestamp<'a>>,
|
pub deadline: Option<Timestamp<'a>>,
|
||||||
|
/// the date when you should start working on the task
|
||||||
pub scheduled: Option<Timestamp<'a>>,
|
pub scheduled: Option<Timestamp<'a>>,
|
||||||
|
/// the date when the task is closed
|
||||||
pub closed: Option<Timestamp<'a>>,
|
pub closed: Option<Timestamp<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +26,9 @@ impl<'a> Planning<'a> {
|
||||||
macro_rules! set_timestamp {
|
macro_rules! set_timestamp {
|
||||||
($timestamp:expr) => {
|
($timestamp:expr) => {
|
||||||
if $timestamp.is_none() {
|
if $timestamp.is_none() {
|
||||||
if next.starts_with('<') {
|
let (timestamp, off) = Timestamp::parse(next)?;
|
||||||
let (timestamp, off) = Timestamp::parse_active(next)
|
$timestamp = Some(timestamp);
|
||||||
.or_else(|| Timestamp::parse_diary(next))?;
|
tail = &next[off..].trim_start();
|
||||||
$timestamp = Some(timestamp);
|
|
||||||
tail = &next[off..].trim_start();
|
|
||||||
} else if next.starts_with('<') {
|
|
||||||
let (timestamp, off) = Timestamp::parse_active(next)?;
|
|
||||||
$timestamp = Some(timestamp);
|
|
||||||
tail = &next[off..].trim_start();
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +72,8 @@ mod tests {
|
||||||
scheduled: Some(Timestamp::Active {
|
scheduled: Some(Timestamp::Active {
|
||||||
start: Datetime {
|
start: Datetime {
|
||||||
date: (2019, 4, 8),
|
date: (2019, 4, 8),
|
||||||
time: None
|
time: None,
|
||||||
|
dayname: "Mon"
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None
|
delay: None
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
//! let result = String::from_utf8(cursor.into_inner()).expect("invalid utf-8");
|
//! let result = String::from_utf8(cursor.into_inner()).expect("invalid utf-8");
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
#[warn(missing_docs)]
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
pub mod headline;
|
pub mod headline;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
/// objects
|
||||||
|
///
|
||||||
|
/// objects is something that included in an element.
|
||||||
pub(crate) mod cookie;
|
pub(crate) mod cookie;
|
||||||
pub(crate) mod emphasis;
|
pub(crate) mod emphasis;
|
||||||
pub(crate) mod fn_ref;
|
pub(crate) mod fn_ref;
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub fn parse(text: &str) -> Option<(&str, usize)> {
|
||||||
|
|
||||||
let bytes = text.as_bytes();
|
let bytes = text.as_bytes();
|
||||||
|
|
||||||
let (target, off) = Substring::new(">>")
|
Substring::new(">>")
|
||||||
.find(text)
|
.find(text)
|
||||||
.filter(|&i| {
|
.filter(|&i| {
|
||||||
bytes[2] != b' '
|
bytes[2] != b' '
|
||||||
|
@ -15,9 +15,7 @@ pub fn parse(text: &str) -> Option<(&str, usize)> {
|
||||||
.iter()
|
.iter()
|
||||||
.all(|&c| c != b'<' && c != b'\n' && c != b'>')
|
.all(|&c| c != b'<' && c != b'\n' && c != b'>')
|
||||||
})
|
})
|
||||||
.map(|i| (&text[2..i], i + 2 /* >> */))?;
|
.map(|i| (&text[2..i], i + 2 /* >> */))
|
||||||
|
|
||||||
Some((target, off))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -2,9 +2,10 @@ use memchr::memchr;
|
||||||
|
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Datetime {
|
pub struct Datetime<'a> {
|
||||||
pub date: (u16, u8, u8),
|
pub date: (u16, u8, u8),
|
||||||
pub time: Option<(u8, u8)>,
|
pub time: Option<(u8, u8)>,
|
||||||
|
pub dayname: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
|
@ -48,28 +49,29 @@ pub struct Delay {
|
||||||
pub unit: TimeUnit,
|
pub unit: TimeUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// timestamp obejcts
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Timestamp<'a> {
|
pub enum Timestamp<'a> {
|
||||||
Active {
|
Active {
|
||||||
start: Datetime,
|
start: Datetime<'a>,
|
||||||
repeater: Option<Repeater>,
|
repeater: Option<Repeater>,
|
||||||
delay: Option<Delay>,
|
delay: Option<Delay>,
|
||||||
},
|
},
|
||||||
Inactive {
|
Inactive {
|
||||||
start: Datetime,
|
start: Datetime<'a>,
|
||||||
repeater: Option<Repeater>,
|
repeater: Option<Repeater>,
|
||||||
delay: Option<Delay>,
|
delay: Option<Delay>,
|
||||||
},
|
},
|
||||||
ActiveRange {
|
ActiveRange {
|
||||||
start: Datetime,
|
start: Datetime<'a>,
|
||||||
end: Datetime,
|
end: Datetime<'a>,
|
||||||
repeater: Option<Repeater>,
|
repeater: Option<Repeater>,
|
||||||
delay: Option<Delay>,
|
delay: Option<Delay>,
|
||||||
},
|
},
|
||||||
InactiveRange {
|
InactiveRange {
|
||||||
start: Datetime,
|
start: Datetime<'a>,
|
||||||
end: Datetime,
|
end: Datetime<'a>,
|
||||||
repeater: Option<Repeater>,
|
repeater: Option<Repeater>,
|
||||||
delay: Option<Delay>,
|
delay: Option<Delay>,
|
||||||
},
|
},
|
||||||
|
@ -77,18 +79,27 @@ pub enum Timestamp<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Timestamp<'a> {
|
impl<'a> Timestamp<'a> {
|
||||||
pub(crate) fn parse_active(text: &str) -> Option<(Timestamp<'_>, usize)> {
|
pub(crate) fn parse(text: &'a str) -> Option<(Timestamp<'a>, usize)> {
|
||||||
|
if text.starts_with('<') {
|
||||||
|
Timestamp::parse_active(text).or_else(|| Timestamp::parse_diary(text))
|
||||||
|
} else if text.starts_with('[') {
|
||||||
|
Timestamp::parse_inactive(text)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_active(text: &'a str) -> Option<(Timestamp<'a>, usize)> {
|
||||||
debug_assert!(text.starts_with('<'));
|
debug_assert!(text.starts_with('<'));
|
||||||
|
|
||||||
let bytes = text.as_bytes();
|
let bytes = text.as_bytes();
|
||||||
let mut off = memchr(b'>', bytes)?;
|
let mut off = memchr(b'>', bytes)?;
|
||||||
let (start, mut end) = Self::parse_datetime(&bytes[1..off])?;
|
let (start, mut end) = Self::parse_datetime(&text[1..off])?;
|
||||||
if end.is_none()
|
|
||||||
&& off <= text.len() - 14 /* --<YYYY-MM-DD> */
|
if end.is_none() && off <= text.len() - 14 /* --<YYYY-MM-DD> */ && text[off + 1..].starts_with("--<")
|
||||||
&& text[off + 1..].starts_with("--<")
|
|
||||||
{
|
{
|
||||||
if let Some(new_off) = memchr(b'>', &bytes[off + 1..]) {
|
if let Some(new_off) = memchr(b'>', &bytes[off + 1..]) {
|
||||||
if let Some((start, _)) = Self::parse_datetime(&bytes[off + 4..off + 1 + new_off]) {
|
if let Some((start, _)) = Self::parse_datetime(&text[off + 4..off + 1 + new_off]) {
|
||||||
end = Some(start);
|
end = Some(start);
|
||||||
off += new_off + 1;
|
off += new_off + 1;
|
||||||
}
|
}
|
||||||
|
@ -114,18 +125,16 @@ impl<'a> Timestamp<'a> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_inactive(text: &str) -> Option<(Timestamp<'_>, usize)> {
|
pub(crate) fn parse_inactive(text: &'a str) -> Option<(Timestamp<'a>, usize)> {
|
||||||
debug_assert!(text.starts_with('['));
|
debug_assert!(text.starts_with('['));
|
||||||
|
|
||||||
let bytes = text.as_bytes();
|
let bytes = text.as_bytes();
|
||||||
let mut off = memchr(b']', bytes)?;
|
let mut off = memchr(b']', bytes)?;
|
||||||
let (start, mut end) = Self::parse_datetime(&bytes[1..off])?;
|
let (start, mut end) = Self::parse_datetime(&text[1..off])?;
|
||||||
if end.is_none()
|
if end.is_none() && off <= text.len() - 14 /* --[YYYY-MM-DD] */ && text[off + 1..].starts_with("--[")
|
||||||
&& off <= text.len() - 14 /* --[YYYY-MM-DD] */
|
|
||||||
&& text[off + 1..].starts_with("--[")
|
|
||||||
{
|
{
|
||||||
if let Some(new_off) = memchr(b']', &bytes[off + 1..]) {
|
if let Some(new_off) = memchr(b']', &bytes[off + 1..]) {
|
||||||
if let Some((start, _)) = Self::parse_datetime(&bytes[off + 4..off + 1 + new_off]) {
|
if let Some((start, _)) = Self::parse_datetime(&text[off + 4..off + 1 + new_off]) {
|
||||||
end = Some(start);
|
end = Some(start);
|
||||||
off += new_off + 1;
|
off += new_off + 1;
|
||||||
}
|
}
|
||||||
|
@ -151,30 +160,30 @@ impl<'a> Timestamp<'a> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_datetime(bytes: &[u8]) -> Option<(Datetime, Option<Datetime>)> {
|
fn parse_datetime(text: &'a str) -> Option<(Datetime<'a>, Option<Datetime<'a>>)> {
|
||||||
if bytes.is_empty()
|
if text.is_empty()
|
||||||
|| !bytes[0].is_ascii_digit()
|
|| !text.starts_with(|c: char| c.is_ascii_digit())
|
||||||
|| !bytes[bytes.len() - 1].is_ascii_alphanumeric()
|
|| !text.ends_with(|c: char| c.is_ascii_alphanumeric())
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// similar to str::split_ascii_whitespace, but for &[u8]
|
let mut words = text.split_ascii_whitespace();
|
||||||
let mut words = bytes
|
|
||||||
.split(u8::is_ascii_whitespace)
|
|
||||||
.filter(|s| !s.is_empty());
|
|
||||||
|
|
||||||
let date = words
|
let date = words
|
||||||
.next()
|
.next()
|
||||||
.filter(|word| {
|
.filter(|word| {
|
||||||
word.len() == 10 /* YYYY-MM-DD */
|
let word = word.as_bytes();
|
||||||
&& word[0..4].iter().all(u8::is_ascii_digit)
|
// YYYY-MM-DD
|
||||||
&& word[4] == b'-'
|
word.len() == 10
|
||||||
&& word[5..7].iter().all(u8::is_ascii_digit)
|
&& word[0..4].iter().all(u8::is_ascii_digit)
|
||||||
&& word[7] == b'-'
|
&& word[4] == b'-'
|
||||||
&& word[8..10].iter().all(u8::is_ascii_digit)
|
&& word[5..7].iter().all(u8::is_ascii_digit)
|
||||||
|
&& word[7] == b'-'
|
||||||
|
&& word[8..10].iter().all(u8::is_ascii_digit)
|
||||||
})
|
})
|
||||||
.map(|word| {
|
.map(|word| {
|
||||||
|
let word = word.as_bytes();
|
||||||
(
|
(
|
||||||
(u16::from(word[0]) - u16::from(b'0')) * 1000
|
(u16::from(word[0]) - u16::from(b'0')) * 1000
|
||||||
+ (u16::from(word[1]) - u16::from(b'0')) * 100
|
+ (u16::from(word[1]) - u16::from(b'0')) * 100
|
||||||
|
@ -185,8 +194,8 @@ impl<'a> Timestamp<'a> {
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let _dayname = words.next().filter(|word| {
|
let dayname = words.next().filter(|word| {
|
||||||
word.iter().all(|&c| {
|
word.as_bytes().iter().all(|&c| {
|
||||||
!(c == b'+'
|
!(c == b'+'
|
||||||
|| c == b'-'
|
|| c == b'-'
|
||||||
|| c == b']'
|
|| c == b']'
|
||||||
|
@ -197,16 +206,20 @@ impl<'a> Timestamp<'a> {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let (start, end) = if let Some(word) = words.next() {
|
let (start, end) = if let Some(word) = words.next() {
|
||||||
|
let word = word.as_bytes();
|
||||||
|
|
||||||
macro_rules! datetime {
|
macro_rules! datetime {
|
||||||
($a:expr, $b:expr, $c:expr) => {
|
($a:expr, $b:expr, $c:expr) => {
|
||||||
Datetime {
|
Datetime {
|
||||||
date,
|
date,
|
||||||
|
dayname,
|
||||||
time: Some((word[$a] - b'0', (word[$b] - b'0') * 10 + (word[$c] - b'0'))),
|
time: Some((word[$a] - b'0', (word[$b] - b'0') * 10 + (word[$c] - b'0'))),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($a:expr, $b:expr, $c:expr, $d:expr) => {
|
($a:expr, $b:expr, $c:expr, $d:expr) => {
|
||||||
Datetime {
|
Datetime {
|
||||||
date,
|
date,
|
||||||
|
dayname,
|
||||||
time: Some((
|
time: Some((
|
||||||
(word[$a] - b'0') * 10 + (word[$b] - b'0'),
|
(word[$a] - b'0') * 10 + (word[$b] - b'0'),
|
||||||
(word[$c] - b'0') * 10 + (word[$d] - b'0'),
|
(word[$c] - b'0') * 10 + (word[$d] - b'0'),
|
||||||
|
@ -215,63 +228,76 @@ impl<'a> Timestamp<'a> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if word.len() == 4 // H:MM
|
if word.len() == 4
|
||||||
&& word[0].is_ascii_digit()
|
&& word[0].is_ascii_digit()
|
||||||
&& word[1] == b':'
|
&& word[1] == b':'
|
||||||
&& word[2..4].iter().all(u8::is_ascii_digit)
|
&& word[2..4].iter().all(u8::is_ascii_digit)
|
||||||
{
|
{
|
||||||
|
// H:MM
|
||||||
(datetime!(0, 2, 3), None)
|
(datetime!(0, 2, 3), None)
|
||||||
} else if word.len() == 5 // HH:MM
|
} else if word.len() == 5
|
||||||
&& word[0..2].iter().all(u8::is_ascii_digit)
|
&& word[0..2].iter().all(u8::is_ascii_digit)
|
||||||
&& word[2] == b':'
|
&& word[2] == b':'
|
||||||
&& word[3..5].iter().all(u8::is_ascii_digit)
|
&& word[3..5].iter().all(u8::is_ascii_digit)
|
||||||
{
|
{
|
||||||
|
// HH:MM
|
||||||
(datetime!(0, 1, 3, 4), None)
|
(datetime!(0, 1, 3, 4), None)
|
||||||
} else if word.len() == 9 // H:MM-H:MM
|
} else if word.len() == 9
|
||||||
&& word[0].is_ascii_digit()
|
&& word[0].is_ascii_digit()
|
||||||
&& word[1] == b':'
|
&& word[1] == b':'
|
||||||
&& word[2..4].iter().all(u8::is_ascii_digit)
|
&& word[2..4].iter().all(u8::is_ascii_digit)
|
||||||
&& word[4] == b'-'
|
&& word[4] == b'-'
|
||||||
&& word[5].is_ascii_digit()
|
&& word[5].is_ascii_digit()
|
||||||
&& word[6] == b':'
|
&& word[6] == b':'
|
||||||
&& word[7..9].iter().all(u8::is_ascii_digit)
|
&& word[7..9].iter().all(u8::is_ascii_digit)
|
||||||
{
|
{
|
||||||
|
// H:MM-H:MM
|
||||||
(datetime!(0, 2, 3), Some(datetime!(5, 7, 8)))
|
(datetime!(0, 2, 3), Some(datetime!(5, 7, 8)))
|
||||||
} else if word.len() == 10 // H:MM-HH:MM
|
} else if word.len() == 10
|
||||||
&& word[0].is_ascii_digit()
|
&& word[0].is_ascii_digit()
|
||||||
&& word[1] == b':'
|
&& word[1] == b':'
|
||||||
&& word[2..4].iter().all(u8::is_ascii_digit)
|
&& word[2..4].iter().all(u8::is_ascii_digit)
|
||||||
&& word[4] == b'-'
|
&& word[4] == b'-'
|
||||||
&& word[5..7].iter().all(u8::is_ascii_digit)
|
&& word[5..7].iter().all(u8::is_ascii_digit)
|
||||||
&& word[7] == b':'
|
&& word[7] == b':'
|
||||||
&& word[8..10].iter().all(u8::is_ascii_digit)
|
&& word[8..10].iter().all(u8::is_ascii_digit)
|
||||||
{
|
{
|
||||||
|
// H:MM-HH:MM
|
||||||
(datetime!(0, 2, 3), Some(datetime!(5, 6, 8, 9)))
|
(datetime!(0, 2, 3), Some(datetime!(5, 6, 8, 9)))
|
||||||
} else if word.len() == 10 // HH:MM-H:MM
|
} else if word.len() == 10
|
||||||
&& word[0..2].iter().all(u8::is_ascii_digit)
|
&& word[0..2].iter().all(u8::is_ascii_digit)
|
||||||
&& word[2] == b':'
|
&& word[2] == b':'
|
||||||
&& word[3..5].iter().all(u8::is_ascii_digit)
|
&& word[3..5].iter().all(u8::is_ascii_digit)
|
||||||
&& word[5] == b'-'
|
&& word[5] == b'-'
|
||||||
&& word[6].is_ascii_digit()
|
&& word[6].is_ascii_digit()
|
||||||
&& word[7] == b':'
|
&& word[7] == b':'
|
||||||
&& word[8..10].iter().all(u8::is_ascii_digit)
|
&& word[8..10].iter().all(u8::is_ascii_digit)
|
||||||
{
|
{
|
||||||
|
// HH:MM-H:MM
|
||||||
(datetime!(0, 1, 3, 4), Some(datetime!(6, 8, 9)))
|
(datetime!(0, 1, 3, 4), Some(datetime!(6, 8, 9)))
|
||||||
} else if word.len() == 11 // HH:MM-HH:MM
|
} else if word.len() == 11
|
||||||
&& word[0..2].iter().all(u8::is_ascii_digit)
|
&& word[0..2].iter().all(u8::is_ascii_digit)
|
||||||
&& word[2] == b':'
|
&& word[2] == b':'
|
||||||
&& word[3..5].iter().all(u8::is_ascii_digit)
|
&& word[3..5].iter().all(u8::is_ascii_digit)
|
||||||
&& word[5] == b'-'
|
&& word[5] == b'-'
|
||||||
&& word[6..8].iter().all(u8::is_ascii_digit)
|
&& word[6..8].iter().all(u8::is_ascii_digit)
|
||||||
&& word[8] == b':'
|
&& word[8] == b':'
|
||||||
&& word[9..11].iter().all(u8::is_ascii_digit)
|
&& word[9..11].iter().all(u8::is_ascii_digit)
|
||||||
{
|
{
|
||||||
|
// HH:MM-HH:MM
|
||||||
(datetime!(0, 1, 3, 4), Some(datetime!(6, 7, 9, 10)))
|
(datetime!(0, 1, 3, 4), Some(datetime!(6, 7, 9, 10)))
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(Datetime { date, time: None }, None)
|
(
|
||||||
|
Datetime {
|
||||||
|
date,
|
||||||
|
dayname,
|
||||||
|
time: None,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: repeater and delay
|
// TODO: repeater and delay
|
||||||
|
@ -309,7 +335,8 @@ mod tests {
|
||||||
Timestamp::Inactive {
|
Timestamp::Inactive {
|
||||||
start: Datetime {
|
start: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: None
|
time: None,
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None,
|
delay: None,
|
||||||
|
@ -323,11 +350,13 @@ mod tests {
|
||||||
Timestamp::InactiveRange {
|
Timestamp::InactiveRange {
|
||||||
start: Datetime {
|
start: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
end: Datetime {
|
end: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((10, 39))
|
time: Some((10, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None
|
delay: None
|
||||||
|
@ -341,11 +370,13 @@ mod tests {
|
||||||
Timestamp::ActiveRange {
|
Timestamp::ActiveRange {
|
||||||
start: Datetime {
|
start: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
end: Datetime {
|
end: Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((10, 39))
|
time: Some((10, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
repeater: None,
|
repeater: None,
|
||||||
delay: None
|
delay: None
|
||||||
|
@ -360,52 +391,57 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Timestamp::parse_datetime(b"2003-09-16 Tue"),
|
Timestamp::parse_datetime("2003-09-16 Tue"),
|
||||||
Some((
|
Some((
|
||||||
Datetime {
|
Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: None
|
time: None,
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
None
|
None
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Timestamp::parse_datetime(b"2003-09-16 Tue 9:39"),
|
Timestamp::parse_datetime("2003-09-16 Tue 9:39"),
|
||||||
Some((
|
Some((
|
||||||
Datetime {
|
Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
None
|
None
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Timestamp::parse_datetime(b"2003-09-16 Tue 09:39"),
|
Timestamp::parse_datetime("2003-09-16 Tue 09:39"),
|
||||||
Some((
|
Some((
|
||||||
Datetime {
|
Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
None
|
None
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Timestamp::parse_datetime(b"2003-09-16 Tue 9:39-10:39"),
|
Timestamp::parse_datetime("2003-09-16 Tue 9:39-10:39"),
|
||||||
Some((
|
Some((
|
||||||
Datetime {
|
Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((9, 39))
|
time: Some((9, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
},
|
},
|
||||||
Some(Datetime {
|
Some(Datetime {
|
||||||
date: (2003, 9, 16),
|
date: (2003, 9, 16),
|
||||||
time: Some((10, 39))
|
time: Some((10, 39)),
|
||||||
|
dayname: "Tue"
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(Timestamp::parse_datetime(b"2003-9-16 Tue"), None);
|
assert_eq!(Timestamp::parse_datetime("2003-9-16 Tue"), None);
|
||||||
assert_eq!(Timestamp::parse_datetime(b"2003-09-16"), None);
|
assert_eq!(Timestamp::parse_datetime("2003-09-16"), None);
|
||||||
assert_eq!(Timestamp::parse_datetime(b"2003-09-16 09:39"), None);
|
assert_eq!(Timestamp::parse_datetime("2003-09-16 09:39"), None);
|
||||||
assert_eq!(Timestamp::parse_datetime(b"2003-09-16 Tue 0939"), None);
|
assert_eq!(Timestamp::parse_datetime("2003-09-16 Tue 0939"), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,19 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// creates a new parser from string, with the specified keywords
|
||||||
|
pub fn with_keywrods(text: &'a str, keywords: &'a [&'a str]) -> Parser<'a> {
|
||||||
|
Parser {
|
||||||
|
text,
|
||||||
|
stack: Vec::new(),
|
||||||
|
next_item: Vec::new(),
|
||||||
|
off: 0,
|
||||||
|
ele_buf: None,
|
||||||
|
obj_buf: None,
|
||||||
|
keywords,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// returns current offset
|
/// returns current offset
|
||||||
pub fn offset(&self) -> usize {
|
pub fn offset(&self) -> usize {
|
||||||
self.off
|
self.off
|
||||||
|
@ -195,10 +208,12 @@ impl<'a> Parser<'a> {
|
||||||
self.stack.len()
|
self.stack.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set keywords
|
||||||
pub fn set_keywords(&mut self, keywords: &'a [&'a str]) {
|
pub fn set_keywords(&mut self, keywords: &'a [&'a str]) {
|
||||||
self.keywords = keywords;
|
self.keywords = keywords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set text
|
||||||
pub fn set_text(&mut self, text: &'a str) {
|
pub fn set_text(&mut self, text: &'a str) {
|
||||||
self.off = 0;
|
self.off = 0;
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
|
|
|
@ -7,9 +7,7 @@ type Keywords<'a> = Vec<(Key<'a>, &'a str)>;
|
||||||
type Footnotes<'a> = Vec<&'a str>;
|
type Footnotes<'a> = Vec<&'a str>;
|
||||||
|
|
||||||
pub fn metadata(src: &str) -> (Headlines<'_>, Keywords<'_>, Footnotes<'_>) {
|
pub fn metadata(src: &str) -> (Headlines<'_>, Keywords<'_>, Footnotes<'_>) {
|
||||||
let mut headlines = Vec::new();
|
let (mut headlines, mut keywords, mut footnotes) = (Vec::new(), Vec::new(), Vec::new());
|
||||||
let mut keywords = Vec::new();
|
|
||||||
let mut footnotes = Vec::new();
|
|
||||||
|
|
||||||
for line in src.lines().filter(|l| !l.is_empty()) {
|
for line in src.lines().filter(|l| !l.is_empty()) {
|
||||||
if line.starts_with('*') {
|
if line.starts_with('*') {
|
||||||
|
|
Loading…
Reference in a new issue