mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Support CLI syntax for changing tags
This commit is contained in:
parent
28c5fb2268
commit
54e8484bc2
4 changed files with 97 additions and 35 deletions
|
@ -58,7 +58,6 @@ pub(super) fn id_list(input: &str) -> IResult<&str, Vec<&str>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recognizes a tag prefixed with `+` and returns the tag value
|
/// Recognizes a tag prefixed with `+` and returns the tag value
|
||||||
#[allow(dead_code)] // tags not implemented yet
|
|
||||||
pub(super) fn plus_tag(input: &str) -> IResult<&str, &str> {
|
pub(super) fn plus_tag(input: &str) -> IResult<&str, &str> {
|
||||||
fn to_tag(input: (char, &str)) -> Result<&str, ()> {
|
fn to_tag(input: (char, &str)) -> Result<&str, ()> {
|
||||||
Ok(input.1)
|
Ok(input.1)
|
||||||
|
@ -70,7 +69,6 @@ pub(super) fn plus_tag(input: &str) -> IResult<&str, &str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recognizes a tag prefixed with `-` and returns the tag value
|
/// Recognizes a tag prefixed with `-` and returns the tag value
|
||||||
#[allow(dead_code)] // tags not implemented yet
|
|
||||||
pub(super) fn minus_tag(input: &str) -> IResult<&str, &str> {
|
pub(super) fn minus_tag(input: &str) -> IResult<&str, &str> {
|
||||||
fn to_tag(input: (char, &str)) -> Result<&str, ()> {
|
fn to_tag(input: (char, &str)) -> Result<&str, ()> {
|
||||||
Ok(input.1)
|
Ok(input.1)
|
||||||
|
@ -81,18 +79,6 @@ pub(super) fn minus_tag(input: &str) -> IResult<&str, &str> {
|
||||||
)(input)
|
)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recognizes a tag prefixed with either `-` or `+`, returning true for + and false for -
|
|
||||||
#[allow(dead_code)] // tags not implemented yet
|
|
||||||
pub(super) fn tag(input: &str) -> IResult<&str, (bool, &str)> {
|
|
||||||
fn to_plus(input: &str) -> Result<(bool, &str), ()> {
|
|
||||||
Ok((true, input))
|
|
||||||
}
|
|
||||||
fn to_minus(input: &str) -> Result<(bool, &str), ()> {
|
|
||||||
Ok((false, input))
|
|
||||||
}
|
|
||||||
alt((map_res(plus_tag, to_plus), map_res(minus_tag, to_minus)))(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consume a single argument from an argument list that matches the given string parser (one
|
/// Consume a single argument from an argument list that matches the given string parser (one
|
||||||
/// of the other functions in this module). The given parser must consume the entire input.
|
/// of the other functions in this module). The given parser must consume the entire input.
|
||||||
pub(super) fn arg_matching<'a, O, F>(f: F) -> impl Fn(ArgList<'a>) -> IResult<ArgList, O>
|
pub(super) fn arg_matching<'a, O, F>(f: F) -> impl Fn(ArgList<'a>) -> IResult<ArgList, O>
|
||||||
|
@ -131,14 +117,10 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_arg_matching() {
|
fn test_arg_matching() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
arg_matching(tag)(argv!["+foo", "bar"]).unwrap(),
|
arg_matching(plus_tag)(argv!["+foo", "bar"]).unwrap(),
|
||||||
(argv!["bar"], (true, "foo"))
|
(argv!["bar"], "foo")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert!(arg_matching(plus_tag)(argv!["foo", "bar"]).is_err());
|
||||||
arg_matching(tag)(argv!["-foo", "bar"]).unwrap(),
|
|
||||||
(argv!["bar"], (false, "foo"))
|
|
||||||
);
|
|
||||||
assert!(arg_matching(tag)(argv!["foo", "bar"]).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -161,16 +143,6 @@ mod test {
|
||||||
assert!(minus_tag("-1abc").is_err());
|
assert!(minus_tag("-1abc").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_tag() {
|
|
||||||
assert_eq!(tag("-abc").unwrap().1, (false, "abc"));
|
|
||||||
assert_eq!(tag("+abc123").unwrap().1, (true, "abc123"));
|
|
||||||
assert!(tag("+abc123 --").is_err());
|
|
||||||
assert!(tag("-abc123 ").is_err());
|
|
||||||
assert!(tag(" -abc123").is_err());
|
|
||||||
assert!(tag("-1abc").is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_literal() {
|
fn test_literal() {
|
||||||
assert_eq!(literal("list")("list").unwrap().1, "list");
|
assert_eq!(literal("list")("list").unwrap().1, "list");
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::args::{any, arg_matching};
|
use super::args::{any, arg_matching, minus_tag, plus_tag};
|
||||||
use super::ArgList;
|
use super::ArgList;
|
||||||
use nom::{combinator::*, multi::fold_many0, IResult};
|
use nom::{branch::alt, combinator::*, multi::fold_many0, IResult};
|
||||||
|
use std::collections::HashSet;
|
||||||
use taskchampion::Status;
|
use taskchampion::Status;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -34,13 +35,21 @@ pub struct Modification {
|
||||||
/// Set the status
|
/// Set the status
|
||||||
pub status: Option<Status>,
|
pub status: Option<Status>,
|
||||||
|
|
||||||
/// Set the "active" status, that is, start (true) or stop (false) the task.
|
/// Set the "active" state, that is, start (true) or stop (false) the task.
|
||||||
pub active: Option<bool>,
|
pub active: Option<bool>,
|
||||||
|
|
||||||
|
/// Add tags
|
||||||
|
pub add_tags: HashSet<String>,
|
||||||
|
|
||||||
|
/// Remove tags
|
||||||
|
pub remove_tags: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single argument that is part of a modification, used internally to this module
|
/// A single argument that is part of a modification, used internally to this module
|
||||||
enum ModArg<'a> {
|
enum ModArg<'a> {
|
||||||
Description(&'a str),
|
Description(&'a str),
|
||||||
|
PlusTag(&'a str),
|
||||||
|
MinusTag(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Modification {
|
impl Modification {
|
||||||
|
@ -55,11 +64,22 @@ impl Modification {
|
||||||
acc.description = DescriptionMod::Set(description.to_string());
|
acc.description = DescriptionMod::Set(description.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ModArg::PlusTag(tag) => {
|
||||||
|
acc.add_tags.insert(tag.to_owned());
|
||||||
|
}
|
||||||
|
ModArg::MinusTag(tag) => {
|
||||||
|
acc.remove_tags.insert(tag.to_owned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
fold_many0(
|
fold_many0(
|
||||||
|
alt((
|
||||||
|
Self::plus_tag,
|
||||||
|
Self::minus_tag,
|
||||||
|
// this must come last
|
||||||
Self::description,
|
Self::description,
|
||||||
|
)),
|
||||||
Modification {
|
Modification {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -73,6 +93,20 @@ impl Modification {
|
||||||
}
|
}
|
||||||
map_res(arg_matching(any), to_modarg)(input)
|
map_res(arg_matching(any), to_modarg)(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn plus_tag(input: ArgList) -> IResult<ArgList, ModArg> {
|
||||||
|
fn to_modarg(input: &str) -> Result<ModArg, ()> {
|
||||||
|
Ok(ModArg::PlusTag(input))
|
||||||
|
}
|
||||||
|
map_res(arg_matching(plus_tag), to_modarg)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minus_tag(input: ArgList) -> IResult<ArgList, ModArg> {
|
||||||
|
fn to_modarg(input: &str) -> Result<ModArg, ()> {
|
||||||
|
Ok(ModArg::MinusTag(input))
|
||||||
|
}
|
||||||
|
map_res(arg_matching(minus_tag), to_modarg)(input)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -104,6 +138,19 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_tags() {
|
||||||
|
let (input, modification) = Modification::parse(argv!["+abc", "+def"]).unwrap();
|
||||||
|
assert_eq!(input.len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
modification,
|
||||||
|
Modification {
|
||||||
|
add_tags: set!["abc".to_owned(), "def".to_owned()],
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multi_arg_description() {
|
fn test_multi_arg_description() {
|
||||||
let (input, modification) = Modification::parse(argv!["new", "desc", "fun"]).unwrap();
|
let (input, modification) = Modification::parse(argv!["new", "desc", "fun"]).unwrap();
|
||||||
|
@ -116,4 +163,20 @@ mod test {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multi_arg_description_and_tags() {
|
||||||
|
let (input, modification) =
|
||||||
|
Modification::parse(argv!["new", "+next", "desc", "-daytime", "fun"]).unwrap();
|
||||||
|
assert_eq!(input.len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
modification,
|
||||||
|
Modification {
|
||||||
|
description: DescriptionMod::Set("new desc fun".to_owned()),
|
||||||
|
add_tags: set!["next".to_owned()],
|
||||||
|
remove_tags: set!["daytime".to_owned()],
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::argparse::{DescriptionMod, Modification};
|
use crate::argparse::{DescriptionMod, Modification};
|
||||||
use failure::Fallible;
|
use failure::Fallible;
|
||||||
|
use std::convert::TryInto;
|
||||||
use taskchampion::TaskMut;
|
use taskchampion::TaskMut;
|
||||||
use termcolor::WriteColor;
|
use termcolor::WriteColor;
|
||||||
|
|
||||||
|
@ -32,6 +33,18 @@ pub(super) fn apply_modification<W: WriteColor>(
|
||||||
task.stop()?;
|
task.stop()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for tag in modification.add_tags.iter() {
|
||||||
|
// note that the parser should have already ensured that this tag was valid
|
||||||
|
let tag = tag.try_into()?;
|
||||||
|
task.add_tag(&tag)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag in modification.remove_tags.iter() {
|
||||||
|
// note that the parser should have already ensured that this tag was valid
|
||||||
|
let tag = tag.try_into()?;
|
||||||
|
task.remove_tag(&tag)?;
|
||||||
|
}
|
||||||
|
|
||||||
write!(w, "modified task {}\n", task.get_uuid())?;
|
write!(w, "modified task {}\n", task.get_uuid())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -10,3 +10,17 @@ macro_rules! argv {
|
||||||
&[$($x),*][..]
|
&[$($x),*][..]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a hashset, similar to vec!
|
||||||
|
#[cfg(test)]
|
||||||
|
macro_rules! set(
|
||||||
|
{ $($key:expr),+ } => {
|
||||||
|
{
|
||||||
|
let mut s = ::std::collections::HashSet::new();
|
||||||
|
$(
|
||||||
|
s.insert($key);
|
||||||
|
)+
|
||||||
|
s
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue