1mod exec;
2mod types;
3mod utils;
4
5use crate::exec::extract;
17use crate::types::{Terminal, TerminalInfo};
18use std::path::Path;
19
20pub fn which_terminal() -> Option<TerminalInfo> {
22 if let Some(info) = detect_by_term_program() {
24 return Some(info);
25 }
26
27 if let Some(info) = detect_by_specific_env_vars() {
29 return Some(info);
30 }
31
32 if let Some(info) = detect_by_terminal_env_vars() {
34 return Some(info);
35 }
36
37 if let Some(info) = detect_by_term_patterns() {
39 return Some(info);
40 }
41
42 detect_generic()
44}
45
46fn detect_by_term_program() -> Option<TerminalInfo> {
48 let term_program = utils::get_env("TERM_PROGRAM")?;
49 let version = utils::get_env("TERM_PROGRAM_VERSION");
50
51 let terminal = match term_program.as_str() {
52 "Apple_Terminal" => Terminal::AppleTerminal,
54 "iTerm.app" => Terminal::ITerm2,
55
56 "vscode" => Terminal::VSCode,
58 "kiro" => Terminal::Kiro,
59 "WezTerm" => Terminal::WezTerm,
60 "Hyper" => Terminal::Hyper,
61 "Tabby" => Terminal::Tabby,
62
63 _ => return None,
65 };
66
67 Some(TerminalInfo::with_version(terminal, version))
68}
69
70fn detect_by_specific_env_vars() -> Option<TerminalInfo> {
73 if utils::has_env("WT_SESSION") || utils::has_env("WT_PROFILE_ID") {
75 let version = extract(&Terminal::WindowsTerminal);
76 return Some(TerminalInfo::with_version(
77 Terminal::WindowsTerminal,
78 version,
79 ));
80 }
81
82 if let Some(version) = utils::get_env("TERMUX_VERSION") {
84 return Some(TerminalInfo::with_version(Terminal::Termux, Some(version)));
85 }
86
87 if utils::has_env("ITERM_SESSION_ID") {
89 let version = extract(&Terminal::ITerm2);
90 return Some(TerminalInfo::with_version(Terminal::ITerm2, version));
91 }
92
93 if utils::has_env("ConEmuPID") || utils::has_env("ConEmuBuild") {
95 let version = utils::get_env("ConEmuBuild");
96 return Some(TerminalInfo::with_version(Terminal::ConEmu, version));
97 }
98
99 if utils::has_env("KITTY_WINDOW_ID") {
101 let version = extract(&Terminal::Kitty);
102 return Some(TerminalInfo::with_version(Terminal::Kitty, version));
103 }
104
105 None
106}
107
108fn detect_by_terminal_env_vars() -> Option<TerminalInfo> {
110 if utils::has_env("GNOME_TERMINAL_SERVICE") || utils::has_env("GNOME_TERMINAL_SCREEN") {
112 let version = extract(&Terminal::GnomeTerminal);
113 return Some(TerminalInfo::with_version(Terminal::GnomeTerminal, version));
114 }
115
116 if utils::has_env("KONSOLE_VERSION") || utils::has_env("KONSOLE_DBUS_SESSION") {
118 let version = utils::get_env("KONSOLE_VERSION").or_else(|| extract(&Terminal::Konsole));
119 return Some(TerminalInfo::with_version(Terminal::Konsole, version));
120 }
121
122 if utils::has_env("TERMINATOR_UUID") {
124 return Some(TerminalInfo::new(Terminal::Terminator));
125 }
126
127 if utils::has_env("TILIX_ID") {
129 let version = extract(&Terminal::Tilix);
130 return Some(TerminalInfo::with_version(Terminal::Tilix, version));
131 }
132
133 if utils::has_env("CMDER_ROOT") {
135 return Some(TerminalInfo::new(Terminal::Cmder));
136 }
137
138 if let Some(prefix) = utils::get_env("PREFIX")
140 && prefix.contains("com.termux")
141 {
142 let version = extract(&Terminal::Termux);
143 return Some(TerminalInfo::with_version(Terminal::Termux, version));
144 }
145
146 if Path::new("/data/data/com.termux").exists() {
148 let version = extract(&Terminal::Termux);
149 return Some(TerminalInfo::with_version(Terminal::Termux, version));
150 }
151
152 None
153}
154
155fn detect_by_term_patterns() -> Option<TerminalInfo> {
157 let term = utils::get_env("TERM")?;
158
159 if term.contains("alacritty") {
161 let version = extract(&Terminal::Alacritty);
162 return Some(TerminalInfo::with_version(Terminal::Alacritty, version));
163 }
164
165 if term.contains("kitty") {
167 let version = extract(&Terminal::Kitty);
168 return Some(TerminalInfo::with_version(Terminal::Kitty, version));
169 }
170
171 if term.contains("xterm") {
173 let version = extract(&Terminal::XTerm);
174 return Some(TerminalInfo::with_version(Terminal::XTerm, version));
175 }
176
177 if term.contains("rxvt") {
179 return Some(TerminalInfo::new(Terminal::Rxvt));
180 }
181
182 if utils::has_env("PSModulePath") {
184 return Some(TerminalInfo::new(Terminal::PowerShell));
185 }
186
187 if utils::has_env("COMSPEC") && !utils::has_env("PSModulePath") {
189 return Some(TerminalInfo::new(Terminal::CommandPrompt));
190 }
191
192 None
193}
194
195fn detect_generic() -> Option<TerminalInfo> {
197 if let Some(term) = utils::get_env("TERM") {
198 let terminal = Terminal::Generic(term.clone());
199 Some(TerminalInfo::new(terminal))
200 } else {
201 None
202 }
203}