1use std::str::FromStr;
2use sysinfo::{get_current_pid, ProcessExt, ProcessRefreshKind, RefreshKind, System, SystemExt};
3use thiserror::Error;
4
5#[derive(Error, Debug, PartialEq, Clone)]
8#[non_exhaustive]
9pub enum Error {
10 #[error("The platform is not supported")]
11 UnsupportedPlatform,
12 #[error("Current process does not have a parent")]
13 NoParent,
14 #[error("Unknown shell")]
15 Unknown,
16 #[error("Unavailable with some su implementations")]
17 InSu,
18}
19
20pub fn get_shell_name() -> Result<String, Error> {
28 let sys =
29 System::new_with_specifics(RefreshKind::new().with_processes(ProcessRefreshKind::new()));
30 let process = sys
31 .process(get_current_pid().map_err(|_| Error::UnsupportedPlatform)?)
32 .expect("Process with current pid does not exist");
33 let parent = sys
34 .process(process.parent().ok_or(Error::NoParent)?)
35 .expect("Process with parent pid does not exist");
36 let shell = parent.name().trim().to_lowercase();
37 let shell = shell.strip_suffix(".exe").unwrap_or(&shell); let shell = shell.strip_prefix('-').unwrap_or(shell); Ok(shell.to_owned())
40}
41pub fn get_shell() -> Result<Shell, Error> {
42 Shell::get()
43}
44
45#[derive(Debug, PartialEq, Eq, Clone, Copy)]
47#[non_exhaustive]
48pub enum Shell {
49 Bash,
50 Elvish,
51 Fish,
52 Ion,
53 Nushell,
54 Powershell,
55 Xonsh,
56 Zsh,
57}
58
59impl Shell {
60 pub fn get() -> Result<Self, Error> {
64 match get_shell_name()?.as_str() {
65 "su" => Err(Error::InSu),
66 shell if shell.starts_with("python") => Ok(Self::Xonsh),
67 shell => Self::from_str(shell),
68 }
69 }
70 pub fn to_str(self) -> &'static str {
79 match self {
80 Shell::Bash => "bash",
81 Shell::Elvish => "elvish",
82 Shell::Fish => "fish",
83 Shell::Ion => "ion",
84 Shell::Nushell => "nu",
85 Shell::Powershell => "powershell",
86 Shell::Xonsh => "xonsh",
87 Shell::Zsh => "zsh",
88 }
89 }
90}
91
92impl FromStr for Shell {
93 type Err = Error;
94
95 fn from_str(s: &str) -> Result<Self, Self::Err> {
96 match s {
97 "bash" => Ok(Shell::Bash),
98 "elvish" => Ok(Shell::Elvish),
99 "fish" => Ok(Shell::Fish),
100 "ion" => Ok(Shell::Ion),
101 "nu" | "nushell" => Ok(Shell::Nushell),
102 "pwsh" | "powershell" => Ok(Shell::Powershell),
103 "xonsh" | "xon.sh" => Ok(Shell::Xonsh),
104 "zsh" => Ok(Shell::Zsh),
105 _ => Err(Error::Unknown),
106 }
107 }
108}