1pub(crate) mod bash;
2pub(crate) mod fish;
3pub(crate) mod ps1;
4pub(crate) mod zsh;
5
6use std::ffi::OsStr;
7use std::io::Write;
8
9use crate::acore::opt::Opt;
10use crate::acore::opt::Style;
11use crate::acore::trace;
12use crate::acore::HashMap;
13use crate::value::Values;
14use crate::Error;
15
16pub use bash::Bash;
17pub use fish::Fish;
18pub use ps1::PowerShell;
19pub use zsh::Zsh;
20
21pub trait Complete<O> {
22 type Out;
23 type Ctx<'a>;
24 type Err: Into<Error>;
25
26 fn complete<'a, T, W>(
27 &self,
28 s: &mut T,
29 ctx: &mut Self::Ctx<'a>,
30 ) -> Result<Self::Out, Self::Err>
31 where
32 W: Write,
33 T: Shell<O, W>;
34}
35
36macro_rules! name_iter {
37 ($opt:ident) => {
38 std::iter::once($opt.name()).chain(
39 $opt.alias()
40 .iter()
41 .flat_map(|v| v.iter().map(|v| v.as_str())),
42 )
43 };
44}
45
46pub fn complete_cmd<'a, O, I, F>(arg: &str, opts: I, mut f: F) -> Result<bool, Error>
47where
48 O: Opt + 'a,
49 I: Iterator<Item = &'a O>,
50 F: FnMut(&str, &O) -> Result<(), Error>,
51{
52 let mut found = false;
53
54 for opt in opts.filter(|v| v.mat_style(Style::Cmd)) {
55 for name in name_iter!(opt).filter(|v| v.starts_with(arg)) {
56 trace!("available cmd -> {name}");
57 f(name, opt)?;
58 found = true;
59 }
60 }
61 Ok(found)
62}
63
64pub fn complete_val<'a, O, I, F>(
65 arg: &str,
66 bytes: &[u8],
67 opts: I,
68 values: &mut HashMap<String, Box<dyn Values<O, Err = Error>>>,
69 mut f: F,
70) -> Result<bool, Error>
71where
72 O: Opt + 'a,
73 I: Iterator<Item = &'a O>,
74 F: FnMut(&OsStr, &O) -> Result<(), Error>,
75{
76 complete_eq(arg, bytes, opts, values, |_, val, opt| f(val, opt))
77}
78
79pub fn complete_eq<'a, O, I, F>(
80 arg: &str,
81 bytes: &[u8],
82 opts: I,
83 values: &mut HashMap<String, Box<dyn Values<O, Err = Error>>>,
84 mut f: F,
85) -> Result<bool, Error>
86where
87 O: Opt + 'a,
88 I: Iterator<Item = &'a O>,
89 F: FnMut(&str, &OsStr, &O) -> Result<(), Error>,
90{
91 let mut found = false;
92
93 for opt in opts.filter(|v| v.mat_style(Style::Argument)) {
94 for name in name_iter!(opt).filter(|v| v == &arg) {
95 if let Some(getter) = values.get_mut(name) {
96 for val in getter.get_values(opt)? {
97 if !val.is_empty() && bytes.is_empty()
98 || bytes
99 .iter()
100 .zip(val.as_encoded_bytes())
101 .all(|(a, b)| *a == *b)
102 {
103 trace!("available opt value -> {}", val.display());
104 f(arg, val, opt)?;
105 found = true;
106 }
107 }
108 }
109 }
110 }
111 Ok(found)
112}
113
114pub fn complete_opt<'a, O, I, F>(arg: &str, opts: I, mut f: F) -> Result<bool, Error>
115where
116 O: Opt + 'a,
117 I: Iterator<Item = &'a O>,
118 F: FnMut(&str, &O) -> Result<(), Error>,
119{
120 let mut found = false;
121
122 for opt in opts.filter(|v| {
123 v.mat_style(Style::Argument)
124 || v.mat_style(Style::Boolean)
125 || v.mat_style(Style::Combined)
126 || v.mat_style(Style::Flag)
127 }) {
128 for name in name_iter!(opt).filter(|v| v.starts_with(arg)) {
129 trace!("available opt -> {name}");
130 f(name, opt)?;
131 found = true;
132 }
133 }
134 Ok(found)
135}
136
137pub trait Shell<O, W> {
138 type Err: Into<Error>;
139
140 fn is_avail(&self, name: &str) -> bool;
141
142 fn set_buff(&mut self, w: W);
143
144 fn write_cmd(&mut self, name: &str, opt: &O) -> Result<(), Self::Err>;
145
146 fn write_opt(&mut self, name: &str, opt: &O) -> Result<(), Self::Err>;
147
148 fn write_pos(&mut self, name: &str, opt: &O) -> Result<(), Self::Err>;
149
150 fn write_val(&mut self, val: &OsStr, opt: &O) -> Result<(), Self::Err>;
151
152 fn write_eq(&mut self, name: &str, val: &OsStr, opt: &O) -> Result<(), Self::Err>;
153
154 fn finish(&mut self) -> Result<(), Self::Err>;
155
156 fn take_buff(&mut self) -> Option<W>;
157}
158
159impl<O, W, E: Into<Error>> Shell<O, W> for Box<dyn Shell<O, W, Err = E>> {
160 type Err = E;
161
162 fn is_avail(&self, name: &str) -> bool {
163 Shell::is_avail(self.as_ref(), name)
164 }
165
166 fn write_cmd(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
167 Shell::write_cmd(self.as_mut(), name, opt)
168 }
169
170 fn write_opt(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
171 Shell::write_opt(self.as_mut(), name, opt)
172 }
173
174 fn write_pos(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
175 Shell::write_pos(self.as_mut(), name, opt)
176 }
177
178 fn write_val(&mut self, val: &OsStr, opt: &O) -> Result<(), Self::Err> {
179 Shell::write_val(self.as_mut(), val, opt)
180 }
181
182 fn write_eq(&mut self, name: &str, val: &OsStr, opt: &O) -> Result<(), Self::Err> {
183 Shell::write_eq(self.as_mut(), name, val, opt)
184 }
185
186 fn set_buff(&mut self, w: W) {
187 Shell::set_buff(self.as_mut(), w);
188 }
189
190 fn finish(&mut self) -> Result<(), Self::Err> {
191 Shell::finish(self.as_mut())
192 }
193
194 fn take_buff(&mut self) -> Option<W> {
195 Shell::take_buff(self.as_mut())
196 }
197}
198
199pub fn wrap<O, W, S: Shell<O, W>>(inner: S) -> Adapter<S> {
200 Adapter { inner }
201}
202
203pub fn wrapref<'a, O, W, S: Shell<O, W>>(inner: &'a mut S) -> AdapterRef<'a, S> {
204 AdapterRef { inner }
205}
206
207pub struct Adapter<T> {
208 pub inner: T,
209}
210
211impl<O, W, T: Shell<O, W>> Shell<O, W> for Adapter<T> {
212 type Err = Error;
213
214 fn is_avail(&self, name: &str) -> bool {
215 self.inner.is_avail(name)
216 }
217
218 fn write_cmd(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
219 self.inner.write_cmd(name, opt).map_err(Into::into)
220 }
221
222 fn write_opt(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
223 self.inner.write_opt(name, opt).map_err(Into::into)
224 }
225
226 fn write_pos(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
227 self.inner.write_pos(name, opt).map_err(Into::into)
228 }
229
230 fn write_val(&mut self, val: &OsStr, opt: &O) -> Result<(), Self::Err> {
231 self.inner.write_val(val, opt).map_err(Into::into)
232 }
233
234 fn write_eq(&mut self, name: &str, val: &OsStr, opt: &O) -> Result<(), Self::Err> {
235 self.inner.write_eq(name, val, opt).map_err(Into::into)
236 }
237
238 fn set_buff(&mut self, w: W) {
239 self.inner.set_buff(w);
240 }
241
242 fn finish(&mut self) -> Result<(), Self::Err> {
243 self.inner.finish().map_err(Into::into)
244 }
245
246 fn take_buff(&mut self) -> Option<W> {
247 self.inner.take_buff()
248 }
249}
250
251pub struct AdapterRef<'a, T> {
252 pub inner: &'a mut T,
253}
254
255impl<'a, O, W, T: Shell<O, W>> Shell<O, W> for AdapterRef<'a, T> {
256 type Err = Error;
257
258 fn is_avail(&self, name: &str) -> bool {
259 self.inner.is_avail(name)
260 }
261
262 fn write_cmd(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
263 self.inner.write_cmd(name, opt).map_err(Into::into)
264 }
265
266 fn write_opt(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
267 self.inner.write_opt(name, opt).map_err(Into::into)
268 }
269
270 fn write_pos(&mut self, name: &str, opt: &O) -> Result<(), Self::Err> {
271 self.inner.write_pos(name, opt).map_err(Into::into)
272 }
273
274 fn write_val(&mut self, val: &OsStr, opt: &O) -> Result<(), Self::Err> {
275 self.inner.write_val(val, opt).map_err(Into::into)
276 }
277
278 fn write_eq(&mut self, name: &str, val: &OsStr, opt: &O) -> Result<(), Self::Err> {
279 self.inner.write_eq(name, val, opt).map_err(Into::into)
280 }
281
282 fn set_buff(&mut self, w: W) {
283 self.inner.set_buff(w);
284 }
285
286 fn finish(&mut self) -> Result<(), Self::Err> {
287 self.inner.finish().map_err(Into::into)
288 }
289
290 fn take_buff(&mut self) -> Option<W> {
291 self.inner.take_buff()
292 }
293}
294
295pub struct Manager<'a, O, W> {
296 gens: Vec<Box<dyn Shell<O, W, Err = Error> + 'a>>,
297}
298
299impl<'a, O, W> Default for Manager<'a, O, W>
300where
301 W: Write + 'a,
302 O: Opt + 'a,
303{
304 fn default() -> Self {
305 Self {
306 gens: vec![
307 Box::new(Bash::new()),
308 Box::new(Fish::new()),
309 Box::new(PowerShell::new()),
310 Box::new(Zsh::new()),
311 ],
312 }
313 }
314}
315
316impl<'a, O: 'a, W: 'a> Manager<'a, O, W> {
317 pub fn new() -> Self {
318 Self { gens: vec![] }
319 }
320
321 pub fn register(&mut self, r#gen: impl Shell<O, W> + 'a) -> &mut Self {
322 self.gens.push(Box::new(wrap(r#gen)));
323 self
324 }
325
326 pub fn find(&self, shell: &str) -> Result<&(dyn Shell<O, W, Err = Error>), Error> {
327 self.gens
328 .iter()
329 .find(|v| v.as_ref().is_avail(shell))
330 .ok_or_else(|| crate::error!("can not find shell type `{shell}`"))
331 .map(|v| v.as_ref())
332 }
333
334 pub fn find_mut(
335 &mut self,
336 shell: &str,
337 ) -> Result<&mut Box<dyn Shell<O, W, Err = Error> + 'a>, Error> {
338 self.gens
339 .iter_mut()
340 .find(|v| v.as_ref().is_avail(shell))
341 .ok_or_else(|| crate::error!("can not find shell type `{shell}`"))
342 }
343
344 pub fn take(&mut self, shell: &str) -> Result<Box<dyn Shell<O, W, Err = Error> + 'a>, Error> {
345 self.gens
346 .iter()
347 .position(|v| v.as_ref().is_avail(shell))
348 .ok_or_else(|| crate::error!("can not find shell type `{shell}`"))
349 .map(|v| self.gens.swap_remove(v))
350 }
351}