diff --git a/src/files/commands.rs b/src/files/commands.rs index 7d1ec2d..ebb93d0 100644 --- a/src/files/commands.rs +++ b/src/files/commands.rs @@ -337,6 +337,12 @@ pub struct Note { pub desc: Vec, } +#[derive(Debug)] +pub struct Log { + pub date: NaiveDate, + pub desc: Vec, +} + #[derive(Debug)] pub enum Command { Task(Task), @@ -371,5 +377,6 @@ pub struct File { pub contents: String, pub includes: Vec, pub timezone: Option, + pub logs: Vec, pub commands: Vec, } diff --git a/src/files/format.rs b/src/files/format.rs index 0694462..bc46e19 100644 --- a/src/files/format.rs +++ b/src/files/format.rs @@ -6,7 +6,7 @@ use crate::files::commands::DoneKind; use super::commands::{ BirthdaySpec, Command, DateSpec, Delta, DeltaStep, Done, DoneDate, Expr, File, FormulaSpec, - Note, Repeat, Spec, Statement, Task, Var, WeekdaySpec, + Log, Note, Repeat, Spec, Statement, Task, Var, WeekdaySpec, }; use super::primitives::{Spanned, Time, Weekday}; @@ -306,9 +306,19 @@ impl fmt::Display for Command { } } +impl fmt::Display for Log { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "LOG {}", self.date)?; + format_desc(f, &self.desc)?; + Ok(()) + } +} + impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut empty = true; + + // TODO Sort includes alphabetically for include in &self.includes { writeln!(f, "INCLUDE {}", include)?; empty = false; @@ -322,6 +332,11 @@ impl fmt::Display for File { empty = false; } + // TODO Sort logs from old to new + for log in &self.logs { + writeln!(f, "{}", log)?; + } + for command in &self.commands { if !empty { writeln!(f)?; diff --git a/src/files/grammar.pest b/src/files/grammar.pest index 24e9a51..e0a0279 100644 --- a/src/files/grammar.pest +++ b/src/files/grammar.pest @@ -140,8 +140,11 @@ note = { ~ description } +log_head = !{ "LOG" ~ datum ~ eol } +log = { log_head ~ description } + empty_line = _{ WHITESPACE* ~ NEWLINE } -command = { include | timezone | task | note } +command = { include | timezone | task | note | log } file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI } diff --git a/src/files/parse.rs b/src/files/parse.rs index fc869e5..a60c850 100644 --- a/src/files/parse.rs +++ b/src/files/parse.rs @@ -9,7 +9,7 @@ use pest::{Parser, Span}; use super::commands::{ BirthdaySpec, Command, DateSpec, Delta, DeltaStep, Done, DoneDate, DoneKind, Expr, File, - FormulaSpec, Note, Repeat, Spec, Statement, Task, Var, WeekdaySpec, + FormulaSpec, Log, Note, Repeat, Spec, Statement, Task, Var, WeekdaySpec, }; use super::primitives::{Spanned, Time, Weekday}; @@ -795,6 +795,23 @@ fn parse_note(p: Pair<'_, Rule>) -> Result { }) } +fn parse_log_head(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::log_head); + Ok(parse_datum(p.into_inner().next().unwrap())?.value) +} + +fn parse_log(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::log); + let mut p = p.into_inner(); + + let date = parse_log_head(p.next().unwrap())?; + let desc = parse_description(p.next().unwrap())?; + + assert_eq!(p.next(), None); + + Ok(Log { date, desc }) +} + fn parse_command(p: Pair<'_, Rule>, file: &mut File) -> Result<()> { assert_eq!(p.as_rule(), Rule::command); @@ -807,6 +824,7 @@ fn parse_command(p: Pair<'_, Rule>, file: &mut File) -> Result<()> { }, Rule::task => file.commands.push(Command::Task(parse_task(p)?)), Rule::note => file.commands.push(Command::Note(parse_note(p)?)), + Rule::log => file.logs.push(parse_log(p)?), _ => unreachable!(), } @@ -820,6 +838,7 @@ pub fn parse_file(p: Pair<'_, Rule>, contents: String) -> Result { contents, includes: vec![], timezone: None, + logs: vec![], commands: vec![], };