1use std::str::FromStr;
2
3use crate::{
4 cli_error::{CliError, CliResult},
5 input::{Completor, Input, InputType},
6};
7
8pub struct Flag<'a, T: Default + FromStr + Clone> {
12 pub name: String,
13 pub description: Option<String>,
14 pub value: Option<T>,
15 pub bool_flag: bool,
16 pub completor: Option<Completor<'a>>,
17}
18
19impl<'a> Flag<'a, bool> {
20 pub fn bool(name: &str) -> Self {
21 Self {
22 name: name.to_string(),
23 value: None,
24 bool_flag: true,
25 completor: None,
26 description: None,
27 }
28 }
29}
30
31impl<'a, T: FromStr + Default + Clone> Flag<'a, T> {
32 pub fn new(name: &str) -> Self {
33 Self {
34 name: name.to_string(),
35 value: None,
36 bool_flag: false,
37 completor: None,
38 description: None,
39 }
40 }
41
42 pub fn get(&self) -> T {
43 self.value.clone().unwrap_or_default()
44 }
45
46 pub fn description(mut self, description: &str) -> Self {
47 self.description = Some(description.to_string());
48 self
49 }
50
51 pub fn completor<F>(mut self, completor: F) -> Self
52 where
53 F: FnMut(&str) -> CliResult<Vec<String>> + 'a,
54 {
55 self.completor = Some(Box::new(completor));
56 self
57 }
58}
59
60impl<'a, T: FromStr + Default + Clone> Input for Flag<'a, T> {
61 fn parse(&mut self, token: &str) -> CliResult<bool> {
64 if token.len() == 2 && self.bool_flag {
66 if &token[0..1] != "-" {
67 return Ok(false);
69 }
70
71 if token[1..2].to_uppercase() == self.name[0..1].to_uppercase() {
72 self.value = Some("true".parse().unwrap_or_else(|_| unreachable!()));
73 return Ok(true);
74 }
75 }
76
77 let min_size = self.name.len() + 2; if token.len() < min_size {
80 return Ok(false);
81 }
82
83 let flag_length = self.name.len();
85 if token[2..flag_length + 2] != self.name {
86 return Ok(false);
87 }
88
89 if let Some(eq_idx) = token.find('=') {
91 let value = &token[eq_idx + 1..].to_string();
92
93 self.value = Some(value.parse().map_err(|_| {
94 CliError::from(format!("{} cannot be parsed for {}", value, self.name))
95 })?);
96
97 return Ok(true);
98 }
99
100 if self.bool_flag {
101 self.value = Some("true".parse().unwrap_or_else(|_| unreachable!()));
102 return Ok(true);
103 }
104
105 Ok(false)
106 }
107
108 fn display_name(&self) -> String {
109 self.name.clone()
110 }
111
112 fn type_name(&self) -> InputType {
113 InputType::Flag
114 }
115
116 fn parsed(&self) -> bool {
117 self.value.is_some()
118 }
119
120 fn complete(&mut self, value: &str) -> CliResult<Vec<String>> {
121 if let Some(completor) = &mut self.completor {
122 completor(value)
123 } else {
124 Ok(vec![])
125 }
126 }
127
128 fn is_bool_flag(&self) -> bool {
129 self.bool_flag
130 }
131
132 fn description(&self) -> Option<String> {
133 self.description.clone()
134 }
135
136 fn has_default(&self) -> bool {
137 true
138 }
139}