1#![allow(clippy::style)]
4
5extern crate proc_macro;
6
7mod utils;
8use utils::*;
9
10use proc_macro::TokenStream;
11use quote::quote;
12
13use core::fmt::{self, Write};
14
15struct ArgumentEnvInit<'a> {
16 env_key: &'a Option<String>,
17 prefix: &'a str,
18 field_name: &'a str,
19}
20
21impl fmt::Display for ArgumentEnvInit<'_> {
22 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
23 let Self {
24 env_key,
25 prefix,
26 field_name,
27 } = self;
28 if let Some(env_key) = env_key {
29 fmt.write_fmt(format_args!("else if let Ok(_value_) = ::std::env::var(\"{prefix}{env_key}\") {{ match {FROM_FN}(&_value_) {{ Ok(_value_) => _value_, Err(error) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{field_name}\", \"${prefix}{env_key}\"))) }} }}"))
30 } else {
31 Ok(())
32 }
33 }
34}
35
36struct ArgumentEnvDesc<'a> {
37 env_key: &'a Option<String>,
38 prefix: &'a str,
39 desc: &'a str,
40}
41
42impl fmt::Display for ArgumentEnvDesc<'_> {
43 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
44 let Self {
45 env_key,
46 prefix,
47 desc,
48 } = self;
49
50 if let Some(env_key) = &env_key {
51 let desc = desc.trim().trim_end_matches('.');
52 fmt.write_fmt(format_args!("{desc}. Can be set via env {prefix}{env_key}"))
53 } else {
54 fmt.write_str(desc)
55 }
56 }
57}
58
59
60struct Argument {
61 field_name: String,
62 name: String,
63 desc: String,
64 required: bool,
65 is_optional: bool,
66 default: Option<String>,
67 env_key: Option<String>,
68}
69
70impl Argument {
71 #[inline]
72 fn env_init_fmt<'a>(&'a self, prefix: &'a str, field_name: &'a str) -> ArgumentEnvInit<'a> {
73 ArgumentEnvInit {
74 env_key: &self.env_key,
75 prefix,
76 field_name,
77 }
78 }
79
80 #[inline]
81 fn env_desc_fmt<'a>(&'a self, prefix: &'a str) -> ArgumentEnvDesc<'a> {
82 ArgumentEnvDesc {
83 env_key: &self.env_key,
84 prefix,
85 desc: &self.desc
86 }
87 }
88}
89
90#[derive(PartialEq, Eq, Debug)]
91enum OptValueType {
92 Help,
93 Bool,
94 Value,
95 MultiValue,
96}
97
98struct Opt {
99 arg: Argument,
100 long: String,
101 short: Option<String>,
102 typ: OptValueType,
103}
104
105struct Command {
106 variant_name: String,
107 command_name: String,
108 desc: String,
109}
110
111const CONCAT_DEFAULT_PROG_NAME_ARGS: &str = "env!(\"CARGO_PKG_NAME\"), \" \", env!(\"CARGO_PKG_VERSION\")";
112const FROM_FN: &str = "::core::str::FromStr::from_str";
113const TAB: &str = " ";
114const PARSER_TRAIT: &str = "arg::Args";
115const DEFAULT_INIT: &str = "Default::default()";
116const INVALID_ARG_TYPE_STRING: &str = "Attribute accepts only str";
117const INVALID_REQUIRED_BOOL: &str = "Attribute required cannot be applied to bool switch";
118const UNKNOWN_ARG_ATTR: &str = "Unknown attribute is used";
119const ARG_INVALID_CHARS: &[char] = &[' ', '\t'];
120const ARG_NAME_SPACE_ERROR: &str = "Name contains space character";
121
122fn parse_segment(segment: &syn::PathSegment) -> OptValueType {
123 if segment.ident == "bool" {
124 OptValueType::Bool
125 } else if segment.ident == "Vec" {
126 OptValueType::MultiValue
127 } else {
128 OptValueType::Value
129 }
130}
131
132fn from_enum(ast: &syn::DeriveInput, payload: &syn::DataEnum) -> TokenStream {
133 let mut about_prog = String::new();
134 for attr in ast.attrs.iter() {
135 match &attr.meta {
136 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
137 let literal = match &value.value {
138 syn::Expr::Lit(literal) => &literal.lit,
139 _ => return syn::Error::new_spanned(value.clone(), "Attribute should be literal").to_compile_error().into()
140 };
141 if let syn::Lit::Str(ref text) = literal {
142 about_prog.push_str(&text.value());
143 about_prog.push_str("\n");
144 }
145 },
146 _ => (),
147 }
148 }
149 about_prog.pop();
150
151 let mut commands = Vec::new();
152 for variant in payload.variants.iter() {
153 let mut desc = String::new();
154 let variant_name = variant.ident.to_string();
155 if variant_name.is_empty() {
156 return syn::Error::new_spanned(&variant.ident, "Oi, mate, You cannot have enum variant without name").to_compile_error().into()
157 }
158 let command_name = to_hyphenated_lower_case(&variant_name);
159 if command_name.eq_ignore_ascii_case("help") {
160 return syn::Error::new_spanned(&variant.ident, "Oi, mate, You cannot use variant 'Help'").to_compile_error().into()
161 }
162
163 for attr in variant.attrs.iter() {
164 match &attr.meta {
165 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
166 let literal = match &value.value {
167 syn::Expr::Lit(literal) => &literal.lit,
168 _ => return syn::Error::new_spanned(value.clone(), "Attribute should be literal").to_compile_error().into()
169 };
170
171 if let syn::Lit::Str(ref text) = literal {
172 desc.push_str(&text.value());
173 desc.push_str(" ");
174 }
175 },
176 _ => continue
177 }
178 }
179
180 let field = match &variant.fields {
181 syn::Fields::Unit => return syn::Error::new_spanned(&variant.fields, "Unit variant cannot be used").to_compile_error().into(),
182 syn::Fields::Named(_) => return syn::Error::new_spanned(&variant.fields, "I'm too lazy to support named variant").to_compile_error().into(),
183 syn::Fields::Unnamed(fields) => {
184 if fields.unnamed.empty_or_trailing() {
185 return syn::Error::new_spanned(&fields, "MUST specify single field").to_compile_error().into();
186 } else if fields.unnamed.len() > 1 {
187 return syn::Error::new_spanned(fields, "MUST not specify more than 1 field").to_compile_error().into();
188 } else {
189 fields.unnamed.first().unwrap()
190 }
191 },
192 };
193
194 match &field.ty {
195 syn::Type::Path(ref ty) => {
196 let ty = ty.path.segments.last().expect("To have at least one segment");
197 if ty.ident == "Option" {
198 return syn::Error::new_spanned(ty, "Command cannot be optional").to_compile_error().into()
199 } else {
200 match parse_segment(ty) {
201 OptValueType::Bool => return syn::Error::new_spanned(ty, "Command value cannot be boolean").to_compile_error().into(),
202 OptValueType::MultiValue => return syn::Error::new_spanned(ty, "Command value Vec<_>").to_compile_error().into(),
203 _ => (),
204 }
205 }
206 },
207 ty => {
208 return syn::Error::new_spanned(ty, "Expected simple ident or path").to_compile_error().into()
209 }
210 }
211
212 commands.push(Command {
213 command_name,
214 variant_name,
215 desc
216 })
217 }
218
219 if commands.is_empty() {
220 return syn::Error::new_spanned(ast, "Enum must have at least one variant").to_compile_error().into()
221 }
222
223 let (impl_gen, type_gen, where_clause) = ast.generics.split_for_impl();
224
225 let help_msg = {
226 use std::io::Write;
227 use tabwriter::TabWriter;
228
229 let mut tw = TabWriter::new(vec![]);
230
231 let _ = writeln!(tw, "COMMANDS:");
232 for command in commands.iter() {
233 let _ = writeln!(tw, "\t{}\t{}", command.command_name, command.desc);
234 }
235
236 let _ = tw.flush();
237
238 String::from_utf8(tw.into_inner().unwrap()).unwrap()
239 };
240
241 let mut result = String::new();
242 let _ = writeln!(result, "{} {} for {}{} {{", quote!(impl#impl_gen), PARSER_TRAIT, ast.ident, quote!(#type_gen #where_clause));
243
244 let _ = writeln!(result, "{}const HELP: &'static str = \"{}\";", TAB, help_msg);
245
246 let _ = writeln!(result, "{}fn from_args<'a, T: IntoIterator<Item = &'a str>>(_args_: T) -> Result<Self, arg::ParseKind<'a>> {{", TAB);
248
249 let _ = writeln!(result, "{0}{0}let mut _args_ = _args_.into_iter();\n", TAB);
250
251 let _ = writeln!(result, "{0}{0}while let Some(_arg_) = _args_.next() {{", TAB);
253
254 let _ = writeln!(result, "{0}{0}{0}if _arg_.eq_ignore_ascii_case(\"help\") {{", TAB);
256 let _ = writeln!(result, "{0}{0}{0}{0}return Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(Self::HELP)));", TAB);
257 let _ = write!(result, "{0}{0}{0}}}", TAB);
258
259 let mut allowed_commands = String::new();
260 for command in commands.iter() {
261 allowed_commands.push_str(command.command_name.as_str());
262 allowed_commands.push(',');
263 allowed_commands.push(' ');
264
265 let _ = writeln!(result, " else if _arg_.eq_ignore_ascii_case(\"{}\") {{", command.command_name);
267
268 let _ = writeln!(result, "{0}{0}{0}{0}match {1}::from_args(_args_) {{", TAB, PARSER_TRAIT);
269 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(res) => return Ok(Self::{1}(res)),", TAB, command.variant_name);
270 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(error)) => return Err(arg::ParseKind::Sub(\"{1}\", error)),", TAB, command.command_name);
271 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Sub(name, error)) => return Err(arg::ParseKind::Sub(name, error)),", TAB);
272 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
273
274 let _ = write!(result, "{0}{0}{0}}}", TAB);
276 }
277
278 let _ = writeln!(result, " else {{");
280 let _ = writeln!(result, "{0}{0}{0}{0}return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"command\", _arg_)))", TAB);
281 let _ = write!(result, "{0}{0}{0}}}", TAB);
282
283 let _ = writeln!(result, "\n{0}{0}}}", TAB);
285
286 allowed_commands.pop();
287 allowed_commands.pop();
288 let _ = writeln!(result, "{0}{0}Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(\"Missing command, possible values: [{1}]\nSee 'help' for details\")))", TAB, allowed_commands);
290
291 let _ = writeln!(result, "{}}}", TAB);
293
294 let _ = writeln!(result, "}}");
295
296 if let Ok(val) = std::env::var("ARG_RS_PRINT_PARSER") {
297 match val.trim() {
298 "0" | "false" => (),
299 _ => println!("{result}"),
300 }
301 }
302 result.parse().expect("To parse generated code")
303}
304
305fn from_struct(ast: &syn::DeriveInput, payload: &syn::DataStruct) -> TokenStream {
306 let mut env_prefix = None;
307 let mut infer_prog_name = false;
308 let mut about_prog = String::new();
309 for attr in ast.attrs.iter() {
310 match &attr.meta {
311 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
312 let literal = match &value.value {
313 syn::Expr::Lit(literal) => &literal.lit,
314 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
315 };
316 if let syn::Lit::Str(ref text) = literal {
317 about_prog.push_str(&text.value());
318 about_prog.push('\n');
319 }
320 },
321 syn::Meta::List(list) => if list.path.is_ident("arg") {
322 let nested = match attr.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated) {
323 Ok(nested) => nested,
324 Err(error) => {
325 let error = format!("arg attribute should be list of attributes: {error}");
326 return syn::Error::new_spanned(list, error).to_compile_error().into();
327 }
328 };
329 for value_attr in nested {
330 match value_attr {
331 syn::Meta::Path(value_attr) => if value_attr.is_ident("infer_name") {
332 infer_prog_name = true;
333 } else {
334 let ident = utils::FormatOptionalIdent(value_attr.get_ident());
335 return syn::Error::new_spanned(&value_attr, format!("Unknown attribute: '{ident}'. Expected: infer_name")).to_compile_error().into();
336 },
337 syn::Meta::NameValue(value_attr) => if value_attr.path.is_ident("env_prefix") {
338 match &value_attr.value {
339 syn::Expr::Lit(literal) => match &literal.lit {
340 syn::Lit::Str(literal) => {
341 env_prefix = Some(literal.value());
342 }
343 _ => return syn::Error::new_spanned(attr, "Attribute should be string").to_compile_error().into(),
344 },
345 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into(),
346 }
347 } else {
348 return syn::Error::new_spanned(&value_attr, format!("Unknown attribute: '{}'. Expected: infer_name", value_attr.path.get_ident().unwrap())).to_compile_error().into();
349 }
350 unexpected => return syn::Error::new_spanned(&unexpected, "Unexpected attribute").to_compile_error().into(),
351 }
352 }
353 },
354 _ => (),
355 }
356 }
357
358 let env_prefix = match env_prefix {
359 Some(prefix) => {
360 let prefix = prefix.trim();
361 if prefix.is_empty() {
362 String::new()
363 } else {
364 format!("{prefix}_")
365 }
366 },
367 None => "ARG_".to_owned(),
368 };
369
370 about_prog.pop();
371
372 let mut options = Vec::new();
373 let mut arguments = Vec::new();
374
375 options.push(Opt {
376 arg: Argument {
377 field_name: "_".to_owned(),
378 name: "help".to_owned(),
379 desc: "Prints this help information".to_owned(),
380 required: false,
381 is_optional: false,
382 default: None,
383 env_key: None,
384 },
385 short: Some("h".to_owned()),
386 long: "help".to_owned(),
387 typ: OptValueType::Help,
388 });
389
390 let mut sub_command = None;
391 let mut multi_argument = None;
392
393 for field in payload.fields.iter() {
394 let field_name = field.ident.as_ref().unwrap().to_string();
395 let name = field.ident.as_ref().unwrap().to_string().trim_matches(|ch| !char::is_alphanumeric(ch)).to_owned();
396 let mut desc = String::new();
397 let mut short = None;
398 let mut long = None;
399 let mut required = false;
400 let mut is_sub = false;
401
402 let (is_optional, typ) = match field.ty {
403 syn::Type::Path(ref ty) => {
404 let ty = ty.path.segments.last().expect("To have at least one segment");
405
406 if ty.ident == "Option" {
407 let ty = match &ty.arguments {
408 syn::PathArguments::AngleBracketed(ref args) => match args.args.len() {
409 0 => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option is without type arguments. Fix it").to_compile_error().into(),
410 1 => match args.args.first().unwrap() {
411 syn::GenericArgument::Type(syn::Type::Path(ty)) => parse_segment(ty.path.segments.last().expect("To have at least one segment")),
412 _ => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option should have type argument, but got some other shite. Fix it").to_compile_error().into(),
413 },
414 _ => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option has too many type arguments. Fix it").to_compile_error().into()
415 },
416 syn::PathArguments::None => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option is without type arguments. Fix it").to_compile_error().into(),
417 syn::PathArguments::Parenthesized(_) => return syn::Error::new_spanned(&ty.ident, "Oi, mate, you got wrong brackets for your Option . Fix it").to_compile_error().into(),
418 };
419
420 (true, ty)
421 } else {
422 (false, parse_segment(ty))
423 }
424 },
425 _ => (false, OptValueType::Value),
426 };
427
428 if is_optional && typ == OptValueType::MultiValue {
429 return syn::Error::new_spanned(field, "Option<Vec<_>> makes no sense. Just use plain Vec<_>").to_compile_error().into();
430 }
431
432 let mut default = None;
433 let mut env_key = None;
434
435 for attr in field.attrs.iter() {
436 match &attr.meta {
437 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
438 let literal = match &value.value {
439 syn::Expr::Lit(literal) => &literal.lit,
440 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
441 };
442 if let syn::Lit::Str(ref text) = literal {
443 desc.push_str(&text.value());
444 desc.push(' ');
445 }
446 },
447 syn::Meta::List(value) => if value.path.is_ident("arg") {
448 let nested = match attr.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated) {
449 Ok(nested) => nested,
450 Err(error) => {
451 let error = format!("arg attribute should be list of attributes: {error}");
452 return syn::Error::new_spanned(value, error).to_compile_error().into();
453 }
454 };
455
456 for value_attr in nested {
457 match value_attr {
458 syn::Meta::Path(value_attr) => if value_attr.is_ident("short") {
459 short = Some(format!("{}", name.chars().next().unwrap()).to_lowercase());
460 } else if value_attr.is_ident("long") {
461 long = Some(name.to_lowercase());
462 } else if value_attr.is_ident("default_value") {
463 default = Some(DEFAULT_INIT.to_owned());
464 } else if value_attr.is_ident("env_value") {
465 env_key = Some(name.to_uppercase());
466 } else if value_attr.is_ident("required") {
467 required = true;
468 } else if value_attr.is_ident("sub") {
469 if typ == OptValueType::Value {
470 is_sub = true;
471 } else {
472 return syn::Error::new_spanned(value_attr, "Sub-command must be simple value").to_compile_error().into();
473 }
474 } else {
475 return syn::Error::new_spanned(&value_attr, UNKNOWN_ARG_ATTR).to_compile_error().into();
476 }
477 syn::Meta::NameValue(value_attr) => if value_attr.path.is_ident("short") {
478 let literal = match &value_attr.value {
479 syn::Expr::Lit(literal) => &literal.lit,
480 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
481 };
482
483 if let syn::Lit::Str(ref text) = literal {
484 let value_attr_text = text.value();
485
486 if value_attr_text.contains(ARG_INVALID_CHARS) {
487 return syn::Error::new_spanned(literal.clone(), ARG_NAME_SPACE_ERROR).to_compile_error().into();
488 }
489
490 short = Some(value_attr_text);
491 } else {
492 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
493 }
494 } else if value_attr.path.is_ident("long") {
495 let literal = match &value_attr.value {
496 syn::Expr::Lit(literal) => &literal.lit,
497 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
498 };
499
500 if let syn::Lit::Str(ref text) = literal {
501 let value_attr_text = text.value();
502
503 if value_attr_text.contains(ARG_INVALID_CHARS) {
504 return syn::Error::new_spanned(literal.clone(), ARG_NAME_SPACE_ERROR).to_compile_error().into();
505 }
506
507 long = Some(value_attr_text)
508 } else {
509 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
510 }
511 } else if value_attr.path.is_ident("default_value") {
512 let literal = match &value_attr.value {
513 syn::Expr::Lit(literal) => &literal.lit,
514 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
515 };
516
517 if let syn::Lit::Str(ref text) = literal {
518 default = Some(text.value());
519 } else {
520 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
521 }
522 } else if value_attr.path.is_ident("env_value") {
523 let literal = match &value_attr.value {
524 syn::Expr::Lit(literal) => &literal.lit,
525 _ => return syn::Error::new_spanned(attr, "Attribute should be literal").to_compile_error().into()
526 };
527
528 if let syn::Lit::Str(ref text) = literal {
529 env_key = Some(text.value());
530 } else {
531 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
532 }
533 } else {
534 return syn::Error::new_spanned(value_attr.path.clone(), UNKNOWN_ARG_ATTR).to_compile_error().into();
535 }
536 _ => {
537 },
538 }
539 } },
541 _ => (),
542 }
543 }
544
545 desc.pop();
546
547 if required && default.is_some() {
548 return syn::Error::new_spanned(field.ident.clone(), "Marked as required, but default value is provided?").to_compile_error().into();
549 } else if is_optional && default.is_some() {
550 return syn::Error::new_spanned(field.ident.clone(), "Optional, but default value is provided?").to_compile_error().into();
551 } else if is_sub && is_optional {
552 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot be optional").to_compile_error().into();
553 } else if is_sub && default.is_some() {
554 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot have default value").to_compile_error().into();
555 } else if !required && !is_optional && default.is_none() {
556 default = Some(DEFAULT_INIT.to_owned());
557 }
558
559 if short.is_none() && long.is_none() {
560 if typ == OptValueType::MultiValue {
561 if multi_argument.is_some() {
562 return syn::Error::new_spanned(field.ident.clone(), "Second argument collection. There can be only one").to_compile_error().into();
563 } else if sub_command.is_some() {
564 return syn::Error::new_spanned(field.ident.clone(), "Multi-argument collection and sub-command are mutually exclusive").to_compile_error().into();
565 } else if env_key.is_some() {
566 return syn::Error::new_spanned(field.ident.clone(), "Multi-argument cannot be supplied with `env_value` parameter").to_compile_error().into();
567 }
568
569 multi_argument = Some(Argument {
570 field_name,
571 name,
572 desc,
573 required,
574 is_optional,
575 default,
576 env_key,
577 });
578
579 } else if is_sub {
580 if sub_command.is_some() {
581 return syn::Error::new_spanned(field.ident.clone(), "Second sub-command. There can be only one").to_compile_error().into();
582 } else if multi_argument.is_some() {
583 return syn::Error::new_spanned(field.ident.clone(), "Sub-command and multi-argument collection are mutually exclusive").to_compile_error().into();
584 } else if env_key.is_some() {
585 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot be supplied with `env_value` parameter").to_compile_error().into();
586 }
587
588 sub_command = Some(Argument {
589 field_name,
590 name,
591 desc,
592 required: true,
593 is_optional: false,
594 default: None,
595 env_key,
596 });
597 } else {
598 arguments.push(Argument {
599 field_name,
600 name,
601 desc,
602 required,
603 is_optional,
604 default,
605 env_key,
606 })
607 }
608 } else {
609 if OptValueType::Bool == typ && required {
611 return syn::Error::new_spanned(field.ident.clone(), INVALID_REQUIRED_BOOL).to_compile_error().into();
613 }
614
615 let long = match long {
616 Some(long) => long,
617 None => name.clone()
618 };
619
620 options.push(Opt {
621 arg: Argument {
622 field_name,
623 name,
624 desc,
625 required,
626 is_optional,
627 default,
628 env_key,
629 },
630 short,
631 long,
632 typ
633 })
634 }
635 }
636
637 let (impl_gen, type_gen, where_clause) = ast.generics.split_for_impl();
638
639 let help_msg = {
640 use std::io::Write;
641 use tabwriter::TabWriter;
642
643 let mut tw = TabWriter::new(vec![]);
644
645 let _ = write!(tw, "{}
646
647USAGE:", about_prog);
648
649 if !options.is_empty() {
650 let _ = write!(tw, " [OPTIONS]");
651 }
652
653 for argument in arguments.iter() {
654 let _ = if argument.required {
655 write!(tw, " <{}>", argument.name)
656 } else {
657 write!(tw, " [{}]", argument.name)
658 };
659 }
660
661 if let Some(argument) = multi_argument.as_ref() {
662 let _ = if argument.required {
663 write!(tw, " <{}>...", argument.name)
664 } else {
665 write!(tw, " [{}]...", argument.name)
666 };
667 } else if let Some(argument) = sub_command.as_ref() {
668 let _ = write!(tw, " <{}>", argument.name);
669 }
670
671 if !options.is_empty() {
672 let _ = write!(tw, "\n\nOPTIONS:\n");
673 }
674
675 for option in options.iter() {
676 let _ = write!(tw, "\t");
677 if let Some(short) = option.short.as_ref() {
678 let _ = write!(tw, "-{},", short);
679 }
680 let _ = write!(tw, "\t");
681
682 let _ = write!(tw, "--{}", option.long);
683
684 let _ = match option.typ {
685 OptValueType::MultiValue => write!(tw, " <{}>...", option.arg.name),
686 OptValueType::Value => write!(tw, " <{}>", option.arg.name),
687 _ => Ok(()),
688 };
689
690
691 let desc = option.arg.env_desc_fmt(&env_prefix);
692 let _ = writeln!(tw, "\t{desc}");
693 }
694
695 if !arguments.is_empty() || multi_argument.is_some() || sub_command.is_some() {
696 let _ = write!(tw, "\nARGS:\n");
697 }
698
699 for argument in arguments.iter() {
700 let arg_desc = argument.env_desc_fmt(&env_prefix);
701 let _ = if argument.required {
702 writeln!(tw, "\t<{}>\t{arg_desc}", argument.name)
703 } else {
704 writeln!(tw, "\t[{}]\t{arg_desc}", argument.name)
705 };
706 }
707
708 if let Some(argument) = multi_argument.as_ref() {
709 let arg_desc = argument.desc.trim();
710 let _ = writeln!(tw, "\t<{}>...\t{arg_desc}", argument.name);
711 } else if let Some(command) = sub_command.as_ref() {
712 let arg_desc = command.desc.trim();
713 let _ = writeln!(tw, "\t<{}>\t{arg_desc}", command.name);
714 }
715
716 let _ = tw.flush();
717
718 String::from_utf8(tw.into_inner().unwrap()).unwrap()
719 };
720
721 let mut result = String::new();
722 let _ = writeln!(result, "{} {} for {}{} {{", quote!(impl#impl_gen), PARSER_TRAIT, ast.ident, quote!(#type_gen #where_clause));
723 if infer_prog_name {
724 let _ = writeln!(result, "{}const HELP: &'static str = core::concat!({CONCAT_DEFAULT_PROG_NAME_ARGS}, \"\n\", \"{}\");", TAB, help_msg);
725 } else {
726 let _ = writeln!(result, "{}const HELP: &'static str = \"{}\";", TAB, help_msg);
727 }
728
729 let _ = writeln!(result, "{}fn from_args<'a, T: IntoIterator<Item = &'a str>>(_args_: T) -> Result<Self, arg::ParseKind<'a>> {{", TAB);
730
731 for option in options.iter() {
732 if option.arg.field_name == "_" {
733 continue;
734 }
735
736 let _ = match option.typ {
737 OptValueType::MultiValue => writeln!(result, "{0}{0}let mut {1} = Vec::new();", TAB, option.arg.field_name),
738 OptValueType::Bool => match &option.arg.env_key {
739 Some(env_key) => {
740 let _ = writeln!(result, "{0}{0}let mut {1} = if let Ok(_env_val_) = ::std::env::var(\"{env_prefix}{env_key}\") {{", TAB, option.arg.field_name);
741 let _ = writeln!(result, "{0}{0}{0}match {FROM_FN}(_env_val_.trim()) {{", TAB);
742 let _ = writeln!(result, "{0}{0}{0}{0}Ok(_env_val_) => _env_val_,", TAB);
743 let _ = writeln!(result, "{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", \"${env_prefix}{env_key}\"))),", TAB, option.arg.field_name);
744 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
745 let _ = writeln!(result, "{0}{0}}} else {{", TAB);
746 let _ = writeln!(result, "{0}{0}{0}false", TAB);
747 writeln!(result, "{0}{0}}};", TAB)
748 },
749 None => writeln!(result, "{0}{0}let mut {1} = false;", TAB, option.arg.field_name),
750 },
751 _ => writeln!(result, "{0}{0}let mut {1} = None;", TAB, option.arg.field_name),
752 };
753 }
754
755 for argument in arguments.iter() {
756 let _ = writeln!(result, "{0}{0}let mut {1} = None;", TAB, argument.field_name);
757 }
758
759 if let Some(argument) = multi_argument.as_ref() {
760 let _ = writeln!(result, "{0}{0}let mut {1} = Vec::new();", TAB, argument.field_name);
761 } else if let Some(command) = sub_command.as_ref() {
762 let _ = writeln!(result, "{0}{0}let mut {1} = None;", TAB, command.field_name);
763 }
764
765 let _ = writeln!(result, "{0}{0}let mut _args_ = _args_.into_iter();\n", TAB);
766 let _ = writeln!(result, "{0}{0}while let Some(_arg_) = _args_.next() {{", TAB);
767
768 let _ = writeln!(result, "{0}{0}{0}if let Some(_arg_) = _arg_.strip_prefix('-') {{", TAB);
770 let _ = writeln!(result, "{0}{0}{0}{0}match _arg_ {{", TAB);
771 let _ = writeln!(result, "{0}{0}{0}{0}{0}\"h\" | \"-help\" => return Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(Self::HELP))),", TAB);
772 let _ = writeln!(result, "{0}{0}{0}{0}{0}\"\" => (),", TAB);
773
774 for option in options.iter() {
775 if option.arg.field_name == "_" {
776 continue;
777 }
778
779 let _ = write!(result, "{0}{0}{0}{0}{0}", TAB);
780
781 if let Some(short) = option.short.as_ref() {
782 let _ = write!(result, "\"{}\" | ", short);
783 }
784
785 let _ = write!(result, "\"-{}\" => ", option.long);
786
787 let _ = match option.typ {
788 OptValueType::Help => panic!("Option Help is invalid here. Bug report it"),
789 OptValueType::Bool => write!(result, "{{ {0} = !{0}; continue }},", option.arg.field_name),
790 OptValueType::Value => write!(result, "match _args_.next() {{
791{0}{0}{0}{0}{0}{0}Some(_next_arg_) => match {1}(_next_arg_) {{
792{0}{0}{0}{0}{0}{0}{0}Ok(value) => {{ {2} = Some(value); continue }},
793{0}{0}{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidFlagValue(\"{3}\", _next_arg_))),
794{0}{0}{0}{0}{0}{0}}},
795{0}{0}{0}{0}{0}{0}None => return Err(arg::ParseKind::Top(arg::ParseError::MissingValue(\"{3}\"))),
796{0}{0}{0}{0}{0}}}", TAB, FROM_FN, option.arg.field_name, option.arg.name),
797 OptValueType::MultiValue => write!(result, "match _args_.next() {{
798{0}{0}{0}{0}{0}{0}Some(_next_arg_) => match {1}(_next_arg_) {{
799{0}{0}{0}{0}{0}{0}{0}Ok(value) => {{ {2}.push(value); continue }},
800{0}{0}{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidFlagValue(\"{3}\", _next_arg_))),
801{0}{0}{0}{0}{0}{0}}},
802{0}{0}{0}{0}{0}{0}None => return Err(arg::ParseKind::Top(arg::ParseError::MissingValue(\"{3}\"))),
803{0}{0}{0}{0}{0}}}", TAB, FROM_FN, option.arg.field_name, option.arg.name),
804 };
805 result.push('\n');
806 }
807 let _ = writeln!(result, "{0}{0}{0}{0}{0}_ => return Err(arg::ParseKind::Top(arg::ParseError::UnknownFlag(_arg_))),", TAB);
808
809 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
810 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
811 for (idx, arg) in arguments.iter().enumerate() {
813 if idx == 0 {
814 let _ = writeln!(result, "{0}{0}{0}if {1}.is_none() {{", TAB, arg.field_name);
815 } else {
816 let _ = writeln!(result, "{0}{0}{0}}} else if {1}.is_none() {{", TAB, arg.field_name);
817 }
818 let _ = writeln!(result, "{0}{0}{0}{0}match {1}(_arg_) {{", TAB, FROM_FN);
819 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {1} = Some(_res_),", TAB, arg.field_name);
820 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", _arg_))),", TAB, arg.field_name);
821 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
822 }
823 if !arguments.is_empty() {
825 let _ = writeln!(result, "{0}{0}{0}}} else {{", TAB);
826 }
827
828 if let Some(arg) = multi_argument.as_ref() {
829 let _ = writeln!(result, "{0}{0}{0}{0}match {1}(_arg_) {{", TAB, FROM_FN);
830 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {1}.push(_res_),", TAB, arg.field_name);
831 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", _arg_))),", TAB, arg.field_name);
832 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
833 } else if let Some(command) = sub_command.as_ref() {
834 let _ = writeln!(result, "{0}{0}{0}{0}match {1}::from_args(core::iter::once(_arg_).chain(_args_)) {{", TAB, PARSER_TRAIT);
835 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {{ {1} = Some(_res_); break; }},", TAB, command.field_name);
836 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(_, invalid_value))) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", invalid_value))),", TAB, command.field_name);
837 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(_)) => return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{1}\"))),", TAB, command.field_name);
838 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Sub(name, error)) => return Err(arg::ParseKind::Sub(name, error)),", TAB);
839 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
840 } else {
841 let _ = writeln!(result, "{0}{0}{0}{0} return Err(arg::ParseKind::Top(arg::ParseError::TooManyArgs));", TAB);
842 }
843 if !arguments.is_empty() {
845 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
846 let _ = writeln!(result, "{0}{0}}}", TAB);
847 } else {
848 let _ = writeln!(result, "{0}{0}}}", TAB);
849 }
850
851 for option in options.iter() {
853 if option.arg.field_name == "_" {
854 continue;
855 }
856
857 let env_init = option.arg.env_init_fmt(&env_prefix, &option.arg.field_name);
858 let _ = match option.typ {
859 OptValueType::MultiValue => {
860 if let Some(env_key) = option.arg.env_key.as_ref() {
861 let _ = writeln!(result, "\n{0}{0}if let Ok(_env_val_) = ::std::env::var(\"{env_prefix}{env_key}\") {{", TAB);
862 let _ = writeln!(result, "{0}{0}{0}for _env_val_ in _env_val_.split(',') {{", TAB);
863 let _ = writeln!(result, "{0}{0}{0}{0}{1}.push(match {FROM_FN}(_env_val_.trim()) {{ Ok(_env_val_) => {{ _env_val_ }}, Err(_) => {{ return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", \"${env_prefix}{env_key}\"))); }} }})", TAB, option.arg.field_name);
864 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
865 let _ = writeln!(result, "{0}{0}}}\n", TAB);
866 }
867 Ok(())
868 },
869 OptValueType::Bool => Ok(()),
870 _ => match option.arg.default {
871 Some(ref default) => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ {2} }};", TAB, option.arg.field_name, default),
872 None => match option.arg.is_optional {
873 true => if let Some(env_key) = option.arg.env_key.as_ref() {
874 writeln!(result, "{0}{0}if {1}.is_none() {{ {1} = ::std::env::var(\"{env_prefix}{env_key}\").ok().and_then(|value| {FROM_FN}(value.trim()).ok()); }}", TAB, option.arg.field_name)
875 } else {
876 Ok(())
877 },
878 false => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{2}\"))) }};", TAB, option.arg.field_name, option.arg.name),
879 },
880 },
881 };
882 }
883
884 for arg in arguments.iter() {
885 let env_init = arg.env_init_fmt(&env_prefix, &arg.field_name);
886 let _ = match arg.default {
887 Some(ref default) => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ {2} }};", TAB, arg.field_name, default),
888 None => match arg.is_optional {
889 true => Ok(()),
890 false => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} {env_init} else {{ return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{2}\"))) }};", TAB, arg.field_name, arg.name),
891 }
892 };
893 }
894
895 if let Some(command) = sub_command.as_ref() {
896 let _ = writeln!(result, "{0}{0}let {1} = match {1} {{", TAB, command.field_name);
897 let _ = writeln!(result, "{0}{0}{0}Some({1}) => {1},", TAB, command.field_name);
898 let _ = writeln!(result, "{0}{0}{0}None => match {1}::from_args([]) {{", TAB, PARSER_TRAIT);
900 let _ = writeln!(result, "{0}{0}{0}{0}Ok({1}) => {1},", TAB, command.field_name);
901 let _ = writeln!(result, "{0}{0}{0}{0}Err(error) => return Err(error),", TAB);
902 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
903 let _ = writeln!(result, "{0}{0}}};", TAB);
905 }
906
907 let _ = writeln!(result, "{0}{0}Ok(Self {{", TAB);
909
910 for option in options.iter() {
911 if option.arg.field_name == "_" {
912 continue;
913 }
914
915 let _ = if option.arg.is_optional && option.typ == OptValueType::Bool {
916 writeln!(result, "{0}{0}{0}{1}: Some({1}),", TAB, option.arg.field_name)
917 } else {
918 writeln!(result, "{0}{0}{0}{1},", TAB, option.arg.field_name)
919 };
920 }
921
922 for arg in arguments.iter() {
923 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
924 }
925
926 if let Some(arg) = multi_argument.as_ref() {
927 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
928 } else if let Some(arg) = sub_command.as_ref() {
929 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
930 }
931
932 let _ = writeln!(result, "{0}{0}}})", TAB);
933
934 let _ = writeln!(result, "{}}}", TAB);
936
937 let _ = writeln!(result, "}}");
938
939 if let Ok(val) = std::env::var("ARG_RS_PRINT_PARSER") {
940 match val.trim() {
941 "0" | "false" => (),
942 _ => println!("{result}"),
943 }
944 }
945 result.parse().expect("To parse generated code")
946}
947
948#[proc_macro_derive(Args, attributes(parser, arg))]
949pub fn parser_derive(input: TokenStream) -> TokenStream {
950 const INVALID_INPUT_TYPE: &str = "Unsupported parser input type. Expect: struct";
951 let ast: syn::DeriveInput = syn::parse(input).unwrap();
952
953 match ast.data {
954 syn::Data::Struct(ref data) => from_struct(&ast, data),
955 syn::Data::Enum(ref data) => from_enum(&ast, data),
956 _ => syn::Error::new_spanned(ast.ident, INVALID_INPUT_TYPE).to_compile_error().into(),
957 }
958}