feat: guidance for moving backward

This commit is contained in:
xeruf 2024-11-25 01:45:18 +01:00
parent 78438696ac
commit 87392fccb6
2 changed files with 89 additions and 51 deletions

View File

@ -12,7 +12,7 @@ use crate::event_sender::MostrMessage;
use crate::helpers::*; use crate::helpers::*;
use crate::kinds::{format_tag_basic, match_event_tag, Prio, BASIC_KINDS, PROPERTY_COLUMNS, PROP_KINDS}; use crate::kinds::{format_tag_basic, match_event_tag, Prio, BASIC_KINDS, PROPERTY_COLUMNS, PROP_KINDS};
use crate::task::{State, Task, TaskState, MARKER_PROPERTY}; use crate::task::{State, Task, TaskState, MARKER_PROPERTY};
use crate::tasks::{PropertyCollection, StateFilter, TasksRelay}; use crate::tasks::{referenced_event, PropertyCollection, StateFilter, TasksRelay};
use chrono::Local; use chrono::Local;
use colored::Colorize; use colored::Colorize;
use directories::ProjectDirs; use directories::ProjectDirs;
@ -438,7 +438,28 @@ async fn main() -> Result<()> {
Some('&') => { Some('&') => {
match arg { match arg {
None => tasks.undo(), None => tasks.undo(),
Some(text) => match text.parse::<u8>() { Some(text) => {
if text == "&" {
println!(
"My History:\n{}",
tasks.history_before_now()
.take(9)
.enumerate()
.dropping(1)
.map(|(c, e)| {
format!("({}) {}",
c,
match referenced_event(e) {
Some(target) => tasks.get_task_path(Some(target)),
None => "---".to_string(),
},
)
})
.join("\n")
);
continue 'repl;
}
match text.parse::<u8>() {
Ok(int) => { Ok(int) => {
tasks.move_back_by(int as usize); tasks.move_back_by(int as usize);
} }
@ -451,6 +472,7 @@ async fn main() -> Result<()> {
} }
} }
} }
}
Some('@') => { Some('@') => {
match arg { match arg {

View File

@ -256,41 +256,50 @@ impl TasksRelay {
} }
/// Dynamic time tracking overview for current task or current user. /// Dynamic time tracking overview for current task or current user.
pub(crate) fn times_tracked(&self) -> (String, Box<dyn DoubleEndedIterator<Item=String>>) { pub(crate) fn times_tracked(&self) -> (String, Box<dyn DoubleEndedIterator<Item=String> + '_>) {
self.times_tracked_for(&self.sender.pubkey()) self.times_tracked_for(&self.sender.pubkey())
} }
pub(crate) fn times_tracked_for( pub(crate) fn history_for(
&self, &self,
key: &PublicKey, key: &PublicKey,
) -> (String, Box<dyn DoubleEndedIterator<Item=String>>) { ) -> Option<impl DoubleEndedIterator<Item=String> + '_> {
match self.get_position() { self.history.get(key).map(|hist| {
None => {
if let Some(hist) = self.history.get(key) {
let mut last = None; let mut last = None;
let mut full = Vec::with_capacity(hist.len()); // TODO limit history to active tags
for event in hist.values() { hist.values().filter_map(move |event| {
let new = some_non_empty(&event.tags.iter() let new = some_non_empty(&event.tags.iter()
.filter_map(|t| t.content()) .filter_map(|t| t.content())
.map(|str| EventId::from_str(str).ok().map_or(str.to_string(), |id| self.get_task_path(Some(id)))) .map(|str| EventId::from_str(str).ok().map_or(str.to_string(), |id| self.get_task_path(Some(id))))
.join(" ")); .join(" "));
if new != last { if new != last {
// TODO omit intervals <2min - but I think I need threeway for that // TODO omit intervals <2min - but I think I need threeway variable tracking for that
// TODO alternate color with grey between days // TODO alternate color with grey between days
full.push(format!( last = new;
return Some(format!(
"{} {}", "{} {}",
format_timestamp_local(&event.created_at), format_timestamp_local(&event.created_at),
new.as_ref().unwrap_or(&"---".to_string()) last.as_ref().unwrap_or(&"---".to_string())
)); ));
last = new;
} }
None
})
})
} }
// TODO show history for active tags
pub(crate) fn times_tracked_for(
&self,
key: &PublicKey,
) -> (String, Box<dyn DoubleEndedIterator<Item=String> + '_>) {
match self.get_position() {
None => {
match self.history_for(key) {
Some(hist) =>
( (
format!("Time-Tracking History for {}:", self.users.get_displayname(&key)), format!("Time-Tracking History for {}:", self.users.get_displayname(&key)),
Box::from(full.into_iter()), Box::from(hist),
) ),
} else { None =>
( (
"Nothing time-tracked yet".to_string(), "Nothing time-tracked yet".to_string(),
Box::from(empty()), Box::from(empty()),
@ -300,7 +309,7 @@ impl TasksRelay {
Some(id) => { Some(id) => {
// TODO show current recursive with pubkey // TODO show current recursive with pubkey
let ids = [id]; let ids = [id];
let history = let mut history =
self.history.iter().flat_map(|(key, set)| { self.history.iter().flat_map(|(key, set)| {
let mut vec = Vec::with_capacity(set.len() / 2); let mut vec = Vec::with_capacity(set.len() / 2);
let mut iter = timestamps(set.values(), &ids).tuples(); let mut iter = timestamps(set.values(), &ids).tuples();
@ -323,10 +332,13 @@ impl TasksRelay {
)) ))
}); });
vec vec
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people })
.collect_vec();
// TODO sorting depends on timestamp format - needed to interleave different people
history.sort_unstable();
( (
format!("Times Tracked on {:?}", self.get_task_title(&id)), format!("Times Tracked on {:?}", self.get_task_title(&id)),
Box::from(history), Box::from(history.into_iter()),
) )
} }
} }
@ -1200,21 +1212,25 @@ impl TasksRelay {
} }
fn get_own_events_history(&self) -> impl DoubleEndedIterator<Item=&Event> + '_ { fn get_own_events_history(&self) -> impl DoubleEndedIterator<Item=&Event> + '_ {
self.history.get(&self.sender.pubkey()) self.get_own_history()
.into_iter() .into_iter()
.flat_map(|t| t.values()) .flat_map(|t| t.values())
} }
fn history_before_now(&self) -> impl Iterator<Item=&Event> { pub(super) fn history_before_now(&self) -> impl Iterator<Item=&Event> {
self.get_own_history().into_iter().flat_map(|hist| { self.get_own_history().into_iter().flat_map(|hist| {
let now = now(); let now = now();
hist.values().rev().skip_while(move |e| e.created_at > now) hist.values().rev()
.skip_while(move |e| e.created_at > now)
.dedup_by(|e1, e2| e1.id == e2.id)
}) })
} }
pub(crate) fn move_back_to(&mut self, str: &str) -> bool { pub(crate) fn move_back_to(&mut self, str: &str) -> bool {
let lower = str.to_ascii_lowercase(); let lower = str.to_ascii_lowercase();
let found = self.history_before_now().find(|e| { let found =
self.history_before_now()
.find(|e| {
referenced_event(e) referenced_event(e)
.and_then(|id| self.get_by_id(&id)) .and_then(|id| self.get_by_id(&id))
.is_some_and(|t| t.event.content.to_ascii_lowercase().contains(&lower)) .is_some_and(|t| t.event.content.to_ascii_lowercase().contains(&lower))
@ -1506,7 +1522,7 @@ fn referenced_events(event: &Event) -> impl Iterator<Item=EventId> + '_ {
event.tags.iter().filter_map(|tag| match_event_tag(tag).map(|t| t.id)) event.tags.iter().filter_map(|tag| match_event_tag(tag).map(|t| t.id))
} }
fn referenced_event(event: &Event) -> Option<EventId> { pub fn referenced_event(event: &Event) -> Option<EventId> {
referenced_events(event).next() referenced_events(event).next()
} }