diff --git a/src/eval/command.rs b/src/eval/command.rs index 3bbcd65..01364f8 100644 --- a/src/eval/command.rs +++ b/src/eval/command.rs @@ -66,6 +66,22 @@ impl<'a> CommandState<'a> { } } + fn limit_from_until(&self, range: DateRange) -> Option { + let range_from = range.from(); + let from = self + .from + .filter(|&from| from > range_from) + .unwrap_or(range_from); + + let range_until = range.until(); + let until = self + .until + .filter(|&until| until < range_until) + .unwrap_or(range_until); + + DateRange::new(from, until) + } + /// Add an entry, respecting [`Self::from`] and [`Self::until`]. Does not /// overwrite existing entries if a root date is specified. fn add(&mut self, kind: EntryKind, dates: Option) { diff --git a/src/eval/command/date.rs b/src/eval/command/date.rs index df6310f..b67d8c9 100644 --- a/src/eval/command/date.rs +++ b/src/eval/command/date.rs @@ -1,10 +1,12 @@ use chrono::NaiveDate; -use crate::files::commands::{self, Spanned, Time}; +use crate::eval::date::Dates; +use crate::eval::DateRange; +use crate::files::commands::{self, Command, Spanned, Time}; use super::super::command::CommandState; use super::super::delta::{Delta, DeltaStep}; -use super::super::Result; +use super::super::{Error, Result}; pub struct DateSpec { pub start: NaiveDate, @@ -52,8 +54,77 @@ impl From<&commands::DateSpec> for DateSpec { } } -impl<'a> CommandState<'a> { - pub fn eval_date_spec(&mut self, spec: DateSpec) -> Result<()> { - todo!() +impl DateSpec { + fn start_and_range(&self, s: &CommandState<'_>) -> Option<(NaiveDate, DateRange)> { + let (start, range) = match s.command.command { + Command::Task(_) => { + let last_done = s.last_done(); + let start = last_done + .filter(|_| self.start_at_done) + .unwrap_or(self.start); + let range_from = last_done.map(|date| date.succ()).unwrap_or(self.start); + let range = s + .range + .expand_by(&self.end_delta) + .move_by(&self.start_delta) + .with_from(range_from)?; + (start, range) + } + Command::Note(_) => { + let start = self.start; + let range = s + .range + .expand_by(&self.end_delta) + .move_by(&self.start_delta); + (start, range) + } + }; + let range = s.limit_from_until(range)?; + Some((start, range)) + } + + fn step(from: NaiveDate, repeat: &Delta) -> Result { + let to = repeat.apply_date(from)?; + if to > from { + Ok(to) + } else { + Err(Error::RepeatDidNotMoveForwards { + span: todo!(), + from, + to, + }) + } + } + + fn dates(&self, start: NaiveDate) -> Result { + let root = self.start_delta.apply_date(start)?; + Ok(if let Some(root_time) = self.start_time { + let (other, other_time) = self.end_delta.apply_date_time(root, root_time)?; + Dates::new_with_time(root, root_time, other, other_time) + } else { + let other = self.end_delta.apply_date(root)?; + Dates::new(root, other) + }) + } +} + +impl<'a> CommandState<'a> { + pub fn eval_date_spec(&mut self, spec: DateSpec) -> Result<()> { + if let Some(repeat) = &spec.repeat { + if let Some((mut start, range)) = spec.start_and_range(self) { + while start < range.from() { + start = DateSpec::step(start, repeat)?; + } + while start <= range.until() { + let dates = spec.dates(start)?; + self.add(self.kind(), Some(dates)); + start = DateSpec::step(start, repeat)?; + } + } + } else { + let dates = spec.dates(spec.start)?; + self.add(self.kind(), Some(dates)); + } + Ok(()) } } diff --git a/src/eval/delta.rs b/src/eval/delta.rs index e7ab04d..6c63601 100644 --- a/src/eval/delta.rs +++ b/src/eval/delta.rs @@ -266,11 +266,20 @@ impl Delta { self.steps.iter().map(|step| step.value.upper_bound()).sum() } - pub fn apply(&self, start: (NaiveDate, Option