#[cfg(not(feature = "std"))]
use crate::alloc_prelude::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Kind {
Flag,
Count,
Opt,
Positional,
Trailing,
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Clone, Copy, Debug)]
pub struct ArgSpec {
pub long: Option<&'static str>,
pub aliases: &'static [&'static str],
pub short: Option<char>,
pub kind: Kind,
pub required: bool,
pub multi: bool,
pub group: Option<&'static str>,
pub default: Option<&'static str>,
pub env: Option<&'static str>,
pub value_name: &'static str,
pub help: &'static str,
pub possible: Option<&'static [&'static str]>,
pub hidden: bool,
pub global: bool,
}
impl ArgSpec {
#[must_use]
pub const fn new(kind: Kind) -> Self {
Self {
long: None,
aliases: &[],
short: None,
kind,
required: false,
multi: false,
group: None,
default: None,
env: None,
value_name: "",
help: "",
possible: None,
hidden: false,
global: false,
}
}
#[must_use]
pub const fn long(mut self, long: &'static str) -> Self {
self.long = Some(long);
self
}
#[must_use]
pub const fn aliases(mut self, aliases: &'static [&'static str]) -> Self {
self.aliases = aliases;
self
}
#[must_use]
pub const fn short(mut self, short: char) -> Self {
self.short = Some(short);
self
}
#[must_use]
pub const fn required(mut self) -> Self {
self.required = true;
self
}
#[must_use]
pub const fn multi(mut self) -> Self {
self.multi = true;
self
}
#[must_use]
pub const fn group(mut self, group: &'static str) -> Self {
self.group = Some(group);
self
}
#[must_use]
pub const fn default(mut self, default: &'static str) -> Self {
self.default = Some(default);
self
}
#[must_use]
pub const fn env(mut self, env: &'static str) -> Self {
self.env = Some(env);
self
}
#[must_use]
pub const fn value_name(mut self, value_name: &'static str) -> Self {
self.value_name = value_name;
self
}
#[must_use]
pub const fn help(mut self, help: &'static str) -> Self {
self.help = help;
self
}
#[must_use]
pub const fn possible(mut self, possible: &'static [&'static str]) -> Self {
self.possible = Some(possible);
self
}
#[must_use]
pub const fn possible_opt(mut self, possible: Option<&'static [&'static str]>) -> Self {
self.possible = possible;
self
}
#[must_use]
pub const fn hidden(mut self) -> Self {
self.hidden = true;
self
}
#[must_use]
pub const fn global(mut self) -> Self {
self.global = true;
self
}
#[must_use]
pub const fn takes_value(&self) -> bool {
matches!(self.kind, Kind::Opt)
}
#[must_use]
pub const fn is_positional(&self) -> bool {
matches!(self.kind, Kind::Positional | Kind::Trailing)
}
#[must_use]
pub fn display_name(&self) -> String {
if let Some(long) = self.long {
format!("--{long}")
} else if let Some(short) = self.short {
format!("-{short}")
} else if !self.value_name.is_empty() {
format!("<{}>", self.value_name)
} else {
"<value>".to_owned()
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct GroupSpec {
pub name: &'static str,
pub required: bool,
}
impl GroupSpec {
#[must_use]
pub const fn new(name: &'static str) -> Self {
Self {
name,
required: false,
}
}
#[must_use]
pub const fn required(mut self) -> Self {
self.required = true;
self
}
}
#[derive(Clone, Copy, Debug)]
pub struct SubSpec {
pub name: &'static str,
pub aliases: &'static [&'static str],
pub about: &'static str,
pub spec: &'static CommandSpec,
pub hidden: bool,
}
#[derive(Clone, Copy, Debug)]
pub struct CommandSpec {
pub name: &'static str,
pub version: &'static str,
pub about: &'static str,
pub args: &'static [ArgSpec],
pub groups: &'static [GroupSpec],
pub conflicts: &'static [(usize, usize)],
pub subs: &'static [SubSpec],
pub sub_optional: bool,
}
impl CommandSpec {
#[must_use]
pub const fn has_subs(&self) -> bool {
!self.subs.is_empty()
}
#[must_use]
#[allow(clippy::manual_contains)]
pub fn find_long(&self, name: &str) -> Option<usize> {
self.args
.iter()
.position(|a| a.long == Some(name) || a.aliases.iter().any(|&al| al == name))
}
#[must_use]
pub fn find_short(&self, ch: char) -> Option<usize> {
self.args.iter().position(|a| a.short == Some(ch))
}
#[must_use]
#[allow(clippy::manual_contains)]
pub fn find_sub(&self, name: &str) -> Option<usize> {
self.subs
.iter()
.position(|s| s.name == name || s.aliases.iter().any(|&al| al == name))
}
}