refator(elements): rewrite Timestamp struct

This commit is contained in:
PoiScript 2019-08-04 14:12:26 +08:00
parent 9023837eb4
commit 8d18fb04c1
7 changed files with 251 additions and 290 deletions

View file

@ -1,4 +1,4 @@
use crate::elements::{Date, Element, Time, Timestamp}; use crate::elements::{Datetime, Element, Timestamp};
use memchr::memchr; use memchr::memchr;
/// clock elements /// clock elements
@ -10,18 +10,15 @@ use memchr::memchr;
pub enum Clock<'a> { pub enum Clock<'a> {
/// closed Clock /// closed Clock
Closed { Closed {
start_date: Date<'a>, start: Datetime<'a>,
start_time: Option<Time>, end: Datetime<'a>,
end_date: Date<'a>,
end_time: Option<Time>,
repeater: Option<&'a str>, repeater: Option<&'a str>,
delay: Option<&'a str>, delay: Option<&'a str>,
duration: &'a str, duration: &'a str,
}, },
/// running Clock /// running Clock
Running { Running {
start_date: Date<'a>, start: Datetime<'a>,
start_time: Option<Time>,
repeater: Option<&'a str>, repeater: Option<&'a str>,
delay: Option<&'a str>, delay: Option<&'a str>,
}, },
@ -49,50 +46,54 @@ impl Clock<'_> {
match timestamp { match timestamp {
Timestamp::InactiveRange { Timestamp::InactiveRange {
start_date, start,
start_time, end,
end_date,
end_time,
repeater, repeater,
delay, delay,
} if tail.starts_with("=>") => { } => {
let duration = &tail[3..].trim(); if tail.starts_with("=>") {
let colon = memchr(b':', duration.as_bytes())?; let duration = &tail[3..].trim();
if duration.as_bytes()[0..colon].iter().all(u8::is_ascii_digit) let colon = memchr(b':', duration.as_bytes())?;
&& colon == duration.len() - 3 if duration.as_bytes()[0..colon].iter().all(u8::is_ascii_digit)
&& duration.as_bytes()[colon + 1].is_ascii_digit() && colon == duration.len() - 3
&& duration.as_bytes()[colon + 2].is_ascii_digit() && duration.as_bytes()[colon + 1].is_ascii_digit()
{ && duration.as_bytes()[colon + 2].is_ascii_digit()
{
Some((
&text[eol..],
Element::Clock(Clock::Closed {
start,
end,
repeater,
delay,
duration,
}),
))
} else {
None
}
} else {
None
}
}
Timestamp::Inactive {
start,
repeater,
delay,
} => {
if tail.is_empty() {
Some(( Some((
&text[eol..], &text[eol..],
Element::Clock(Clock::Closed { Element::Clock(Clock::Running {
start_date, start,
start_time,
end_date,
end_time,
repeater, repeater,
delay, delay,
duration,
}), }),
)) ))
} else { } else {
None None
} }
} }
Timestamp::Inactive {
start_date,
start_time,
repeater,
delay,
} if tail.is_empty() => Some((
&text[eol..],
Element::Clock(Clock::Running {
start_date,
start_time,
repeater,
delay,
}),
)),
_ => None, _ => None,
} }
} }
@ -123,33 +124,27 @@ impl Clock<'_> {
/// constructs a new timestamp object from the clock /// 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 {
start_date, start,
start_time, end,
end_date,
end_time,
repeater, repeater,
delay, delay,
.. ..
} => Timestamp::InactiveRange { } => Timestamp::InactiveRange {
start_date, start: start.clone(),
start_time, end: end.clone(),
end_date, repeater: repeater.clone(),
end_time, delay: delay.clone(),
repeater,
delay,
}, },
Clock::Running { Clock::Running {
start_date, start,
start_time,
repeater, repeater,
delay, delay,
} => Timestamp::Inactive { } => Timestamp::Inactive {
start_date, start: start.clone(),
start_time, repeater: repeater.clone(),
repeater, delay: delay.clone(),
delay,
}, },
} }
} }
@ -162,16 +157,14 @@ fn parse() {
Some(( Some((
"", "",
Element::Clock(Clock::Running { Element::Clock(Clock::Running {
start_date: Date { start: Datetime {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(9),
minute: Some(39)
}, },
start_time: Some(Time {
hour: 9,
minute: 39
}),
repeater: None, repeater: None,
delay: None, delay: None,
}) })
@ -182,26 +175,22 @@ fn parse() {
Some(( Some((
"", "",
Element::Clock(Clock::Closed { Element::Clock(Clock::Closed {
start_date: Date { start: Datetime {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(9),
minute: Some(39)
}, },
start_time: Some(Time { end: Datetime {
hour: 9,
minute: 39
}),
end_date: Date {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(10),
minute: Some(39)
}, },
end_time: Some(Time {
hour: 10,
minute: 39
}),
repeater: None, repeater: None,
delay: None, delay: None,
duration: "1:00", duration: "1:00",

View file

@ -22,8 +22,8 @@ mod target;
mod timestamp; mod timestamp;
mod title; mod title;
pub(crate) use emphasis::parse as parse_emphasis;
pub(crate) use block::Block; pub(crate) use block::Block;
pub(crate) use emphasis::parse as parse_emphasis;
pub use self::{ pub use self::{
block::{ block::{
@ -47,7 +47,7 @@ pub use self::{
rule::Rule, rule::Rule,
snippet::Snippet, snippet::Snippet,
target::Target, target::Target,
timestamp::{Date, Time, Timestamp}, timestamp::{Datetime, Timestamp},
title::Title, title::Title,
}; };

View file

@ -68,7 +68,7 @@ impl Planning<'_> {
#[test] #[test]
fn prase() { fn prase() {
use crate::elements::Date; use crate::elements::Datetime;
assert_eq!( assert_eq!(
Planning::parse("SCHEDULED: <2019-04-08 Mon>\n"), Planning::parse("SCHEDULED: <2019-04-08 Mon>\n"),
@ -76,13 +76,14 @@ fn prase() {
"", "",
Planning { Planning {
scheduled: Some(Box::new(Timestamp::Active { scheduled: Some(Box::new(Timestamp::Active {
start_date: Date { start: Datetime {
year: 2019, year: 2019,
month: 4, month: 4,
day: 8, day: 8,
dayname: "Mon" dayname: "Mon",
hour: None,
minute: None
}, },
start_time: None,
repeater: None, repeater: None,
delay: None delay: None
})), })),

View file

@ -1,9 +1,9 @@
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::complete::{tag, take, take_while_m_n}, bytes::complete::{tag, take_while_m_n},
character::complete::space0, character::complete::space0,
combinator::{map, not}, error::ErrorKind,
IResult, Err, IResult,
}; };
use std::usize; use std::usize;
@ -17,11 +17,19 @@ impl Rule {
let (input, _) = space0(input)?; let (input, _) = space0(input)?;
let (input, _) = take_while_m_n(5, usize::MAX, |c| c == '-')(input)?; let (input, _) = take_while_m_n(5, usize::MAX, |c| c == '-')(input)?;
let (input, _) = space0(input)?; let (input, _) = space0(input)?;
let (input, _) = alt((tag("\n"), map(not(take(1usize)), |_| "")))(input)?; let (input, _) = alt((tag("\n"), eof))(input)?;
Ok((input, Element::Rule)) Ok((input, Element::Rule))
} }
} }
fn eof(input: &str) -> IResult<&str, &str> {
if input.is_empty() {
Ok(("", ""))
} else {
Err(Err::Error(("", ErrorKind::Tag)))
}
}
#[test] #[test]
fn parse() { fn parse() {
assert_eq!(Rule::parse("-----"), Ok(("", Element::Rule))); assert_eq!(Rule::parse("-----"), Ok(("", Element::Rule)));

View file

@ -1,13 +1,11 @@
#[cfg(feature = "chrono")]
use chrono::*;
use nom::{ use nom::{
bytes::complete::{tag, take, take_till, take_while, take_while_m_n}, bytes::complete::{tag, take, take_till, take_while, take_while_m_n},
character::complete::{space0, space1}, character::complete::{space0, space1},
combinator::{map_res, opt}, combinator::{map, map_res, opt},
IResult, IResult,
}; };
/// Date /// Datetime
/// ///
/// # Syntax /// # Syntax
/// ///
@ -17,117 +15,145 @@ use nom::{
/// ///
#[cfg_attr(test, derive(PartialEq))] #[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct Date<'a> { pub struct Datetime<'a> {
pub year: u16, pub year: u16,
pub month: u8, pub month: u8,
pub day: u8, pub day: u8,
pub dayname: &'a str, pub dayname: &'a str,
pub hour: Option<u8>,
pub minute: Option<u8>,
} }
impl Date<'_> { fn parse_time(input: &str) -> IResult<&str, (u8, u8)> {
fn parse(input: &str) -> IResult<&str, Date<'_>> { let (input, hour) = map_res(take_while_m_n(1, 2, |c: char| c.is_ascii_digit()), |num| {
let (input, year) = map_res(take(4usize), |num| u16::from_str_radix(num, 10))(input)?; u8::from_str_radix(num, 10)
let (input, _) = tag("-")(input)?; })(input)?;
let (input, month) = map_res(take(2usize), |num| u8::from_str_radix(num, 10))(input)?; let (input, _) = tag(":")(input)?;
let (input, _) = tag("-")(input)?; let (input, minute) = map_res(take(2usize), |num| u8::from_str_radix(num, 10))(input)?;
let (input, day) = map_res(take(2usize), |num| u8::from_str_radix(num, 10))(input)?; Ok((input, (hour, minute)))
let (input, _) = space1(input)?; }
let (input, dayname) = take_while(|c: char| {
!c.is_ascii_whitespace()
&& !c.is_ascii_digit()
&& c != '+'
&& c != '-'
&& c != ']'
&& c != '>'
})(input)?;
Ok(( fn parse_datetime(input: &str) -> IResult<&str, Datetime<'_>> {
input, let parse_u8 = |num| u8::from_str_radix(num, 10);
Date {
year, let (input, year) = map_res(take(4usize), |num| u16::from_str_radix(num, 10))(input)?;
month, let (input, _) = tag("-")(input)?;
day, let (input, month) = map_res(take(2usize), parse_u8)(input)?;
dayname, 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()
#[cfg_attr(test, derive(PartialEq))] && c != '+'
#[cfg_attr(feature = "serde", derive(serde::Serialize))] && c != '-'
#[derive(Debug, Clone, Copy)] && c != ']'
pub struct Time { && c != '>'
pub hour: u8, })(input)?;
pub minute: u8, let (input, (hour, minute)) = map(
} opt(|input| {
let (input, _) = space1(input)?;
impl Time { parse_time(input)
fn parse(input: &str) -> IResult<&str, Time> { }),
let (input, hour) = map_res(take_while_m_n(1, 2, |c: char| c.is_ascii_digit()), |num| { |time| (time.map(|t| t.0), time.map(|t| t.1)),
u8::from_str_radix(num, 10) )(input)?;
})(input)?;
let (input, _) = tag(":")(input)?; Ok((
let (input, minute) = map_res(take(2usize), |num| u8::from_str_radix(num, 10))(input)?; input,
Datetime {
Ok((input, Time { hour, minute })) year,
month,
day,
dayname,
hour,
minute,
},
))
}
#[cfg(feature = "chrono")]
mod chrono {
use super::Datetime;
use chrono::*;
impl Into<NaiveDate> for Datetime<'_> {
fn into(self) -> NaiveDate {
NaiveDate::from_ymd(self.year.into(), self.month.into(), self.day.into())
}
}
impl Into<NaiveTime> for Datetime<'_> {
fn into(self) -> NaiveTime {
NaiveTime::from_hms(
self.hour.unwrap_or_default().into(),
self.minute.unwrap_or_default().into(),
0,
)
}
}
impl Into<NaiveDateTime> for Datetime<'_> {
fn into(self) -> NaiveDateTime {
NaiveDate::from_ymd(self.year.into(), self.month.into(), self.day.into()).and_hms(
self.hour.unwrap_or_default().into(),
self.minute.unwrap_or_default().into(),
0,
)
}
} }
} }
#[cfg_attr(test, derive(PartialEq))] #[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename_all = "snake_case"))]
#[derive(Debug)] #[derive(Debug)]
pub enum Timestamp<'a> { pub enum Timestamp<'a> {
Active { Active {
start_date: Date<'a>, start: Datetime<'a>,
start_time: Option<Time>,
repeater: Option<&'a str>, repeater: Option<&'a str>,
delay: Option<&'a str>, delay: Option<&'a str>,
}, },
Inactive { Inactive {
start_date: Date<'a>, start: Datetime<'a>,
start_time: Option<Time>,
repeater: Option<&'a str>, repeater: Option<&'a str>,
delay: Option<&'a str>, delay: Option<&'a str>,
}, },
ActiveRange { ActiveRange {
start_date: Date<'a>, start: Datetime<'a>,
start_time: Option<Time>, end: Datetime<'a>,
end_date: Date<'a>,
end_time: Option<Time>,
repeater: Option<&'a str>, repeater: Option<&'a str>,
delay: Option<&'a str>, delay: Option<&'a str>,
}, },
InactiveRange { InactiveRange {
start_date: Date<'a>, start: Datetime<'a>,
start_time: Option<Time>, end: Datetime<'a>,
end_date: Date<'a>,
end_time: Option<Time>,
repeater: Option<&'a str>, repeater: Option<&'a str>,
delay: Option<&'a str>, delay: Option<&'a str>,
}, },
Diary(&'a str), Diary {
value: &'a str,
},
} }
impl Timestamp<'_> { impl Timestamp<'_> {
pub(crate) fn parse_active(input: &str) -> IResult<&str, Timestamp<'_>> { pub(crate) fn parse_active(input: &str) -> IResult<&str, Timestamp<'_>> {
let (input, _) = tag("<")(input)?; let (input, _) = tag("<")(input)?;
let (input, start_date) = Date::parse(input)?; let (input, start) = parse_datetime(input)?;
let (input, _) = space0(input)?;
let (input, start_time) = opt(Time::parse)(input)?;
if input.starts_with('-') { if input.starts_with('-') {
let (input, end_time) = opt(Time::parse)(&input[1..])?; let (input, (hour, minute)) = parse_time(&input[1..])?;
let (input, _) = space0(input)?; let (input, _) = space0(input)?;
// TODO: delay-or-repeater // TODO: delay-or-repeater
let (input, _) = tag(">")(input)?; let (input, _) = tag(">")(input)?;
let mut end = start.clone();
end.hour = Some(hour);
end.minute = Some(minute);
return Ok(( return Ok((
input, input,
Timestamp::ActiveRange { Timestamp::ActiveRange {
start_date, start,
start_time, end,
end_date: start_date,
end_time,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -139,19 +165,15 @@ impl Timestamp<'_> {
let (input, _) = tag(">")(input)?; let (input, _) = tag(">")(input)?;
if input.starts_with("--<") { if input.starts_with("--<") {
let (input, end_date) = Date::parse(&input["--<".len()..])?; let (input, end) = parse_datetime(&input["--<".len()..])?;
let (input, _) = space0(input)?;
let (input, end_time) = opt(Time::parse)(input)?;
let (input, _) = space0(input)?; let (input, _) = space0(input)?;
// TODO: delay-or-repeater // TODO: delay-or-repeater
let (input, _) = tag(">")(input)?; let (input, _) = tag(">")(input)?;
Ok(( Ok((
input, input,
Timestamp::ActiveRange { Timestamp::ActiveRange {
start_date, start,
start_time, end,
end_date,
end_time,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -160,8 +182,7 @@ impl Timestamp<'_> {
Ok(( Ok((
input, input,
Timestamp::Active { Timestamp::Active {
start_date, start,
start_time,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -171,22 +192,21 @@ impl Timestamp<'_> {
pub(crate) fn parse_inactive(input: &str) -> IResult<&str, Timestamp<'_>> { pub(crate) fn parse_inactive(input: &str) -> IResult<&str, Timestamp<'_>> {
let (input, _) = tag("[")(input)?; let (input, _) = tag("[")(input)?;
let (input, start_date) = Date::parse(input)?; let (input, start) = parse_datetime(input)?;
let (input, _) = space0(input)?;
let (input, start_time) = opt(Time::parse)(input)?;
if input.starts_with('-') { if input.starts_with('-') {
let (input, end_time) = opt(Time::parse)(&input[1..])?; let (input, (hour, minute)) = parse_time(&input[1..])?;
let (input, _) = space0(input)?; let (input, _) = space0(input)?;
// TODO: delay-or-repeater // TODO: delay-or-repeater
let (input, _) = tag("]")(input)?; let (input, _) = tag("]")(input)?;
let mut end = start.clone();
end.hour = Some(hour);
end.minute = Some(minute);
return Ok(( return Ok((
input, input,
Timestamp::InactiveRange { Timestamp::InactiveRange {
start_date, start,
start_time, end,
end_date: start_date,
end_time,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -198,19 +218,15 @@ impl Timestamp<'_> {
let (input, _) = tag("]")(input)?; let (input, _) = tag("]")(input)?;
if input.starts_with("--[") { if input.starts_with("--[") {
let (input, end_date) = Date::parse(&input["--[".len()..])?; let (input, end) = parse_datetime(&input["--[".len()..])?;
let (input, _) = space0(input)?;
let (input, end_time) = opt(Time::parse)(input)?;
let (input, _) = space0(input)?; let (input, _) = space0(input)?;
// TODO: delay-or-repeater // TODO: delay-or-repeater
let (input, _) = tag("]")(input)?; let (input, _) = tag("]")(input)?;
Ok(( Ok((
input, input,
Timestamp::InactiveRange { Timestamp::InactiveRange {
start_date, start,
start_time, end,
end_date,
end_time,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -219,8 +235,7 @@ impl Timestamp<'_> {
Ok(( Ok((
input, input,
Timestamp::Inactive { Timestamp::Inactive {
start_date, start,
start_time,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -230,10 +245,10 @@ impl Timestamp<'_> {
pub(crate) fn parse_diary(input: &str) -> IResult<&str, Timestamp<'_>> { pub(crate) fn parse_diary(input: &str) -> IResult<&str, Timestamp<'_>> {
let (input, _) = tag("<%%(")(input)?; let (input, _) = tag("<%%(")(input)?;
let (input, sexp) = take_till(|c| c == ')' || c == '>' || c == '\n')(input)?; let (input, value) = take_till(|c| c == ')' || c == '>' || c == '\n')(input)?;
let (input, _) = tag(")>")(input)?; let (input, _) = tag(")>")(input)?;
Ok((input, Timestamp::Diary(sexp))) Ok((input, Timestamp::Diary { value }))
} }
} }
@ -291,13 +306,14 @@ fn parse() {
Ok(( Ok((
"", "",
Timestamp::Inactive { Timestamp::Inactive {
start_date: Date { start: Datetime {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: None,
minute: None
}, },
start_time: None,
repeater: None, repeater: None,
delay: None, delay: None,
}, },
@ -308,26 +324,22 @@ fn parse() {
Ok(( Ok((
"", "",
Timestamp::InactiveRange { Timestamp::InactiveRange {
start_date: Date { start: Datetime {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(9),
minute: Some(39)
}, },
start_time: Some(Time { end: Datetime {
hour: 9,
minute: 39
}),
end_date: Date {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(10),
minute: Some(39),
}, },
end_time: Some(Time {
hour: 10,
minute: 39
}),
repeater: None, repeater: None,
delay: None delay: None
}, },
@ -338,26 +350,22 @@ fn parse() {
Ok(( Ok((
"", "",
Timestamp::ActiveRange { Timestamp::ActiveRange {
start_date: Date { start: Datetime {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(9),
minute: Some(39),
}, },
start_time: Some(Time { end: Datetime {
hour: 9,
minute: 39
}),
end_date: Date {
year: 2003, year: 2003,
month: 9, month: 9,
day: 16, day: 16,
dayname: "Tue" dayname: "Tue",
hour: Some(10),
minute: Some(39),
}, },
end_time: Some(Time {
hour: 10,
minute: 39
}),
repeater: None, repeater: None,
delay: None delay: None
}, },

View file

@ -1,4 +1,4 @@
use crate::elements::Element; use crate::elements::{Datetime, Element};
use jetscii::bytes; use jetscii::bytes;
use std::fmt; use std::fmt;
use std::io::{Error, Write}; use std::io::{Error, Write};
@ -104,7 +104,7 @@ pub trait HtmlHandler<E: From<Error>> {
Target(_target) => (), Target(_target) => (),
Text { value } => write!(w, "{}", Escape(value))?, Text { value } => write!(w, "{}", Escape(value))?,
Timestamp(timestamp) => { Timestamp(timestamp) => {
use crate::elements::{Date, Time, Timestamp::*}; use crate::elements::Timestamp;
write!( write!(
&mut w, &mut w,
@ -114,61 +114,37 @@ pub trait HtmlHandler<E: From<Error>> {
fn write_datetime<W: Write>( fn write_datetime<W: Write>(
mut w: W, mut w: W,
start: &str, start: &str,
date: &Date, datetime: &Datetime,
time: &Option<Time>,
end: &str, end: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
write!(w, "{}", start)?; write!(w, "{}", start)?;
write!( write!(
w, w,
"{}-{}-{} {}", "{}-{}-{} {}",
date.year, datetime.year, datetime.month, datetime.day, datetime.dayname
date.month,
date.day,
Escape(date.dayname)
)?; )?;
if let Some(time) = time { if let (Some(hour), Some(minute)) = (datetime.hour, datetime.minute) {
write!(w, " {}:{}", time.hour, time.minute)?; write!(w, " {}:{}", hour, minute)?;
} }
write!(w, "{}", end) write!(w, "{}", end)
} }
match timestamp { match timestamp {
Active { Timestamp::Active { start, .. } => {
start_date, write_datetime(&mut w, "&lt;", start, "&gt;")?;
start_time,
..
} => {
write_datetime(&mut w, "&lt;", start_date, start_time, "&gt;")?;
} }
Inactive { Timestamp::Inactive { start, .. } => {
start_date, write_datetime(&mut w, "[", start, "]")?;
start_time,
..
} => {
write_datetime(&mut w, "[", start_date, start_time, "]")?;
} }
ActiveRange { Timestamp::ActiveRange { start, end, .. } => {
start_date, write_datetime(&mut w, "&lt;", start, "&gt;&#x2013;")?;
start_time, write_datetime(&mut w, "&lt;", end, "&gt;")?;
end_date,
end_time,
..
} => {
write_datetime(&mut w, "&lt;", start_date, start_time, "&gt;&#x2013;")?;
write_datetime(&mut w, "&lt;", end_date, end_time, "&gt;")?;
} }
InactiveRange { Timestamp::InactiveRange { start, end, .. } => {
start_date, write_datetime(&mut w, "[", start, "]&#x2013;")?;
start_time, write_datetime(&mut w, "[", end, "]")?;
end_date,
end_time,
..
} => {
write_datetime(&mut w, "[", start_date, start_time, "]&#x2013;")?;
write_datetime(&mut w, "[", end_date, end_time, "]")?;
} }
Diary(value) => write!(&mut w, "&lt;%%({})&gt;", Escape(value))?, Timestamp::Diary { value } => write!(&mut w, "&lt;%%({})&gt;", Escape(value))?,
} }
write!(&mut w, "</span></span>")?; write!(&mut w, "</span></span>")?;

View file

@ -1,4 +1,4 @@
use crate::elements::Element; use crate::elements::{Datetime, Element};
use std::io::{Error, Write}; use std::io::{Error, Write};
pub trait OrgHandler<E: From<Error>> { pub trait OrgHandler<E: From<Error>> {
@ -89,63 +89,42 @@ pub trait OrgHandler<E: From<Error>> {
Target(_target) => (), Target(_target) => (),
Text { value } => write!(w, "{}", value)?, Text { value } => write!(w, "{}", value)?,
Timestamp(timestamp) => { Timestamp(timestamp) => {
use crate::elements::{Date, Time, Timestamp::*}; use crate::elements::Timestamp;
fn write_datetime<W: Write>( fn write_datetime<W: Write>(
mut w: W, mut w: W,
start: &str, start: &str,
date: &Date, datetime: &Datetime,
time: &Option<Time>,
end: &str, end: &str,
) -> Result<(), Error> { ) -> Result<(), Error> {
write!(w, "{}", start)?; write!(w, "{}", start)?;
write!( write!(
w, w,
"{}-{}-{} {}", "{}-{}-{} {}",
date.year, date.month, date.day, date.dayname datetime.year, datetime.month, datetime.day, datetime.dayname
)?; )?;
if let Some(time) = time { if let (Some(hour), Some(minute)) = (datetime.hour, datetime.minute) {
write!(w, " {}:{}", time.hour, time.minute,)?; write!(w, " {}:{}", hour, minute)?;
} }
write!(w, "{}", end) write!(w, "{}", end)
} }
match timestamp { match timestamp {
Active { Timestamp::Active { start, .. } => {
start_date, write_datetime(&mut w, "<", start, ">")?;
start_time,
..
} => {
write_datetime(&mut w, "<", start_date, start_time, ">")?;
} }
Inactive { Timestamp::Inactive { start, .. } => {
start_date, write_datetime(&mut w, "[", start, "]")?;
start_time,
..
} => {
write_datetime(&mut w, "[", start_date, start_time, "]")?;
} }
ActiveRange { Timestamp::ActiveRange { start, end, .. } => {
start_date, write_datetime(&mut w, "<", start, ">--")?;
start_time, write_datetime(&mut w, "<", end, ">")?;
end_date,
end_time,
..
} => {
write_datetime(&mut w, "<", start_date, start_time, ">--")?;
write_datetime(&mut w, "<", end_date, end_time, ">")?;
} }
InactiveRange { Timestamp::InactiveRange { start, end, .. } => {
start_date, write_datetime(&mut w, "[", start, "]--")?;
start_time, write_datetime(&mut w, "[", end, "]")?;
end_date,
end_time,
..
} => {
write_datetime(&mut w, "[", start_date, start_time, "]--")?;
write_datetime(&mut w, "[", end_date, end_time, "]")?;
} }
Diary(value) => write!(w, "<%%({})>", value)?, Timestamp::Diary { value } => write!(w, "<%%({})>", value)?,
} }
} }
Verbatim { value } => write!(w, "={}=", value)?, Verbatim { value } => write!(w, "={}=", value)?,