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 server_url: arg_matches
79 .get_one::<String>("SERVER_URL")
80 .unwrap()
81 .to_string(),
82 generator_uri: arg_matches
83 .get_one::<String>("GENERATOR_URI")
84 .unwrap()
85 .to_string(),
86 lister_uri: arg_matches
87 .get_one::<String>("LISTER_URI")
88 .unwrap()
89 .to_string(),
90 timeout: match arg_matches.get_one::<u64>("TIMEOUT") {
91 Some(timeout) => *timeout,
92 None => constant::template_manager::TIMEOUT_INT,
93 },
94 timeout_unit: arg_matches
95 .get_one::<TimeoutUnit>("TIMEOUT_UNIT")
96 .unwrap()
97 .to_owned(),
98 check_template_names: arg_matches.get_flag("CHECK"),
99 show_help: arg_matches.get_flag("HELP"),
100 show_version: arg_matches.get_flag("VERSION"),
101 show_author: arg_matches.get_flag("AUTHOR"),
102 show_list: arg_matches.get_flag("LIST"),
103 }
104 }
105
106 fn print_error_message(error: &ProgramExit, message: &str) {
107 match error.kind {
108 ExitKind::VersionInfos
109 | ExitKind::HelpInfos
110 | ExitKind::AuthorInfos => println!("{message}"),
111 ExitKind::Error => eprintln!("{message}"),
112 }
113 }
114}
115
116impl ArgsParser for ClapArgsParser {
117 fn parse(&self, args: impl IntoIterator<Item = OsString>) -> Args {
129 match self.try_parse(args) {
130 Ok(parsed_args) => parsed_args,
131 Err(error) => {
132 if let Some(value) = &error.styled_message {
133 Self::print_error_message(&error, value);
134 } else {
135 Self::print_error_message(&error, &error.message);
136 }
137
138 exit(error.exit_status);
139 }
140 }
141 }
142
143 fn try_parse(
144 &self,
145 args: impl IntoIterator<Item = OsString>,
146 ) -> Result<Args, ProgramExit> {
147 match self.cli_parser.clone().try_get_matches_from(args) {
148 Ok(parsing_result) => {
149 let parsed_args =
150 Self::map_arg_matches_to_struct(&parsing_result);
151 match self.parse_global_options(&parsed_args) {
152 Some(error) => Err(error),
153 None => Ok(parsed_args),
154 }
155 }
156 Err(error) => Err(ProgramExit {
157 message: format!(
158 "{}\nFor more information, try '--help'.",
159 error.render()
160 ),
161 exit_status: error.exit_code(),
162 styled_message: Some(format!(
163 "{}\nFor more information, try '\u{1b}[1m--help\u{1b}[0m'.",
164 error.render().ansi()
165 )),
166 kind: ExitKind::Error,
167 }),
168 }
169 }
170}