gitignore_template_generator/config/
impls.rs

1use std::{ffi::OsString, process::exit};
2
3use clap::{CommandFactory, Parser};
4
5use crate::{
6    config::{Args, ArgsParser},
7    constant,
8    http_client::{ErrorKind, ProgramError},
9};
10
11pub struct DefaultArgsParser;
12
13impl DefaultArgsParser {
14    fn parse_global_options(args: &Args) -> Option<ProgramError> {
15        if args.show_help {
16            let mut cmd = Args::command();
17            let rendered_help = cmd.render_help();
18            Some(ProgramError {
19                message: rendered_help.to_string().trim_end().to_string(),
20                exit_status: constant::exit_status::SUCCESS,
21                styled_message: Some(
22                    rendered_help.ansi().to_string().trim_end().to_string(),
23                ),
24                error_kind: Some(ErrorKind::HelpInfos),
25            })
26        } else if args.show_version {
27            let cmd = Args::command();
28            let message = match cmd.get_version() {
29                Some(version) => {
30                    format!("{} {version}", env!("CARGO_PKG_NAME"))
31                }
32                None => constant::error_messages::VERSION_INFOS_NOT_AVAILABLE
33                    .to_string(),
34            };
35
36            Some(ProgramError {
37                message,
38                exit_status: constant::exit_status::SUCCESS,
39                styled_message: None,
40                error_kind: Some(ErrorKind::VersionInfos),
41            })
42        } else if args.show_author {
43            let cmd = Args::command();
44            let message = String::from(match cmd.get_author() {
45                Some(author) => author,
46                None => constant::error_messages::AUTHOR_INFOS_NOT_AVAILABLE,
47            });
48
49            Some(ProgramError {
50                message,
51                exit_status: constant::exit_status::SUCCESS,
52                styled_message: None,
53                error_kind: Some(ErrorKind::AuthorInfos),
54            })
55        } else {
56            None
57        }
58    }
59
60    fn print_error_message(error: &ProgramError, message: &str) {
61        if let Some(kind) = &error.error_kind {
62            match kind {
63                ErrorKind::VersionInfos
64                | ErrorKind::HelpInfos
65                | ErrorKind::AuthorInfos => println!("{message}"),
66                ErrorKind::Other => eprintln!("{message}"),
67            }
68        } else {
69            eprintln!("{message}");
70        }
71    }
72}
73
74impl ArgsParser for DefaultArgsParser {
75    fn parse(args: impl IntoIterator<Item = OsString>) -> Args {
76        match DefaultArgsParser::try_parse(args) {
77            Ok(parsed_args) => parsed_args,
78            Err(error) => {
79                if let Some(value) = &error.styled_message {
80                    Self::print_error_message(&error, value);
81                } else {
82                    Self::print_error_message(&error, &error.message);
83                }
84
85                exit(error.exit_status);
86            }
87        }
88    }
89
90    fn try_parse(
91        args: impl IntoIterator<Item = OsString>,
92    ) -> Result<Args, ProgramError> {
93        match Args::try_parse_from(args) {
94            Ok(parsed_args) => match Self::parse_global_options(&parsed_args) {
95                Some(error) => Err(error),
96                None => Ok(parsed_args),
97            },
98            Err(error) => Err(ProgramError {
99                message: format!(
100                    "{}\nFor more information, try '--help'.",
101                    error.render()
102                ),
103                exit_status: error.exit_code(),
104                styled_message: Some(format!(
105                    "{}\nFor more information, try '\u{1b}[1m--help\u{1b}[0m'.",
106                    error.render().ansi()
107                )),
108                error_kind: Some(ErrorKind::Other),
109            }),
110        }
111    }
112}