forked from janek/mostr
feat: automatically add tags from task properties
This commit is contained in:
parent
44feea9894
commit
2cec689bf1
|
@ -146,10 +146,10 @@ pub(crate) fn to_prio_tag(value: Prio) -> Tag {
|
|||
|
||||
#[test]
|
||||
fn test_extract_tags() {
|
||||
assert_eq!(extract_tags("Hello from #mars with #greetings *4 # # yeah done-it"),
|
||||
("Hello from #mars with #greetings".to_string(),
|
||||
["mars", "greetings", "yeah", "done-it"].into_iter().map(to_hashtag)
|
||||
.chain(std::iter::once(Tag::custom(TagKind::Custom(Cow::from(PRIO)), [40.to_string()]))).collect()));
|
||||
assert_eq!(extract_tags("Hello from #mars with #greetings #yeah *4 # # yeah done-it"),
|
||||
("Hello from #mars with #greetings #yeah".to_string(),
|
||||
std::iter::once(Tag::custom(TagKind::Custom(Cow::from(PRIO)), [40.to_string()]))
|
||||
.chain(["done-it", "greetings", "mars", "yeah"].into_iter().map(to_hashtag)).collect()));
|
||||
assert_eq!(extract_tags("So tagless #"),
|
||||
("So tagless".to_string(), vec![]));
|
||||
}
|
|
@ -677,7 +677,7 @@ async fn main() -> Result<()> {
|
|||
let filtered =
|
||||
tasks.get_filtered(pos, |t| {
|
||||
transform(&t.event.content).contains(&remaining) ||
|
||||
t.tags.iter().flatten().any(
|
||||
t.get_hashtags().any(
|
||||
|tag| tag.content().is_some_and(|s| transform(s).contains(&remaining)))
|
||||
});
|
||||
if filtered.len() == 1 {
|
||||
|
|
34
src/task.rs
34
src/task.rs
|
@ -10,7 +10,7 @@ use colored::{ColoredString, Colorize};
|
|||
use itertools::Either::{Left, Right};
|
||||
use itertools::Itertools;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use nostr_sdk::{Event, EventId, Kind, Tag, TagStandard, Timestamp};
|
||||
use nostr_sdk::{Alphabet, Event, EventId, Kind, Tag, TagStandard, Timestamp};
|
||||
|
||||
use crate::helpers::{format_timestamp_local, some_non_empty};
|
||||
use crate::kinds::{is_hashtag, Prio, PRIO, PROCEDURE_KIND, PROCEDURE_KIND_ID, TASK_KIND};
|
||||
|
@ -23,8 +23,8 @@ pub static MARKER_PROPERTY: &str = "property";
|
|||
pub(crate) struct Task {
|
||||
/// Event that defines this task
|
||||
pub(crate) event: Event,
|
||||
/// Cached sorted tags of the event with references remove - do not modify!
|
||||
pub(crate) tags: Option<BTreeSet<Tag>>,
|
||||
/// Cached sorted tags of the event with references removed
|
||||
tags: Option<BTreeSet<Tag>>,
|
||||
/// Task references derived from the event tags
|
||||
refs: Vec<(String, EventId)>,
|
||||
/// Events belonging to this task, such as state updates and notes
|
||||
|
@ -172,16 +172,26 @@ impl Task {
|
|||
}
|
||||
}
|
||||
|
||||
fn filter_tags<P>(&self, predicate: P) -> Option<String>
|
||||
pub(crate) fn get_hashtags(&self) -> impl Iterator<Item=&Tag> {
|
||||
self.tags().filter(|t| is_hashtag(t))
|
||||
}
|
||||
|
||||
fn tags(&self) -> impl Iterator<Item=&Tag> {
|
||||
self.props.iter().flat_map(|e| e.tags.iter()
|
||||
.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
|
||||
where
|
||||
P: FnMut(&&Tag) -> bool,
|
||||
{
|
||||
self.tags.as_ref().map(|tags| {
|
||||
tags.iter()
|
||||
.filter(predicate)
|
||||
.map(|t| t.content().unwrap().to_string())
|
||||
.join(" ")
|
||||
})
|
||||
self.tags()
|
||||
.filter(predicate)
|
||||
.map(|t| t.content().unwrap().to_string())
|
||||
.sorted_unstable()
|
||||
.dedup()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, property: &str) -> Option<String> {
|
||||
|
@ -198,8 +208,8 @@ impl Task {
|
|||
"status" => self.state_label().map(|c| c.to_string()),
|
||||
"desc" => self.descriptions().last().cloned(),
|
||||
"description" => Some(self.descriptions().join(" ")),
|
||||
"hashtags" => self.filter_tags(|tag| { is_hashtag(tag) }),
|
||||
"tags" => self.filter_tags(|_| true),
|
||||
"hashtags" => Some(self.join_tags(|tag| { is_hashtag(tag) })),
|
||||
"tags" => Some(self.join_tags(|_| true)),
|
||||
"alltags" => Some(format!("{:?}", self.tags)),
|
||||
"refs" => Some(format!("{:?}", self.refs.iter().map(|re| format!("{}: {}", re.0, re.1)).collect_vec())),
|
||||
"props" => Some(format!(
|
||||
|
|
20
src/tasks.rs
20
src/tasks.rs
|
@ -241,8 +241,7 @@ impl TasksRelay {
|
|||
pub(crate) fn all_hashtags(&self) -> impl Iterator<Item=&str> {
|
||||
self.tasks.values()
|
||||
.filter(|t| t.pure_state() != State::Closed)
|
||||
.filter_map(|t| t.tags.as_ref()).flatten()
|
||||
.filter(|tag| is_hashtag(tag))
|
||||
.flat_map(|t| t.get_hashtags())
|
||||
.filter_map(|tag| tag.content().map(|s| s.trim()))
|
||||
.sorted_unstable()
|
||||
.dedup()
|
||||
|
@ -449,14 +448,11 @@ impl TasksRelay {
|
|||
self.priority.is_none_or(|prio| {
|
||||
task.priority().unwrap_or(DEFAULT_PRIO) >= prio
|
||||
}) &&
|
||||
task.tags.as_ref().map_or(true, |tags| {
|
||||
!tags.iter().any(|tag| self.tags_excluded.contains(tag))
|
||||
}) &&
|
||||
(self.tags.is_empty() ||
|
||||
task.tags.as_ref().map_or(false, |tags| {
|
||||
let mut iter = tags.iter();
|
||||
self.tags.iter().all(|tag| iter.any(|t| t == tag))
|
||||
}))
|
||||
!task.get_hashtags().any(|tag| self.tags_excluded.contains(tag)) &&
|
||||
(self.tags.is_empty() || {
|
||||
let mut iter = task.get_hashtags().sorted_unstable();
|
||||
self.tags.iter().all(|tag| iter.any(|t| t == tag))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn filtered_tasks<'a>(&'a self, position: Option<&'a EventId>, sparse: bool) -> Vec<&'a Task> {
|
||||
|
@ -1654,6 +1650,10 @@ mod tasks_test {
|
|||
tasks.move_to(Some(parent));
|
||||
let sub = tasks.make_task("sub # tag2");
|
||||
assert_eq!(tasks.all_hashtags().collect_vec(), vec!["tag1", "tag2"]);
|
||||
tasks.make_note("note with #tag3 # yeah");
|
||||
assert_eq!(tasks.all_hashtags().collect_vec(), vec!["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.update_state("Closing Down", State::Closed);
|
||||
assert_eq!(tasks.get_by_id(&sub).unwrap().pure_state(), State::Closed);
|
||||
assert_eq!(tasks.all_hashtags().next(), None);
|
||||
|
|
Loading…
Reference in New Issue