1use std::fmt::Debug;
4
5use crate::{Completer, Prompter, Validator};
6
7#[derive(Debug, Clone, PartialEq, Eq, Default)]
9pub enum ArgKind {
10 #[default]
12 Positional,
13 Flag {
15 short: Option<char>,
16 long: String,
17 aliases: Vec<String>,
18 },
19 Option {
21 short: Option<char>,
22 long: String,
23 aliases: Vec<String>,
24 },
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum ArgType {
30 String,
31 Int,
32 Float,
33 Bool,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub struct ArgSchema {
38 pub ty: ArgType,
39 pub required: bool,
40 pub default_value: Option<String>,
41 pub multiple: bool,
42 pub enum_options: Option<Vec<(String, String)>>,
43}
44
45pub struct Arg {
46 pub info: ArgInfo,
47 pub validators: Vec<Box<dyn Validator>>,
48 pub completers: Vec<Box<dyn Completer>>,
49 pub prompters: Vec<Box<dyn Prompter>>,
50}
51
52#[derive(Debug, Clone, PartialEq)]
53pub struct ArgInfo {
54 pub name: String,
55 pub title: String,
56 pub description: String,
57 pub kind: ArgKind,
58 pub schema: ArgSchema,
59 pub env: Option<String>,
60}
61
62impl Arg {
63 pub fn flag(long: impl Into<String>) -> Self {
69 let long_str = long.into();
70 Self {
71 info: ArgInfo {
72 name: long_str.clone(),
73 title: String::new(),
74 description: String::new(),
75 kind: ArgKind::Flag {
76 short: None,
77 long: long_str,
78 aliases: Vec::new(),
79 },
80 schema: ArgSchema {
81 ty: ArgType::Bool,
82 required: false,
83 default_value: None,
84 multiple: false,
85 enum_options: None,
86 },
87 env: None,
88 },
89 validators: Vec::new(),
90 completers: Vec::new(),
91 prompters: Vec::new(),
92 }
93 }
94
95 pub fn option(long: impl Into<String>, ty: ArgType) -> Self {
97 let long_str = long.into();
98 Self {
99 info: ArgInfo {
100 name: long_str.clone(),
101 title: String::new(),
102 description: String::new(),
103 kind: ArgKind::Option {
104 short: None,
105 long: long_str,
106 aliases: Vec::new(),
107 },
108 schema: ArgSchema {
109 ty,
110 required: false,
111 default_value: None,
112 multiple: false,
113 enum_options: None,
114 },
115 env: None,
116 },
117 validators: Vec::new(),
118 completers: Vec::new(),
119 prompters: Vec::new(),
120 }
121 }
122
123 pub fn positional(name: impl Into<String>, ty: ArgType) -> Self {
125 Self {
126 info: ArgInfo {
127 name: name.into(),
128 title: String::new(),
129 description: String::new(),
130 kind: ArgKind::Positional,
131 schema: ArgSchema {
132 ty,
133 required: false,
134 default_value: None,
135 multiple: false,
136 enum_options: None,
137 },
138 env: None,
139 },
140 validators: Vec::new(),
141 completers: Vec::new(),
142 prompters: Vec::new(),
143 }
144 }
145
146 pub fn title(mut self, title: impl Into<String>) -> Self {
152 self.info.title = title.into();
153 self
154 }
155
156 pub fn description(mut self, description: impl Into<String>) -> Self {
158 self.info.description = description.into();
159 self
160 }
161
162 pub fn short(mut self, short: char) -> Self {
164 match &mut self.info.kind {
165 ArgKind::Flag { short: s, .. } | ArgKind::Option { short: s, .. } => {
166 *s = Some(short);
167 }
168 ArgKind::Positional => (),
169 }
170 self
171 }
172
173 pub fn aliases(mut self, aliases: Vec<String>) -> Self {
174 match &mut self.info.kind {
175 ArgKind::Flag { aliases: a, .. } | ArgKind::Option { aliases: a, .. } => {
176 *a = aliases;
177 }
178 ArgKind::Positional => (),
179 }
180 self
181 }
182
183 pub fn ty(mut self, ty: ArgType) -> Self {
184 self.info.schema.ty = ty;
185 self
186 }
187
188 pub fn required(mut self) -> Self {
190 self.info.schema.required = true;
191 self
192 }
193
194 pub fn default(mut self, value: impl Into<String>) -> Self {
196 self.info.schema.default_value = Some(value.into());
197 self
198 }
199
200 pub fn multiple(mut self) -> Self {
202 self.info.schema.multiple = true;
203 self
204 }
205
206 pub fn env(mut self, env_var: impl Into<String>) -> Self {
208 self.info.env = Some(env_var.into());
209 self
210 }
211
212 pub fn enums(mut self, options: Vec<(impl Into<String>, impl Into<String>)>) -> Self {
214 self.info.schema.enum_options = Some(
215 options
216 .into_iter()
217 .map(|(label, value)| (label.into(), value.into()))
218 .collect(),
219 );
220 self
221 }
222
223 pub fn validator(mut self, v: Box<dyn Validator + 'static>) -> Self {
225 self.validators.push(v);
226 self
227 }
228
229 pub fn completer(mut self, c: Box<dyn Completer + 'static>) -> Self {
231 self.completers.push(c);
232 self
233 }
234
235 pub fn prompter(mut self, p: Box<dyn Prompter + 'static>) -> Self {
237 self.prompters.push(p);
238 self
239 }
240}