clap_complete/aot/shells/
shell.rs
1use std::fmt::Display;
2use std::io::Error;
3use std::path::Path;
4use std::str::FromStr;
5
6use clap::builder::PossibleValue;
7use clap::ValueEnum;
8
9use crate::shells;
10use crate::Generator;
11
12#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14#[non_exhaustive]
15pub enum Shell {
16 Bash,
18 Elvish,
20 Fish,
22 PowerShell,
24 Zsh,
26}
27
28impl Display for Shell {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 self.to_possible_value()
31 .expect("no values are skipped")
32 .get_name()
33 .fmt(f)
34 }
35}
36
37impl FromStr for Shell {
38 type Err = String;
39
40 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 for variant in Self::value_variants() {
42 if variant.to_possible_value().unwrap().matches(s, false) {
43 return Ok(*variant);
44 }
45 }
46 Err(format!("invalid variant: {s}"))
47 }
48}
49
50impl ValueEnum for Shell {
52 fn value_variants<'a>() -> &'a [Self] {
53 &[
54 Shell::Bash,
55 Shell::Elvish,
56 Shell::Fish,
57 Shell::PowerShell,
58 Shell::Zsh,
59 ]
60 }
61
62 fn to_possible_value(&self) -> Option<PossibleValue> {
63 Some(match self {
64 Shell::Bash => PossibleValue::new("bash"),
65 Shell::Elvish => PossibleValue::new("elvish"),
66 Shell::Fish => PossibleValue::new("fish"),
67 Shell::PowerShell => PossibleValue::new("powershell"),
68 Shell::Zsh => PossibleValue::new("zsh"),
69 })
70 }
71}
72
73impl Generator for Shell {
74 fn file_name(&self, name: &str) -> String {
75 match self {
76 Shell::Bash => shells::Bash.file_name(name),
77 Shell::Elvish => shells::Elvish.file_name(name),
78 Shell::Fish => shells::Fish.file_name(name),
79 Shell::PowerShell => shells::PowerShell.file_name(name),
80 Shell::Zsh => shells::Zsh.file_name(name),
81 }
82 }
83
84 fn generate(&self, cmd: &clap::Command, buf: &mut dyn std::io::Write) {
85 self.try_generate(cmd, buf)
86 .expect("failed to write completion file");
87 }
88
89 fn try_generate(&self, cmd: &clap::Command, buf: &mut dyn std::io::Write) -> Result<(), Error> {
90 match self {
91 Shell::Bash => shells::Bash.try_generate(cmd, buf),
92 Shell::Elvish => shells::Elvish.try_generate(cmd, buf),
93 Shell::Fish => shells::Fish.try_generate(cmd, buf),
94 Shell::PowerShell => shells::PowerShell.try_generate(cmd, buf),
95 Shell::Zsh => shells::Zsh.try_generate(cmd, buf),
96 }
97 }
98}
99
100impl Shell {
101 pub fn from_shell_path<P: AsRef<Path>>(path: P) -> Option<Shell> {
113 parse_shell_from_path(path.as_ref())
114 }
115
116 pub fn from_env() -> Option<Shell> {
139 if let Some(env_shell) = std::env::var_os("SHELL") {
140 Shell::from_shell_path(env_shell)
141 } else if cfg!(windows) {
142 Some(Shell::PowerShell)
143 } else {
144 None
145 }
146 }
147}
148
149fn parse_shell_from_path(path: &Path) -> Option<Shell> {
152 let name = path.file_stem()?.to_str()?;
153 match name {
154 "bash" => Some(Shell::Bash),
155 "zsh" => Some(Shell::Zsh),
156 "fish" => Some(Shell::Fish),
157 "elvish" => Some(Shell::Elvish),
158 "powershell" | "powershell_ise" => Some(Shell::PowerShell),
159 _ => None,
160 }
161}