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