From ddb68f7107725e265ff223758510b2395d9676da Mon Sep 17 00:00:00 2001 From: xeruf <27jf@pm.me> Date: Sat, 14 Sep 2024 15:53:27 +0300 Subject: [PATCH] feat: recognize hashtags in task name --- README.md | 3 --- src/kinds.rs | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3aecf29..6a31a4a 100644 --- a/README.md +++ b/README.md @@ -166,9 +166,6 @@ Considering to use Calendar: https://github.com/nostr-protocol/nips/blob/master/ - Remove status filter when moving up? - Task markdown support? - colored - Time tracking: Ability to postpone task and add planned timestamps (calendar entry) -- Parse Hashtag tags from task name -- Unified Filter object - -> include subtasks of matched tasks - Speedup: Offline caching & Expiry (no need to fetch potential years of history) + Fetch most recent tasks first + Relay: compress tracked time for old tasks, filter closed tasks diff --git a/src/kinds.rs b/src/kinds.rs index e42872f..b351e26 100644 --- a/src/kinds.rs +++ b/src/kinds.rs @@ -1,9 +1,10 @@ use itertools::Itertools; use log::info; -use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagStandard}; use nostr_sdk::TagStandard::Hashtag; +use nostr_sdk::{Alphabet, EventBuilder, EventId, Kind, Tag, TagStandard}; +use std::collections::HashSet; -use crate::task::{MARKER_PARENT, State}; +use crate::task::{State, MARKER_PARENT}; pub const TASK_KIND: Kind = Kind::GitIssue; pub const PROCEDURE_KIND_ID: u16 = 1639; @@ -82,21 +83,33 @@ pub(crate) fn build_prop( ) } -/// Expects sanitized input +/// Return Hashtags embedded in the string. +pub(crate) fn extract_hashtags(input: &str) -> impl Iterator + '_ { + input.split_ascii_whitespace() + .filter(|s| s.starts_with('#')) + .map(|s| s.trim_start_matches('#')) + .map(to_hashtag) +} + +/// Extracts everything after a ": " as a list of tags. +/// +/// Expects sanitized input. pub(crate) fn extract_tags(input: &str) -> (&str, Vec) { match input.split_once(": ") { - None => (input, vec![]), - Some(s) => { - let tags = s - .1 - .split_ascii_whitespace() - .map(|t| Hashtag(t.to_string()).into()) + None => (input, extract_hashtags(input).collect_vec()), + Some((name, tags)) => { + let tags = extract_hashtags(name) + .chain(tags.split_ascii_whitespace().map(to_hashtag)) .collect(); - (s.0, tags) + (name, tags) } } } +fn to_hashtag(tag: &str) -> Tag { + Hashtag(tag.to_string()).into() +} + fn format_tag(tag: &Tag) -> String { match tag.as_standardized() { Some(TagStandard::Event { @@ -123,3 +136,9 @@ pub(crate) fn is_hashtag(tag: &Tag) -> bool { .is_some_and(|letter| letter.character == Alphabet::T) } + +#[test] +fn test_extract_tags() { + assert_eq!(extract_tags("Hello from #mars with #greetings: yeah done-it"), + ("Hello from #mars with #greetings", ["mars", "greetings", "yeah", "done-it"].into_iter().map(to_hashtag).collect())) +} \ No newline at end of file