From e9ec2998f0429218a6649694818c8858c0ec6cd5 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 19 Dec 2021 00:36:40 +0100 Subject: [PATCH] Implement --range --- src/cli.rs | 46 +++++++++++++++++++++++++-------------------- src/eval.rs | 35 +++++++++++++++++++++++++++++++++- src/eval/command.rs | 6 +++++- src/eval/range.rs | 37 +++++++++++++++++++++++++----------- 4 files changed, 91 insertions(+), 33 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 8a66b96..25d064d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,11 +1,13 @@ use std::path::PathBuf; +use std::str::FromStr; use std::{process, result}; -use chrono::{Duration, NaiveDate, NaiveDateTime}; +use chrono::{NaiveDate, NaiveDateTime}; use directories::ProjectDirs; use structopt::StructOpt; -use crate::eval::{DateRange, Entry, EntryMode}; +use crate::eval::{DateRange, Entry, EntryMode, SourceInfo}; +use crate::files::arguments::Range; use crate::files::{self, Files}; use self::error::Result; @@ -25,14 +27,9 @@ pub struct Opt { /// Overwrite the current date #[structopt(short, long)] date: Option, - // TODO Allow negative numbers for `before` and `after` - // TODO Or just allow any Delta - /// How many days to include before the current date - #[structopt(short, long, default_value = "3")] - before: u32, - /// How many days to include after the current date - #[structopt(short, long, default_value = "13")] - after: u32, + /// The range days to focus on + #[structopt(short, long, default_value = "today-2d--today+13d")] + range: String, #[structopt(subcommand)] command: Option, } @@ -77,15 +74,6 @@ fn find_now(opt: &Opt, files: &Files) -> NaiveDateTime { } } -fn find_range(opt: &Opt, now: NaiveDateTime) -> DateRange { - let range_date = opt.date.unwrap_or_else(|| now.date()); - DateRange::new( - range_date - Duration::days(opt.before.into()), - range_date + Duration::days(opt.after.into()), - ) - .expect("determine range") -} - fn find_entries(files: &Files, range: DateRange) -> Result> { Ok(files.eval(EntryMode::Relevant, range)?) } @@ -136,7 +124,25 @@ pub fn run() { }; let now = find_now(&opt, &files); - let range = find_range(&opt, now); + + // Kinda ugly, but it can stay for now (until it grows at least). + let range = match Range::from_str(&opt.range) { + Ok(range) => match range.eval(0, now.date()) { + Ok(range) => range, + Err(e) => { + eprintln!("Failed to evaluate --range:"); + e.print(&[SourceInfo { + name: Some("--range".to_string()), + content: &opt.range, + }]); + process::exit(1) + } + }, + Err(e) => { + eprintln!("Failed to parse --range:\n{}", e.with_path("--range")); + process::exit(1) + } + }; if let Err(e) = run_command(&opt, &mut files, range, now) { e.print(&files.sources()); diff --git a/src/eval.rs b/src/eval.rs index cdfe20e..e596ab1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,10 +1,14 @@ +use chrono::NaiveDate; + +use crate::files::arguments::{Range, RangeDate}; use crate::files::Files; use self::command::CommandState; pub use self::date::Dates; +use self::delta::Delta; use self::entry::Entries; pub use self::entry::{Entry, EntryKind, EntryMode}; -pub use self::error::{Error, Result}; +pub use self::error::{Error, Result, SourceInfo}; pub use self::range::DateRange; mod command; @@ -26,3 +30,32 @@ impl Files { Ok(entries.entries()) } } + +impl Range { + pub fn eval(&self, index: usize, today: NaiveDate) -> Result { + let mut start = match self.start { + RangeDate::Date(d) => d, + RangeDate::Today => today, + }; + + if let Some(delta) = &self.start_delta { + let delta: Delta = delta.into(); + start = delta.apply_date(index, start)?; + } + + let mut end = start; + + match self.end { + Some(RangeDate::Date(d)) => end = d, + Some(RangeDate::Today) => end = today, + None => {} + } + + if let Some(delta) = &self.end_delta { + let delta: Delta = delta.into(); + end = delta.apply_date(index, end)?; + } + + Ok(DateRange::new(start, end)) + } +} diff --git a/src/eval/command.rs b/src/eval/command.rs index 6406c55..cec8e2d 100644 --- a/src/eval/command.rs +++ b/src/eval/command.rs @@ -106,7 +106,11 @@ impl<'a> CommandState<'a> { .filter(|&until| until < range_until) .unwrap_or(range_until); - DateRange::new(from, until) + if from <= until { + Some(DateRange::new(from, until)) + } else { + None + } } /// Add an entry, respecting [`Self::from`] and [`Self::until`]. Does not diff --git a/src/eval/range.rs b/src/eval/range.rs index 5309c59..8a7cef5 100644 --- a/src/eval/range.rs +++ b/src/eval/range.rs @@ -12,20 +12,37 @@ pub struct DateRange { } impl DateRange { - pub fn new(from: NaiveDate, until: NaiveDate) -> Option { + pub fn new(from: NaiveDate, until: NaiveDate) -> Self { if from <= until { - Some(Self { from, until }) + Self { from, until } + } else { + Self { + from: until, + until: from, + } + } + } + + /// Return a new range with its [`Self::from`] set to a new value. + /// + /// Returns [`None`] if the new value is later than [`Self::until`]. + pub fn with_from(&self, from: NaiveDate) -> Option { + if from <= self.until { + Some(Self::new(from, self.until)) } else { None } } - pub fn with_from(&self, from: NaiveDate) -> Option { - Self::new(from, self.until) - } - + /// Return a new range with its [`Self::until`] set to a new value. + /// + /// Returns [`None`] if the new value is earlier than [`Self::from`]. pub fn with_until(&self, until: NaiveDate) -> Option { - Self::new(self.from, until) + if self.from <= until { + Some(Self::new(self.from, until)) + } else { + None + } } pub fn containing(&self, date: NaiveDate) -> Self { @@ -75,8 +92,7 @@ impl DateRange { self.from + Duration::days(expand_lower.into()), self.until + Duration::days(expand_upper.into()), ) - // The range is never shrunk, so the new range should always be valid. - .expect("expanded range shrunk") + // The range should never shrink. } /// Return a new range that contains at least all dates from which the @@ -90,7 +106,6 @@ impl DateRange { self.until + Duration::days(move_upper.into()), ) // The delta's upper bound is greater or equal than its lower bound, so - // the range should never become smaller. It can only move and expand. - .expect("moved range shrunk") + // the range should never shrink. It can only move and expand. } }