1use std::iter::FromIterator;
2
3use proc_macro2::TokenStream;
4use quote::ToTokens;
5use quote::quote;
6use syn::spanned::Spanned;
7use syn::{
8 Attribute, Expr, Ident, LitStr, Token, parenthesized,
9 parse::{Parse, ParseStream},
10 punctuated::Punctuated,
11};
12
13use crate::utils::Sp;
14
15#[derive(#[automatically_derived]
impl ::core::clone::Clone for ClapAttr {
#[inline]
fn clone(&self) -> ClapAttr {
ClapAttr {
kind: ::core::clone::Clone::clone(&self.kind),
name: ::core::clone::Clone::clone(&self.name),
magic: ::core::clone::Clone::clone(&self.magic),
value: ::core::clone::Clone::clone(&self.value),
}
}
}Clone)]
16pub(crate) struct ClapAttr {
17 pub(crate) kind: Sp<AttrKind>,
18 pub(crate) name: Ident,
19 pub(crate) magic: Option<MagicAttrName>,
20 pub(crate) value: Option<AttrValue>,
21}
22
23impl ClapAttr {
24 pub(crate) fn parse_all(all_attrs: &[Attribute]) -> Result<Vec<Self>, syn::Error> {
25 let mut parsed = Vec::new();
26 for attr in all_attrs {
27 let kind = if attr.path().is_ident("clap") {
28 Sp::new(AttrKind::Clap, attr.path().span())
29 } else if attr.path().is_ident("structopt") {
30 Sp::new(AttrKind::StructOpt, attr.path().span())
31 } else if attr.path().is_ident("command") {
32 Sp::new(AttrKind::Command, attr.path().span())
33 } else if attr.path().is_ident("group") {
34 Sp::new(AttrKind::Group, attr.path().span())
35 } else if attr.path().is_ident("arg") {
36 Sp::new(AttrKind::Arg, attr.path().span())
37 } else if attr.path().is_ident("value") {
38 Sp::new(AttrKind::Value, attr.path().span())
39 } else {
40 continue;
41 };
42 for mut attr in
43 attr.parse_args_with(Punctuated::<ClapAttr, ::syn::token::CommaToken![,]>::parse_terminated)?
44 {
45 attr.kind = kind;
46 parsed.push(attr);
47 }
48 }
49 Ok(parsed)
50 }
51
52 pub(crate) fn value_or_abort(&self) -> Result<&AttrValue, syn::Error> {
53 self.value
54 .as_ref()
55 .ok_or_else(|| {
#[allow(unused_imports)]
use crate::utils::error::*;
let msg =
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("attribute `{0}` requires a value",
self.name))
});
self.name.EXPECTED_Span_OR_ToTokens(msg)
}format_err!(self.name, "attribute `{}` requires a value", self.name))
56 }
57
58 pub(crate) fn lit_str_or_abort(&self) -> Result<&LitStr, syn::Error> {
59 let value = self.value_or_abort()?;
60 match value {
61 AttrValue::LitStr(tokens) => Ok(tokens),
62 AttrValue::Expr(_) | AttrValue::Call(_) => {
63 {
return Err({
#[allow(unused_imports)]
use crate::utils::error::*;
let msg =
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("attribute `{0}` can only accept string literals",
self.name))
});
self.name.EXPECTED_Span_OR_ToTokens(msg)
});
}abort!(
64 self.name,
65 "attribute `{}` can only accept string literals",
66 self.name
67 )
68 }
69 }
70 }
71}
72
73impl Parse for ClapAttr {
74 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
75 let name: Ident = input.parse()?;
76 let name_str = name.to_string();
77
78 let magic = match name_str.as_str() {
79 "rename_all" => Some(MagicAttrName::RenameAll),
80 "rename_all_env" => Some(MagicAttrName::RenameAllEnv),
81 "skip" => Some(MagicAttrName::Skip),
82 "next_display_order" => Some(MagicAttrName::NextDisplayOrder),
83 "next_help_heading" => Some(MagicAttrName::NextHelpHeading),
84 "default_value_t" => Some(MagicAttrName::DefaultValueT),
85 "default_values_t" => Some(MagicAttrName::DefaultValuesT),
86 "default_value_os_t" => Some(MagicAttrName::DefaultValueOsT),
87 "default_values_os_t" => Some(MagicAttrName::DefaultValuesOsT),
88 "long" => Some(MagicAttrName::Long),
89 "short" => Some(MagicAttrName::Short),
90 "value_parser" => Some(MagicAttrName::ValueParser),
91 "action" => Some(MagicAttrName::Action),
92 "env" => Some(MagicAttrName::Env),
93 "flatten" => Some(MagicAttrName::Flatten),
94 "value_enum" => Some(MagicAttrName::ValueEnum),
95 "from_global" => Some(MagicAttrName::FromGlobal),
96 "subcommand" => Some(MagicAttrName::Subcommand),
97 "external_subcommand" => Some(MagicAttrName::ExternalSubcommand),
98 "verbatim_doc_comment" => Some(MagicAttrName::VerbatimDocComment),
99 "about" => Some(MagicAttrName::About),
100 "long_about" => Some(MagicAttrName::LongAbout),
101 "long_help" => Some(MagicAttrName::LongHelp),
102 "author" => Some(MagicAttrName::Author),
103 "version" => Some(MagicAttrName::Version),
104 _ => None,
105 };
106
107 let value = if input.peek(::syn::token::EqToken![=]) {
108 let assign_token = input.parse::<::syn::token::EqToken![=]>()?; if input.peek(LitStr) {
111 let lit: LitStr = input.parse()?;
112 Some(AttrValue::LitStr(lit))
113 } else {
114 match input.parse::<Expr>() {
115 Ok(expr) => Some(AttrValue::Expr(expr)),
116
117 Err(_) => {
return Err({
#[allow(unused_imports)]
use crate::utils::error::*;
let msg =
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `string literal` or `expression` after `=`"))
});
assign_token.EXPECTED_Span_OR_ToTokens(msg)
});
}abort! {
118 assign_token,
119 "expected `string literal` or `expression` after `=`"
120 },
121 }
122 }
123 } else if input.peek(syn::token::Paren) {
124 let nested;
126 match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => {
nested = parens.content;
_ = nested;
parens.token
}
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};parenthesized!(nested in input);
127
128 let method_args: Punctuated<_, _> = nested.parse_terminated(Expr::parse, ::syn::token::CommaToken![,])?;
129 Some(AttrValue::Call(Vec::from_iter(method_args)))
130 } else {
131 None
132 };
133
134 Ok(Self {
135 kind: Sp::new(AttrKind::Clap, name.span()),
136 name,
137 magic,
138 value,
139 })
140 }
141}
142
143#[derive(#[automatically_derived]
impl ::core::marker::Copy for MagicAttrName { }Copy, #[automatically_derived]
impl ::core::clone::Clone for MagicAttrName {
#[inline]
fn clone(&self) -> MagicAttrName { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for MagicAttrName {
#[inline]
fn eq(&self, other: &MagicAttrName) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for MagicAttrName {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
144pub(crate) enum MagicAttrName {
145 Short,
146 Long,
147 ValueParser,
148 Action,
149 Env,
150 Flatten,
151 ValueEnum,
152 FromGlobal,
153 Subcommand,
154 VerbatimDocComment,
155 ExternalSubcommand,
156 About,
157 LongAbout,
158 LongHelp,
159 Author,
160 Version,
161 RenameAllEnv,
162 RenameAll,
163 Skip,
164 DefaultValueT,
165 DefaultValuesT,
166 DefaultValueOsT,
167 DefaultValuesOsT,
168 NextDisplayOrder,
169 NextHelpHeading,
170}
171
172#[derive(#[automatically_derived]
#[allow(clippy::large_enum_variant)]
impl ::core::clone::Clone for AttrValue {
#[inline]
fn clone(&self) -> AttrValue {
match self {
AttrValue::LitStr(__self_0) =>
AttrValue::LitStr(::core::clone::Clone::clone(__self_0)),
AttrValue::Expr(__self_0) =>
AttrValue::Expr(::core::clone::Clone::clone(__self_0)),
AttrValue::Call(__self_0) =>
AttrValue::Call(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
173#[allow(clippy::large_enum_variant)]
174pub(crate) enum AttrValue {
175 LitStr(LitStr),
176 Expr(Expr),
177 Call(Vec<Expr>),
178}
179
180impl ToTokens for AttrValue {
181 fn to_tokens(&self, tokens: &mut TokenStream) {
182 match self {
183 Self::LitStr(t) => t.to_tokens(tokens),
184 Self::Expr(t) => t.to_tokens(tokens),
185 Self::Call(t) => {
186 let t = {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let mut _first = true;
let has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut t, i) = t.quote_into_iter();
let has_iter = has_iter | i;
<_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let t =
match t.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
if !_first { ::quote::__private::push_comma(&mut _s); }
_first = false;
::quote::ToTokens::to_tokens(&t, &mut _s);
}
}
_s
}quote!(#(#t),*);
187 t.to_tokens(tokens);
188 }
189 }
190 }
191}
192
193#[derive(#[automatically_derived]
impl ::core::marker::Copy for AttrKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for AttrKind {
#[inline]
fn clone(&self) -> AttrKind { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for AttrKind {
#[inline]
fn eq(&self, other: &AttrKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for AttrKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
194pub(crate) enum AttrKind {
195 Clap,
196 StructOpt,
197 Command,
198 Group,
199 Arg,
200 Value,
201}
202
203impl AttrKind {
204 pub(crate) fn as_str(&self) -> &'static str {
205 match self {
206 Self::Clap => "clap",
207 Self::StructOpt => "structopt",
208 Self::Command => "command",
209 Self::Group => "group",
210 Self::Arg => "arg",
211 Self::Value => "value",
212 }
213 }
214}