lnchr 0.2.2

A fuzzy terminal app launcher
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()
    }
}