feat: guidance for moving backward
This commit is contained in:
parent
78438696ac
commit
87392fccb6
26
src/main.rs
26
src/main.rs
|
@ -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 {
|
||||||
|
|
64
src/tasks.rs
64
src/tasks.rs
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue