mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 06:12:40 +00:00
feat(generate): 'impl ArgEnum for Shell'
These keeps `FromStr` for ease of use with `value_of_t`. This includes adding test to make sure everything works as expected.
This commit is contained in:
parent
562e64c723
commit
35d53d9dcf
4 changed files with 56 additions and 49 deletions
|
@ -12,23 +12,13 @@
|
|||
//! . ./value_hints_derive.fish
|
||||
//! ./target/debug/examples/value_hints_derive --<TAB>
|
||||
//! ```
|
||||
use clap::{App, AppSettings, ArgEnum, IntoApp, Parser, ValueHint};
|
||||
use clap::{App, AppSettings, IntoApp, Parser, ValueHint};
|
||||
use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh};
|
||||
use clap_generate::{generate, Generator};
|
||||
use clap_generate::{generate, Generator, Shell};
|
||||
use std::ffi::OsString;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(ArgEnum, Debug, PartialEq, Clone)]
|
||||
enum GeneratorChoice {
|
||||
Bash,
|
||||
Elvish,
|
||||
Fish,
|
||||
#[clap(name = "powershell")]
|
||||
PowerShell,
|
||||
Zsh,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, PartialEq)]
|
||||
#[clap(
|
||||
name = "value_hints_derive",
|
||||
|
@ -38,7 +28,7 @@ enum GeneratorChoice {
|
|||
struct Opt {
|
||||
/// If provided, outputs the completion file for given shell
|
||||
#[clap(long = "generate", arg_enum)]
|
||||
generator: Option<GeneratorChoice>,
|
||||
generator: Option<Shell>,
|
||||
// Showcasing all possible ValueHints:
|
||||
#[clap(long, value_hint = ValueHint::Unknown)]
|
||||
unknown: Option<String>,
|
||||
|
@ -79,11 +69,12 @@ fn main() {
|
|||
let mut app = Opt::into_app();
|
||||
eprintln!("Generating completion file for {:?}...", generator);
|
||||
match generator {
|
||||
GeneratorChoice::Bash => print_completions::<Bash>(&mut app),
|
||||
GeneratorChoice::Elvish => print_completions::<Elvish>(&mut app),
|
||||
GeneratorChoice::Fish => print_completions::<Fish>(&mut app),
|
||||
GeneratorChoice::PowerShell => print_completions::<PowerShell>(&mut app),
|
||||
GeneratorChoice::Zsh => print_completions::<Zsh>(&mut app),
|
||||
Shell::Bash => print_completions::<Bash>(&mut app),
|
||||
Shell::Elvish => print_completions::<Elvish>(&mut app),
|
||||
Shell::Fish => print_completions::<Fish>(&mut app),
|
||||
Shell::PowerShell => print_completions::<PowerShell>(&mut app),
|
||||
Shell::Zsh => print_completions::<Zsh>(&mut app),
|
||||
_ => unimplemented!("New shell type"),
|
||||
}
|
||||
} else {
|
||||
println!("{:#?}", opt);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::{ArgEnum, ArgValue};
|
||||
|
||||
/// Shell with auto-generated completion script available.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
|
@ -17,22 +19,12 @@ pub enum Shell {
|
|||
Zsh,
|
||||
}
|
||||
|
||||
impl Shell {
|
||||
/// A list of supported shells in `[&'static str]` form.
|
||||
pub fn variants() -> [&'static str; 5] {
|
||||
["bash", "elvish", "fish", "powershell", "zsh"]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Shell {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
Shell::Bash => write!(f, "bash"),
|
||||
Shell::Elvish => write!(f, "elvish"),
|
||||
Shell::Fish => write!(f, "fish"),
|
||||
Shell::PowerShell => write!(f, "powershell"),
|
||||
Shell::Zsh => write!(f, "zsh"),
|
||||
}
|
||||
self.to_arg_value()
|
||||
.expect("no values are skipped")
|
||||
.get_name()
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,15 +32,35 @@ impl FromStr for Shell {
|
|||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"bash" => Ok(Shell::Bash),
|
||||
"elvish" => Ok(Shell::Elvish),
|
||||
"fish" => Ok(Shell::Fish),
|
||||
"powershell" => Ok(Shell::PowerShell),
|
||||
"zsh" => Ok(Shell::Zsh),
|
||||
_ => Err(String::from(
|
||||
"[valid values: bash, elvish, fish, powershell, zsh]",
|
||||
)),
|
||||
for variant in Self::value_variants() {
|
||||
if variant.to_arg_value().unwrap().matches(s, false) {
|
||||
return Ok(*variant);
|
||||
}
|
||||
}
|
||||
Err(format!("Invalid variant: {}", s))
|
||||
}
|
||||
}
|
||||
|
||||
// Hand-rolled so it can work even when `derive` feature is disabled
|
||||
impl ArgEnum for Shell {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
&[
|
||||
Shell::Bash,
|
||||
Shell::Elvish,
|
||||
Shell::Fish,
|
||||
Shell::PowerShell,
|
||||
Shell::Zsh,
|
||||
]
|
||||
}
|
||||
|
||||
fn to_arg_value<'a>(&self) -> Option<ArgValue<'a>> {
|
||||
let value = match self {
|
||||
Shell::Bash => ArgValue::new("bash"),
|
||||
Shell::Elvish => ArgValue::new("elvish"),
|
||||
Shell::Fish => ArgValue::new("fish"),
|
||||
Shell::PowerShell => ArgValue::new("powershell"),
|
||||
Shell::Zsh => ArgValue::new("zsh"),
|
||||
};
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ use std::ffi::OsString;
|
|||
/// throughout the application representing the normalized values coming from
|
||||
/// the CLI.
|
||||
///
|
||||
/// ```rust
|
||||
#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
|
||||
#[cfg_attr(feature = "derive", doc = " ```")]
|
||||
/// /// My super CLI
|
||||
/// #[derive(clap::Parser)]
|
||||
/// #[clap(name = "demo")]
|
||||
|
@ -150,7 +151,8 @@ pub trait FromArgMatches: Sized {
|
|||
/// Motivation: If our application had two CLI options, `--name
|
||||
/// <STRING>` and the flag `--debug`, we may create a struct as follows:
|
||||
///
|
||||
/// ```no_run
|
||||
#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
|
||||
#[cfg_attr(feature = "derive", doc = " ```no_run")]
|
||||
/// struct Context {
|
||||
/// name: String,
|
||||
/// debug: bool
|
||||
|
@ -160,7 +162,8 @@ pub trait FromArgMatches: Sized {
|
|||
/// We then need to convert the `ArgMatches` that `clap` generated into our struct.
|
||||
/// `from_arg_matches` serves as the equivalent of:
|
||||
///
|
||||
/// ```no_run
|
||||
#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
|
||||
#[cfg_attr(feature = "derive", doc = " ```no_run")]
|
||||
/// # use clap::ArgMatches;
|
||||
/// # struct Context {
|
||||
/// # name: String,
|
||||
|
@ -192,7 +195,8 @@ pub trait FromArgMatches: Sized {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
|
||||
#[cfg_attr(feature = "derive", doc = " ```")]
|
||||
/// #[derive(clap::Parser)]
|
||||
/// struct Args {
|
||||
/// #[clap(flatten)]
|
||||
|
@ -229,7 +233,8 @@ pub trait Args: FromArgMatches + Sized {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
|
||||
#[cfg_attr(feature = "derive", doc = " ```")]
|
||||
/// #[derive(clap::Parser)]
|
||||
/// struct Args {
|
||||
/// #[clap(subcommand)]
|
||||
|
@ -265,7 +270,8 @@ pub trait Subcommand: FromArgMatches + Sized {
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
#[cfg_attr(not(feature = "derive"), doc = " ```ignore")]
|
||||
#[cfg_attr(feature = "derive", doc = " ```")]
|
||||
/// #[derive(clap::Parser)]
|
||||
/// struct Args {
|
||||
/// #[clap(arg_enum)]
|
||||
|
|
|
@ -31,7 +31,6 @@ pub use crate::{
|
|||
parse::{ArgMatches, Indices, OsValues, Values},
|
||||
};
|
||||
|
||||
#[cfg(feature = "derive")]
|
||||
pub use crate::derive::{ArgEnum, Args, FromArgMatches, IntoApp, Parser, Subcommand};
|
||||
|
||||
#[cfg(feature = "yaml")]
|
||||
|
@ -50,7 +49,6 @@ pub use lazy_static;
|
|||
#[allow(missing_docs)]
|
||||
mod macros;
|
||||
|
||||
#[cfg(feature = "derive")]
|
||||
mod derive;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
|
|
Loading…
Reference in a new issue