use error::*;
use flags::help;
use flags::spec::Specs;
use flags::value::Values;
use std::fmt;
use std::io::Write;
use std::iter::Peekable;
pub type CommandResult<E> = ::std::result::Result<(), E>;
pub type CommandCallback<'a, E> = Box<FnMut(Values) -> CommandResult<E> + 'a>;
pub struct Command<'a, E> {
pub name: String,
pub help: String,
pub flags: Specs,
pub callback: CommandCallback<'a, E>,
}
impl<'a, E> Command<'a, E> {
pub fn new(name: &str, help: &str, flags: Specs, callback: CommandCallback<'a, E>) -> Self {
Command {
name: name.to_owned(),
help: help.to_owned(),
flags: flags,
callback: callback,
}
}
pub fn execute(&mut self, values: Values) -> CommandResult<E> {
self.callback.as_mut()(values)
}
}
impl<'a, E> fmt::Debug for Command<'a, E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(
format!(
"Command {{ {:#?}, {:#?}, {:#?} }}",
self.name, self.help, self.flags
).as_str(),
)
}
}
impl<'a, E> PartialEq for Command<'a, E> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
pub fn parse_command<'a, 'b, I: Iterator<Item = &'a String>, E, W: Write>(
program: &str,
args: &mut Peekable<I>,
mut commands: Vec<Command<'b, E>>,
output_writer: Option<&mut W>,
print_program_help: bool,
) -> Result<Command<'b, E>> {
let idx: Result<usize> = match args.next() {
Some(command_arg) => match commands
.iter()
.position(|command| command.name == *command_arg)
{
Some(command) => Ok(command),
None => Err(Error::InvalidArgument(format_err!(
"Unrecognized command '{}'",
command_arg
))),
},
None => Err(Error::InvalidArgument(format_err!("No command specified"))),
};
if let Err(e) = idx {
if print_program_help {
help::print_program_help(output_writer, program, &commands)?;
}
return Err(e);
}
Ok(commands.remove(idx.unwrap()))
}