whattheshell/
shell.rs

1use crate::{
2    errors::{Error, Result},
3    infer::Infer,
4};
5use core::fmt;
6use std::str::FromStr;
7
8impl Shell {
9    /// Tries to infer the shell in which the program is currently
10    /// running in from the environment.
11    ///
12    /// ## Example
13    /// ```
14    /// # use whattheshell::Shell;
15    /// let shell = Shell::infer().unwrap();
16    /// dbg!(shell);
17    /// ```
18    pub fn infer() -> Result<Self> {
19        Infer::infer()
20    }
21}
22
23macro_rules! define_shells {
24    ($( $name:literal $(| $alias:literal ),* => $shell:tt ),*) => {
25        /// Shell declares a type of shell and allows to
26        /// infer the type of shell.
27        #[derive(Clone, Debug)]
28        pub enum Shell {
29            $(
30                $shell,
31            )*
32        }
33
34        impl FromStr for Shell {
35            type Err = Error;
36
37            fn from_str(s: &str) -> Result<Self, Self::Err> {
38                match s {
39                    $(
40                        $name $(| $alias)* => Ok(Self::$shell),
41                    )*
42                    _ => Err(Error::NoShellFound),
43                }
44            }
45        }
46
47        impl fmt::Display for Shell {
48            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49                match self {
50                    $(
51                        Self::$shell => write!(f, $name),
52                    )*
53                }
54            }
55        }
56    };
57}
58
59define_shells!(
60    "sh" => Sh,
61    "bash" => Bash,
62    "zsh" =>  Zsh,
63    "fish" =>  Fish,
64    "nu" => Nushell,
65    "powershell" | "pwsh" => PowerShell,
66    "cmd" => Cmd
67);
68
69#[cfg(test)]
70mod test {
71    use super::*;
72    use std::env;
73
74    #[test]
75    fn integrate() {
76        let actual = env::var("ACTUAL_SHELL").expect("env var \"ACTUAL_SHELL\" is not specified");
77
78        let res = Shell::infer().unwrap();
79        assert_eq!(actual, res.to_string());
80    }
81}