• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
2 // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
3 // Ana Hobden (@hoverbear) <operator@hoverbear.org>
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 //
11 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13 // MIT/Apache 2.0 license.
14 
15 use std::env;
16 
17 use heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
18 use proc_macro2::{self, Span, TokenStream};
19 use proc_macro_error::abort;
20 use quote::{format_ident, quote, quote_spanned, ToTokens};
21 use syn::DeriveInput;
22 use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Field, Ident, LitStr, Type, Variant};
23 
24 use crate::attr::*;
25 use crate::utils::{extract_doc_comment, format_doc_comment, inner_type, is_simple_ty, Sp, Ty};
26 
27 /// Default casing style for generated arguments.
28 pub const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
29 
30 /// Default casing style for environment variables
31 pub const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
32 
33 #[derive(Clone)]
34 pub struct Item {
35     name: Name,
36     ident: Ident,
37     casing: Sp<CasingStyle>,
38     env_casing: Sp<CasingStyle>,
39     ty: Option<Type>,
40     doc_comment: Vec<Method>,
41     methods: Vec<Method>,
42     deprecations: Vec<Deprecation>,
43     value_parser: Option<ValueParser>,
44     action: Option<Action>,
45     verbatim_doc_comment: bool,
46     force_long_help: bool,
47     next_display_order: Option<Method>,
48     next_help_heading: Option<Method>,
49     is_enum: bool,
50     is_positional: bool,
51     skip_group: bool,
52     kind: Sp<Kind>,
53 }
54 
55 impl Item {
from_args_struct(input: &DeriveInput, name: Name) -> Self56     pub fn from_args_struct(input: &DeriveInput, name: Name) -> Self {
57         let ident = input.ident.clone();
58         let span = input.ident.span();
59         let attrs = &input.attrs;
60         let argument_casing = Sp::new(DEFAULT_CASING, span);
61         let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
62         let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
63 
64         let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
65         let parsed_attrs = ClapAttr::parse_all(attrs);
66         res.infer_kind(&parsed_attrs);
67         res.push_attrs(&parsed_attrs);
68         res.push_doc_comment(attrs, "about", Some("long_about"));
69 
70         res
71     }
72 
from_subcommand_enum(input: &DeriveInput, name: Name) -> Self73     pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Self {
74         let ident = input.ident.clone();
75         let span = input.ident.span();
76         let attrs = &input.attrs;
77         let argument_casing = Sp::new(DEFAULT_CASING, span);
78         let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
79         let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
80 
81         let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
82         let parsed_attrs = ClapAttr::parse_all(attrs);
83         res.infer_kind(&parsed_attrs);
84         res.push_attrs(&parsed_attrs);
85         res.push_doc_comment(attrs, "about", Some("long_about"));
86 
87         res
88     }
89 
from_value_enum(input: &DeriveInput, name: Name) -> Self90     pub fn from_value_enum(input: &DeriveInput, name: Name) -> Self {
91         let ident = input.ident.clone();
92         let span = input.ident.span();
93         let attrs = &input.attrs;
94         let argument_casing = Sp::new(DEFAULT_CASING, span);
95         let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
96         let kind = Sp::new(Kind::Value, span);
97 
98         let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
99         let parsed_attrs = ClapAttr::parse_all(attrs);
100         res.infer_kind(&parsed_attrs);
101         res.push_attrs(&parsed_attrs);
102         // Ignoring `push_doc_comment` as there is no top-level clap builder to add documentation
103         // to
104 
105         if res.has_explicit_methods() {
106             abort!(
107                 res.methods[0].name.span(),
108                 "{} doesn't exist for `ValueEnum` enums",
109                 res.methods[0].name
110             );
111         }
112 
113         res
114     }
115 
from_subcommand_variant( variant: &Variant, struct_casing: Sp<CasingStyle>, env_casing: Sp<CasingStyle>, ) -> Self116     pub fn from_subcommand_variant(
117         variant: &Variant,
118         struct_casing: Sp<CasingStyle>,
119         env_casing: Sp<CasingStyle>,
120     ) -> Self {
121         let name = variant.ident.clone();
122         let ident = variant.ident.clone();
123         let span = variant.span();
124         let ty = match variant.fields {
125             syn::Fields::Unnamed(syn::FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
126                 Ty::from_syn_ty(&unnamed[0].ty)
127             }
128             syn::Fields::Named(_) | syn::Fields::Unnamed(..) | syn::Fields::Unit => {
129                 Sp::new(Ty::Other, span)
130             }
131         };
132         let kind = Sp::new(Kind::Command(ty), span);
133         let mut res = Self::new(
134             Name::Derived(name),
135             ident,
136             None,
137             struct_casing,
138             env_casing,
139             kind,
140         );
141         let parsed_attrs = ClapAttr::parse_all(&variant.attrs);
142         res.infer_kind(&parsed_attrs);
143         res.push_attrs(&parsed_attrs);
144         if matches!(&*res.kind, Kind::Command(_) | Kind::Subcommand(_)) {
145             res.push_doc_comment(&variant.attrs, "about", Some("long_about"));
146         }
147 
148         match &*res.kind {
149             Kind::Flatten(_) => {
150                 if res.has_explicit_methods() {
151                     abort!(
152                         res.kind.span(),
153                         "methods are not allowed for flattened entry"
154                     );
155                 }
156             }
157 
158             Kind::Subcommand(_)
159             | Kind::ExternalSubcommand
160             | Kind::FromGlobal(_)
161             | Kind::Skip(_, _)
162             | Kind::Command(_)
163             | Kind::Value
164             | Kind::Arg(_) => (),
165         }
166 
167         res
168     }
169 
from_value_enum_variant( variant: &Variant, argument_casing: Sp<CasingStyle>, env_casing: Sp<CasingStyle>, ) -> Self170     pub fn from_value_enum_variant(
171         variant: &Variant,
172         argument_casing: Sp<CasingStyle>,
173         env_casing: Sp<CasingStyle>,
174     ) -> Self {
175         let ident = variant.ident.clone();
176         let span = variant.span();
177         let kind = Sp::new(Kind::Value, span);
178         let mut res = Self::new(
179             Name::Derived(variant.ident.clone()),
180             ident,
181             None,
182             argument_casing,
183             env_casing,
184             kind,
185         );
186         let parsed_attrs = ClapAttr::parse_all(&variant.attrs);
187         res.infer_kind(&parsed_attrs);
188         res.push_attrs(&parsed_attrs);
189         if matches!(&*res.kind, Kind::Value) {
190             res.push_doc_comment(&variant.attrs, "help", None);
191         }
192 
193         res
194     }
195 
from_args_field( field: &Field, struct_casing: Sp<CasingStyle>, env_casing: Sp<CasingStyle>, ) -> Self196     pub fn from_args_field(
197         field: &Field,
198         struct_casing: Sp<CasingStyle>,
199         env_casing: Sp<CasingStyle>,
200     ) -> Self {
201         let name = field.ident.clone().unwrap();
202         let ident = field.ident.clone().unwrap();
203         let span = field.span();
204         let ty = Ty::from_syn_ty(&field.ty);
205         let kind = Sp::new(Kind::Arg(ty), span);
206         let mut res = Self::new(
207             Name::Derived(name),
208             ident,
209             Some(field.ty.clone()),
210             struct_casing,
211             env_casing,
212             kind,
213         );
214         let parsed_attrs = ClapAttr::parse_all(&field.attrs);
215         res.infer_kind(&parsed_attrs);
216         res.push_attrs(&parsed_attrs);
217         if matches!(&*res.kind, Kind::Arg(_)) {
218             res.push_doc_comment(&field.attrs, "help", Some("long_help"));
219         }
220 
221         match &*res.kind {
222             Kind::Flatten(_) => {
223                 if res.has_explicit_methods() {
224                     abort!(
225                         res.kind.span(),
226                         "methods are not allowed for flattened entry"
227                     );
228                 }
229             }
230 
231             Kind::Subcommand(_) => {
232                 if res.has_explicit_methods() {
233                     abort!(
234                         res.kind.span(),
235                         "methods in attributes are not allowed for subcommand"
236                     );
237                 }
238             }
239             Kind::Skip(_, _)
240             | Kind::FromGlobal(_)
241             | Kind::Arg(_)
242             | Kind::Command(_)
243             | Kind::Value
244             | Kind::ExternalSubcommand => {}
245         }
246 
247         res
248     }
249 
new( name: Name, ident: Ident, ty: Option<Type>, casing: Sp<CasingStyle>, env_casing: Sp<CasingStyle>, kind: Sp<Kind>, ) -> Self250     fn new(
251         name: Name,
252         ident: Ident,
253         ty: Option<Type>,
254         casing: Sp<CasingStyle>,
255         env_casing: Sp<CasingStyle>,
256         kind: Sp<Kind>,
257     ) -> Self {
258         Self {
259             name,
260             ident,
261             ty,
262             casing,
263             env_casing,
264             doc_comment: vec![],
265             methods: vec![],
266             deprecations: vec![],
267             value_parser: None,
268             action: None,
269             verbatim_doc_comment: false,
270             force_long_help: false,
271             next_display_order: None,
272             next_help_heading: None,
273             is_enum: false,
274             is_positional: true,
275             skip_group: false,
276             kind,
277         }
278     }
279 
push_method(&mut self, kind: AttrKind, name: Ident, arg: impl ToTokens)280     fn push_method(&mut self, kind: AttrKind, name: Ident, arg: impl ToTokens) {
281         if name == "id" {
282             match kind {
283                 AttrKind::Command | AttrKind::Value => {
284                     self.deprecations.push(Deprecation {
285                         span: name.span(),
286                         id: "id_is_only_for_arg",
287                         version: "4.0.0",
288                         description: format!(
289                             "`#[{}(id)] was allowed by mistake, instead use `#[{}(name)]`",
290                             kind.as_str(),
291                             kind.as_str()
292                         ),
293                     });
294                 }
295                 AttrKind::Group | AttrKind::Arg | AttrKind::Clap | AttrKind::StructOpt => {}
296             }
297             self.name = Name::Assigned(quote!(#arg));
298         } else if name == "name" {
299             match kind {
300                 AttrKind::Arg => {
301                     self.deprecations.push(Deprecation {
302                         span: name.span(),
303                         id: "id_is_only_for_arg",
304                         version: "4.0.0",
305                         description: format!(
306                             "`#[{}(name)] was allowed by mistake, instead use `#[{}(id)]` or `#[{}(value_name)]`",
307                             kind.as_str(),
308                             kind.as_str(),
309                             kind.as_str()
310                         ),
311                     });
312                 }
313                 AttrKind::Group
314                 | AttrKind::Command
315                 | AttrKind::Value
316                 | AttrKind::Clap
317                 | AttrKind::StructOpt => {}
318             }
319             self.name = Name::Assigned(quote!(#arg));
320         } else if name == "value_parser" {
321             self.value_parser = Some(ValueParser::Explicit(Method::new(name, quote!(#arg))));
322         } else if name == "action" {
323             self.action = Some(Action::Explicit(Method::new(name, quote!(#arg))));
324         } else {
325             if name == "short" || name == "long" {
326                 self.is_positional = false;
327             }
328             self.methods.push(Method::new(name, quote!(#arg)));
329         }
330     }
331 
infer_kind(&mut self, attrs: &[ClapAttr])332     fn infer_kind(&mut self, attrs: &[ClapAttr]) {
333         for attr in attrs {
334             if let Some(AttrValue::Call(_)) = &attr.value {
335                 continue;
336             }
337 
338             let actual_attr_kind = *attr.kind.get();
339             let kind = match &attr.magic {
340                 Some(MagicAttrName::FromGlobal) => {
341                     if attr.value.is_some() {
342                         let expr = attr.value_or_abort();
343                         abort!(expr, "attribute `{}` does not accept a value", attr.name);
344                     }
345                     let ty = self
346                         .kind()
347                         .ty()
348                         .cloned()
349                         .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
350                     let kind = Sp::new(Kind::FromGlobal(ty), attr.name.clone().span());
351                     Some(kind)
352                 }
353                 Some(MagicAttrName::Subcommand) if attr.value.is_none() => {
354                     if attr.value.is_some() {
355                         let expr = attr.value_or_abort();
356                         abort!(expr, "attribute `{}` does not accept a value", attr.name);
357                     }
358                     let ty = self
359                         .kind()
360                         .ty()
361                         .cloned()
362                         .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
363                     let kind = Sp::new(Kind::Subcommand(ty), attr.name.clone().span());
364                     Some(kind)
365                 }
366                 Some(MagicAttrName::ExternalSubcommand) if attr.value.is_none() => {
367                     if attr.value.is_some() {
368                         let expr = attr.value_or_abort();
369                         abort!(expr, "attribute `{}` does not accept a value", attr.name);
370                     }
371                     let kind = Sp::new(Kind::ExternalSubcommand, attr.name.clone().span());
372                     Some(kind)
373                 }
374                 Some(MagicAttrName::Flatten) if attr.value.is_none() => {
375                     if attr.value.is_some() {
376                         let expr = attr.value_or_abort();
377                         abort!(expr, "attribute `{}` does not accept a value", attr.name);
378                     }
379                     let ty = self
380                         .kind()
381                         .ty()
382                         .cloned()
383                         .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
384                     let kind = Sp::new(Kind::Flatten(ty), attr.name.clone().span());
385                     Some(kind)
386                 }
387                 Some(MagicAttrName::Skip) if actual_attr_kind != AttrKind::Group => {
388                     let expr = attr.value.clone();
389                     let kind = Sp::new(
390                         Kind::Skip(expr, self.kind.attr_kind()),
391                         attr.name.clone().span(),
392                     );
393                     Some(kind)
394                 }
395                 _ => None,
396             };
397 
398             if let Some(kind) = kind {
399                 self.set_kind(kind);
400             }
401         }
402     }
403 
push_attrs(&mut self, attrs: &[ClapAttr])404     fn push_attrs(&mut self, attrs: &[ClapAttr]) {
405         for attr in attrs {
406             let actual_attr_kind = *attr.kind.get();
407             let expected_attr_kind = self.kind.attr_kind();
408             match (actual_attr_kind, expected_attr_kind) {
409                 (AttrKind::Clap, _) | (AttrKind::StructOpt, _) => {
410                     self.deprecations.push(Deprecation::attribute(
411                         "4.0.0",
412                         actual_attr_kind,
413                         expected_attr_kind,
414                         attr.kind.span(),
415                     ));
416                 }
417 
418                 (AttrKind::Group, AttrKind::Command) => {}
419 
420                 _ if attr.kind != expected_attr_kind => {
421                     abort!(
422                         attr.kind.span(),
423                         "Expected `{}` attribute instead of `{}`",
424                         expected_attr_kind.as_str(),
425                         actual_attr_kind.as_str()
426                     );
427                 }
428 
429                 _ => {}
430             }
431 
432             if let Some(AttrValue::Call(tokens)) = &attr.value {
433                 // Force raw mode with method call syntax
434                 self.push_method(*attr.kind.get(), attr.name.clone(), quote!(#(#tokens),*));
435                 continue;
436             }
437 
438             match &attr.magic {
439                 Some(MagicAttrName::Short) if attr.value.is_none() => {
440                     assert_attr_kind(attr, &[AttrKind::Arg]);
441 
442                     self.push_method(
443                         *attr.kind.get(),
444                         attr.name.clone(),
445                         self.name.clone().translate_char(*self.casing),
446                     );
447                 }
448 
449                 Some(MagicAttrName::Long) if attr.value.is_none() => {
450                     assert_attr_kind(attr, &[AttrKind::Arg]);
451 
452                     self.push_method(*attr.kind.get(), attr.name.clone(), self.name.clone().translate(*self.casing));
453                 }
454 
455                 Some(MagicAttrName::ValueParser) if attr.value.is_none() => {
456                     assert_attr_kind(attr, &[AttrKind::Arg]);
457 
458                     self.deprecations.push(Deprecation {
459                         span: attr.name.span(),
460                         id: "bare_value_parser",
461                         version: "4.0.0",
462                         description: "`#[arg(value_parser)]` is now the default and is no longer needed`".to_owned(),
463                     });
464                     self.value_parser = Some(ValueParser::Implicit(attr.name.clone()));
465                 }
466 
467                 Some(MagicAttrName::Action) if attr.value.is_none() => {
468                     assert_attr_kind(attr, &[AttrKind::Arg]);
469 
470                     self.deprecations.push(Deprecation {
471                         span: attr.name.span(),
472                         id: "bare_action",
473                         version: "4.0.0",
474                         description: "`#[arg(action)]` is now the default and is no longer needed`".to_owned(),
475                     });
476                     self.action = Some(Action::Implicit(attr.name.clone()));
477                 }
478 
479                 Some(MagicAttrName::Env) if attr.value.is_none() => {
480                     assert_attr_kind(attr, &[AttrKind::Arg]);
481 
482                     self.push_method(
483                         *attr.kind.get(),
484                         attr.name.clone(),
485                         self.name.clone().translate(*self.env_casing),
486                     );
487                 }
488 
489                 Some(MagicAttrName::ValueEnum) if attr.value.is_none() => {
490                     assert_attr_kind(attr, &[AttrKind::Arg]);
491 
492                     self.is_enum = true
493                 }
494 
495                 Some(MagicAttrName::VerbatimDocComment) if attr.value.is_none() => {
496                     self.verbatim_doc_comment = true
497                 }
498 
499                 Some(MagicAttrName::About) if attr.value.is_none() => {
500                     assert_attr_kind(attr, &[AttrKind::Command]);
501 
502                     if let Some(method) =
503                         Method::from_env(attr.name.clone(), "CARGO_PKG_DESCRIPTION")
504                     {
505                         self.methods.push(method);
506                     }
507                 }
508 
509                 Some(MagicAttrName::LongAbout) if attr.value.is_none() => {
510                     assert_attr_kind(attr, &[AttrKind::Command]);
511 
512                     self.force_long_help = true;
513                 }
514 
515                 Some(MagicAttrName::LongHelp) if attr.value.is_none() => {
516                     assert_attr_kind(attr, &[AttrKind::Arg]);
517 
518                     self.force_long_help = true;
519                 }
520 
521                 Some(MagicAttrName::Author) if attr.value.is_none() => {
522                     assert_attr_kind(attr, &[AttrKind::Command]);
523 
524                     if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_AUTHORS") {
525                         self.methods.push(method);
526                     }
527                 }
528 
529                 Some(MagicAttrName::Version) if attr.value.is_none() => {
530                     assert_attr_kind(attr, &[AttrKind::Command]);
531 
532                     if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_VERSION") {
533                         self.methods.push(method);
534                     }
535                 }
536 
537                 Some(MagicAttrName::DefaultValueT) => {
538                     assert_attr_kind(attr, &[AttrKind::Arg]);
539 
540                     let ty = if let Some(ty) = self.ty.as_ref() {
541                         ty
542                     } else {
543                         abort!(
544                             attr.name.clone(),
545                             "#[arg(default_value_t)] (without an argument) can be used \
546                             only on field level";
547 
548                             note = "see \
549                                 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
550                     };
551 
552                     let val = if let Some(expr) = &attr.value {
553                         quote!(#expr)
554                     } else {
555                         quote!(<#ty as ::std::default::Default>::default())
556                     };
557 
558                     let val = if attrs
559                         .iter()
560                         .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
561                     {
562                         quote_spanned!(attr.name.clone().span()=> {
563                             static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<String> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
564                                 let val: #ty = #val;
565                                 clap::ValueEnum::to_possible_value(&val).unwrap().get_name().to_owned()
566                             });
567                             let s: &'static str = &*DEFAULT_VALUE;
568                             s
569                         })
570                     } else {
571                         quote_spanned!(attr.name.clone().span()=> {
572                             static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<String> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
573                                 let val: #ty = #val;
574                                 ::std::string::ToString::to_string(&val)
575                             });
576                             let s: &'static str = &*DEFAULT_VALUE;
577                             s
578                         })
579                     };
580 
581                     let raw_ident = Ident::new("default_value", attr.name.clone().span());
582                     self.methods.push(Method::new(raw_ident, val));
583                 }
584 
585                 Some(MagicAttrName::DefaultValuesT) => {
586                     assert_attr_kind(attr, &[AttrKind::Arg]);
587 
588                     let ty = if let Some(ty) = self.ty.as_ref() {
589                         ty
590                     } else {
591                         abort!(
592                             attr.name.clone(),
593                             "#[arg(default_values_t)] (without an argument) can be used \
594                             only on field level";
595 
596                             note = "see \
597                                 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
598                     };
599                     let expr = attr.value_or_abort();
600 
601                     let container_type = Ty::from_syn_ty(ty);
602                     if *container_type != Ty::Vec {
603                         abort!(
604                             attr.name.clone(),
605                             "#[arg(default_values_t)] can be used only on Vec types";
606 
607                             note = "see \
608                                 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
609                     }
610                     let inner_type = inner_type(ty);
611 
612                     // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and
613                     // `Vec<#inner_type>`.
614                     let val = if attrs
615                         .iter()
616                         .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
617                     {
618                         quote_spanned!(attr.name.clone().span()=> {
619                             {
620                                 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=String>
621                                 where
622                                     T: ::std::borrow::Borrow<#inner_type>
623                                 {
624                                     iterable
625                                         .into_iter()
626                                         .map(|val| {
627                                             clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name().to_owned()
628                                         })
629                                 }
630 
631                                 static DEFAULT_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::string::String>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
632                                     iter_to_vals(#expr).collect()
633                                 });
634 
635                                 static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&str>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
636                                     DEFAULT_STRINGS.iter().map(::std::string::String::as_str).collect()
637                                 });
638                                 DEFAULT_VALUES.iter().copied()
639                             }
640                         })
641                     } else {
642                         quote_spanned!(attr.name.clone().span()=> {
643                             {
644                                 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=String>
645                                 where
646                                     T: ::std::borrow::Borrow<#inner_type>
647                                 {
648                                     iterable.into_iter().map(|val| val.borrow().to_string())
649                                 }
650 
651                                 static DEFAULT_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::string::String>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
652                                     iter_to_vals(#expr).collect()
653                                 });
654 
655                                 static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&str>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
656                                     DEFAULT_STRINGS.iter().map(::std::string::String::as_str).collect()
657                                 });
658                                 DEFAULT_VALUES.iter().copied()
659                             }
660                         })
661                     };
662 
663                     self.methods.push(Method::new(
664                         Ident::new("default_values", attr.name.clone().span()),
665                         val,
666                     ));
667                 }
668 
669                 Some(MagicAttrName::DefaultValueOsT) => {
670                     assert_attr_kind(attr, &[AttrKind::Arg]);
671 
672                     let ty = if let Some(ty) = self.ty.as_ref() {
673                         ty
674                     } else {
675                         abort!(
676                             attr.name.clone(),
677                             "#[arg(default_value_os_t)] (without an argument) can be used \
678                             only on field level";
679 
680                             note = "see \
681                                 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
682                     };
683 
684                     let val = if let Some(expr) = &attr.value {
685                         quote!(#expr)
686                     } else {
687                         quote!(<#ty as ::std::default::Default>::default())
688                     };
689 
690                     let val = if attrs
691                         .iter()
692                         .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
693                     {
694                         quote_spanned!(attr.name.clone().span()=> {
695                             static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<::std::ffi::OsString> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
696                                 let val: #ty = #val;
697                                 clap::ValueEnum::to_possible_value(&val).unwrap().get_name().to_owned()
698                             });
699                             let s: &'static ::std::ffi::OsStr = &*DEFAULT_VALUE;
700                             s
701                         })
702                     } else {
703                         quote_spanned!(attr.name.clone().span()=> {
704                             static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<::std::ffi::OsString> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
705                                 let val: #ty = #val;
706                                 ::std::ffi::OsString::from(val)
707                             });
708                             let s: &'static ::std::ffi::OsStr = &*DEFAULT_VALUE;
709                             s
710                         })
711                     };
712 
713                     let raw_ident = Ident::new("default_value", attr.name.clone().span());
714                     self.methods.push(Method::new(raw_ident, val));
715                 }
716 
717                 Some(MagicAttrName::DefaultValuesOsT) => {
718                     assert_attr_kind(attr, &[AttrKind::Arg]);
719 
720                     let ty = if let Some(ty) = self.ty.as_ref() {
721                         ty
722                     } else {
723                         abort!(
724                             attr.name.clone(),
725                             "#[arg(default_values_os_t)] (without an argument) can be used \
726                             only on field level";
727 
728                             note = "see \
729                                 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
730                     };
731                     let expr = attr.value_or_abort();
732 
733                     let container_type = Ty::from_syn_ty(ty);
734                     if *container_type != Ty::Vec {
735                         abort!(
736                             attr.name.clone(),
737                             "#[arg(default_values_os_t)] can be used only on Vec types";
738 
739                             note = "see \
740                                 https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
741                     }
742                     let inner_type = inner_type(ty);
743 
744                     // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and
745                     // `Vec<#inner_type>`.
746                     let val = if attrs
747                         .iter()
748                         .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
749                     {
750                         quote_spanned!(attr.name.clone().span()=> {
751                             {
752                                 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=::std::ffi::OsString>
753                                 where
754                                     T: ::std::borrow::Borrow<#inner_type>
755                                 {
756                                     iterable
757                                         .into_iter()
758                                         .map(|val| {
759                                             clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name().to_owned().into()
760                                         })
761                                 }
762 
763                                 static DEFAULT_OS_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::ffi::OsString>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
764                                     iter_to_vals(#expr).collect()
765                                 });
766 
767                                 static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&::std::ffi::OsStr>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
768                                     DEFAULT_OS_STRINGS.iter().map(::std::ffi::OsString::as_os_str).collect()
769                                 });
770                                 DEFAULT_VALUES.iter().copied()
771                             }
772                         })
773                     } else {
774                         quote_spanned!(attr.name.clone().span()=> {
775                             {
776                                 fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=::std::ffi::OsString>
777                                 where
778                                     T: ::std::borrow::Borrow<#inner_type>
779                                 {
780                                     iterable.into_iter().map(|val| val.borrow().into())
781                                 }
782 
783                                 static DEFAULT_OS_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::ffi::OsString>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
784                                     iter_to_vals(#expr).collect()
785                                 });
786 
787                                 static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&::std::ffi::OsStr>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
788                                     DEFAULT_OS_STRINGS.iter().map(::std::ffi::OsString::as_os_str).collect()
789                                 });
790                                 DEFAULT_VALUES.iter().copied()
791                             }
792                         })
793                     };
794 
795                     self.methods.push(Method::new(
796                         Ident::new("default_values", attr.name.clone().span()),
797                         val,
798                     ));
799                 }
800 
801                 Some(MagicAttrName::NextDisplayOrder) => {
802                     assert_attr_kind(attr, &[AttrKind::Command]);
803 
804                     let expr = attr.value_or_abort();
805                     self.next_display_order = Some(Method::new(attr.name.clone(), quote!(#expr)));
806                 }
807 
808                 Some(MagicAttrName::NextHelpHeading) => {
809                     assert_attr_kind(attr, &[AttrKind::Command]);
810 
811                     let expr = attr.value_or_abort();
812                     self.next_help_heading = Some(Method::new(attr.name.clone(), quote!(#expr)));
813                 }
814 
815                 Some(MagicAttrName::RenameAll) => {
816                     let lit = attr.lit_str_or_abort();
817                     self.casing = CasingStyle::from_lit(lit);
818                 }
819 
820                 Some(MagicAttrName::RenameAllEnv) => {
821                     assert_attr_kind(attr, &[AttrKind::Command, AttrKind::Arg]);
822 
823                     let lit = attr.lit_str_or_abort();
824                     self.env_casing = CasingStyle::from_lit(lit);
825                 }
826 
827                 Some(MagicAttrName::Skip) if actual_attr_kind == AttrKind::Group => {
828                     self.skip_group = true;
829                 }
830 
831                 None
832                 // Magic only for the default, otherwise just forward to the builder
833                 | Some(MagicAttrName::Short)
834                 | Some(MagicAttrName::Long)
835                 | Some(MagicAttrName::Env)
836                 | Some(MagicAttrName::About)
837                 | Some(MagicAttrName::LongAbout)
838                 | Some(MagicAttrName::LongHelp)
839                 | Some(MagicAttrName::Author)
840                 | Some(MagicAttrName::Version)
841                  => {
842                     let expr = attr.value_or_abort();
843                     self.push_method(*attr.kind.get(), attr.name.clone(), expr);
844                 }
845 
846                 // Magic only for the default, otherwise just forward to the builder
847                 Some(MagicAttrName::ValueParser) | Some(MagicAttrName::Action) => {
848                     let expr = attr.value_or_abort();
849                     self.push_method(*attr.kind.get(), attr.name.clone(), expr);
850                 }
851 
852                 // Directives that never receive a value
853                 Some(MagicAttrName::ValueEnum)
854                 | Some(MagicAttrName::VerbatimDocComment) => {
855                     let expr = attr.value_or_abort();
856                     abort!(expr, "attribute `{}` does not accept a value", attr.name);
857                 }
858 
859                 // Kinds
860                 Some(MagicAttrName::FromGlobal)
861                 | Some(MagicAttrName::Subcommand)
862                 | Some(MagicAttrName::ExternalSubcommand)
863                 | Some(MagicAttrName::Flatten)
864                 | Some(MagicAttrName::Skip) => {
865                 }
866             }
867         }
868 
869         if self.has_explicit_methods() {
870             if let Kind::Skip(_, attr) = &*self.kind {
871                 abort!(
872                     self.methods[0].name.span(),
873                     "`{}` cannot be used with `#[{}(skip)]",
874                     self.methods[0].name,
875                     attr.as_str(),
876                 );
877             }
878             if let Kind::FromGlobal(_) = &*self.kind {
879                 abort!(
880                     self.methods[0].name.span(),
881                     "`{}` cannot be used with `#[arg(from_global)]",
882                     self.methods[0].name,
883                 );
884             }
885         }
886     }
887 
push_doc_comment(&mut self, attrs: &[Attribute], short_name: &str, long_name: Option<&str>)888     fn push_doc_comment(&mut self, attrs: &[Attribute], short_name: &str, long_name: Option<&str>) {
889         let lines = extract_doc_comment(attrs);
890 
891         if !lines.is_empty() {
892             let (short_help, long_help) =
893                 format_doc_comment(&lines, !self.verbatim_doc_comment, self.force_long_help);
894             let short_name = format_ident!("{}", short_name);
895             let short = Method::new(
896                 short_name,
897                 short_help
898                     .map(|h| quote!(#h))
899                     .unwrap_or_else(|| quote!(None)),
900             );
901             self.doc_comment.push(short);
902             if let Some(long_name) = long_name {
903                 let long_name = format_ident!("{}", long_name);
904                 let long = Method::new(
905                     long_name,
906                     long_help
907                         .map(|h| quote!(#h))
908                         .unwrap_or_else(|| quote!(None)),
909                 );
910                 self.doc_comment.push(long);
911             }
912         }
913     }
914 
set_kind(&mut self, kind: Sp<Kind>)915     fn set_kind(&mut self, kind: Sp<Kind>) {
916         match (self.kind.get(), kind.get()) {
917             (Kind::Arg(_), Kind::FromGlobal(_))
918             | (Kind::Arg(_), Kind::Subcommand(_))
919             | (Kind::Arg(_), Kind::Flatten(_))
920             | (Kind::Arg(_), Kind::Skip(_, _))
921             | (Kind::Command(_), Kind::Subcommand(_))
922             | (Kind::Command(_), Kind::Flatten(_))
923             | (Kind::Command(_), Kind::Skip(_, _))
924             | (Kind::Command(_), Kind::ExternalSubcommand)
925             | (Kind::Value, Kind::Skip(_, _)) => {
926                 self.kind = kind;
927             }
928 
929             (_, _) => {
930                 let old = self.kind.name();
931                 let new = kind.name();
932                 abort!(kind.span(), "`{}` cannot be used with `{}`", new, old);
933             }
934         }
935     }
936 
find_default_method(&self) -> Option<&Method>937     pub fn find_default_method(&self) -> Option<&Method> {
938         self.methods
939             .iter()
940             .find(|m| m.name == "default_value" || m.name == "default_value_os")
941     }
942 
943     /// generate methods from attributes on top of struct or enum
initial_top_level_methods(&self) -> TokenStream944     pub fn initial_top_level_methods(&self) -> TokenStream {
945         let next_display_order = self.next_display_order.as_ref().into_iter();
946         let next_help_heading = self.next_help_heading.as_ref().into_iter();
947         quote!(
948             #(#next_display_order)*
949             #(#next_help_heading)*
950         )
951     }
952 
final_top_level_methods(&self) -> TokenStream953     pub fn final_top_level_methods(&self) -> TokenStream {
954         let methods = &self.methods;
955         let doc_comment = &self.doc_comment;
956 
957         quote!( #(#doc_comment)* #(#methods)*)
958     }
959 
960     /// generate methods on top of a field
field_methods(&self) -> proc_macro2::TokenStream961     pub fn field_methods(&self) -> proc_macro2::TokenStream {
962         let methods = &self.methods;
963         let doc_comment = &self.doc_comment;
964         quote!( #(#doc_comment)* #(#methods)* )
965     }
966 
deprecations(&self) -> proc_macro2::TokenStream967     pub fn deprecations(&self) -> proc_macro2::TokenStream {
968         let deprecations = &self.deprecations;
969         quote!( #(#deprecations)* )
970     }
971 
next_display_order(&self) -> TokenStream972     pub fn next_display_order(&self) -> TokenStream {
973         let next_display_order = self.next_display_order.as_ref().into_iter();
974         quote!( #(#next_display_order)* )
975     }
976 
next_help_heading(&self) -> TokenStream977     pub fn next_help_heading(&self) -> TokenStream {
978         let next_help_heading = self.next_help_heading.as_ref().into_iter();
979         quote!( #(#next_help_heading)* )
980     }
981 
ident(&self) -> &Ident982     pub fn ident(&self) -> &Ident {
983         &self.ident
984     }
985 
id(&self) -> TokenStream986     pub fn id(&self) -> TokenStream {
987         self.name.clone().raw()
988     }
989 
cased_name(&self) -> TokenStream990     pub fn cased_name(&self) -> TokenStream {
991         self.name.clone().translate(*self.casing)
992     }
993 
value_name(&self) -> TokenStream994     pub fn value_name(&self) -> TokenStream {
995         self.name.clone().translate(CasingStyle::ScreamingSnake)
996     }
997 
value_parser(&self, field_type: &Type) -> Method998     pub fn value_parser(&self, field_type: &Type) -> Method {
999         self.value_parser
1000             .clone()
1001             .map(|p| {
1002                 let inner_type = inner_type(field_type);
1003                 p.resolve(inner_type)
1004             })
1005             .unwrap_or_else(|| {
1006                 let inner_type = inner_type(field_type);
1007                 if let Some(action) = self.action.as_ref() {
1008                     let span = action.span();
1009                     default_value_parser(inner_type, span)
1010                 } else {
1011                     let span = self
1012                         .action
1013                         .as_ref()
1014                         .map(|a| a.span())
1015                         .unwrap_or_else(|| self.kind.span());
1016                     default_value_parser(inner_type, span)
1017                 }
1018             })
1019     }
1020 
action(&self, field_type: &Type) -> Method1021     pub fn action(&self, field_type: &Type) -> Method {
1022         self.action
1023             .clone()
1024             .map(|p| p.resolve(field_type))
1025             .unwrap_or_else(|| {
1026                 if let Some(value_parser) = self.value_parser.as_ref() {
1027                     let span = value_parser.span();
1028                     default_action(field_type, span)
1029                 } else {
1030                     let span = self
1031                         .value_parser
1032                         .as_ref()
1033                         .map(|a| a.span())
1034                         .unwrap_or_else(|| self.kind.span());
1035                     default_action(field_type, span)
1036                 }
1037             })
1038     }
1039 
kind(&self) -> Sp<Kind>1040     pub fn kind(&self) -> Sp<Kind> {
1041         self.kind.clone()
1042     }
1043 
is_positional(&self) -> bool1044     pub fn is_positional(&self) -> bool {
1045         self.is_positional
1046     }
1047 
casing(&self) -> Sp<CasingStyle>1048     pub fn casing(&self) -> Sp<CasingStyle> {
1049         self.casing
1050     }
1051 
env_casing(&self) -> Sp<CasingStyle>1052     pub fn env_casing(&self) -> Sp<CasingStyle> {
1053         self.env_casing
1054     }
1055 
has_explicit_methods(&self) -> bool1056     pub fn has_explicit_methods(&self) -> bool {
1057         self.methods
1058             .iter()
1059             .any(|m| m.name != "help" && m.name != "long_help")
1060     }
1061 
skip_group(&self) -> bool1062     pub fn skip_group(&self) -> bool {
1063         self.skip_group
1064     }
1065 }
1066 
1067 #[derive(Clone)]
1068 enum ValueParser {
1069     Explicit(Method),
1070     Implicit(Ident),
1071 }
1072 
1073 impl ValueParser {
resolve(self, _inner_type: &Type) -> Method1074     fn resolve(self, _inner_type: &Type) -> Method {
1075         match self {
1076             Self::Explicit(method) => method,
1077             Self::Implicit(ident) => default_value_parser(_inner_type, ident.span()),
1078         }
1079     }
1080 
span(&self) -> Span1081     fn span(&self) -> Span {
1082         match self {
1083             Self::Explicit(method) => method.name.span(),
1084             Self::Implicit(ident) => ident.span(),
1085         }
1086     }
1087 }
1088 
default_value_parser(inner_type: &Type, span: Span) -> Method1089 fn default_value_parser(inner_type: &Type, span: Span) -> Method {
1090     let func = Ident::new("value_parser", span);
1091     Method::new(
1092         func,
1093         quote_spanned! { span=>
1094             clap::value_parser!(#inner_type)
1095         },
1096     )
1097 }
1098 
1099 #[derive(Clone)]
1100 pub enum Action {
1101     Explicit(Method),
1102     Implicit(Ident),
1103 }
1104 
1105 impl Action {
resolve(self, _field_type: &Type) -> Method1106     pub fn resolve(self, _field_type: &Type) -> Method {
1107         match self {
1108             Self::Explicit(method) => method,
1109             Self::Implicit(ident) => default_action(_field_type, ident.span()),
1110         }
1111     }
1112 
span(&self) -> Span1113     pub fn span(&self) -> Span {
1114         match self {
1115             Self::Explicit(method) => method.name.span(),
1116             Self::Implicit(ident) => ident.span(),
1117         }
1118     }
1119 }
1120 
default_action(field_type: &Type, span: Span) -> Method1121 fn default_action(field_type: &Type, span: Span) -> Method {
1122     let ty = Ty::from_syn_ty(field_type);
1123     let args = match *ty {
1124         Ty::Vec | Ty::OptionVec | Ty::VecVec | Ty::OptionVecVec => {
1125             quote_spanned! { span=>
1126                 clap::ArgAction::Append
1127             }
1128         }
1129         Ty::Option | Ty::OptionOption => {
1130             quote_spanned! { span=>
1131                 clap::ArgAction::Set
1132             }
1133         }
1134         _ => {
1135             if is_simple_ty(field_type, "bool") {
1136                 quote_spanned! { span=>
1137                     clap::ArgAction::SetTrue
1138                 }
1139             } else {
1140                 quote_spanned! { span=>
1141                     clap::ArgAction::Set
1142                 }
1143             }
1144         }
1145     };
1146 
1147     let func = Ident::new("action", span);
1148     Method::new(func, args)
1149 }
1150 
1151 #[allow(clippy::large_enum_variant)]
1152 #[derive(Clone)]
1153 pub enum Kind {
1154     Arg(Sp<Ty>),
1155     Command(Sp<Ty>),
1156     Value,
1157     FromGlobal(Sp<Ty>),
1158     Subcommand(Sp<Ty>),
1159     Flatten(Sp<Ty>),
1160     Skip(Option<AttrValue>, AttrKind),
1161     ExternalSubcommand,
1162 }
1163 
1164 impl Kind {
name(&self) -> &'static str1165     pub fn name(&self) -> &'static str {
1166         match self {
1167             Self::Arg(_) => "arg",
1168             Self::Command(_) => "command",
1169             Self::Value => "value",
1170             Self::FromGlobal(_) => "from_global",
1171             Self::Subcommand(_) => "subcommand",
1172             Self::Flatten(_) => "flatten",
1173             Self::Skip(_, _) => "skip",
1174             Self::ExternalSubcommand => "external_subcommand",
1175         }
1176     }
1177 
attr_kind(&self) -> AttrKind1178     pub fn attr_kind(&self) -> AttrKind {
1179         match self {
1180             Self::Arg(_) => AttrKind::Arg,
1181             Self::Command(_) => AttrKind::Command,
1182             Self::Value => AttrKind::Value,
1183             Self::FromGlobal(_) => AttrKind::Arg,
1184             Self::Subcommand(_) => AttrKind::Command,
1185             Self::Flatten(_) => AttrKind::Command,
1186             Self::Skip(_, kind) => *kind,
1187             Self::ExternalSubcommand => AttrKind::Command,
1188         }
1189     }
1190 
ty(&self) -> Option<&Sp<Ty>>1191     pub fn ty(&self) -> Option<&Sp<Ty>> {
1192         match self {
1193             Self::Arg(ty)
1194             | Self::Command(ty)
1195             | Self::Flatten(ty)
1196             | Self::FromGlobal(ty)
1197             | Self::Subcommand(ty) => Some(ty),
1198             Self::Value | Self::Skip(_, _) | Self::ExternalSubcommand => None,
1199         }
1200     }
1201 }
1202 
1203 #[derive(Clone)]
1204 pub struct Method {
1205     name: Ident,
1206     args: TokenStream,
1207 }
1208 
1209 impl Method {
new(name: Ident, args: TokenStream) -> Self1210     pub fn new(name: Ident, args: TokenStream) -> Self {
1211         Method { name, args }
1212     }
1213 
from_env(ident: Ident, env_var: &str) -> Option<Self>1214     fn from_env(ident: Ident, env_var: &str) -> Option<Self> {
1215         let mut lit = match env::var(env_var) {
1216             Ok(val) => {
1217                 if val.is_empty() {
1218                     return None;
1219                 }
1220                 LitStr::new(&val, ident.span())
1221             }
1222             Err(_) => {
1223                 abort!(ident,
1224                     "cannot derive `{}` from Cargo.toml", ident;
1225                     note = "`{}` environment variable is not set", env_var;
1226                     help = "use `{} = \"...\"` to set {} manually", ident, ident;
1227                 );
1228             }
1229         };
1230 
1231         if ident == "author" {
1232             let edited = process_author_str(&lit.value());
1233             lit = LitStr::new(&edited, lit.span());
1234         }
1235 
1236         Some(Method::new(ident, quote!(#lit)))
1237     }
1238 
args(&self) -> &TokenStream1239     pub(crate) fn args(&self) -> &TokenStream {
1240         &self.args
1241     }
1242 }
1243 
1244 impl ToTokens for Method {
to_tokens(&self, ts: &mut proc_macro2::TokenStream)1245     fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1246         let Method { ref name, ref args } = self;
1247 
1248         let tokens = quote!( .#name(#args) );
1249 
1250         tokens.to_tokens(ts);
1251     }
1252 }
1253 
1254 #[derive(Clone)]
1255 pub struct Deprecation {
1256     pub span: Span,
1257     pub id: &'static str,
1258     pub version: &'static str,
1259     pub description: String,
1260 }
1261 
1262 impl Deprecation {
attribute(version: &'static str, old: AttrKind, new: AttrKind, span: Span) -> Self1263     fn attribute(version: &'static str, old: AttrKind, new: AttrKind, span: Span) -> Self {
1264         Self {
1265             span,
1266             id: "old_attribute",
1267             version,
1268             description: format!(
1269                 "Attribute `#[{}(...)]` has been deprecated in favor of `#[{}(...)]`",
1270                 old.as_str(),
1271                 new.as_str()
1272             ),
1273         }
1274     }
1275 }
1276 
1277 impl ToTokens for Deprecation {
to_tokens(&self, ts: &mut proc_macro2::TokenStream)1278     fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1279         let tokens = if cfg!(feature = "deprecated") {
1280             let Deprecation {
1281                 span,
1282                 id,
1283                 version,
1284                 description,
1285             } = self;
1286             let span = *span;
1287             let id = Ident::new(id, span);
1288 
1289             quote_spanned!(span=> {
1290                 #[deprecated(since = #version, note = #description)]
1291                 fn #id() {}
1292                 #id();
1293             })
1294         } else {
1295             quote!()
1296         };
1297 
1298         tokens.to_tokens(ts);
1299     }
1300 }
1301 
assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind])1302 fn assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind]) {
1303     if *attr.kind.get() == AttrKind::Clap || *attr.kind.get() == AttrKind::StructOpt {
1304         // deprecated
1305     } else if !possible_kind.contains(attr.kind.get()) {
1306         let options = possible_kind
1307             .iter()
1308             .map(|k| format!("`#[{}({})]`", k.as_str(), attr.name))
1309             .collect::<Vec<_>>();
1310         abort!(
1311             attr.name,
1312             "Unknown `#[{}({})]` attribute ({} exists)",
1313             attr.kind.as_str(),
1314             attr.name,
1315             options.join(", ")
1316         );
1317     }
1318 }
1319 
1320 /// replace all `:` with `, ` when not inside the `<>`
1321 ///
1322 /// `"author1:author2:author3" => "author1, author2, author3"`
1323 /// `"author1 <http://website1.com>:author2" => "author1 <http://website1.com>, author2"
process_author_str(author: &str) -> String1324 fn process_author_str(author: &str) -> String {
1325     let mut res = String::with_capacity(author.len());
1326     let mut inside_angle_braces = 0usize;
1327 
1328     for ch in author.chars() {
1329         if inside_angle_braces > 0 && ch == '>' {
1330             inside_angle_braces -= 1;
1331             res.push(ch);
1332         } else if ch == '<' {
1333             inside_angle_braces += 1;
1334             res.push(ch);
1335         } else if inside_angle_braces == 0 && ch == ':' {
1336             res.push_str(", ");
1337         } else {
1338             res.push(ch);
1339         }
1340     }
1341 
1342     res
1343 }
1344 
1345 /// Defines the casing for the attributes long representation.
1346 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1347 pub enum CasingStyle {
1348     /// Indicate word boundaries with uppercase letter, excluding the first word.
1349     Camel,
1350     /// Keep all letters lowercase and indicate word boundaries with hyphens.
1351     Kebab,
1352     /// Indicate word boundaries with uppercase letter, including the first word.
1353     Pascal,
1354     /// Keep all letters uppercase and indicate word boundaries with underscores.
1355     ScreamingSnake,
1356     /// Keep all letters lowercase and indicate word boundaries with underscores.
1357     Snake,
1358     /// Keep all letters lowercase and remove word boundaries.
1359     Lower,
1360     /// Keep all letters uppercase and remove word boundaries.
1361     Upper,
1362     /// Use the original attribute name defined in the code.
1363     Verbatim,
1364 }
1365 
1366 impl CasingStyle {
from_lit(name: &LitStr) -> Sp<Self>1367     fn from_lit(name: &LitStr) -> Sp<Self> {
1368         use self::CasingStyle::*;
1369 
1370         let normalized = name.value().to_upper_camel_case().to_lowercase();
1371         let cs = |kind| Sp::new(kind, name.span());
1372 
1373         match normalized.as_ref() {
1374             "camel" | "camelcase" => cs(Camel),
1375             "kebab" | "kebabcase" => cs(Kebab),
1376             "pascal" | "pascalcase" => cs(Pascal),
1377             "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
1378             "snake" | "snakecase" => cs(Snake),
1379             "lower" | "lowercase" => cs(Lower),
1380             "upper" | "uppercase" => cs(Upper),
1381             "verbatim" | "verbatimcase" => cs(Verbatim),
1382             s => abort!(name, "unsupported casing: `{}`", s),
1383         }
1384     }
1385 }
1386 
1387 #[derive(Clone)]
1388 pub enum Name {
1389     Derived(Ident),
1390     Assigned(TokenStream),
1391 }
1392 
1393 impl Name {
raw(self) -> TokenStream1394     pub fn raw(self) -> TokenStream {
1395         match self {
1396             Name::Assigned(tokens) => tokens,
1397             Name::Derived(ident) => {
1398                 let s = ident.unraw().to_string();
1399                 quote_spanned!(ident.span()=> #s)
1400             }
1401         }
1402     }
1403 
translate(self, style: CasingStyle) -> TokenStream1404     pub fn translate(self, style: CasingStyle) -> TokenStream {
1405         use CasingStyle::*;
1406 
1407         match self {
1408             Name::Assigned(tokens) => tokens,
1409             Name::Derived(ident) => {
1410                 let s = ident.unraw().to_string();
1411                 let s = match style {
1412                     Pascal => s.to_upper_camel_case(),
1413                     Kebab => s.to_kebab_case(),
1414                     Camel => s.to_lower_camel_case(),
1415                     ScreamingSnake => s.to_shouty_snake_case(),
1416                     Snake => s.to_snake_case(),
1417                     Lower => s.to_snake_case().replace('_', ""),
1418                     Upper => s.to_shouty_snake_case().replace('_', ""),
1419                     Verbatim => s,
1420                 };
1421                 quote_spanned!(ident.span()=> #s)
1422             }
1423         }
1424     }
1425 
translate_char(self, style: CasingStyle) -> TokenStream1426     pub fn translate_char(self, style: CasingStyle) -> TokenStream {
1427         use CasingStyle::*;
1428 
1429         match self {
1430             Name::Assigned(tokens) => quote!( (#tokens).chars().next().unwrap() ),
1431             Name::Derived(ident) => {
1432                 let s = ident.unraw().to_string();
1433                 let s = match style {
1434                     Pascal => s.to_upper_camel_case(),
1435                     Kebab => s.to_kebab_case(),
1436                     Camel => s.to_lower_camel_case(),
1437                     ScreamingSnake => s.to_shouty_snake_case(),
1438                     Snake => s.to_snake_case(),
1439                     Lower => s.to_snake_case(),
1440                     Upper => s.to_shouty_snake_case(),
1441                     Verbatim => s,
1442                 };
1443 
1444                 let s = s.chars().next().unwrap();
1445                 quote_spanned!(ident.span()=> #s)
1446             }
1447         }
1448     }
1449 }
1450