use crate::flags::Flag;
#[derive(Default)]
pub struct Command {
pub(crate) name: String,
pub(crate) description: String,
pub(crate) known_flags: Vec<Flag>,
pub(crate) usage: Option<String>,
pub(crate) handler: Option<fn(&CommandContext)>,
pub(crate) strict_flags: bool,
pub(crate) subcommands: Vec<Command>,
pub(crate) print_help_if_no_args: bool,
}
impl Command {
pub fn new(name: impl Into<String>, handler: fn(&CommandContext)) -> Self {
Self {
name: name.into(),
handler: Some(handler),
..Default::default()
}
}
pub fn parent(name: impl Into<String>) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = description.into();
self
}
pub fn usage(mut self, usage: impl Into<String>) -> Self {
self.usage = Some(usage.into());
self
}
pub fn strict_flags(mut self, strict: bool) -> Self {
self.strict_flags = strict;
self
}
pub fn flag(mut self, flag: Flag) -> Self {
self.known_flags.push(flag);
self
}
pub fn subcommand(mut self, subcommand: Command) -> Self {
self.subcommands.push(subcommand);
self
}
pub fn print_help_if_no_args(mut self, print: bool) -> Self {
self.print_help_if_no_args = print;
self
}
pub(crate) fn print_help(&self, prog: &str) {
if let Some(usage) = &self.usage {
println!("USAGE: {} {} {}", prog, self.name, usage);
} else if !self.known_flags.is_empty() {
println!("USAGE: {} {} [options]", prog, self.name);
}
println!(" {}", self.description);
println!();
if !self.known_flags.is_empty() {
println!("OPTIONS:");
let longest = self
.known_flags
.iter()
.map(|f| {
let alias_part = f.alias.as_ref().map_or(0, |a| a.len() + 4);
f.name.len() + alias_part
})
.max()
.unwrap_or(0);
for flag in &self.known_flags {
let left = if let Some(alias) = &flag.alias {
format!("--{}, -{}", flag.name, alias)
} else {
format!("--{}", flag.name)
};
let description = flag.description.as_deref().unwrap_or("");
println!(" {:<width$} {}", left, description, width = longest + 10);
}
}
if !self.subcommands.is_empty() {
println!();
println!("SUBCOMMANDS:");
let longest = self
.subcommands
.iter()
.map(|s| s.name.len())
.max()
.unwrap_or(0)
+ 10;
for subcommand in &self.subcommands {
println!(
" {:<width$} {}",
subcommand.name,
subcommand.description,
width = longest
);
}
}
}
}
pub struct CommandContext {
pub subcommand: String,
pub positionals: Vec<String>,
pub flags: std::collections::HashMap<String, String>,
}