use std::env;
const SUPPORTED_TERMINALS: [&str; 11] = [
"alacritty",
"kitty",
"konsole",
"ghostty",
"xterm",
"gnome-terminal",
"xfce4-terminal", "tilix",
"mate-terminal",
"wezterm", "wezterm-gui", ];
const TERMINAL_ALIASES: [(&str, &str); 3] = [
("xfce-terminal", "xfce4-terminal"),
("gnome-terminal-server", "gnome-terminal"),
("mate-terminal.wrapper", "mate-terminal"),
];
#[must_use]
pub fn is_supported_terminal_for_theme() -> bool {
if !is_tty() {
return false;
}
if let Ok(term_program) = env::var("TERM_PROGRAM")
&& is_supported_name(&term_program)
{
return true;
}
if let Ok(term) = env::var("TERM")
&& is_supported_name(&term)
{
return true;
}
if let Ok(colorterm) = env::var("COLORTERM")
&& colorterm != "truecolor"
&& colorterm != "24bit"
&& is_supported_name(&colorterm)
{
return true;
}
#[cfg(target_os = "linux")]
{
if let Some(parent_name) = get_parent_process_name()
&& is_supported_name(&parent_name)
{
return true;
}
}
false
}
#[must_use]
#[allow(dead_code)]
pub fn get_terminal_name() -> Option<String> {
if let Ok(term_program) = env::var("TERM_PROGRAM")
&& !term_program.is_empty()
{
return Some(term_program);
}
if let Ok(term) = env::var("TERM")
&& !term.is_empty()
{
return Some(term);
}
if let Ok(colorterm) = env::var("COLORTERM")
&& !colorterm.is_empty()
&& colorterm != "truecolor"
&& colorterm != "24bit"
{
return Some(colorterm);
}
#[cfg(target_os = "linux")]
{
if let Some(parent_name) = get_parent_process_name() {
return Some(parent_name);
}
}
None
}
fn is_tty() -> bool {
use std::io::IsTerminal;
std::io::stdout().is_terminal()
}
fn is_supported_name(name: &str) -> bool {
let lower = name.to_ascii_lowercase();
if SUPPORTED_TERMINALS
.iter()
.any(|t| lower == *t || lower.contains(t))
{
return true;
}
for (alias, canonical) in &TERMINAL_ALIASES {
if lower == *alias || lower.contains(alias) {
return SUPPORTED_TERMINALS.contains(canonical);
}
}
false
}
#[cfg(target_os = "linux")]
fn get_parent_process_name() -> Option<String> {
use std::fs;
let stat = fs::read_to_string("/proc/self/stat").ok()?;
let close_paren = stat.rfind(')')?;
let after_comm = &stat[close_paren + 2..]; let mut parts = after_comm.split_whitespace();
parts.next()?; let ppid_str = parts.next()?;
let ppid: u32 = ppid_str.parse().ok()?;
let comm_path = format!("/proc/{ppid}/comm");
let comm = fs::read_to_string(comm_path).ok()?;
Some(comm.trim().to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_supported_name_direct_match() {
assert!(is_supported_name("alacritty"));
assert!(is_supported_name("Alacritty"));
assert!(is_supported_name("kitty"));
assert!(is_supported_name("KITTY"));
assert!(is_supported_name("konsole"));
assert!(is_supported_name("ghostty"));
assert!(is_supported_name("xterm"));
assert!(is_supported_name("gnome-terminal"));
assert!(is_supported_name("tilix"));
assert!(is_supported_name("mate-terminal"));
}
#[test]
fn test_is_supported_name_aliases() {
assert!(is_supported_name("xfce-terminal"));
assert!(is_supported_name("gnome-terminal-server"));
assert!(is_supported_name("mate-terminal.wrapper"));
}
#[test]
fn test_is_supported_name_contains() {
assert!(is_supported_name("alacritty-0.13.0"));
assert!(is_supported_name("/usr/bin/kitty"));
assert!(is_supported_name("xterm-256color"));
assert!(is_supported_name("xterm-direct"));
}
#[test]
fn test_is_supported_name_wezterm() {
assert!(is_supported_name("wezterm"));
assert!(is_supported_name("WezTerm"));
assert!(is_supported_name("wezterm-gui"));
assert!(is_supported_name("WezTerm"));
}
#[test]
fn test_is_supported_name_unsupported() {
assert!(!is_supported_name("urxvt"));
assert!(!is_supported_name("st"));
assert!(!is_supported_name("screen"));
assert!(!is_supported_name("tmux"));
assert!(!is_supported_name("unknown"));
assert!(!is_supported_name(""));
}
}