use std::env;
use std::os::unix::process::CommandExt;
use std::process::{Command, Stdio};
use crate::path_ext::IsExecutable;
const TERMINALS: &[&str] = &[
"foot",
"alacritty",
"kitty",
"st",
"urxvt",
"rxvt",
"wezterm",
"ghostty",
"contour",
"rio",
"xterm",
"kgx",
"gnome-terminal",
"mate-terminal",
"xfce4-terminal",
"tilix",
"konsole",
"lxterminal",
"qterminal",
"sakura",
"terminator",
"terminology",
"nxterm",
"color-xterm",
"dtterm",
];
fn terminal_args(term: &str) -> &[&str] {
match term {
"wezterm" => &["start", "--"],
"kgx" => &["--"],
"gnome-terminal" => &["--"],
"mate-terminal" => &["-x"],
"xfce4-terminal" => &["-x"],
_ => &["-e"],
}
}
fn find_inner(cli_terminal: Option<&str>) -> Option<String> {
if let Some(term) = cli_terminal {
return Some(term.to_string());
}
if let Ok(term) = env::var("TERMINAL") {
return Some(term);
}
let paths = env::var_os("PATH")
.map(|p| env::split_paths(&p).collect::<Vec<_>>())
.unwrap_or_default();
for term in TERMINALS {
for dir in &paths {
if dir.join(term).is_executable() {
return Some(term.to_string());
}
}
}
None
}
pub fn exec(command: &[String], cli_terminal: Option<&str>) -> bool {
let Some(term) = find_inner(cli_terminal) else {
return false;
};
unsafe {
Command::new(&term)
.args(terminal_args(&term))
.args(command)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.pre_exec(|| {
libc::setsid();
Ok(())
})
.spawn()
.is_ok()
}
}