diff --git a/cli/src/cmd/delete.rs b/cli/src/cmd/delete.rs new file mode 100644 index 000000000..67acf4693 --- /dev/null +++ b/cli/src/cmd/delete.rs @@ -0,0 +1,51 @@ +use clap::{App, ArgMatches, SubCommand as ClapSubCommand}; +use failure::Fallible; +use taskchampion::Status; + +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("delete") + .about("mark the given task as deleted") + .arg(shared::task_arg())) + } + + fn arg_match<'a>(&self, matches: &ArgMatches<'a>) -> ArgMatchResult { + match matches.subcommand() { + ("delete", 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 mut replica = command.get_replica()?; + let task = shared::get_task(&mut replica, &self.task)?; + let mut task = task.into_mut(&mut replica); + task.stop()?; + task.set_status(Status::Deleted)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parse_command() { + with_subcommand_invocation!(vec!["task", "delete", "1"], |inv: &Invocation| { + assert_eq!(inv.task, "1".to_string()); + }); + } +} diff --git a/cli/src/cmd/done.rs b/cli/src/cmd/done.rs new file mode 100644 index 000000000..713a747a8 --- /dev/null +++ b/cli/src/cmd/done.rs @@ -0,0 +1,51 @@ +use clap::{App, ArgMatches, SubCommand as ClapSubCommand}; +use failure::Fallible; +use taskchampion::Status; + +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("done") + .about("finish the given task (status Completed)") + .arg(shared::task_arg())) + } + + fn arg_match<'a>(&self, matches: &ArgMatches<'a>) -> ArgMatchResult { + match matches.subcommand() { + ("done", 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 mut replica = command.get_replica()?; + let task = shared::get_task(&mut replica, &self.task)?; + let mut task = task.into_mut(&mut replica); + task.stop()?; + task.set_status(Status::Completed)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parse_command() { + with_subcommand_invocation!(vec!["task", "done", "1"], |inv: &Invocation| { + assert_eq!(inv.task, "1".to_string()); + }); + } +} diff --git a/cli/src/cmd/list.rs b/cli/src/cmd/list.rs index 4dddd5265..7b1b5078d 100644 --- a/cli/src/cmd/list.rs +++ b/cli/src/cmd/list.rs @@ -2,6 +2,7 @@ use crate::table; use clap::{App, ArgMatches, SubCommand as ClapSubCommand}; use failure::Fallible; use prettytable::{cell, row, Table}; +use taskchampion::Status; use crate::cmd::{ArgMatchResult, CommandInvocation}; @@ -28,6 +29,9 @@ subcommand_invocation! { t.set_format(table::format()); t.set_titles(row![b->"id", b->"act", b->"description"]); for (uuid, task) in replica.all_tasks().unwrap() { + if task.get_status() != Status::Pending { + continue; + } let mut id = uuid.to_string(); if let Some(i) = replica.get_working_set_index(&uuid)? { id = i.to_string(); diff --git a/cli/src/cmd/mod.rs b/cli/src/cmd/mod.rs index d58237816..17275c52e 100644 --- a/cli/src/cmd/mod.rs +++ b/cli/src/cmd/mod.rs @@ -7,6 +7,8 @@ mod shared; mod add; mod debug; +mod delete; +mod done; mod gc; mod info; mod list; @@ -21,6 +23,8 @@ pub(crate) fn subcommands() -> Vec> { vec![ add::cmd(), debug::cmd(), + delete::cmd(), + done::cmd(), gc::cmd(), info::cmd(), list::cmd(), diff --git a/taskchampion/src/replica.rs b/taskchampion/src/replica.rs index 525be9888..6e4550ebd 100644 --- a/taskchampion/src/replica.rs +++ b/taskchampion/src/replica.rs @@ -135,8 +135,10 @@ impl Replica { } /// Delete a task. The task must exist. Note that this is different from setting status to - /// Deleted; this is the final purge of the task. - pub fn delete_task(&mut self, uuid: &Uuid) -> Fallible<()> { + /// Deleted; this is the final purge of the task. This is not a public method as deletion + /// should only occur through expiration. + #[allow(dead_code)] + fn delete_task(&mut self, uuid: &Uuid) -> Fallible<()> { // check that it already exists; this is a convenience check, as the task may already exist // when this Create operation is finally sync'd with operations from other replicas if self.taskdb.get_task(&uuid)?.is_none() {