1use std::env;
2use std::path::PathBuf;
3use sysinfo::System;
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum OsType {
8 Windows,
9 Linux,
10 MacOS,
11}
12
13impl OsType {
14 pub fn as_str(&self) -> &str {
15 match self {
16 OsType::Windows => "Windows",
17 OsType::Linux => "Linux",
18 OsType::MacOS => "macOS",
19 }
20 }
21}
22
23#[derive(Debug, Clone, PartialEq)]
25pub enum ShellType {
26 Cmd,
27 PowerShell,
28 Bash,
29 Zsh,
30 Fish,
31 Unknown,
32}
33
34impl ShellType {
35 pub fn as_str(&self) -> &str {
36 match self {
37 ShellType::Cmd => "cmd.exe",
38 ShellType::PowerShell => "PowerShell",
39 ShellType::Bash => "bash",
40 ShellType::Zsh => "zsh",
41 ShellType::Fish => "fish",
42 ShellType::Unknown => "unknown",
43 }
44 }
45}
46
47#[derive(Debug, Clone)]
49pub struct SystemInfo {
50 pub os: OsType,
51 pub shell: ShellType,
52 pub current_dir: PathBuf,
53 pub username: Option<String>,
54 pub hostname: Option<String>,
55}
56
57impl SystemInfo {
58 pub fn display(&self) -> String {
59 format!(
60 "OS: {}\nShell: {}\nCurrent Dir: {}\nUsername: {}\nHostname: {}",
61 self.os.as_str(),
62 self.shell.as_str(),
63 self.current_dir.display(),
64 self.username.as_deref().unwrap_or("(unknown)"),
65 self.hostname.as_deref().unwrap_or("(unknown)")
66 )
67 }
68}
69
70pub fn get_system_info() -> SystemInfo {
72 SystemInfo {
73 os: detect_os(),
74 shell: detect_shell(),
75 current_dir: env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
76 username: env::var("USERNAME").or_else(|_| env::var("USER")).ok(),
77 hostname: env::var("COMPUTERNAME")
78 .or_else(|_| env::var("HOSTNAME"))
79 .ok(),
80 }
81}
82
83pub fn detect_os() -> OsType {
85 #[cfg(target_os = "windows")]
86 return OsType::Windows;
87
88 #[cfg(target_os = "linux")]
89 return OsType::Linux;
90
91 #[cfg(target_os = "macos")]
92 return OsType::MacOS;
93
94 #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
95 return OsType::Linux; }
97
98pub fn detect_shell() -> ShellType {
100 if let Some(name) = detect_shell_from_parent() {
102 let name = name.to_lowercase();
103 if name.contains("bash") {
104 return ShellType::Bash;
105 } else if name.contains("zsh") {
106 return ShellType::Zsh;
107 } else if name.contains("fish") {
108 return ShellType::Fish;
109 } else if name.contains("powershell") || name.contains("pwsh") {
110 return ShellType::PowerShell;
111 } else if name.contains("cmd") {
112 return ShellType::Cmd;
113 }
114 }
115
116 if cfg!(target_os = "windows") {
118 if let Ok(comspec) = env::var("COMSPEC")
120 && comspec.to_lowercase().contains("cmd.exe")
121 {
122 return ShellType::Cmd;
123 }
124
125 if env::var("PSModulePath").is_ok() {
127 return ShellType::PowerShell;
128 }
129 } else {
130 if let Ok(shell) = env::var("SHELL") {
132 let shell_lower = shell.to_lowercase();
133
134 if shell_lower.contains("bash") {
135 return ShellType::Bash;
136 } else if shell_lower.contains("zsh") {
137 return ShellType::Zsh;
138 } else if shell_lower.contains("fish") {
139 return ShellType::Fish;
140 }
141 }
142 }
143
144 ShellType::Unknown
146}
147
148fn detect_shell_from_parent() -> Option<String> {
150 let mut system = System::new();
151 system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
152
153 let current_pid = sysinfo::Pid::from_u32(std::process::id());
154 let current = system.process(current_pid)?;
155 let parent_pid = current.parent()?;
156
157 let parent = system.process(parent_pid)?;
158 Some(parent.name().to_string_lossy().to_string())
159}