gitignore_template_generator/parser/
impls.rs1use std::{ffi::OsString, process::exit};
2
3use clap::{ArgMatches, Command};
4
5use super::{Args, ArgsParser, TimeoutUnit, command::build_clap_args};
6use crate::{ExitKind, ProgramExit, constant};
7
8pub struct ClapArgsParser {
11 cli_parser: Command,
12}
13
14#[allow(clippy::new_without_default)]
15impl ClapArgsParser {
16 pub fn new() -> Self {
17 Self {
18 cli_parser: Command::new(env!("CARGO_PKG_NAME"))
19 .version(env!("CARGO_PKG_VERSION"))
20 .author(env!("CARGO_PKG_AUTHORS"))
21 .about(constant::parser_infos::ABOUT)
22 .help_template(include_str!("../../assets/help_template.txt"))
23 .disable_help_flag(true)
24 .disable_version_flag(true)
25 .args(build_clap_args()),
26 }
27 }
28
29 fn parse_global_options(&self, args: &Args) -> Option<ProgramExit> {
30 if args.show_help {
31 let rendered_help = self.cli_parser.clone().render_help();
32 Some(ProgramExit {
33 message: rendered_help.to_string().trim_end().to_string(),
34 exit_status: constant::exit_status::SUCCESS,
35 styled_message: Some(
36 rendered_help.ansi().to_string().trim_end().to_string(),
37 ),
38 kind: ExitKind::HelpInfos,
39 })
40 } else if args.show_version {
41 let message = match self.cli_parser.get_version() {
42 Some(version) => {
43 format!("{} {version}", env!("CARGO_PKG_NAME"))
44 }
45 None => constant::error_messages::VERSION_INFOS_NOT_AVAILABLE
46 .to_string(),
47 };
48
49 Some(ProgramExit {
50 message,
51 exit_status: constant::exit_status::SUCCESS,
52 styled_message: None,
53 kind: ExitKind::VersionInfos,
54 })
55 } else if args.show_author {
56 let message = String::from(match self.cli_parser.get_author() {
57 Some(author) => author,
58 None => constant::error_messages::AUTHOR_INFOS_NOT_AVAILABLE,
59 });
60
61 Some(ProgramExit {
62 message,
63 exit_status: constant::exit_status::SUCCESS,
64 styled_message: None,
65 kind: ExitKind::AuthorInfos,
66 })
67 } else {
68 None
69 }
70 }
71
72 fn map_arg_matches_to_struct(arg_matches: &ArgMatches) -> Args {
73 Args {
74 template_names: arg_matches
75 .get_many::<String>("TEMPLATE_NAMES")
76 .map(|vals| vals.cloned().collect())
77 .unwrap_or_default(),
78
79 server_url: arg_matches
80 .get_one::<String>("SERVER_URL")
81 .unwrap()
82 .to_string(),
83
84 generator_uri: arg_matches
85 .get_one::<String>("GENERATOR_URI")
86 .unwrap()
87 .to_string(),
88
89 lister_uri: arg_matches
90 .get_one::<String>("LISTER_URI")
91 .unwrap()
92 .to_string(),
93
94 timeout: arg_matches.get_one::<u64>("TIMEOUT").unwrap().to_owned(),
95
96 timeout_unit: arg_matches
97 .get_one::<TimeoutUnit>("TIMEOUT_UNIT")
98 .unwrap()
99 .to_owned(),
100
101 check_template_names: arg_matches.get_flag("CHECK"),
102 show_help: arg_matches.get_flag("HELP"),
103 show_version: arg_matches.get_flag("VERSION"),
104 show_author: arg_matches.get_flag("AUTHOR"),
105 show_list: arg_matches.get_flag("LIST"),
106 }
107 }
108
109 fn print_error_message(error: &ProgramExit, message: &str) {
110 match error.kind {
111 ExitKind::VersionInfos
112 | ExitKind::HelpInfos
113 | ExitKind::AuthorInfos => println!("{message}"),
114 ExitKind::Error => eprintln!("{message}"),
115 }
116 }
117}
118
119impl ArgsParser for ClapArgsParser {
120 fn parse(&self, args: impl IntoIterator<Item = OsString>) -> Args {
132 match self.try_parse(args) {
133 Ok(parsed_args) => parsed_args,
134 Err(error) => {
135 if let Some(value) = &error.styled_message {
136 Self::print_error_message(&error, value);
137 } else {
138 Self::print_error_message(&error, &error.message);
139 }
140
141 exit(error.exit_status);
142 }
143 }
144 }
145
146 fn try_parse(
147 &self,
148 args: impl IntoIterator<Item = OsString>,
149 ) -> Result<Args, ProgramExit> {
150 match self.cli_parser.clone().try_get_matches_from(args) {
151 Ok(parsing_result) => {
152 let parsed_args =
153 Self::map_arg_matches_to_struct(&parsing_result);
154 match self.parse_global_options(&parsed_args) {
155 Some(error) => Err(error),
156 None => Ok(parsed_args),
157 }
158 }
159 Err(error) => Err(ProgramExit {
160 message: format!(
161 "{}\nFor more information, try '--help'.",
162 error.render()
163 ),
164 exit_status: error.exit_code(),
165 styled_message: Some(format!(
166 "{}\nFor more information, try '\u{1b}[1m--help\u{1b}[0m'.",
167 error.render().ansi()
168 )),
169 kind: ExitKind::Error,
170 }),
171 }
172 }
173}