1 use std::iter::FromIterator;
3 use proc_macro2::TokenStream;
6 use syn::spanned::Spanned;
9 parse::{Parse, ParseStream},
10 punctuated::Punctuated,
11 Attribute, Expr, Ident, LitStr, Token,
18 pub kind: Sp<AttrKind>,
20 pub magic: Option<MagicAttrName>,
21 pub value: Option<AttrValue>,
25 pub fn parse_all(all_attrs: &[Attribute]) -> Result<Vec<Self>, syn::Error> {
26 let mut parsed = Vec::new();
27 for attr in all_attrs {
28 let kind = if attr.path().is_ident("clap") {
29 Sp::new(AttrKind::Clap, attr.path().span())
30 } else if attr.path().is_ident("structopt") {
31 Sp::new(AttrKind::StructOpt, attr.path().span())
32 } else if attr.path().is_ident("command") {
33 Sp::new(AttrKind::Command, attr.path().span())
34 } else if attr.path().is_ident("group") {
35 Sp::new(AttrKind::Group, attr.path().span())
36 } else if attr.path().is_ident("arg") {
37 Sp::new(AttrKind::Arg, attr.path().span())
38 } else if attr.path().is_ident("value") {
39 Sp::new(AttrKind::Value, attr.path().span())
44 attr.parse_args_with(Punctuated::<ClapAttr, Token![,]>::parse_terminated)?
53 pub fn value_or_abort(&self) -> Result<&AttrValue, syn::Error> {
56 .ok_or_else(|| format_err!(self.name, "attribute `{}` requires a value", self.name))
59 pub fn lit_str_or_abort(&self) -> Result<&LitStr, syn::Error> {
60 let value = self.value_or_abort()?;
62 AttrValue::LitStr(tokens) => Ok(tokens),
63 AttrValue::Expr(_) | AttrValue::Call(_) => {
66 "attribute `{}` can only accept string literals",
74 impl Parse for ClapAttr {
75 fn parse(input: ParseStream) -> syn::Result<Self> {
76 let name: Ident = input.parse()?;
77 let name_str = name.to_string();
79 let magic = match name_str.as_str() {
80 "rename_all" => Some(MagicAttrName::RenameAll),
81 "rename_all_env" => Some(MagicAttrName::RenameAllEnv),
82 "skip" => Some(MagicAttrName::Skip),
83 "next_display_order" => Some(MagicAttrName::NextDisplayOrder),
84 "next_help_heading" => Some(MagicAttrName::NextHelpHeading),
85 "default_value_t" => Some(MagicAttrName::DefaultValueT),
86 "default_values_t" => Some(MagicAttrName::DefaultValuesT),
87 "default_value_os_t" => Some(MagicAttrName::DefaultValueOsT),
88 "default_values_os_t" => Some(MagicAttrName::DefaultValuesOsT),
89 "long" => Some(MagicAttrName::Long),
90 "short" => Some(MagicAttrName::Short),
91 "value_parser" => Some(MagicAttrName::ValueParser),
92 "action" => Some(MagicAttrName::Action),
93 "env" => Some(MagicAttrName::Env),
94 "flatten" => Some(MagicAttrName::Flatten),
95 "value_enum" => Some(MagicAttrName::ValueEnum),
96 "from_global" => Some(MagicAttrName::FromGlobal),
97 "subcommand" => Some(MagicAttrName::Subcommand),
98 "external_subcommand" => Some(MagicAttrName::ExternalSubcommand),
99 "verbatim_doc_comment" => Some(MagicAttrName::VerbatimDocComment),
100 "about" => Some(MagicAttrName::About),
101 "long_about" => Some(MagicAttrName::LongAbout),
102 "long_help" => Some(MagicAttrName::LongHelp),
103 "author" => Some(MagicAttrName::Author),
104 "version" => Some(MagicAttrName::Version),
108 let value = if input.peek(Token![=]) {
109 // `name = value` attributes.
110 let assign_token = input.parse::<Token![=]>()?; // skip '='
111 if input.peek(LitStr) {
112 let lit: LitStr = input.parse()?;
113 Some(AttrValue::LitStr(lit))
115 match input.parse::<Expr>() {
116 Ok(expr) => Some(AttrValue::Expr(expr)),
120 "expected `string literal` or `expression` after `=`"
124 } else if input.peek(syn::token::Paren) {
125 // `name(...)` attributes.
127 parenthesized!(nested in input);
129 let method_args: Punctuated<_, _> = nested.parse_terminated(Expr::parse, Token![,])?;
130 Some(AttrValue::Call(Vec::from_iter(method_args)))
136 kind: Sp::new(AttrKind::Clap, name.span()),
144 #[derive(Copy, Clone, PartialEq, Eq)]
145 pub enum MagicAttrName {
174 #[allow(clippy::large_enum_variant)]
181 impl ToTokens for AttrValue {
182 fn to_tokens(&self, tokens: &mut TokenStream) {
184 Self::LitStr(t) => t.to_tokens(tokens),
185 Self::Expr(t) => t.to_tokens(tokens),
187 let t = quote!(#(#t),*);
194 #[derive(Copy, Clone, PartialEq, Eq)]
205 pub fn as_str(&self) -> &'static str {
207 Self::Clap => "clap",
208 Self::StructOpt => "structopt",
209 Self::Command => "command",
210 Self::Group => "group",
212 Self::Value => "value",