use {
once_cell::sync::Lazy,
std::path::{Path, PathBuf},
};
const TERMINFO_DIRS_DEBIAN: &str = "/etc/terminfo:/lib/terminfo:/usr/share/terminfo";
const TERMINFO_DIRS_REDHAT: &str = "/etc/terminfo:/usr/share/terminfo";
const TERMINFO_DIRS_MACOS: &str = "/usr/share/terminfo";
static TERMINFO_DIRS_COMMON: Lazy<Vec<PathBuf>> = Lazy::new(|| {
vec![
PathBuf::from("/usr/local/etc/terminfo"),
PathBuf::from("/usr/local/lib/terminfo"),
PathBuf::from("/usr/local/share/terminfo"),
PathBuf::from("/etc/terminfo"),
PathBuf::from("/usr/lib/terminfo"),
PathBuf::from("/lib/terminfo"),
PathBuf::from("/usr/share/terminfo"),
]
});
#[derive(Clone)]
enum OsVariant {
Linux,
MacOs,
Windows,
Other,
}
enum LinuxDistroVariant {
Debian,
RedHat,
Unknown,
}
static TARGET_OS: Lazy<OsVariant> = Lazy::new(|| {
if cfg!(target_os = "linux") {
OsVariant::Linux
} else if cfg!(target_os = "macos") {
OsVariant::MacOs
} else if cfg!(target_os = "windows") {
OsVariant::Windows
} else {
OsVariant::Other
}
});
struct OsInfo {
os: OsVariant,
linux_distro: Option<LinuxDistroVariant>,
}
fn resolve_linux_distro() -> LinuxDistroVariant {
let os_release = Path::new("/etc/os-release");
if let Ok(data) = std::fs::read_to_string(os_release) {
for line in data.split('\n') {
if line.starts_with("ID_LIKE=") {
if line.contains("debian") {
return LinuxDistroVariant::Debian;
} else if line.contains("rhel") || line.contains("fedora") {
return LinuxDistroVariant::RedHat;
}
} else if line.starts_with("ID=") && line.contains("fedora") {
return LinuxDistroVariant::RedHat;
}
}
}
LinuxDistroVariant::Unknown
}
fn resolve_os_info() -> OsInfo {
let os = TARGET_OS.clone();
let linux_distro = match os {
OsVariant::Linux => Some(resolve_linux_distro()),
_ => None,
};
OsInfo { os, linux_distro }
}
pub fn resolve_terminfo_dirs() -> Option<String> {
if std::env::var("TERMINFO_DIRS").is_ok() {
return None;
}
let os_info = resolve_os_info();
match os_info.os {
OsVariant::Linux => match os_info.linux_distro.unwrap() {
LinuxDistroVariant::Debian => Some(TERMINFO_DIRS_DEBIAN.to_string()),
LinuxDistroVariant::RedHat => Some(TERMINFO_DIRS_REDHAT.to_string()),
LinuxDistroVariant::Unknown => {
let paths = TERMINFO_DIRS_COMMON
.iter()
.filter_map(|p| {
if p.exists() {
Some(p.display().to_string())
} else {
None
}
})
.collect::<Vec<String>>()
.join(":");
Some(paths)
}
},
OsVariant::MacOs => Some(TERMINFO_DIRS_MACOS.to_string()),
OsVariant::Windows => None,
OsVariant::Other => None,
}
}