mirror of
https://github.com/clap-rs/clap
synced 2024-11-10 14:54:15 +00:00
Allow separate derives, but do not give examples
This commit is contained in:
parent
ddaa371d0c
commit
fe52d77f4e
12 changed files with 158 additions and 59 deletions
|
@ -10,16 +10,37 @@
|
|||
|
||||
use crate::{
|
||||
attrs::{Attrs, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
|
||||
dummies,
|
||||
utils::Sp,
|
||||
};
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, DataEnum, Ident, Variant,
|
||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataEnum, DeriveInput,
|
||||
Fields, Ident, Variant,
|
||||
};
|
||||
|
||||
pub fn derive_arg_enum(input: &DeriveInput) -> TokenStream {
|
||||
let ident = &input.ident;
|
||||
|
||||
dummies::arg_enum(ident);
|
||||
|
||||
match input.data {
|
||||
Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
|
||||
_ => abort_call_site!("`#[derive(ArgEnum)]` only supports enums"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
|
||||
if !e.variants.iter().all(|v| match v.fields {
|
||||
Fields::Unit => true,
|
||||
_ => false,
|
||||
}) {
|
||||
return quote!();
|
||||
};
|
||||
|
||||
let attrs = Attrs::from_struct(
|
||||
Span::call_site(),
|
||||
attrs,
|
||||
|
|
|
@ -13,40 +13,37 @@
|
|||
// MIT/Apache 2.0 license.
|
||||
|
||||
use crate::{
|
||||
derives::{arg_enum, from_argmatches, into_app, subcommand},
|
||||
derives::{arg_enum, from_arg_matches, into_app, subcommand},
|
||||
dummies,
|
||||
};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro_error::abort_call_site;
|
||||
use quote::quote;
|
||||
use syn::{self, punctuated, token, Attribute, DataEnum, DeriveInput, Field, Ident};
|
||||
use syn::{
|
||||
self, punctuated::Punctuated, token::Comma, Attribute, Data, DataEnum, DataStruct, DeriveInput,
|
||||
Field, Fields, Ident,
|
||||
};
|
||||
|
||||
pub fn derive_clap(input: &DeriveInput) -> TokenStream {
|
||||
use syn::Data::*;
|
||||
|
||||
let ident = &input.ident;
|
||||
|
||||
match input.data {
|
||||
Struct(syn::DataStruct {
|
||||
fields: syn::Fields::Named(ref fields),
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(ref fields),
|
||||
..
|
||||
}) => {
|
||||
dummies::clap_struct(ident);
|
||||
gen_for_struct(ident, &fields.named, &input.attrs)
|
||||
}
|
||||
Struct(syn::DataStruct {
|
||||
fields: syn::Fields::Unit,
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Unit,
|
||||
..
|
||||
}) => {
|
||||
dummies::clap_struct(ident);
|
||||
gen_for_struct(
|
||||
ident,
|
||||
&punctuated::Punctuated::<Field, token::Comma>::new(),
|
||||
&input.attrs,
|
||||
)
|
||||
gen_for_struct(ident, &Punctuated::<Field, Comma>::new(), &input.attrs)
|
||||
}
|
||||
Enum(ref e) => {
|
||||
Data::Enum(ref e) => {
|
||||
dummies::clap_enum(ident);
|
||||
gen_for_enum(ident, &input.attrs, e)
|
||||
}
|
||||
|
@ -56,11 +53,11 @@ pub fn derive_clap(input: &DeriveInput) -> TokenStream {
|
|||
|
||||
fn gen_for_struct(
|
||||
name: &Ident,
|
||||
fields: &punctuated::Punctuated<Field, token::Comma>,
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
attrs: &[Attribute],
|
||||
) -> TokenStream {
|
||||
let (into_app, attrs) = into_app::gen_for_struct(name, fields, attrs);
|
||||
let from_arg_matches = from_argmatches::gen_for_struct(name, fields, &attrs);
|
||||
let from_arg_matches = from_arg_matches::gen_for_struct(name, fields, &attrs);
|
||||
|
||||
quote! {
|
||||
impl ::clap::Clap for #name {}
|
||||
|
@ -72,20 +69,12 @@ fn gen_for_struct(
|
|||
|
||||
fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
|
||||
let into_app = into_app::gen_for_enum(name);
|
||||
let from_arg_matches = from_argmatches::gen_for_enum(name);
|
||||
let from_arg_matches = from_arg_matches::gen_for_enum(name);
|
||||
let subcommand = subcommand::gen_for_enum(name, attrs, e);
|
||||
|
||||
let arg_enum = if e.variants.iter().all(|v| match v.fields {
|
||||
syn::Fields::Unit => true,
|
||||
_ => false,
|
||||
}) {
|
||||
arg_enum::gen_for_enum(name, attrs, e)
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
let arg_enum = arg_enum::gen_for_enum(name, attrs, e);
|
||||
|
||||
quote! {
|
||||
impl ::clap::Clap for #name { }
|
||||
impl ::clap::Clap for #name {}
|
||||
|
||||
#into_app
|
||||
#from_arg_matches
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use proc_macro_error::abort;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, Field, Ident, Token, Type};
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Field, Ident, Type};
|
||||
|
||||
use crate::{
|
||||
attrs::{Attrs, Kind, ParserKind},
|
||||
|
@ -23,7 +23,7 @@ use crate::{
|
|||
|
||||
pub fn gen_for_struct(
|
||||
struct_name: &Ident,
|
||||
fields: &Punctuated<Field, Token![,]>,
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
parent_attribute: &Attrs,
|
||||
) -> TokenStream {
|
||||
let constructor = gen_constructor(fields, parent_attribute);
|
||||
|
@ -81,10 +81,7 @@ fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn gen_constructor(
|
||||
fields: &Punctuated<Field, Token![,]>,
|
||||
parent_attribute: &Attrs,
|
||||
) -> TokenStream {
|
||||
pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
||||
let fields = fields.iter().map(|field| {
|
||||
let attrs = Attrs::from_field(
|
||||
field,
|
|
@ -14,19 +14,42 @@
|
|||
|
||||
use std::env;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro_error::abort;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use proc_macro_error::{abort, abort_call_site};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, Attribute, Field, Ident, Token, Type};
|
||||
use syn::{
|
||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataStruct,
|
||||
DeriveInput, Field, Fields, Ident, Type,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
attrs::{Attrs, GenOutput, Kind, Name, ParserKind, DEFAULT_CASING, DEFAULT_ENV_CASING},
|
||||
dummies,
|
||||
utils::{sub_type, subty_if_name, Sp, Ty},
|
||||
};
|
||||
|
||||
pub fn derive_into_app(input: &DeriveInput) -> TokenStream {
|
||||
let ident = &input.ident;
|
||||
|
||||
dummies::into_app(ident);
|
||||
|
||||
match input.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(ref fields),
|
||||
..
|
||||
}) => gen_for_struct(ident, &fields.named, &input.attrs).0,
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Unit,
|
||||
..
|
||||
}) => gen_for_struct(ident, &Punctuated::<Field, Comma>::new(), &input.attrs).0,
|
||||
Data::Enum(_) => gen_for_enum(ident),
|
||||
_ => abort_call_site!("`#[derive(IntoApp)]` only supports non-tuple structs and enums"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_for_struct(
|
||||
struct_name: &Ident,
|
||||
fields: &Punctuated<Field, Token![,]>,
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
attrs: &[Attribute],
|
||||
) -> GenOutput {
|
||||
let (into_app, attrs) = gen_into_app_fn(attrs);
|
||||
|
@ -88,7 +111,7 @@ fn gen_into_app_fn(attrs: &[Attribute]) -> GenOutput {
|
|||
let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
|
||||
|
||||
let attrs = Attrs::from_struct(
|
||||
proc_macro2::Span::call_site(),
|
||||
Span::call_site(),
|
||||
attrs,
|
||||
Name::Assigned(quote!(#app_name)),
|
||||
Sp::call_site(DEFAULT_CASING),
|
||||
|
@ -105,11 +128,8 @@ fn gen_into_app_fn(attrs: &[Attribute]) -> GenOutput {
|
|||
(tokens, attrs)
|
||||
}
|
||||
|
||||
fn gen_augment_clap_fn(
|
||||
fields: &Punctuated<Field, Token![,]>,
|
||||
parent_attribute: &Attrs,
|
||||
) -> TokenStream {
|
||||
let app_var = Ident::new("app", proc_macro2::Span::call_site());
|
||||
fn gen_augment_clap_fn(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
|
||||
let app_var = Ident::new("app", Span::call_site());
|
||||
let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute);
|
||||
quote! {
|
||||
fn augment_clap<'b>(#app_var: ::clap::App<'b>) -> ::clap::App<'b> {
|
||||
|
@ -127,7 +147,7 @@ fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream {
|
|||
/// Generate a block of code to add arguments/subcommands corresponding to
|
||||
/// the `fields` to an app.
|
||||
pub fn gen_app_augmentation(
|
||||
fields: &Punctuated<Field, Token![,]>,
|
||||
fields: &Punctuated<Field, Comma>,
|
||||
app_var: &Ident,
|
||||
parent_attribute: &Attrs,
|
||||
) -> TokenStream {
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
// MIT/Apache 2.0 license.
|
||||
mod arg_enum;
|
||||
mod clap;
|
||||
mod from_argmatches;
|
||||
mod from_arg_matches;
|
||||
mod into_app;
|
||||
mod subcommand;
|
||||
|
||||
pub use self::clap::derive_clap;
|
||||
pub use arg_enum::derive_arg_enum;
|
||||
// pub use from_arg_matches::derive_from_arg_matches;
|
||||
pub use into_app::derive_into_app;
|
||||
pub use subcommand::derive_subcommand;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
|
||||
derives::{from_argmatches, into_app},
|
||||
derives::{from_arg_matches, into_app},
|
||||
dummies,
|
||||
utils::{is_simple_ty, subty_if_name, Sp},
|
||||
};
|
||||
|
||||
|
@ -8,9 +9,21 @@ use proc_macro2::{Ident, Span, TokenStream};
|
|||
use proc_macro_error::{abort, abort_call_site};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{
|
||||
punctuated::Punctuated, spanned::Spanned, Attribute, DataEnum, FieldsUnnamed, Token, Variant,
|
||||
punctuated::Punctuated, spanned::Spanned, Attribute, Data, DataEnum, DeriveInput,
|
||||
FieldsUnnamed, Token, Variant,
|
||||
};
|
||||
|
||||
pub fn derive_subcommand(input: &DeriveInput) -> TokenStream {
|
||||
let ident = &input.ident;
|
||||
|
||||
dummies::subcommand(ident);
|
||||
|
||||
match input.data {
|
||||
Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
|
||||
_ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
|
||||
let attrs = Attrs::from_struct(
|
||||
Span::call_site(),
|
||||
|
@ -209,7 +222,7 @@ fn gen_from_subcommand(
|
|||
let sub_name = attrs.cased_name();
|
||||
let variant_name = &variant.ident;
|
||||
let constructor_block = match variant.fields {
|
||||
Named(ref fields) => from_argmatches::gen_constructor(&fields.named, &attrs),
|
||||
Named(ref fields) => from_arg_matches::gen_constructor(&fields.named, &attrs),
|
||||
Unit => quote!(),
|
||||
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
||||
let ty = &fields.unnamed[0];
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro_error::proc_macro_error;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
mod attrs;
|
||||
mod derives;
|
||||
|
@ -26,17 +28,42 @@ mod dummies;
|
|||
mod parse;
|
||||
mod utils;
|
||||
|
||||
// /// It is required to have this seperate and specificly defined.
|
||||
// #[proc_macro_derive(ArgEnum, attributes(case_sensitive))]
|
||||
// pub fn arg_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
// let input: syn::DeriveInput = syn::parse(input).unwrap();
|
||||
// derives::derive_arg_enum(&input).into()
|
||||
// }
|
||||
/// Generates the `ArgEnum` impl.
|
||||
#[proc_macro_derive(ArgEnum, attributes(clap))]
|
||||
#[proc_macro_error]
|
||||
pub fn arg_enum(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = parse_macro_input!(input);
|
||||
derives::derive_arg_enum(&input).into()
|
||||
}
|
||||
|
||||
/// Generates the `Clap` impl.
|
||||
#[proc_macro_derive(Clap, attributes(clap))]
|
||||
#[proc_macro_error]
|
||||
pub fn clap(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input: syn::DeriveInput = syn::parse_macro_input!(input);
|
||||
pub fn clap(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = parse_macro_input!(input);
|
||||
derives::derive_clap(&input).into()
|
||||
}
|
||||
|
||||
// /// Generates the `FromArgMatches` impl.
|
||||
// #[proc_macro_derive(FromArgMatches, attributes(clap))]
|
||||
// #[proc_macro_error]
|
||||
// pub fn from_arg_matches(input: TokenStream) -> TokenStream {
|
||||
// let input: DeriveInput = parse_macro_input!(input);
|
||||
// derives::derive_from_arg_matches(&input).into()
|
||||
// }
|
||||
|
||||
/// Generates the `IntoApp` impl.
|
||||
#[proc_macro_derive(IntoApp, attributes(clap))]
|
||||
#[proc_macro_error]
|
||||
pub fn into_app(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = parse_macro_input!(input);
|
||||
derives::derive_into_app(&input).into()
|
||||
}
|
||||
|
||||
/// Generates the `Subcommand` impl.
|
||||
#[proc_macro_derive(Subcommand, attributes(clap))]
|
||||
#[proc_macro_error]
|
||||
pub fn subcommand(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = parse_macro_input!(input);
|
||||
derives::derive_subcommand(&input).into()
|
||||
}
|
||||
|
|
8
clap_derive/tests/ui/arg_enum_on_struct.rs
Normal file
8
clap_derive/tests/ui/arg_enum_on_struct.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use clap::ArgEnum;
|
||||
|
||||
#[derive(ArgEnum, Debug)]
|
||||
struct Opt {}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", Opt::VARIANTS);
|
||||
}
|
7
clap_derive/tests/ui/arg_enum_on_struct.stderr
Normal file
7
clap_derive/tests/ui/arg_enum_on_struct.stderr
Normal file
|
@ -0,0 +1,7 @@
|
|||
error: `#[derive(ArgEnum)]` only supports enums
|
||||
--> $DIR/arg_enum_on_struct.rs:3:10
|
||||
|
|
||||
3 | #[derive(ArgEnum, Debug)]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
6
clap_derive/tests/ui/subcommand_on_struct.rs
Normal file
6
clap_derive/tests/ui/subcommand_on_struct.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
use clap::Subcommand;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
struct Opt {}
|
||||
|
||||
fn main() {}
|
7
clap_derive/tests/ui/subcommand_on_struct.stderr
Normal file
7
clap_derive/tests/ui/subcommand_on_struct.stderr
Normal file
|
@ -0,0 +1,7 @@
|
|||
error: `#[derive(Subcommand)]` only supports enums
|
||||
--> $DIR/subcommand_on_struct.rs:3:10
|
||||
|
|
||||
3 | #[derive(Subcommand, Debug)]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
@ -41,9 +41,9 @@ pub use lazy_static;
|
|||
|
||||
#[macro_use]
|
||||
#[allow(missing_docs)]
|
||||
pub mod macros;
|
||||
mod macros;
|
||||
|
||||
pub mod derive;
|
||||
mod derive;
|
||||
|
||||
mod build;
|
||||
mod mkeymap;
|
||||
|
|
Loading…
Reference in a new issue