gitignore_template_generator/parser/
impls.rs

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