gitignore_template_generator/parser/
impls.rs1use std::{ffi::OsString, process::exit};
2
3use clap::{ArgMatches, Command};
4
5use super::{Args, ArgsParser, 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 show_help: arg_matches.get_flag("HELP"),
95 show_version: arg_matches.get_flag("VERSION"),
96 show_author: arg_matches.get_flag("AUTHOR"),
97 show_list: arg_matches.get_flag("LIST"),
98 }
99 }
100
101 fn print_error_message(error: &ProgramExit, message: &str) {
102 match error.kind {
103 ExitKind::VersionInfos
104 | ExitKind::HelpInfos
105 | ExitKind::AuthorInfos => println!("{message}"),
106 ExitKind::Error => eprintln!("{message}"),
107 }
108 }
109}
110
111impl ArgsParser for ClapArgsParser {
112 fn parse(&self, args: impl IntoIterator<Item = OsString>) -> Args {
124 match self.try_parse(args) {
125 Ok(parsed_args) => parsed_args,
126 Err(error) => {
127 if let Some(value) = &error.styled_message {
128 Self::print_error_message(&error, value);
129 } else {
130 Self::print_error_message(&error, &error.message);
131 }
132
133 exit(error.exit_status);
134 }
135 }
136 }
137
138 fn try_parse(
139 &self,
140 args: impl IntoIterator<Item = OsString>,
141 ) -> Result<Args, ProgramExit> {
142 match self.cli_parser.clone().try_get_matches_from(args) {
143 Ok(parsing_result) => {
144 let parsed_args =
145 Self::map_arg_matches_to_struct(&parsing_result);
146 match self.parse_global_options(&parsed_args) {
147 Some(error) => Err(error),
148 None => Ok(parsed_args),
149 }
150 }
151 Err(error) => Err(ProgramExit {
152 message: format!(
153 "{}\nFor more information, try '--help'.",
154 error.render()
155 ),
156 exit_status: error.exit_code(),
157 styled_message: Some(format!(
158 "{}\nFor more information, try '\u{1b}[1m--help\u{1b}[0m'.",
159 error.render().ansi()
160 )),
161 kind: ExitKind::Error,
162 }),
163 }
164 }
165}