Implement --range

This commit is contained in:
Joscha 2021-12-19 00:36:40 +01:00
parent ff627b98df
commit e9ec2998f0
4 changed files with 91 additions and 33 deletions

View file

@ -1,11 +1,13 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use std::{process, result}; use std::{process, result};
use chrono::{Duration, NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use directories::ProjectDirs; use directories::ProjectDirs;
use structopt::StructOpt; 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 crate::files::{self, Files};
use self::error::Result; use self::error::Result;
@ -25,14 +27,9 @@ pub struct Opt {
/// Overwrite the current date /// Overwrite the current date
#[structopt(short, long)] #[structopt(short, long)]
date: Option<NaiveDate>, date: Option<NaiveDate>,
// TODO Allow negative numbers for `before` and `after` /// The range days to focus on
// TODO Or just allow any Delta #[structopt(short, long, default_value = "today-2d--today+13d")]
/// How many days to include before the current date range: String,
#[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,
#[structopt(subcommand)] #[structopt(subcommand)]
command: Option<Command>, command: Option<Command>,
} }
@ -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<Vec<Entry>> { fn find_entries(files: &Files, range: DateRange) -> Result<Vec<Entry>> {
Ok(files.eval(EntryMode::Relevant, range)?) Ok(files.eval(EntryMode::Relevant, range)?)
} }
@ -136,7 +124,25 @@ pub fn run() {
}; };
let now = find_now(&opt, &files); 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) { if let Err(e) = run_command(&opt, &mut files, range, now) {
e.print(&files.sources()); e.print(&files.sources());

View file

@ -1,10 +1,14 @@
use chrono::NaiveDate;
use crate::files::arguments::{Range, RangeDate};
use crate::files::Files; use crate::files::Files;
use self::command::CommandState; use self::command::CommandState;
pub use self::date::Dates; pub use self::date::Dates;
use self::delta::Delta;
use self::entry::Entries; use self::entry::Entries;
pub use self::entry::{Entry, EntryKind, EntryMode}; 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; pub use self::range::DateRange;
mod command; mod command;
@ -26,3 +30,32 @@ impl Files {
Ok(entries.entries()) Ok(entries.entries())
} }
} }
impl Range {
pub fn eval(&self, index: usize, today: NaiveDate) -> Result<DateRange> {
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))
}
}

View file

@ -106,7 +106,11 @@ impl<'a> CommandState<'a> {
.filter(|&until| until < range_until) .filter(|&until| until < range_until)
.unwrap_or(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 /// Add an entry, respecting [`Self::from`] and [`Self::until`]. Does not

View file

@ -12,20 +12,37 @@ pub struct DateRange {
} }
impl DateRange { impl DateRange {
pub fn new(from: NaiveDate, until: NaiveDate) -> Option<Self> { pub fn new(from: NaiveDate, until: NaiveDate) -> Self {
if from <= until { 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<Self> {
if from <= self.until {
Some(Self::new(from, self.until))
} else { } else {
None None
} }
} }
pub fn with_from(&self, from: NaiveDate) -> Option<Self> { /// Return a new range with its [`Self::until`] set to a new value.
Self::new(from, self.until) ///
} /// Returns [`None`] if the new value is earlier than [`Self::from`].
pub fn with_until(&self, until: NaiveDate) -> Option<Self> { pub fn with_until(&self, until: NaiveDate) -> Option<Self> {
Self::new(self.from, until) if self.from <= until {
Some(Self::new(self.from, until))
} else {
None
}
} }
pub fn containing(&self, date: NaiveDate) -> Self { pub fn containing(&self, date: NaiveDate) -> Self {
@ -75,8 +92,7 @@ impl DateRange {
self.from + Duration::days(expand_lower.into()), self.from + Duration::days(expand_lower.into()),
self.until + Duration::days(expand_upper.into()), self.until + Duration::days(expand_upper.into()),
) )
// The range is never shrunk, so the new range should always be valid. // The range should never shrink.
.expect("expanded range shrunk")
} }
/// Return a new range that contains at least all dates from which the /// 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()), self.until + Duration::days(move_upper.into()),
) )
// The delta's upper bound is greater or equal than its lower bound, so // 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. // the range should never shrink. It can only move and expand.
.expect("moved range shrunk")
} }
} }