#[derive(Debug, Clone, Copy)]
pub struct CommandDef {
pub name: &'static str,
pub about: &'static str,
pub aliases: &'static [&'static str],
pub args: &'static [ArgDef],
pub arg_groups: &'static [&'static [ArgDef]],
pub subcommands: &'static [CommandDef],
pub default_subcommand: Option<&'static str>,
pub trailing_var_arg: bool,
pub passthrough: bool,
}
impl CommandDef {
pub const fn new(name: &'static str) -> Self {
Self {
name,
about: "",
aliases: &[],
args: &[],
arg_groups: &[],
subcommands: &[],
default_subcommand: None,
trailing_var_arg: false,
passthrough: false,
}
}
pub fn find_subcommand(&self, name: &str) -> Option<&CommandDef> {
self
.subcommands
.iter()
.find(|cmd| cmd.name == name || cmd.aliases.contains(&name))
}
pub fn all_args(&self) -> impl Iterator<Item = &ArgDef> {
self
.args
.iter()
.chain(self.arg_groups.iter().flat_map(|g| g.iter()))
}
pub fn find_arg_long(&self, long: &str) -> Option<&ArgDef> {
self
.all_args()
.find(|a| a.long == Some(long) || a.long_aliases.contains(&long))
}
pub fn find_arg_short(&self, short: char) -> Option<&ArgDef> {
self
.all_args()
.find(|a| a.short == Some(short) || a.short_aliases.contains(&short))
}
}
#[derive(Debug, Clone, Copy)]
pub struct ArgDef {
pub name: &'static str,
pub short: Option<char>,
pub long: Option<&'static str>,
pub short_aliases: &'static [char],
pub long_aliases: &'static [&'static str],
pub help: &'static str,
pub action: ArgAction,
pub num_args: NumArgs,
pub value_delimiter: Option<char>,
pub require_equals: bool,
pub required: bool,
pub default_value: Option<&'static str>,
pub global: bool,
pub hidden: bool,
pub positional: bool,
pub trailing: bool,
pub value_name: Option<&'static str>,
}
impl ArgDef {
pub const fn new(name: &'static str) -> Self {
Self {
name,
short: None,
long: None,
short_aliases: &[],
long_aliases: &[],
help: "",
action: ArgAction::Set,
num_args: NumArgs::Exact(1),
value_delimiter: None,
require_equals: false,
required: false,
default_value: None,
global: false,
hidden: false,
positional: false,
trailing: false,
value_name: None,
}
}
pub const fn long(mut self, long: &'static str) -> Self {
self.long = Some(long);
self
}
pub const fn short(mut self, short: char) -> Self {
self.short = Some(short);
self
}
pub const fn action(mut self, action: ArgAction) -> Self {
self.action = action;
self
}
pub const fn num_args(mut self, num_args: NumArgs) -> Self {
self.num_args = num_args;
self
}
pub const fn set_true(mut self) -> Self {
self.action = ArgAction::SetTrue;
self.num_args = NumArgs::Exact(0);
self
}
pub const fn positional(mut self) -> Self {
self.positional = true;
self
}
pub const fn required(mut self) -> Self {
self.required = true;
self
}
pub const fn global(mut self) -> Self {
self.global = true;
self
}
pub const fn value_delimiter(mut self, delim: char) -> Self {
self.value_delimiter = Some(delim);
self
}
pub const fn require_equals(mut self) -> Self {
self.require_equals = true;
self
}
pub const fn hidden(mut self) -> Self {
self.hidden = true;
self
}
pub const fn default_value(mut self, val: &'static str) -> Self {
self.default_value = Some(val);
self
}
pub const fn help(mut self, help: &'static str) -> Self {
self.help = help;
self
}
pub const fn short_aliases(mut self, aliases: &'static [char]) -> Self {
self.short_aliases = aliases;
self
}
pub const fn long_aliases(
mut self,
aliases: &'static [&'static str],
) -> Self {
self.long_aliases = aliases;
self
}
pub const fn trailing(mut self) -> Self {
self.trailing = true;
self
}
pub const fn value_name(mut self, name: &'static str) -> Self {
self.value_name = Some(name);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArgAction {
SetTrue,
Set,
Append,
Count,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NumArgs {
Exact(usize),
Optional,
ZeroOrMore,
OneOrMore,
}
#[derive(Debug, Clone)]
pub struct ParseResult {
pub subcommand: Option<String>,
pub args: Vec<ParsedArg>,
pub trailing: Vec<String>,
}
impl ParseResult {
pub fn new() -> Self {
Self {
subcommand: None,
args: Vec::new(),
trailing: Vec::new(),
}
}
pub fn get_bool(&self, name: &str) -> bool {
self.args.iter().any(|a| a.name == name && a.is_present)
}
pub fn get_one(&self, name: &str) -> Option<&str> {
self
.args
.iter()
.find(|a| a.name == name)
.and_then(|a| a.values.first())
.map(|s| s.as_str())
}
pub fn get_many(&self, name: &str) -> Option<&[String]> {
self
.args
.iter()
.find(|a| a.name == name)
.filter(|a| a.is_present)
.map(|a| a.values.as_slice())
}
pub fn contains(&self, name: &str) -> bool {
self.args.iter().any(|a| a.name == name && a.is_present)
}
pub fn get_count(&self, name: &str) -> usize {
self
.args
.iter()
.find(|a| a.name == name)
.map(|a| a.count)
.unwrap_or(0)
}
}
impl Default for ParseResult {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ParsedArg {
pub name: &'static str,
pub values: Vec<String>,
pub is_present: bool,
pub count: usize,
}
impl ParsedArg {
pub fn new(name: &'static str) -> Self {
Self {
name,
values: Vec::new(),
is_present: false,
count: 0,
}
}
}