jargon_args/
keys.rs

1use std::fmt::Formatter;
2
3/// # Key
4///
5/// This is the Key enum that represents processable arguments. This has four variants.
6///
7/// ## Dual
8///
9/// Key::Dual represents ONLY Key::Long and Key::Short in one, they both must start with the same character.
10///
11/// ```
12/// let key: jargon_args::Key = ["-a", "--all"].into();
13/// assert!(key.is_dual())
14/// ```
15///
16/// ## Long
17///
18/// Key::Long represents a full name argument like `--all`.
19///
20/// ```
21/// let key: jargon_args::Key = "--all".into();
22/// assert!(key.is_long())
23/// ```
24///
25/// ## Short
26///
27/// Key::Short represents a single letter argument like `-a`.
28///
29/// ```
30/// let key: jargon_args::Key = "-a".into();
31/// assert!(key.is_short())
32/// ```
33///
34/// ## sub
35///
36/// Key::Sub represents a subcommand argument, anything not converted into any other time becomes Key::Sub.
37///
38/// ```
39/// let key: jargon_args::Key = "list".into();
40/// assert!(key.is_sub())
41/// ```
42#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
43pub enum Key {
44    /// # Dual
45    ///
46    /// Key::Dual represents ONLY Key::Long and Key::Short in one, they both must start with the same character.
47    ///
48    /// ```
49    /// let key: jargon_args::Key = ["-a", "--all"].into();
50    /// assert!(key.is_dual())
51    /// ```
52    Dual {
53        /// The character at the beginning of each argument.
54        char: char,
55        /// The single character for the short argument.
56        s_txt: char,
57        /// The word for the long argument.
58        l_txt: String,
59    },
60
61    /// # Long
62    ///
63    /// Key::Long represents a full name argument like `--all`.
64    ///
65    /// ```
66    /// let key: jargon_args::Key = "--all".into();
67    /// assert!(key.is_long())
68    /// ```
69    Long {
70        /// The character at the beginning of the argument.
71        char: char,
72        /// The word for the argument.
73        txt: String,
74    },
75
76    /// # Short
77    ///
78    /// Key::Short represents a single letter argument like `-a`.
79    ///
80    /// ```
81    /// let key: jargon_args::Key = "-a".into();
82    /// assert!(key.is_short())
83    /// ```
84    Short {
85        /// The character at the beginning of the argument.
86        char: char,
87        /// The character for the argument.
88        txt: char,
89    },
90
91    /// # sub
92    ///
93    /// Key::Sub represents a subcommand argument, anything not converted into any other time becomes Key::Sub.
94    ///
95    /// ```
96    /// let key: jargon_args::Key = "list".into();
97    /// assert!(key.is_sub())
98    /// ```
99    Sub {
100        /// The word for the subcommand.
101        txt: String,
102    },
103}
104
105impl Key {
106    /// Return the char at the beginning of each argument, Key::sub returns `\0`.
107    pub fn char(&self) -> char {
108        match self {
109            Key::Dual { char: c, .. } => *c,
110            Key::Long { char: c, .. } => *c,
111            Key::Short { char: c, .. } => *c,
112            Key::Sub { .. } => '\0',
113        }
114    }
115
116    /// Returns only the text of each argument as String. `--all` is `all`.
117    pub fn text(&self) -> String {
118        match self {
119            Key::Dual { l_txt: txt, .. } => txt.clone(),
120            Key::Long { txt, .. } => txt.clone(),
121            Key::Short { txt, .. } => txt.to_string(),
122            Key::Sub { txt, .. } => txt.clone(),
123        }
124    }
125
126    /// Returns true if Key is Key::Dual.
127    pub fn is_dual(&self) -> bool {
128        match self {
129            Key::Dual { .. } => true,
130            Key::Long { .. } => false,
131            Key::Short { .. } => false,
132            Key::Sub { .. } => false,
133        }
134    }
135
136    /// Returns true if Key is Key::Long.
137    pub fn is_long(&self) -> bool {
138        match self {
139            Key::Dual { .. } => false,
140            Key::Long { .. } => true,
141            Key::Short { .. } => false,
142            Key::Sub { .. } => false,
143        }
144    }
145
146    /// Returns true if Key is Key::Short.
147    pub fn is_short(&self) -> bool {
148        match self {
149            Key::Dual { .. } => false,
150            Key::Long { .. } => false,
151            Key::Short { .. } => true,
152            Key::Sub { .. } => false,
153        }
154    }
155
156    /// Returns true if Key is Key::Sub.
157    pub fn is_sub(&self) -> bool {
158        match self {
159            Key::Dual { .. } => false,
160            Key::Long { .. } => false,
161            Key::Short { .. } => false,
162            Key::Sub { .. } => true,
163        }
164    }
165}
166
167impl From<String> for Key {
168    fn from(s: String) -> Self {
169        let chars: Vec<char> = s.chars().collect();
170
171        if !chars[0].is_alphabetic() {
172            let char: char = chars[0];
173            if s.len() == 2 {
174                let txt: char = chars[1];
175
176                Self::Short { char, txt }
177            } else {
178                let mut txt: String = String::new();
179
180                chars
181                    .iter()
182                    .skip_while(|x| **x == chars[0])
183                    .for_each(|x| txt = format!("{}{}", txt, x));
184
185                Self::Long { char, txt }
186            }
187        } else {
188            Self::Sub { txt: s }
189        }
190    }
191}
192
193impl From<&str> for Key {
194    fn from(s: &str) -> Self {
195        s.to_string().into()
196    }
197}
198
199impl<T: Clone + Into<Key>> From<[T; 2]> for Key {
200    fn from(dk: [T; 2]) -> Self {
201        let one: Key = dk[0].clone().into();
202        let two: Key = dk[1].clone().into();
203
204        if one.is_sub() || two.is_sub() {
205            panic!("dual cannot contain a subcommand!");
206        }
207
208        if one.is_long() && two.is_short() {
209            Key::Dual {
210                char: one.char(),
211                s_txt: two.text().parse().unwrap(),
212                l_txt: one.text(),
213            }
214        } else {
215            Key::Dual {
216                char: two.char(),
217                s_txt: one.text().parse().unwrap(),
218                l_txt: two.text(),
219            }
220        }
221    }
222}
223
224impl std::fmt::Display for Key {
225    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
226        write!(
227            f,
228            "{}",
229            match self {
230                Key::Dual {
231                    char: c,
232                    s_txt: s,
233                    l_txt: l,
234                } => format!("{}{}, {}{}{}", c, s, c, c, l),
235                Key::Long { char: c, txt: t } => format!("{}{}{}", c, c, t),
236                Key::Short { char: c, txt: t } => format!("{}{}", c, t),
237                Key::Sub { txt: t } => t.to_string(),
238            }
239        )
240    }
241}