1 use std::fmt::Display;
2 use std::str::FromStr;
3 
4 use clap::builder::PossibleValue;
5 use clap::ValueEnum;
6 
7 /// Completion support for built-in shells
8 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
9 #[non_exhaustive]
10 pub enum Shell {
11     /// Bourne Again `SHell` (bash)
12     Bash,
13     /// Friendly Interactive `SHell` (fish)
14     Fish,
15 }
16 
17 impl Display for Shell {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result18     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19         self.to_possible_value()
20             .expect("no values are skipped")
21             .get_name()
22             .fmt(f)
23     }
24 }
25 
26 impl FromStr for Shell {
27     type Err = String;
28 
from_str(s: &str) -> Result<Self, Self::Err>29     fn from_str(s: &str) -> Result<Self, Self::Err> {
30         for variant in Self::value_variants() {
31             if variant.to_possible_value().unwrap().matches(s, false) {
32                 return Ok(*variant);
33             }
34         }
35         Err(format!("invalid variant: {s}"))
36     }
37 }
38 
39 // Hand-rolled so it can work even when `derive` feature is disabled
40 impl ValueEnum for Shell {
value_variants<'a>() -> &'a [Self]41     fn value_variants<'a>() -> &'a [Self] {
42         &[Shell::Bash, Shell::Fish]
43     }
44 
to_possible_value(&self) -> Option<PossibleValue>45     fn to_possible_value(&self) -> Option<PossibleValue> {
46         Some(match self {
47             Shell::Bash => PossibleValue::new("bash"),
48             Shell::Fish => PossibleValue::new("fish"),
49         })
50     }
51 }
52 
53 impl Shell {
completer(&self) -> &dyn crate::dynamic::Completer54     fn completer(&self) -> &dyn crate::dynamic::Completer {
55         match self {
56             Self::Bash => &super::Bash,
57             Self::Fish => &super::Fish,
58         }
59     }
60 }
61 
62 impl crate::dynamic::Completer for Shell {
file_name(&self, name: &str) -> String63     fn file_name(&self, name: &str) -> String {
64         self.completer().file_name(name)
65     }
write_registration( &self, name: &str, bin: &str, completer: &str, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error>66     fn write_registration(
67         &self,
68         name: &str,
69         bin: &str,
70         completer: &str,
71         buf: &mut dyn std::io::Write,
72     ) -> Result<(), std::io::Error> {
73         self.completer()
74             .write_registration(name, bin, completer, buf)
75     }
write_complete( &self, cmd: &mut clap::Command, args: Vec<std::ffi::OsString>, current_dir: Option<&std::path::Path>, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error>76     fn write_complete(
77         &self,
78         cmd: &mut clap::Command,
79         args: Vec<std::ffi::OsString>,
80         current_dir: Option<&std::path::Path>,
81         buf: &mut dyn std::io::Write,
82     ) -> Result<(), std::io::Error> {
83         self.completer().write_complete(cmd, args, current_dir, buf)
84     }
85 }
86