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}