feat: more adaptive tag filtering

Make tag exclusions more persistent
This commit is contained in:
xeruf 2024-08-25 15:37:05 +03:00
parent dedda147c0
commit f381608b4c
3 changed files with 20 additions and 15 deletions

View File

@ -95,7 +95,7 @@ To stop time-tracking completely, simply move to the root of all tasks.
- `TASK` - create task - `TASK` - create task
+ prefix with space if you want a task to start with a command character + prefix with space if you want a task to start with a command character
+ copy in text with newlines to create one task per line + copy in text with newlines to create one task per line
- `.` - clear filters - `.` - clear all filters
- `.TASK` - `.TASK`
+ activate task by id + activate task by id
+ match by task name prefix: if one or more tasks match, filter / activate (tries case-sensitive then case-insensitive) + match by task name prefix: if one or more tasks match, filter / activate (tries case-sensitive then case-insensitive)
@ -125,9 +125,9 @@ Dot or slash can be repeated to move to parent tasks before acting.
Property Filters: Property Filters:
- `#TAG1 TAG2` - set tag filter (empty: list all used tags) - `#TAG1 TAG2` - set tag filter
- `+TAG` - add tag filter - `+TAG` - add tag filter (empty: list all used tags)
- `-TAG` - remove tag filters by prefix - `-TAG` - remove tag filters (by prefix)
- `?STATUS` - filter by status (type or description) - plain `?` to reset, `??` to show all - `?STATUS` - filter by status (type or description) - plain `?` to reset, `??` to show all
- `@AUTHOR` - filter by time or author (pubkey, or `@` for self, TBI: id prefix, name prefix) - `@AUTHOR` - filter by time or author (pubkey, or `@` for self, TBI: id prefix, name prefix)
- TBI: `**INT` - filter by priority - TBI: `**INT` - filter by priority

View File

@ -536,24 +536,24 @@ async fn main() -> Result<()> {
} }
Some('#') => Some('#') =>
match arg { tasks.set_tags(arg_default.split_whitespace().map(|s| Hashtag(s.to_string()).into())),
Some(arg) => tasks.set_tags(arg.split_whitespace().map(|s| Hashtag(s.to_string()).into())),
None => {
println!("Hashtags of all known tasks:\n{}", tasks.all_hashtags().join(" "));
continue;
}
}
Some('+') => Some('+') =>
match arg { match arg {
Some(arg) => tasks.add_tag(arg.to_string()), Some(arg) => tasks.add_tag(arg.to_string()),
None => tasks.clear_filter() None => {
println!("Hashtags of all known tasks:\n{}", tasks.all_hashtags().join(" ").italic());
if tasks.has_tag_filter() {
println!("Use # to remove tag filters and . to remove all filters.")
}
continue;
}
} }
Some('-') => Some('-') =>
match arg { match arg {
Some(arg) => tasks.remove_tag(arg), Some(arg) => tasks.remove_tag(arg),
None => tasks.clear_filter() None => tasks.clear_filters()
} }
Some('(') => { Some('(') => {
@ -597,6 +597,8 @@ async fn main() -> Result<()> {
tasks.move_to(pos.cloned()); tasks.move_to(pos.cloned());
if dots > 1 { if dots > 1 {
info!("Moving up {} tasks", dots - 1) info!("Moving up {} tasks", dots - 1)
} else {
tasks.clear_filters();
} }
} else if let Ok(depth) = slice.parse::<i8>() { } else if let Ok(depth) = slice.parse::<i8>() {
if pos != tasks.get_position_ref() { if pos != tasks.get_position_ref() {

View File

@ -505,15 +505,18 @@ impl Tasks {
self.view = view; self.view = view;
} }
pub(crate) fn clear_filter(&mut self) { pub(crate) fn clear_filters(&mut self) {
self.view.clear(); self.view.clear();
self.tags.clear(); self.tags.clear();
self.tags_excluded.clear(); self.tags_excluded.clear();
info!("Removed all filters"); info!("Removed all filters");
} }
pub(crate) fn has_tag_filter(&self) -> bool {
!self.tags.is_empty() || !self.tags_excluded.is_empty()
}
pub(crate) fn set_tags(&mut self, tags: impl IntoIterator<Item=Tag>) { pub(crate) fn set_tags(&mut self, tags: impl IntoIterator<Item=Tag>) {
self.tags_excluded.clear();
self.tags.clear(); self.tags.clear();
self.tags.extend(tags); self.tags.extend(tags);
} }