diff --git a/src/main.rs b/src/main.rs index 8277b59..15ade0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -631,32 +631,17 @@ async fn main() -> Result<()> { Err(e) => warn!("Ignoring extra {:?}: {}\nSyntax: ((INT", remaining, e), } } - let (label, times) = tasks.times_tracked(); - let vec = times.rev().take(max).collect_vec(); - println!("{}\n{}", - if vec.is_empty() { - label - } else { - format!("{} {}", - if max == usize::MAX { "All".to_string() } else { format!("Latest {max} entries of") }, - label) - }.italic(), - vec.iter().rev().join("\n")); + println!("{}", tasks.times_tracked(max)); } else if let Some((key, _)) = tasks.find_user(arg) { let (label, mut times) = tasks.times_tracked_for(&key); - println!("{}\n{}", label.italic(), - times.join("\n")); + println!("{}\n{}", label.italic(), times.join("\n")); } else { if tasks.track_from(arg) { - let (label, times) = tasks.times_tracked(); - println!("{}\n{}", label.italic(), - times.rev().take(15).collect_vec().iter().rev().join("\n")); + println!("{}", tasks.times_tracked(15)); } } } else { - let (label, times) = tasks.times_tracked(); - println!("{}\n{}", label.italic(), - times.rev().take(80).collect_vec().iter().rev().join("\n")); + println!("{}", tasks.times_tracked(60)); } continue 'repl; } @@ -666,9 +651,7 @@ async fn main() -> Result<()> { None => tasks.move_to(None), Some(arg) => { if parse_tracking_stamp(arg).and_then(|stamp| tasks.track_at(stamp, None)).is_some() { - let (label, times) = tasks.times_tracked(); - println!("{}\n{}", label.italic(), - times.rev().take(15).collect_vec().iter().rev().join("\n")); + println!("{}", tasks.times_tracked(15)); } // So the error message is not covered up continue 'repl; diff --git a/src/tasks.rs b/src/tasks.rs index 8c30dc4..6c8c893 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -269,8 +269,20 @@ impl TasksRelay { } /// Dynamic time tracking overview for current task or current user. - pub(crate) fn times_tracked(&self) -> (String, Box + '_>) { - self.times_tracked_with(&self.sender.pubkey()) + pub(crate) fn times_tracked(&self, limit: usize) -> String { + let (label, times) = self.times_tracked_with(&self.sender.pubkey()); + let times = times.collect_vec(); + format!("{}\n{}", + if times.is_empty() { + label + } else { + format!("{}{}", + if limit > times.len() || limit == usize::MAX { "All ".to_string() } + else if limit < 20 { "Recent ".to_string() } + else { format!("Latest {limit} Entries of ") }, + label) + }.italic(), + ×[times.len().saturating_sub(limit)..].join("\n")) } pub(crate) fn history_for( @@ -318,6 +330,8 @@ impl TasksRelay { } } + /// Time tracked for current position or key + /// Note: reversing the iterator skips most recent timetracking stops pub(crate) fn times_tracked_with( &self, key: &PublicKey, @@ -1454,10 +1468,7 @@ impl Display for TasksRelay { if self.tasks.children_for(self.get_position()).next().is_some() { writeln!(lock, "No tasks here matching{}", self.get_prompt_suffix())?; } - let (label, times) = self.times_tracked(); - let mut times_recent = times.rev().take(6).collect_vec(); - times_recent.reverse(); - writeln!(lock, "{}\n{}", format!("Recent {}", label).italic(), times_recent.join("\n"))?; + writeln!(lock, "{}", self.times_tracked(6))?; return Ok(()); } diff --git a/src/tasks/tests.rs b/src/tasks/tests.rs index c60b69c..9633e68 100644 --- a/src/tasks/tests.rs +++ b/src/tasks/tests.rs @@ -281,6 +281,20 @@ fn test_filter_or_create() { assert_eq!(tasks.len(), 3); } +#[test] +fn test_history() { + let mut tasks = stub_tasks(); + let zero = EventId::all_zeros(); + + tasks.track_at(Timestamp::now() - 3, Some(zero)); + tasks.move_to(None); + assert_eq!(tasks.times_tracked(1).len(), 121); + let all = tasks.times_tracked(10); + assert_eq!(all.len(), 202, "{}", all); + assert!(all.contains(" 0000000000000000000000000000000000000000000000000000000000000000"), "{}", all); + assert!(all.ends_with(" ---"), "{}", all); +} + #[test] fn test_tracking() { let mut tasks = stub_tasks();