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