diff --git a/cli/src/cmd/info.rs b/cli/src/cmd/info.rs new file mode 100644 index 000000000..bcb84d279 --- /dev/null +++ b/cli/src/cmd/info.rs @@ -0,0 +1,55 @@ +use crate::table; +use clap::{App, ArgMatches, SubCommand as ClapSubCommand}; +use failure::Fallible; +use prettytable::{cell, row, Table}; + +use crate::cmd::{shared, ArgMatchResult, CommandInvocation}; + +#[derive(Debug)] +struct Invocation { + task: String, +} + +define_subcommand! { + fn decorate_app<'a>(&self, app: App<'a, 'a>) -> App<'a, 'a> { + app.subcommand( + ClapSubCommand::with_name("info") + .about("info on the given task") + .arg(shared::task_arg())) + } + + fn arg_match<'a>(&self, matches: &ArgMatches<'a>) -> ArgMatchResult { + match matches.subcommand() { + ("info", Some(matches)) => ArgMatchResult::Ok(Box::new(Invocation { + task: matches.value_of("task").unwrap().into(), + })), + _ => ArgMatchResult::None, + } + } +} + +subcommand_invocation! { + fn run(&self, command: &CommandInvocation) -> Fallible<()> { + let task = shared::get_task(&mut command.get_replica(), &self.task)?; + + let mut t = Table::new(); + t.set_format(table::format()); + t.add_row(row![b->"Uuid", task.get_uuid()]); + t.add_row(row![b->"Description", task.get_description()]); + t.add_row(row![b->"Status", task.get_status()]); + t.printstd(); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parse_command() { + with_subcommand_invocation!(vec!["task", "info", "1"], |inv: &Invocation| { + assert_eq!(inv.task, "1".to_string()); + }); + } +} diff --git a/cli/src/cmd/mod.rs b/cli/src/cmd/mod.rs index 0ec5ae5fd..e7d27255b 100644 --- a/cli/src/cmd/mod.rs +++ b/cli/src/cmd/mod.rs @@ -5,15 +5,23 @@ use taskchampion::{taskstorage, Replica}; #[macro_use] mod macros; +mod shared; mod add; mod gc; +mod info; mod list; mod pending; /// Get a list of all subcommands in this crate pub(crate) fn subcommands() -> Vec> { - vec![add::cmd(), gc::cmd(), list::cmd(), pending::cmd()] + vec![ + add::cmd(), + gc::cmd(), + list::cmd(), + pending::cmd(), + info::cmd(), + ] } /// The result of a [`crate::cmd::SubCommand::arg_match`] call diff --git a/cli/src/cmd/shared.rs b/cli/src/cmd/shared.rs new file mode 100644 index 000000000..eb472ab23 --- /dev/null +++ b/cli/src/cmd/shared.rs @@ -0,0 +1,38 @@ +use clap::Arg; +use failure::{format_err, Fallible}; +use taskchampion::{Replica, Task}; +use uuid::Uuid; + +pub(super) fn task_arg<'a>() -> Arg<'a, 'a> { + Arg::with_name("task") + .help("task id or uuid") + .required(true) +} + +pub(super) fn get_task>(replica: &mut Replica, task_arg: S) -> Fallible { + let task_arg = task_arg.as_ref(); + + // first try treating task as a working-set reference + match task_arg.parse::() { + Ok(i) => { + let mut working_set = replica.working_set().unwrap(); + if i > 0 && i < working_set.len() as u64 { + if let Some(task) = working_set[i as usize].take() { + return Ok(task); + } + } + } + Err(_) => {} + } + + match Uuid::parse_str(task_arg) { + Ok(uuid) => { + if let Some(task) = replica.get_task(&uuid)? { + return Ok(task); + } + } + Err(_) => {} + } + + Err(format_err!("Cannot interpret {:?} as a task", task_arg)) +} diff --git a/taskchampion/src/task.rs b/taskchampion/src/task.rs index c0ccc1480..69d2a6f56 100644 --- a/taskchampion/src/task.rs +++ b/taskchampion/src/task.rs @@ -68,6 +68,16 @@ impl Status { Status::Deleted => "D", } } + + /// Get the full-name value for this status to use in the TaskMap. + pub fn to_string(&self) -> &str { + // TODO: should be impl Display + match self { + Status::Pending => "Pending", + Status::Completed => "Completed", + Status::Deleted => "Deleted", + } + } } #[derive(Debug, PartialEq)]