arkham/src/command.rs

91 lines
2.2 KiB
Rust

use crate::{
context::Context,
opt::{self, Opt},
vox, App,
};
pub type Handler = fn(&App, &Context, &[String]);
#[derive(Clone)]
pub struct Command {
pub name: String,
pub commands: Vec<Command>,
pub handler: Option<Handler>,
pub opts: Vec<opt::Opt>,
pub long_desc: Option<String>,
pub short_desc: Option<String>,
}
impl Command {
pub fn new<T: Into<String>>(name: T) -> Self {
Command {
name: name.into(),
commands: vec![],
handler: None,
opts: vec![],
long_desc: None,
short_desc: None,
}
}
pub fn handler(mut self, f: Handler) -> Self {
self.handler = Some(f);
self
}
pub fn opt(mut self, opt: Opt) -> Self {
self.opts.push(opt);
self
}
pub fn short_desc(mut self, short_desc: &str) -> Self {
self.short_desc = Some(short_desc.into());
self
}
pub fn long_desc(mut self, long_desc: &str) -> Self {
self.short_desc = Some(long_desc.into());
self
}
}
pub(crate) fn help(app: &App, _ctx: &Context, args: &[String]) {
vox::print(app.application_header());
print_command_help(&app.root, args);
}
pub(crate) fn print_command_help(cmd: &Command, args: &[String]) {
if !args.is_empty() {
if let Some(cmd) = cmd.commands.iter().find(|c| Some(&c.name) == args.first()) {
return print_command_help(cmd, &args[1..]);
}
}
vox::print("");
if let Some(desc) = cmd.long_desc.as_ref().or(cmd.short_desc.as_ref()) {
if cmd.name != "root" {
vox::header(&cmd.name.to_uppercase());
}
vox::print(desc);
vox::print("");
}
if !cmd.opts.is_empty() {
vox::header("OPTIONS");
vox::description_list(
cmd.opts
.iter()
.map(|o| (o.usage(), o.desc.clone().unwrap_or_default()))
.collect(),
)
}
if !cmd.commands.is_empty() {
vox::header("Subcommands");
vox::description_list(
cmd.commands
.iter()
.map(|c| (c.name.clone(), c.short_desc.clone().unwrap_or_default()))
.collect(),
)
}
}