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