From ca50bdf3bb2d809518fcd6b8c3b98cd7ec7a9b35 Mon Sep 17 00:00:00 2001 From: xeruf <27jf@pm.me> Date: Wed, 20 Nov 2024 19:34:40 +0100 Subject: [PATCH] feat: enhance display of task history --- src/helpers.rs | 5 +++++ src/kinds.rs | 10 +++++++--- src/main.rs | 35 ++++++++++++++++++++++------------- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ec66b58..a640af4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -146,6 +146,11 @@ pub fn format_timestamp_local(stamp: &Timestamp) -> String { format_timestamp(stamp, "%y-%m-%d %a %H:%M") } +/// Format nostr timestamp with seconds precision. +pub fn format_timestamp_full(stamp: &Timestamp) -> String { + format_timestamp(stamp, "%y-%m-%d %a %H:%M:%S") +} + pub fn format_timestamp_relative_to(stamp: &Timestamp, reference: &Timestamp) -> String { // Rough difference in days match (stamp.as_u64() as i64 - reference.as_u64() as i64) / 80_000 { diff --git a/src/kinds.rs b/src/kinds.rs index b34e8a4..2c611df 100644 --- a/src/kinds.rs +++ b/src/kinds.rs @@ -132,12 +132,16 @@ pub fn to_hashtag(tag: &str) -> Tag { TagStandard::Hashtag(tag.to_string()).into() } -fn format_tag(tag: &Tag) -> String { +pub fn format_tag(tag: &Tag) -> String { if let Some(et) = match_event_tag(tag) { return format!("{}: {:.8}", et.marker.as_ref().map(|m| m.to_string()).unwrap_or(MARKER_PARENT.to_string()), et.id); } + format_tag_basic(tag) +} + +pub fn format_tag_basic(tag: &Tag) -> String { match tag.as_standardized() { Some(TagStandard::PublicKey { public_key, @@ -150,12 +154,12 @@ fn format_tag(tag: &Tag) -> String { } } -pub(crate) fn is_hashtag(tag: &Tag) -> bool { +pub fn is_hashtag(tag: &Tag) -> bool { tag.single_letter_tag() .is_some_and(|letter| letter.character == Alphabet::T) } -pub(crate) fn to_prio_tag(value: Prio) -> Tag { +pub fn to_prio_tag(value: Prio) -> Tag { Tag::custom(TagKind::Custom(Cow::from(PRIO)), [value.to_string()]) } diff --git a/src/main.rs b/src/main.rs index b9d3b76..1da7667 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use std::time::Duration; use crate::event_sender::MostrMessage; use crate::helpers::*; -use crate::kinds::{join_tags, 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::tasks::{PropertyCollection, StateFilter, TasksRelay}; use chrono::Local; @@ -385,20 +385,29 @@ async fn main() -> Result<()> { match arg { None => { if let Some(task) = tasks.get_current_task() { + println!("Change History:"); for e in once(&task.event).chain(task.props.iter().rev()) { - let content = match State::try_from(e.kind) { - Ok(state) => { - format!("State: {state}{}", - if e.content.is_empty() { String::new() } else { format!(" - {}", e.content) }) - } - Err(_) => { - e.content.to_string() - } - }; println!("{} {} [{}]", - format_timestamp_local(&e.created_at), - content, - join_tags(e.tags.iter().filter(|t| match_event_tag(t).is_some_and(|e| e.marker.as_ref().is_none_or(|m| m != MARKER_PROPERTY))))); + format_timestamp_full(&e.created_at), + match State::try_from(e.kind) { + Ok(state) => { + format!("State: {state}{}", + if e.content.is_empty() { String::new() } else { format!(" - {}", e.content) }) + } + Err(_) => { + e.content.to_string() + } + }, + e.tags.iter().filter_map(|t| { + match match_event_tag(t) { + Some(et) => + Some(et).take_if(|et| et.marker.as_ref().is_some_and(|m| m != MARKER_PROPERTY)) + .map(|et| format!("{}: {}", et.marker.as_ref().unwrap(), tasks.get_relative_path(et.id))), + None => + Some(format_tag_basic(t)), + } + }).join(", ") + ) } continue 'repl; } else {