allow for documentation to be placed on subcommands

This commit is contained in:
William Yao 2017-07-04 16:59:27 -05:00 committed by Guillaume P
parent 3772285091
commit 91fb4a40e4
3 changed files with 65 additions and 5 deletions

40
examples/git.rs Normal file
View file

@ -0,0 +1,40 @@
//! `git.rs` serves as a demonstration of how to use subcommands,
//! as well as a demonstration of adding documentation to subcommands.
//! Documentation can be added either through doc comments or the
//! `about` attribute.
extern crate structopt;
#[macro_use] extern crate structopt_derive;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "git")]
/// the stupid content tracker
enum Opt {
#[structopt(name = "fetch")]
/// fetch branches from remote repository
Fetch {
#[structopt(long = "dry-run")]
dry_run: bool,
#[structopt(long = "all")]
all: bool,
#[structopt(default_value = "origin")]
repository: String
},
#[structopt(name = "add")]
/// add files to the staging area
Add {
#[structopt(short = "i")]
interactive: bool,
#[structopt(short = "a")]
all: bool,
files: Vec<String>
}
}
fn main() {
let matches = Opt::from_args();
println!("{:?}", matches);
}

View file

@ -537,10 +537,14 @@ fn gen_augment_clap_enum(variants: &[Variant]) -> quote::Tokens {
VariantData::Struct(ref fields) => gen_augmentation(fields, &app_var),
_ => unreachable!()
};
let from_attr = extract_attrs(&variant.attrs, AttrSource::Struct)
.filter(|&(ref i, _)| i != "name")
.map(|(i, l)| quote!( .#i(#l) ));
quote! {
.subcommand({
let #app_var = _structopt::clap::SubCommand::with_name( #name );
let #app_var = _structopt::clap::SubCommand::with_name( #name )
#( #from_attr )* ;
#arg_block
})
}
@ -567,11 +571,11 @@ fn gen_from_subcommand(name: &Ident, variants: &[Variant]) -> quote::Tokens {
let sub_name = extract_attrs(&variant.attrs, AttrSource::Struct)
.filter_map(|attr| match attr {
(ref i, Lit::Str(ref s, ..)) if i == "name" =>
Some(Ident::new(s as &str)),
Some(s.to_string()),
_ => None
})
.next()
.unwrap_or_else(|| variant.ident.clone());
.unwrap_or_else(|| variant.ident.as_ref().to_string());
let variant_name = &variant.ident;
let constructor_block = match variant.data {
VariantData::Struct(ref fields) => gen_constructor(fields),
@ -579,7 +583,7 @@ fn gen_from_subcommand(name: &Ident, variants: &[Variant]) -> quote::Tokens {
};
quote! {
(stringify!(#sub_name), Some(matches)) =>
(#sub_name, Some(matches)) =>
Some(#name :: #variant_name #constructor_block)
}
});

View file

@ -12,7 +12,7 @@ use structopt::StructOpt;
#[derive(StructOpt, PartialEq, Debug)]
enum Opt {
#[structopt(name = "fetch")]
#[structopt(name = "fetch", about = "Fetch stuff from GitHub.")]
Fetch {
#[structopt(long = "all")]
all: bool,
@ -55,3 +55,19 @@ fn test_no_parse() {
let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badoption"]);
assert!(result.is_err());
}
#[derive(StructOpt, PartialEq, Debug)]
enum Opt2 {
#[structopt(name = "do-something")]
DoSomething {
arg: String
}
}
#[test]
/// This test is specifically to make sure that hyphenated subcommands get
/// processed correctly.
fn test_hyphenated_subcommands() {
assert_eq!(Opt2::DoSomething { arg: "blah".to_string() },
Opt2::from_clap(Opt2::clap().get_matches_from(&["test", "do-something", "blah"])));
}