Files
taskwarrior-2.x/cli/src/argparse/command.rs
Dustin J. Mitchell 0f0f2b0e75 rename CLI to ta
2021-05-04 17:09:47 -04:00

60 lines
1.8 KiB
Rust

use super::args::*;
use super::{ArgList, Subcommand};
use anyhow::bail;
use nom::{combinator::*, sequence::*, Err, IResult};
/// A command is the overall command that the CLI should execute.
///
/// It consists of some information common to all commands and a `Subcommand` identifying the
/// particular kind of behavior desired.
#[derive(Debug, PartialEq)]
pub(crate) struct Command {
pub(crate) command_name: String,
pub(crate) subcommand: Subcommand,
}
impl Command {
pub(super) fn parse(input: ArgList) -> IResult<ArgList, Command> {
fn to_command(input: (&str, Subcommand)) -> Result<Command, ()> {
let command = Command {
command_name: input.0.to_owned(),
subcommand: input.1,
};
Ok(command)
}
map_res(
all_consuming(tuple((arg_matching(any), Subcommand::parse))),
to_command,
)(input)
}
/// Parse a command from the given list of strings.
pub fn from_argv(argv: &[&str]) -> anyhow::Result<Command> {
match Command::parse(argv) {
Ok((&[], cmd)) => Ok(cmd),
Ok((trailing, _)) => bail!("command line has trailing arguments: {:?}", trailing),
Err(Err::Incomplete(_)) => unreachable!(),
Err(Err::Error(e)) => bail!("command line not recognized: {:?}", e),
Err(Err::Failure(e)) => bail!("command line not recognized: {:?}", e),
}
}
}
#[cfg(test)]
mod test {
use super::*;
// NOTE: most testing of specific subcommands is handled in `subcommand.rs`.
#[test]
fn test_version() {
assert_eq!(
Command::from_argv(argv!["ta", "version"]).unwrap(),
Command {
subcommand: Subcommand::Version,
command_name: s!("ta"),
}
);
}
}