use std::{
ffi::{OsStr, OsString},
fmt,
path::{Path, PathBuf},
};
use crate::private::{ArgumentDescImpl, ArgumentNameImpl, CommandDescImpl, CommandDescInner};
#[derive(Debug, Clone)]
pub struct CommandDesc(pub(crate) CommandDescImpl);
impl CommandDesc {
fn inner(&self) -> &'static CommandDescInner {
self.0.0
}
#[inline]
pub fn canonical_name(&self) -> &str {
self.inner().canonical_name
}
#[inline]
pub fn description(&self) -> Option<&str> {
self.inner().description
}
#[inline]
pub fn version(&self) -> Option<&str> {
self.inner().version
}
#[inline]
pub fn authors(&self) -> Option<&str> {
self.inner().authors
}
#[inline]
pub fn license(&self) -> Option<&str> {
self.inner().license
}
#[inline]
pub fn homepage(&self) -> Option<&str> {
self.inner().homepage
}
#[inline]
pub fn repository(&self) -> Option<&str> {
self.inner().repository
}
#[inline]
pub fn args(&self) -> &[ArgumentDesc] {
self.inner().args
}
#[inline]
pub fn is_subcommand_optional(&self) -> bool {
self.inner().subcommand_optional
}
#[inline]
pub fn has_subcommand_fallback(&self) -> bool {
self.inner()
.subcommands
.as_ref()
.is_some_and(|d| d.has_fallback)
}
pub fn discover_subcommands(&self) -> Vec<DiscoveredSubcommand> {
match self
.inner()
.subcommands
.as_ref()
.and_then(|d| d.discover_subcommands)
{
Some(desc) => desc(self),
None => Vec::new(),
}
}
#[inline]
pub fn subcommands(&self) -> &[SubcommandDesc] {
match self.inner().subcommands.as_ref() {
Some(desc) => desc.subcommands,
None => &[],
}
}
}
#[derive(Debug)]
pub struct SubcommandDesc(pub(crate) CommandDesc);
impl SubcommandDesc {
#[inline]
pub fn canonical_name(&self) -> &str {
self.0.canonical_name()
}
#[inline]
pub fn description(&self) -> Option<&str> {
self.0.description()
}
#[inline]
pub fn args(&self) -> &[ArgumentDesc] {
self.0.args()
}
#[inline]
pub fn subcommands(&self) -> &[SubcommandDesc] {
self.0.subcommands()
}
}
#[derive(Debug)]
pub struct DiscoveredSubcommand {
name: OsString,
description: Option<String>,
path: Option<PathBuf>,
}
impl DiscoveredSubcommand {
pub fn new(name: impl Into<OsString>) -> Self {
Self {
name: name.into(),
description: None,
path: None,
}
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn with_path(mut self, path: impl Into<PathBuf>) -> Self {
self.path = Some(path.into());
self
}
#[inline]
pub fn name(&self) -> &OsStr {
&self.name
}
#[inline]
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
#[inline]
pub fn path(&self) -> Option<&Path> {
self.path.as_deref()
}
}
#[derive(Debug)]
pub struct ArgumentDesc(pub(crate) ArgumentDescImpl);
impl ArgumentDesc {
#[inline]
pub fn is_positional(&self) -> bool {
self.short().is_none() && self.long().is_none()
}
#[inline]
pub fn is_optional(&self) -> bool {
self.0.optional
}
#[inline]
pub fn is_required(&self) -> bool {
!self.is_optional()
}
#[inline]
pub fn is_repeating(&self) -> bool {
self.0.repeating
}
#[inline]
pub fn takes_value(&self) -> bool {
self.value_name().is_some()
}
#[inline]
pub fn value_name(&self) -> Option<&str> {
self.0.name.0.value_name
}
#[inline]
pub fn description(&self) -> Option<&str> {
self.0.description
}
#[inline]
pub fn custom_default(&self) -> Option<&str> {
self.0.custom_default
}
#[inline]
pub fn short(&self) -> Option<char> {
self.0.name.0.short
}
#[inline]
pub fn long(&self) -> Option<&str> {
self.0.name.0.long
}
pub fn name(&self) -> &ArgumentName {
&self.0.name
}
}
#[derive(Debug)]
pub struct ArgumentName(pub(crate) ArgumentNameImpl);
impl fmt::Display for ArgumentName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (self.0.short, self.0.long) {
(Some(short), None) => write!(f, "-{short}"),
(None, Some(long)) => write!(f, "--{long}"),
(Some(short), Some(long)) => write!(f, "-{short}/--{long}"),
(None, None) => f.write_str(self.0.value_name.unwrap()),
}
}
}