support filtering by tags
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use super::args::{arg_matching, id_list, TaskId};
|
||||
use super::args::{arg_matching, id_list, minus_tag, plus_tag, TaskId};
|
||||
use super::ArgList;
|
||||
use nom::{combinator::*, multi::fold_many0, IResult};
|
||||
use nom::{branch::alt, combinator::*, multi::fold_many0, IResult};
|
||||
|
||||
/// A filter represents a selection of a particular set of tasks.
|
||||
///
|
||||
@@ -9,8 +9,12 @@ use nom::{combinator::*, multi::fold_many0, IResult};
|
||||
/// pending tasks, or all tasks.
|
||||
#[derive(Debug, PartialEq, Default, Clone)]
|
||||
pub(crate) struct Filter {
|
||||
/// A list of numeric IDs or prefixes of UUIDs
|
||||
/// The universe of tasks from which this filter can select
|
||||
pub(crate) universe: Universe,
|
||||
|
||||
/// A set of filter conditions, all of which must match a task in order for that task to be
|
||||
/// selected.
|
||||
pub(crate) conditions: Vec<Condition>,
|
||||
}
|
||||
|
||||
/// The universe of tasks over which a filter should be applied.
|
||||
@@ -39,15 +43,26 @@ impl Default for Universe {
|
||||
}
|
||||
}
|
||||
|
||||
/// A condition which tasks must match to be accepted by the filter.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub(crate) enum Condition {
|
||||
/// Task has the given tag
|
||||
HasTag(String),
|
||||
|
||||
/// Task does not have the given tag
|
||||
NoTag(String),
|
||||
}
|
||||
|
||||
/// Internal struct representing a parsed filter argument
|
||||
enum FilterArg {
|
||||
IdList(Vec<TaskId>),
|
||||
Condition(Condition),
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub(super) fn parse(input: ArgList) -> IResult<ArgList, Filter> {
|
||||
fold_many0(
|
||||
Self::id_list,
|
||||
alt((Self::id_list, Self::plus_tag, Self::minus_tag)),
|
||||
Filter {
|
||||
..Default::default()
|
||||
},
|
||||
@@ -68,6 +83,9 @@ impl Filter {
|
||||
acc.universe = Universe::IdList(id_list);
|
||||
}
|
||||
}
|
||||
FilterArg::Condition(cond) => {
|
||||
acc.conditions.push(cond);
|
||||
}
|
||||
}
|
||||
acc
|
||||
}
|
||||
@@ -78,6 +96,20 @@ impl Filter {
|
||||
}
|
||||
map_res(arg_matching(id_list), to_filterarg)(input)
|
||||
}
|
||||
|
||||
fn plus_tag(input: ArgList) -> IResult<ArgList, FilterArg> {
|
||||
fn to_filterarg(input: &str) -> Result<FilterArg, ()> {
|
||||
Ok(FilterArg::Condition(Condition::HasTag(input.to_owned())))
|
||||
}
|
||||
map_res(arg_matching(plus_tag), to_filterarg)(input)
|
||||
}
|
||||
|
||||
fn minus_tag(input: ArgList) -> IResult<ArgList, FilterArg> {
|
||||
fn to_filterarg(input: &str) -> Result<FilterArg, ()> {
|
||||
Ok(FilterArg::Condition(Condition::NoTag(input.to_owned())))
|
||||
}
|
||||
map_res(arg_matching(minus_tag), to_filterarg)(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -159,4 +191,21 @@ mod test {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tags() {
|
||||
let (input, filter) = Filter::parse(argv!["1", "+yes", "-no"]).unwrap();
|
||||
assert_eq!(input.len(), 0);
|
||||
assert_eq!(
|
||||
filter,
|
||||
Filter {
|
||||
universe: Universe::IdList(vec![TaskId::WorkingSetId(1),]),
|
||||
conditions: vec![
|
||||
Condition::HasTag("yes".into()),
|
||||
Condition::NoTag("no".into()),
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ mod subcommand;
|
||||
|
||||
pub(crate) use args::TaskId;
|
||||
pub(crate) use command::Command;
|
||||
pub(crate) use filter::{Filter, Universe};
|
||||
pub(crate) use filter::{Condition, Filter, Universe};
|
||||
pub(crate) use modification::{DescriptionMod, Modification};
|
||||
pub(crate) use report::Report;
|
||||
pub(crate) use subcommand::Subcommand;
|
||||
|
||||
Reference in New Issue
Block a user