forked from janek/mostr
refactor: reformat tasks file
This commit is contained in:
parent
2400f7c45b
commit
adcd35967f
14
src/kinds.rs
14
src/kinds.rs
|
@ -62,7 +62,7 @@ pub struct EventTag {
|
||||||
pub(crate) fn match_event_tag(tag: &Tag) -> Option<EventTag> {
|
pub(crate) fn match_event_tag(tag: &Tag) -> Option<EventTag> {
|
||||||
let mut vec = tag.as_slice().into_iter();
|
let mut vec = tag.as_slice().into_iter();
|
||||||
if vec.next() == Some(&"e".to_string()) {
|
if vec.next() == Some(&"e".to_string()) {
|
||||||
if let Some(id) = vec.next().and_then(|v| EventId::parse(v).ok()) {
|
if let Some(id) = vec.next().and_then(|v| EventId::parse(v).ok()) {
|
||||||
vec.next();
|
vec.next();
|
||||||
return Some(EventTag { id, marker: vec.next().cloned() });
|
return Some(EventTag { id, marker: vec.next().cloned() });
|
||||||
}
|
}
|
||||||
|
@ -107,15 +107,15 @@ pub(crate) fn extract_tags(input: &str) -> (String, Vec<Tag>) {
|
||||||
if s.starts_with('*') {
|
if s.starts_with('*') {
|
||||||
if s.len() == 1 {
|
if s.len() == 1 {
|
||||||
prio = Some(HIGH_PRIO);
|
prio = Some(HIGH_PRIO);
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
return match s[1..].parse::<Prio>() {
|
return match s[1..].parse::<Prio>() {
|
||||||
Ok(num) => {
|
Ok(num) => {
|
||||||
prio = Some(num * (if s.len() > 2 { 1 } else { 10 }));
|
prio = Some(num * (if s.len() > 2 { 1 } else { 10 }));
|
||||||
false
|
false
|
||||||
},
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}).collect_vec();
|
}).collect_vec();
|
||||||
|
@ -136,9 +136,9 @@ pub fn to_hashtag(tag: &str) -> Tag {
|
||||||
|
|
||||||
fn format_tag(tag: &Tag) -> String {
|
fn format_tag(tag: &Tag) -> String {
|
||||||
if let Some(et) = match_event_tag(tag) {
|
if let Some(et) = match_event_tag(tag) {
|
||||||
return format!("{}: {:.8}",
|
return format!("{}: {:.8}",
|
||||||
et.marker.as_ref().map(|m| m.to_string()).unwrap_or(MARKER_PARENT.to_string()),
|
et.marker.as_ref().map(|m| m.to_string()).unwrap_or(MARKER_PARENT.to_string()),
|
||||||
et.id)
|
et.id);
|
||||||
}
|
}
|
||||||
match tag.as_standardized() {
|
match tag.as_standardized() {
|
||||||
Some(TagStandard::PublicKey {
|
Some(TagStandard::PublicKey {
|
||||||
|
|
179
src/tasks.rs
179
src/tasks.rs
|
@ -197,7 +197,10 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if elements > 0 {
|
if elements > 0 {
|
||||||
info!("Reprocessed {elements} updates with {issues} issues{}", self.sender.url.clone().map(|url| format!(" from {url}")).unwrap_or_default());
|
info!(
|
||||||
|
"Reprocessed {elements} updates with {issues} issues{}",
|
||||||
|
self.sender.url.as_ref().map(|url| format!(" from {url}")).unwrap_or_default()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,14 +272,24 @@ impl TasksRelay {
|
||||||
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 for that
|
||||||
// TODO alternate color with grey between days
|
// TODO alternate color with grey between days
|
||||||
full.push(format!("{} {}", format_timestamp_local(&event.created_at), new.as_ref().unwrap_or(&"---".to_string())));
|
full.push(format!(
|
||||||
|
"{} {}",
|
||||||
|
format_timestamp_local(&event.created_at),
|
||||||
|
new.as_ref().unwrap_or(&"---".to_string())
|
||||||
|
));
|
||||||
last = new;
|
last = new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO show history for active tags
|
// TODO show history for active tags
|
||||||
("Your Time-Tracking History:".to_string(), Box::from(full.into_iter()))
|
(
|
||||||
|
"Your Time-Tracking History:".to_string(),
|
||||||
|
Box::from(full.into_iter()),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
("You have nothing time-tracked yet".to_string(), Box::from(empty()))
|
(
|
||||||
|
"You have nothing time-tracked yet".to_string(),
|
||||||
|
Box::from(empty()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
|
@ -289,15 +302,21 @@ impl TasksRelay {
|
||||||
while let Some(((start, _), (end, _))) = iter.next() {
|
while let Some(((start, _), (end, _))) = iter.next() {
|
||||||
// Filter out intervals <2 mins
|
// Filter out intervals <2 mins
|
||||||
if start.as_u64() + 120 < end.as_u64() {
|
if start.as_u64() + 120 < end.as_u64() {
|
||||||
vec.push(format!("{} - {} by {}",
|
vec.push(format!(
|
||||||
format_timestamp_local(start),
|
"{} - {} by {}",
|
||||||
format_timestamp_relative_to(end, start),
|
format_timestamp_local(start),
|
||||||
self.get_username(key)))
|
format_timestamp_relative_to(end, start),
|
||||||
|
self.get_username(key)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iter.into_buffer()
|
iter.into_buffer().for_each(|(stamp, _)| {
|
||||||
.for_each(|(stamp, _)|
|
vec.push(format!(
|
||||||
vec.push(format!("{} started by {}", format_timestamp_local(stamp), self.get_username(key))));
|
"{} started by {}",
|
||||||
|
format_timestamp_local(stamp),
|
||||||
|
self.get_username(key)
|
||||||
|
))
|
||||||
|
});
|
||||||
vec
|
vec
|
||||||
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people
|
}).sorted_unstable(); // TODO sorting depends on timestamp format - needed to interleave different people
|
||||||
(
|
(
|
||||||
|
@ -321,7 +340,9 @@ impl TasksRelay {
|
||||||
|
|
||||||
let children = ChildIterator::from(&self, id).get_all();
|
let children = ChildIterator::from(&self, id).get_all();
|
||||||
for user in self.history.values() {
|
for user in self.history.values() {
|
||||||
total += Durations::from(user.values(), &children).sum::<Duration>().as_secs();
|
total += Durations::from(user.values(), &children)
|
||||||
|
.sum::<Duration>()
|
||||||
|
.as_secs();
|
||||||
}
|
}
|
||||||
total
|
total
|
||||||
}
|
}
|
||||||
|
@ -340,13 +361,7 @@ impl TasksRelay {
|
||||||
sum += prog;
|
sum += prog;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
Some(
|
Some(if count > 0 { sum / (count as f32) } else { 0.0 })
|
||||||
if count > 0 {
|
|
||||||
sum / (count as f32)
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -421,7 +436,8 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if new_depth > 0 {
|
if new_depth > 0 {
|
||||||
let mut children = self.resolve_tasks_rec(self.tasks.children_of(&task), sparse, new_depth);
|
let mut children =
|
||||||
|
self.resolve_tasks_rec(self.tasks.children_of(&task), sparse, new_depth);
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
if !sparse {
|
if !sparse {
|
||||||
children.push(task);
|
children.push(task);
|
||||||
|
@ -430,7 +446,8 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if self.filter(task) { vec![task] } else { vec![] };
|
return if self.filter(task) { vec![task] } else { vec![] };
|
||||||
}).collect_vec()
|
})
|
||||||
|
.collect_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the given function with each task referenced by this event with no or property marker.
|
/// Executes the given function with each task referenced by this event with no or property marker.
|
||||||
|
@ -477,7 +494,8 @@ impl TasksRelay {
|
||||||
sparse: bool,
|
sparse: bool,
|
||||||
) -> Vec<&Task> {
|
) -> Vec<&Task> {
|
||||||
let roots = self.tasks.children_for(position);
|
let roots = self.tasks.children_for(position);
|
||||||
let mut current = self.resolve_tasks_rec(roots, sparse, self.search_depth + self.view_depth);
|
let mut current =
|
||||||
|
self.resolve_tasks_rec(roots, sparse, self.search_depth + self.view_depth);
|
||||||
if current.is_empty() {
|
if current.is_empty() {
|
||||||
if !self.tags.is_empty() {
|
if !self.tags.is_empty() {
|
||||||
let mut children = self.tasks.children_for(position).peekable();
|
let mut children = self.tasks.children_for(position).peekable();
|
||||||
|
@ -512,6 +530,7 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is a relict for tests
|
// TODO this is a relict for tests
|
||||||
|
#[deprecated]
|
||||||
fn visible_tasks(&self) -> Vec<&Task> {
|
fn visible_tasks(&self) -> Vec<&Task> {
|
||||||
if self.search_depth == 0 {
|
if self.search_depth == 0 {
|
||||||
return vec![];
|
return vec![];
|
||||||
|
@ -546,8 +565,15 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"state" => {
|
"state" => {
|
||||||
if let Some(task) = task.get_dependendees().iter().filter_map(|id| self.get_by_id(id)).find(|t| t.pure_state().is_open()) {
|
if let Some(task) = task
|
||||||
return format!("Blocked by \"{}\"", task.get_title()).bright_red().to_string();
|
.get_dependendees()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|id| self.get_by_id(id))
|
||||||
|
.find(|t| t.pure_state().is_open())
|
||||||
|
{
|
||||||
|
return format!("Blocked by \"{}\"", task.get_title())
|
||||||
|
.bright_red()
|
||||||
|
.to_string();
|
||||||
}
|
}
|
||||||
let state = task.pure_state();
|
let state = task.pure_state();
|
||||||
if state.is_open() && progress.is_some_and(|p| p > 0.1) {
|
if state.is_open() && progress.is_some_and(|p| p > 0.1) {
|
||||||
|
@ -559,11 +585,16 @@ impl TasksRelay {
|
||||||
"progress" => prog_string.clone(),
|
"progress" => prog_string.clone(),
|
||||||
|
|
||||||
"author" | "creator" => format!("{:.6}", self.get_username(&task.event.pubkey)), // FIXME temporary until proper column alignment
|
"author" | "creator" => format!("{:.6}", self.get_username(&task.event.pubkey)), // FIXME temporary until proper column alignment
|
||||||
"prio" => self.traverse_up_from(Some(*task.get_id())).find_map(Task::priority_raw).map(|p| p.to_string()).unwrap_or_else(||
|
"prio" => self
|
||||||
if self.priority.is_some() {
|
.traverse_up_from(Some(task.event.id))
|
||||||
DEFAULT_PRIO.to_string().dimmed().to_string()
|
.find_map(Task::priority_raw)
|
||||||
} else {
|
.map(|p| p.to_string())
|
||||||
"".to_string()
|
.unwrap_or_else(|| {
|
||||||
|
if self.priority.is_some() {
|
||||||
|
DEFAULT_PRIO.to_string().dimmed().to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
"path" => self.get_task_path(Some(task.event.id)),
|
"path" => self.get_task_path(Some(task.event.id)),
|
||||||
"rpath" => self.relative_path(task.event.id),
|
"rpath" => self.relative_path(task.event.id),
|
||||||
|
@ -602,9 +633,11 @@ impl TasksRelay {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.sender.submit(
|
self.sender.submit(EventBuilder::new(
|
||||||
EventBuilder::new(Kind::Bookmarks, "mostr pins",
|
Kind::Bookmarks,
|
||||||
self.bookmarks.iter().map(|id| Tag::event(*id))))?;
|
"mostr pins",
|
||||||
|
self.bookmarks.iter().map(|id| Tag::event(*id)),
|
||||||
|
))?;
|
||||||
Ok(added)
|
Ok(added)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +697,10 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_hashtags(&self) {
|
pub(crate) fn print_hashtags(&self) {
|
||||||
println!("Hashtags of all known tasks:\n{}", self.all_hashtags().join(" ").italic());
|
println!(
|
||||||
|
"Hashtags of all known tasks:\n{}",
|
||||||
|
self.all_hashtags().join(" ").italic()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if tags have been updated, false if it printed something
|
/// Returns true if tags have been updated, false if it printed something
|
||||||
|
@ -698,7 +734,9 @@ impl TasksRelay {
|
||||||
pub(crate) fn remove_tag(&mut self, tag: &str) {
|
pub(crate) fn remove_tag(&mut self, tag: &str) {
|
||||||
self.view.clear();
|
self.view.clear();
|
||||||
let len = self.tags.len();
|
let len = self.tags.len();
|
||||||
self.tags.retain(|t| !t.content().is_some_and(|value| value.to_string().starts_with(tag)));
|
self.tags.retain(|t| {
|
||||||
|
!t.content().is_some_and(|value| value.to_string().starts_with(tag))
|
||||||
|
});
|
||||||
if self.tags.len() < len {
|
if self.tags.len() < len {
|
||||||
info!("Removed tag filters starting with {tag}");
|
info!("Removed tag filters starting with {tag}");
|
||||||
} else {
|
} else {
|
||||||
|
@ -762,7 +800,8 @@ impl TasksRelay {
|
||||||
for task in self.tasks.values() {
|
for task in self.tasks.values() {
|
||||||
if task.get_filter_title().to_ascii_lowercase() == lowercase_arg &&
|
if task.get_filter_title().to_ascii_lowercase() == lowercase_arg &&
|
||||||
// exclude closed tasks and their subtasks
|
// exclude closed tasks and their subtasks
|
||||||
!self.traverse_up_from(Some(*task.get_id())).any(|t| !t.pure_state().is_open()) {
|
!self.traverse_up_from(Some(*task.get_id())).any(|t| !t.pure_state().is_open())
|
||||||
|
{
|
||||||
return vec![task.event.id];
|
return vec![task.event.id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -815,9 +854,10 @@ impl TasksRelay {
|
||||||
|
|
||||||
/// Returns all recent events from history until the first event at or before the given timestamp.
|
/// Returns all recent events from history until the first event at or before the given timestamp.
|
||||||
fn history_from(&self, stamp: Timestamp) -> impl Iterator<Item=&Event> {
|
fn history_from(&self, stamp: Timestamp) -> impl Iterator<Item=&Event> {
|
||||||
self.history.get(&self.sender.pubkey()).map(|hist| {
|
self.history.get(&self.sender.pubkey())
|
||||||
hist.values().rev().take_while_inclusive(move |e| e.created_at > stamp)
|
.map(|hist| {
|
||||||
}).into_iter().flatten()
|
hist.values().rev().take_while_inclusive(move |e| e.created_at > stamp)
|
||||||
|
}).into_iter().flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_to(&mut self, target: Option<EventId>) {
|
pub(crate) fn move_to(&mut self, target: Option<EventId>) {
|
||||||
|
@ -838,13 +878,16 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = Timestamp::now();
|
let now = Timestamp::now();
|
||||||
let offset: u64 = self.history_from(now).skip_while(|e| e.created_at.as_u64() > now.as_u64() + MAX_OFFSET).count() as u64;
|
let offset: u64 = self
|
||||||
|
.history_from(now)
|
||||||
|
.skip_while(|e| e.created_at.as_u64() > now.as_u64() + MAX_OFFSET)
|
||||||
|
.count() as u64;
|
||||||
if offset >= MAX_OFFSET {
|
if offset >= MAX_OFFSET {
|
||||||
warn!("Whoa you are moving around quickly! Give me a few seconds to process.")
|
warn!("Whoa you are moving around quickly! Give me a few seconds to process.")
|
||||||
}
|
}
|
||||||
self.submit(
|
self.submit(
|
||||||
build_tracking(target)
|
build_tracking(target)
|
||||||
.custom_created_at(Timestamp::from(now.as_u64() + offset))
|
.custom_created_at(Timestamp::from(now.as_u64() + offset)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,9 +956,12 @@ impl TasksRelay {
|
||||||
self.move_up();
|
self.move_up();
|
||||||
self.make_task_with(
|
self.make_task_with(
|
||||||
input,
|
input,
|
||||||
self.get_position().map(|par| self.make_event_tag_from_id(par, MARKER_PARENT))
|
self.get_position()
|
||||||
.into_iter().chain(once(self.make_event_tag_from_id(pos, MARKER_DEPENDS))),
|
.map(|par| self.make_event_tag_from_id(par, MARKER_PARENT))
|
||||||
true);
|
.into_iter()
|
||||||
|
.chain(once(self.make_event_tag_from_id(pos, MARKER_DEPENDS))),
|
||||||
|
true,
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -944,7 +990,7 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_task_title(&self, id: &EventId) -> String {
|
pub(crate) fn get_task_title(&self, id: &EventId) -> String {
|
||||||
self.tasks.get(id).map_or(id.to_string(), |t| t.get_title())
|
self.get_by_id(id).map_or(id.to_string(), |t| t.get_title())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse relative time string and track for current position
|
/// Parse relative time string and track for current position
|
||||||
|
@ -956,7 +1002,11 @@ impl TasksRelay {
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn track_at(&mut self, mut time: Timestamp, target: Option<EventId>) -> Option<EventId> {
|
pub(crate) fn track_at(
|
||||||
|
&mut self,
|
||||||
|
mut time: Timestamp,
|
||||||
|
target: Option<EventId>,
|
||||||
|
) -> Option<EventId> {
|
||||||
if target.is_none() {
|
if target.is_none() {
|
||||||
// Prevent random overlap with tracking started in the same second
|
// Prevent random overlap with tracking started in the same second
|
||||||
time = time - 1;
|
time = time - 1;
|
||||||
|
@ -1012,11 +1062,10 @@ impl TasksRelay {
|
||||||
pub(crate) fn add(&mut self, event: Event) {
|
pub(crate) fn add(&mut self, event: Event) {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
Kind::GitIssue => self.add_task(event),
|
Kind::GitIssue => self.add_task(event),
|
||||||
Kind::Metadata =>
|
Kind::Metadata => match Metadata::from_json(event.content.as_str()) {
|
||||||
match Metadata::from_json(event.content.as_str()) {
|
Ok(metadata) => { self.users.insert(event.pubkey, metadata); }
|
||||||
Ok(metadata) => { self.users.insert(event.pubkey, metadata); }
|
Err(e) => warn!("Cannot parse metadata: {} from {:?}", e, event),
|
||||||
Err(e) => warn!("Cannot parse metadata: {} from {:?}", e, event)
|
},
|
||||||
}
|
|
||||||
Kind::Bookmarks => {
|
Kind::Bookmarks => {
|
||||||
if event.pubkey == self.sender.pubkey() {
|
if event.pubkey == self.sender.pubkey() {
|
||||||
self.bookmarks = referenced_events(&event).collect_vec()
|
self.bookmarks = referenced_events(&event).collect_vec()
|
||||||
|
@ -1073,7 +1122,9 @@ 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()).into_iter().flat_map(|t| t.values())
|
self.history.get(&self.sender.pubkey())
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|t| t.values())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn history_before_now(&self) -> impl Iterator<Item=&Event> {
|
fn history_before_now(&self) -> impl Iterator<Item=&Event> {
|
||||||
|
@ -1098,7 +1149,9 @@ impl TasksRelay {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_back_by(&mut self, steps: usize) {
|
pub(crate) fn move_back_by(&mut self, steps: usize) {
|
||||||
let id = self.history_before_now().nth(steps)
|
let id = self
|
||||||
|
.history_before_now()
|
||||||
|
.nth(steps)
|
||||||
.and_then(|e| referenced_event(e));
|
.and_then(|e| referenced_event(e));
|
||||||
self.move_to(id)
|
self.move_to(id)
|
||||||
}
|
}
|
||||||
|
@ -1336,7 +1389,10 @@ impl Display for TasksRelay {
|
||||||
total_time += self.total_time_tracked(task.event.id) // TODO include parent if it matches
|
total_time += self.total_time_tracked(task.event.id) // TODO include parent if it matches
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(lock, "{} visible tasks{}", count, display_time(" tracked a total of HHhMMm", total_time))?;
|
writeln!(lock,
|
||||||
|
"{count} visible tasks{}",
|
||||||
|
display_time(" tracked a total of HHhMMm", total_time)
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1389,7 +1445,7 @@ fn display_time(format: &str, secs: u64) -> String {
|
||||||
.map_or(String::new(), |mins| format
|
.map_or(String::new(), |mins| format
|
||||||
.replace("MMM", &format!("{:3}", mins))
|
.replace("MMM", &format!("{:3}", mins))
|
||||||
.replace("HH", &format!("{:02}", mins.div(60)))
|
.replace("HH", &format!("{:02}", mins.div(60)))
|
||||||
.replace("MM", &format!("{:02}", mins.rem(60))),
|
.replace("MM", &format!("{:02}", mins.rem(60)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1402,8 +1458,7 @@ pub(crate) fn join_tasks<'a>(
|
||||||
.iter()
|
.iter()
|
||||||
.map(|t| t.get_title())
|
.map(|t| t.get_title())
|
||||||
.chain(if include_last_id {
|
.chain(if include_last_id {
|
||||||
tasks
|
tasks.last()
|
||||||
.last()
|
|
||||||
.and_then(|t| t.parent_id())
|
.and_then(|t| t.parent_id())
|
||||||
.map(|id| id.to_string())
|
.map(|id| id.to_string())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1411,7 +1466,10 @@ pub(crate) fn join_tasks<'a>(
|
||||||
None.into_iter()
|
None.into_iter()
|
||||||
})
|
})
|
||||||
.fold(None, |acc, val| {
|
.fold(None, |acc, val| {
|
||||||
Some(acc.map_or_else(|| val.clone(), |cur| format!("{}{}{}", val, ">".dimmed(), cur)))
|
Some(acc.map_or_else(
|
||||||
|
|| val.clone(),
|
||||||
|
|cur| format!("{}{}{}", val, ">".dimmed(), cur),
|
||||||
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1477,7 +1535,8 @@ impl Iterator for Durations<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let now = self.threshold.unwrap_or(Timestamp::now()).as_u64();
|
let now = self.threshold.unwrap_or(Timestamp::now()).as_u64();
|
||||||
start.filter(|t| t < &now).map(|stamp| Duration::from_secs(now.saturating_sub(stamp)))
|
start.filter(|t| t < &now)
|
||||||
|
.map(|stamp| Duration::from_secs(now.saturating_sub(stamp)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1635,7 +1694,6 @@ impl<'a> Iterator for ChildIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ParentIterator<'a> {
|
struct ParentIterator<'a> {
|
||||||
tasks: &'a TaskMap,
|
tasks: &'a TaskMap,
|
||||||
current: Option<EventId>,
|
current: Option<EventId>,
|
||||||
|
@ -1653,9 +1711,8 @@ impl<'a> Iterator for ParentIterator<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tasks_test {
|
mod tasks_test {
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
fn stub_tasks() -> TasksRelay {
|
fn stub_tasks() -> TasksRelay {
|
||||||
use nostr_sdk::Keys;
|
use nostr_sdk::Keys;
|
||||||
|
|
Loading…
Reference in New Issue