rusty_cli/flags/
flag_parser.rs

1use std::collections::HashMap;
2use crate::flags::flag::Flag;
3
4pub struct FlagParser {
5    /// All flags that are provided by the cli
6    flags: Vec<Flag>
7}
8
9impl FlagParser {
10
11    /// Creates a new instance of the flag parser
12    pub fn new(flags: Vec<Flag>) -> Self {
13        FlagParser {flags}
14    }
15
16    /// Parses all provided flags into a hashMap
17    /// If one of the provided flags is unknown the function will
18    /// return None and the cli will throw an error
19    pub fn parse_flags(&mut self) -> Option<HashMap<String, Option<String>>> {
20
21        let mut args = std::env::args();
22        let mut flags = HashMap::new();
23        if args.len() < 2 {
24            return Some(flags);
25        }
26        let mut i = 2;
27        while i<args.len() {
28            let arg = args.nth(i);
29            let flag = self.filter_flag_in_array(arg.unwrap());
30            if flag.is_none() {
31                // TODO: Log more specific errors
32                return None;
33            }
34            let safe_flag = flag.unwrap();
35            if safe_flag.has_arguments {
36                let flag_arguments = self.get_flag_value(i);
37                if flag_arguments.is_none() {
38                    // TODO: panic with value not given error
39                    return None;
40                }
41                flags.insert(safe_flag.clone().id, flag_arguments);
42                i += 2;
43            } else {
44                flags.insert(safe_flag.id, None);
45                i += 1;
46            }
47
48        }
49
50        return Some(flags);
51    }
52
53    /// Gets an flag by the raw argument provided by the rust interface
54    fn filter_flag_in_array(&mut self, arg: String) -> Option<Flag> {
55        if arg.starts_with("--") {
56            let parsed_arg = arg.split("--").collect::<Vec<&str>>()[1];
57            return self.get_flag_by_id(String::from(parsed_arg));
58        } else if arg.starts_with("-") {
59            let parsed_arg = arg.split("-").collect::<Vec<&str>>()[1];
60            return self.get_flag_by_shorthand(String::from(parsed_arg));
61        }
62        return None;
63    }
64
65    /// Gets the flag that is identified by the given id.
66    /// If there is no flag with this ID, the result will
67    /// be none
68    fn get_flag_by_id(&mut self, id: String) -> Option<Flag> {
69        for flag in self.flags.clone() {
70            if flag.id == id {
71                return Some(flag.clone());
72            }
73        }
74        return None;
75    }
76
77    /// Gets the flag that is identified by the given shorthand.
78    /// If there is no flag with this shorthand, the result will
79    /// be none
80    fn get_flag_by_shorthand(&mut self, shorthand: String) -> Option<Flag> {
81        for flag in self.flags.clone() {
82            if flag.shorthands.contains(&shorthand) {
83                return Some(flag.clone());
84            }
85        }
86        return None;
87    }
88
89    /// Gets the value of a flag if it must be provided
90    fn get_flag_value(&mut self, current_index: usize) -> Option<String> {
91        let mut args = std::env::args();
92        let max_size = args.len();
93        let next_index = current_index+1;
94        if next_index > max_size {
95            return None;
96        }
97        let value = args.nth(next_index).unwrap();
98        if value.starts_with("-") {
99            return None;
100        }
101        return Some(value);
102
103    }
104
105}