forked from janek/mostr
1
0
Fork 0

feat(task): extract tags from state updates

This commit is contained in:
xeruf 2024-11-13 11:12:08 +01:00
parent 2cec689bf1
commit 6b8bf29b20
3 changed files with 21 additions and 12 deletions

View File

@ -113,7 +113,7 @@ pub(crate) fn extract_tags(input: &str) -> (String, Vec<Tag>) {
(main, tags) (main, tags)
} }
fn to_hashtag(tag: &str) -> Tag { pub fn to_hashtag(tag: &str) -> Tag {
TagStandard::Hashtag(tag.to_string()).into() TagStandard::Hashtag(tag.to_string()).into()
} }

View File

@ -14,6 +14,7 @@ use nostr_sdk::{Alphabet, Event, EventId, Kind, Tag, TagStandard, Timestamp};
use crate::helpers::{format_timestamp_local, some_non_empty}; use crate::helpers::{format_timestamp_local, some_non_empty};
use crate::kinds::{is_hashtag, Prio, PRIO, PROCEDURE_KIND, PROCEDURE_KIND_ID, TASK_KIND}; use crate::kinds::{is_hashtag, Prio, PRIO, PROCEDURE_KIND, PROCEDURE_KIND_ID, TASK_KIND};
use crate::tasks::now;
pub static MARKER_PARENT: &str = "parent"; pub static MARKER_PARENT: &str = "parent";
pub static MARKER_DEPENDS: &str = "depends"; pub static MARKER_DEPENDS: &str = "depends";
@ -137,7 +138,7 @@ impl Task {
} }
pub(crate) fn state(&self) -> Option<TaskState> { pub(crate) fn state(&self) -> Option<TaskState> {
let now = Timestamp::now(); let now = now();
// TODO do not iterate constructed state objects // TODO do not iterate constructed state objects
let state = self.states().rev().take_while_inclusive(|ts| ts.time > now); let state = self.states().rev().take_while_inclusive(|ts| ts.time > now);
state.last().map(|ts| { state.last().map(|ts| {
@ -177,9 +178,10 @@ impl Task {
} }
fn tags(&self) -> impl Iterator<Item=&Tag> { fn tags(&self) -> impl Iterator<Item=&Tag> {
self.tags.iter().flatten().chain(
self.props.iter().flat_map(|e| e.tags.iter() self.props.iter().flat_map(|e| e.tags.iter()
.filter(|t| t.single_letter_tag().is_none_or(|s| s.character != Alphabet::E))) .filter(|t| t.single_letter_tag().is_none_or(|s| s.character != Alphabet::E)))
.chain(self.tags.iter().flatten()) )
} }
fn join_tags<P>(&self, predicate: P) -> String fn join_tags<P>(&self, predicate: P) -> String
@ -200,7 +202,7 @@ impl Task {
"id" => Some(self.event.id.to_string()), "id" => Some(self.event.id.to_string()),
"parentid" => self.parent_id().map(|i| i.to_string()), "parentid" => self.parent_id().map(|i| i.to_string()),
"name" => Some(self.event.content.clone()), "name" => Some(self.event.content.clone()),
"pubkey" => Some(self.event.pubkey.to_string()), "key" | "pubkey" => Some(self.event.pubkey.to_string()),
"created" => Some(format_timestamp_local(&self.event.created_at)), "created" => Some(format_timestamp_local(&self.event.created_at)),
"kind" => Some(self.event.kind.to_string()), "kind" => Some(self.event.kind.to_string()),
// Dynamic // Dynamic
@ -209,7 +211,7 @@ impl Task {
"desc" => self.descriptions().last().cloned(), "desc" => self.descriptions().last().cloned(),
"description" => Some(self.descriptions().join(" ")), "description" => Some(self.descriptions().join(" ")),
"hashtags" => Some(self.join_tags(|tag| { is_hashtag(tag) })), "hashtags" => Some(self.join_tags(|tag| { is_hashtag(tag) })),
"tags" => Some(self.join_tags(|_| true)), "tags" => Some(self.join_tags(|_| true)), // TODO test these!
"alltags" => Some(format!("{:?}", self.tags)), "alltags" => Some(format!("{:?}", self.tags)),
"refs" => Some(format!("{:?}", self.refs.iter().map(|re| format!("{}: {}", re.0, re.1)).collect_vec())), "refs" => Some(format!("{:?}", self.refs.iter().map(|re| format!("{}: {}", re.0, re.1)).collect_vec())),
"props" => Some(format!( "props" => Some(format!(

View File

@ -1646,14 +1646,21 @@ mod tasks_test {
#[test] #[test]
fn test_recursive_closing() { fn test_recursive_closing() {
let mut tasks = stub_tasks(); let mut tasks = stub_tasks();
tasks.custom_time = Some(Timestamp::zero());
let parent = tasks.make_task("parent #tag1"); let parent = tasks.make_task("parent #tag1");
tasks.move_to(Some(parent)); tasks.move_to(Some(parent));
let sub = tasks.make_task("sub # tag2"); let sub = tasks.make_task("sub #oi # tag2");
assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2"]); assert_eq!(tasks.all_hashtags().collect_vec(), vec!["oi", "tag1", "tag2"]);
tasks.make_note("note with #tag3 # yeah"); tasks.make_note("note with #tag3 # yeah");
assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2", "tag3", "yeah"]); assert_eq!(tasks.all_hashtags().collect_vec(), vec!["oi", "tag1", "tag2", "tag3", "yeah"]);
tasks.update_state("Done #yei", State::Done);
// TODO assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2", "tag3", "yeah", "yei"]); tasks.custom_time = Some(Timestamp::now());
tasks.update_state("Finished #yeah # oi", State::Done);
assert_eq!(tasks.get_by_id(&parent).unwrap().get_hashtags().cloned().collect_vec(), ["tag1", "tag3", "yeah", "oi", "yeah"].map(to_hashtag));
assert_eq!(tasks.all_hashtags().collect_vec(), vec!["oi", "tag1", "tag2", "tag3", "yeah"]);
tasks.custom_time = Some(now());
tasks.update_state("Closing Down", State::Closed); tasks.update_state("Closing Down", State::Closed);
assert_eq!(tasks.get_by_id(&sub).unwrap().pure_state(), State::Closed); assert_eq!(tasks.get_by_id(&sub).unwrap().pure_state(), State::Closed);
assert_eq!(tasks.all_hashtags().next(), None); assert_eq!(tasks.all_hashtags().next(), None);