diff --git a/src/cli.rs b/src/cli.rs index d1d9005..4664fcc 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -8,7 +8,7 @@ use directories::ProjectDirs; use structopt::StructOpt; use crate::eval::{DateRange, Entry, EntryMode}; -use crate::files::arguments::Range; +use crate::files::arguments::CliRange; use crate::files::{self, FileSource, Files}; use self::error::Error; @@ -29,8 +29,8 @@ pub struct Opt { /// Overwrite the current date #[structopt(short, long)] date: Option, - /// The range days to focus on - #[structopt(short, long, default_value = "today-2d--today+13d")] + /// Range of days to focus on + #[structopt(short, long, default_value = "t-2d--t+13d")] range: String, #[structopt(subcommand)] command: Option, @@ -57,7 +57,7 @@ pub enum Command { #[structopt(required = true)] entries: Vec, }, - /// Reformat all loaded files + /// Reformats all loaded files Fmt, } @@ -145,7 +145,7 @@ pub fn run() { let now = find_now(&opt, &files); // Kinda ugly, but it can stay for now (until it grows at least). - let range = match Range::from_str(&opt.range) { + let range = match CliRange::from_str(&opt.range) { Ok(range) => match range.eval((), now.date()) { Ok(range) => range, Err(e) => { diff --git a/src/eval.rs b/src/eval.rs index 80f3033..def8a51 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,6 @@ use chrono::NaiveDate; -use crate::files::arguments::{Range, RangeDate}; +use crate::files::arguments::{CliDate, CliDatum, CliRange}; use crate::files::{FileSource, Files}; use self::command::{CommandState, EvalCommand}; @@ -34,11 +34,27 @@ impl Files { } } -impl Range { +impl CliDate { + pub fn eval(&self, index: S, today: NaiveDate) -> Result> { + let mut date = match self.datum { + CliDatum::Date(d) => d, + CliDatum::Today => today, + }; + + if let Some(delta) = &self.delta { + let delta: Delta = delta.into(); + date = delta.apply_date(index, date)?; + } + + Ok(date) + } +} + +impl CliRange { pub fn eval(&self, index: S, today: NaiveDate) -> Result> { let mut start = match self.start { - RangeDate::Date(d) => d, - RangeDate::Today => today, + CliDatum::Date(d) => d, + CliDatum::Today => today, }; if let Some(delta) = &self.start_delta { @@ -49,8 +65,8 @@ impl Range { let mut end = start; match self.end { - Some(RangeDate::Date(d)) => end = d, - Some(RangeDate::Today) => end = today, + Some(CliDatum::Date(d)) => end = d, + Some(CliDatum::Today) => end = today, None => {} } diff --git a/src/files/arguments.rs b/src/files/arguments.rs index 13cbf29..c04f991 100644 --- a/src/files/arguments.rs +++ b/src/files/arguments.rs @@ -8,35 +8,83 @@ use super::commands::Delta; use super::parse::{self, Error, Result, Rule, TodayfileParser}; #[derive(Debug)] -pub enum RangeDate { +pub enum CliDatum { Date(NaiveDate), Today, } -#[derive(Debug)] -pub struct Range { - pub start: RangeDate, - pub start_delta: Option, - pub end: Option, - pub end_delta: Option, -} - -/* Parsing */ - -fn parse_range_date(p: Pair<'_, Rule>) -> Result { - assert!(matches!(p.as_rule(), Rule::datum | Rule::today)); +fn parse_cli_datum(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::cli_datum); + let p = p.into_inner().next().unwrap(); Ok(match p.as_rule() { - Rule::datum => RangeDate::Date(parse::parse_datum(p)?.value), - Rule::today => RangeDate::Today, + Rule::datum => CliDatum::Date(parse::parse_datum(p)?.value), + Rule::today => CliDatum::Today, _ => unreachable!(), }) } -fn parse_range_start(p: Pair<'_, Rule>) -> Result<(RangeDate, Option)> { - assert_eq!(p.as_rule(), Rule::range_start); +#[derive(Debug)] +pub struct CliDate { + pub datum: CliDatum, + pub delta: Option, +} + +fn parse_cli_date(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::cli_date); let mut p = p.into_inner(); - let start = parse_range_date(p.next().unwrap())?; + let datum = parse_cli_datum(p.next().unwrap())?; + let delta = match p.next() { + Some(p) => Some(parse::parse_delta(p)?.value), + None => None, + }; + + assert_eq!(p.next(), None); + + Ok(CliDate { datum, delta }) +} + +#[derive(Debug)] +pub enum CliIdent { + Number(usize), + Date(CliDate), +} + +fn parse_cli_ident(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::cli_ident); + let p = p.into_inner().next().unwrap(); + Ok(match p.as_rule() { + Rule::number => CliIdent::Number(parse::parse_number(p) as usize), + Rule::cli_date => CliIdent::Date(parse_cli_date(p)?), + _ => unreachable!(), + }) +} + +impl FromStr for CliIdent { + type Err = Error; + + fn from_str(s: &str) -> Result { + let mut pairs = TodayfileParser::parse(Rule::cli_ident, s)?; + let p = pairs.next().unwrap(); + assert_eq!(pairs.next(), None); + + parse_cli_ident(p) + } +} + +#[derive(Debug)] +pub struct CliRange { + pub start: CliDatum, + pub start_delta: Option, + pub end: Option, + pub end_delta: Option, +} + +fn parse_cli_range_start(p: Pair<'_, Rule>) -> Result<(CliDatum, Option)> { + assert_eq!(p.as_rule(), Rule::cli_range_start); + let mut p = p.into_inner(); + + let start = parse_cli_datum(p.next().unwrap())?; let start_delta = match p.next() { None => None, Some(p) => Some(parse::parse_delta(p)?.value), @@ -47,15 +95,15 @@ fn parse_range_start(p: Pair<'_, Rule>) -> Result<(RangeDate, Option)> { Ok((start, start_delta)) } -fn parse_range_end(p: Pair<'_, Rule>) -> Result<(Option, Option)> { - assert_eq!(p.as_rule(), Rule::range_end); +fn parse_cli_range_end(p: Pair<'_, Rule>) -> Result<(Option, Option)> { + assert_eq!(p.as_rule(), Rule::cli_range_end); let mut end = None; let mut end_delta = None; for p in p.into_inner() { match p.as_rule() { - Rule::datum | Rule::today => end = Some(parse_range_date(p)?), + Rule::cli_datum => end = Some(parse_cli_datum(p)?), Rule::delta => end_delta = Some(parse::parse_delta(p)?.value), _ => unreachable!(), } @@ -64,18 +112,18 @@ fn parse_range_end(p: Pair<'_, Rule>) -> Result<(Option, Option) -> Result { - assert_eq!(p.as_rule(), Rule::range); +fn parse_cli_range(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::cli_range); let mut p = p.into_inner(); - let (start, start_delta) = parse_range_start(p.next().unwrap())?; + let (start, start_delta) = parse_cli_range_start(p.next().unwrap())?; let (end, end_delta) = match p.next() { // For some reason, the EOI gets captured but the SOI doesn't. - Some(p) if p.as_rule() != Rule::EOI => parse_range_end(p)?, + Some(p) if p.as_rule() != Rule::EOI => parse_cli_range_end(p)?, _ => (None, None), }; - Ok(Range { + Ok(CliRange { start, start_delta, end, @@ -83,14 +131,14 @@ fn parse_range(p: Pair<'_, Rule>) -> Result { }) } -impl FromStr for Range { +impl FromStr for CliRange { type Err = Error; fn from_str(s: &str) -> Result { - let mut pairs = TodayfileParser::parse(Rule::range, s)?; + let mut pairs = TodayfileParser::parse(Rule::cli_range, s)?; let p = pairs.next().unwrap(); assert_eq!(pairs.next(), None); - parse_range(p) + parse_cli_range(p) } } diff --git a/src/files/grammar.pest b/src/files/grammar.pest index e0a0279..dba2273 100644 --- a/src/files/grammar.pest +++ b/src/files/grammar.pest @@ -148,7 +148,10 @@ command = { include | timezone | task | note | log } file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI } -today = { "today" } -range_start = { (datum | today) ~ delta? } -range_end = { (datum | today) ~ delta? | delta } -range = { SOI ~ range_start ~ ("--" ~ range_end)? ~ EOI} +today = { "today" | "t" } +cli_datum = { datum | today } +cli_date = { cli_datum ~ delta? } +cli_ident = { SOI ~ (number | cli_date) ~ EOI } +cli_range_start = { cli_datum ~ delta? } +cli_range_end = { cli_datum ~ delta? | delta } +cli_range = { SOI ~ cli_range_start ~ ("--" ~ cli_range_end)? ~ EOI } diff --git a/src/files/parse.rs b/src/files/parse.rs index f817d1d..67c0da9 100644 --- a/src/files/parse.rs +++ b/src/files/parse.rs @@ -49,7 +49,7 @@ fn parse_timezone(p: Pair<'_, Rule>) -> Spanned { Spanned::new(span, name) } -fn parse_number(p: Pair<'_, Rule>) -> i32 { +pub fn parse_number(p: Pair<'_, Rule>) -> i32 { assert_eq!(p.as_rule(), Rule::number); p.as_str().parse().unwrap() }