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