diff --git a/src/eval.rs b/src/eval.rs index 78c21a0..3f12526 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -60,7 +60,7 @@ impl Eval { title: task.title.clone(), desc: task.desc.clone(), source: self.source, - date: done.date, + root: done.date, }; self.map.insert(entry); } @@ -109,7 +109,7 @@ impl Eval { title: task.title.clone(), desc: task.desc.clone(), source: self.source, - date: None, + root: None, }); } else { let last_done = Self::determine_last_done(task); @@ -130,7 +130,7 @@ impl Eval { title: task.title.clone(), desc: task.desc.clone(), source, - date, + root: date, })?; } } @@ -162,7 +162,7 @@ impl Eval { title: note.title.clone(), desc: note.desc.clone(), source: self.source, - date: None, + root: None, }); } else { if let Some(range) = self.determine_note_range(note) { @@ -181,7 +181,7 @@ impl Eval { title: note.title.clone(), desc: note.desc.clone(), source, - date, + root: date, })?; } } @@ -207,7 +207,7 @@ impl Eval { title: title.clone(), desc: birthday.desc.clone(), source: self.source, - date: Some(DoneDate::Date { root: date }), + root: Some(DoneDate::Date { root: date }), }; self.map.insert(entry); } else { @@ -220,7 +220,7 @@ impl Eval { title: format!("{} (first half)", title), desc: birthday.desc.clone(), source: self.source, - date: Some(DoneDate::Date { root: date }), + root: Some(DoneDate::Date { root: date }), }; self.map.insert(entry); @@ -230,7 +230,7 @@ impl Eval { title: format!("{} (second half)", title), desc: birthday.desc.clone(), source: self.source, - date: Some(DoneDate::Date { root: date }), + root: Some(DoneDate::Date { root: date }), }; self.map.insert(entry); } diff --git a/src/eval/entry.rs b/src/eval/entry.rs index 98f8fb9..f08c566 100644 --- a/src/eval/entry.rs +++ b/src/eval/entry.rs @@ -22,7 +22,95 @@ pub struct Entry { pub desc: Vec, pub source: Source, - pub date: Option, + pub root: Option, +} + +/// Mode that determines how entries are filtered when they are added to +/// an [`Entries`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EntryMode { + /// The entry's root date must be contained in the range. + Rooted, + /// The entry must overlap the range. + Touching, + /// The entry must be in some way relevant to the range. It may + /// - touch the range, + /// - be an unfinished task that lies before the range, + /// - be a finished task that was completed inside the range, or + /// - have no root date. + Relevant, +} + +pub struct Entries { + mode: EntryMode, + range: DateRange, + entries: Vec, +} + +impl Entries { + pub fn new(mode: EntryMode, range: DateRange) -> Self { + Self { + mode, + range, + entries: vec![], + } + } + + fn is_rooted(&self, entry: &Entry) -> bool { + match entry.root { + Some(date) => self.range.contains(date.root()), + None => false, + } + } + + fn is_touching(&self, entry: &Entry) -> bool { + if let Some(date) = entry.root { + // Inside the range or overlapping it + date.first() <= self.range.until() && self.range.from() <= date.last() + } else { + false + } + } + + fn is_relevant(&self, entry: &Entry) -> bool { + if entry.root.is_none() { + return true; + } + + // Anything close to the range + if self.is_touching(entry) { + return true; + } + + // Tasks that were finished inside the range + if let EntryKind::TaskDone(done) = entry.kind { + if self.range.contains(done) { + return true; + } + } + + // Unfinished tasks before or inside the range + if let EntryKind::Task = entry.kind { + if let Some(date) = entry.root { + if date.first() <= self.range.until() { + return true; + } + } + } + + return false; + } + + pub fn add(&mut self, entry: Entry) { + let keep = match self.mode { + EntryMode::Rooted => self.is_rooted(&entry), + EntryMode::Touching => self.is_touching(&entry), + EntryMode::Relevant => self.is_relevant(&entry), + }; + if keep { + self.entries.push(entry); + } + } } pub struct EntryMap { @@ -47,7 +135,7 @@ impl EntryMap { } pub fn insert(&mut self, entry: Entry) { - if let Some(date) = entry.date { + if let Some(date) = entry.root { let date = date.root(); if self.range.contains(date) { self.map.entry(date).or_insert(Some(entry)); diff --git a/src/files/commands.rs b/src/files/commands.rs index 42ac4a1..dc9d49a 100644 --- a/src/files/commands.rs +++ b/src/files/commands.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{cmp, fmt}; use chrono::NaiveDate; @@ -372,6 +372,29 @@ impl DoneDate { DoneDate::DateToDateWithTime { root, .. } => *root, } } + + pub fn other(&self) -> Option { + match self { + DoneDate::Date { .. } => None, + DoneDate::DateWithTime { .. } => None, + DoneDate::DateToDate { other, .. } => Some(*other), + DoneDate::DateToDateWithTime { other, .. } => Some(*other), + } + } + + pub fn first(&self) -> NaiveDate { + match self.other() { + None => self.root(), + Some(other) => cmp::min(self.root(), other), + } + } + + pub fn last(&self) -> NaiveDate { + match self.other() { + None => self.root(), + Some(other) => cmp::max(self.root(), other), + } + } } #[derive(Debug)]