use crate::ported::lib::shell::run_cmd;
use regex::Regex;
use std::process::Command;
use std::sync::OnceLock;
#[derive(Debug, Clone, PartialEq)]
pub struct TmuxVersionInfo {
pub major: f64, pub minor: i32,
pub suffix: Option<String>,
}
pub fn get_tmux_executable_name() -> String {
std::env::var("POWERLINE_TMUX_EXE").unwrap_or_else(|_| "tmux".to_string())
}
pub fn _run_tmux(args: &[&str]) -> std::io::Result<std::process::Output> {
let exe = get_tmux_executable_name();
Command::new(&exe).args(args).output()
}
pub fn run_tmux_command(args: &[&str]) {
let _ = _run_tmux(args);
}
pub fn get_tmux_output(pl: &(), args: &[&str]) -> Option<String> {
let mut cmd_vec: Vec<String> = vec![get_tmux_executable_name()];
for a in args {
cmd_vec.push(a.to_string());
}
run_cmd(pl, &cmd_vec, None, true)
}
pub fn set_tmux_environment(varname: &str, value: &str, remove: bool) {
run_tmux_command(&["set-environment", "-g", varname, value]);
if remove {
let _ = _run_tmux(&["set-environment", "-r", varname]);
}
}
pub fn source_tmux_file(fname: &str) {
run_tmux_command(&["source", fname]);
}
#[allow(non_snake_case)]
pub fn NON_DIGITS() -> &'static Regex {
static R: OnceLock<Regex> = OnceLock::new();
R.get_or_init(|| Regex::new(r"[^0-9]+").unwrap())
}
#[allow(non_snake_case)]
pub fn DIGITS() -> &'static Regex {
static R: OnceLock<Regex> = OnceLock::new();
R.get_or_init(|| Regex::new(r"[0-9]+").unwrap())
}
#[allow(non_snake_case, dead_code)]
pub fn NON_LETTERS() -> &'static Regex {
static R: OnceLock<Regex> = OnceLock::new();
R.get_or_init(|| Regex::new(r"[^a-z]+").unwrap())
}
pub fn get_tmux_version(pl: &()) -> Option<TmuxVersionInfo> {
let version_string = get_tmux_output(pl, &["-V"])?;
let mut parts = version_string.splitn(2, ' ');
let _ = parts.next()?;
let version_string = parts.next()?.trim();
if version_string == "master" {
return Some(TmuxVersionInfo {
major: f64::INFINITY,
minor: 0,
suffix: Some(version_string.to_string()),
});
}
let (major_raw, minor_raw) = version_string.split_once('.')?;
let major_str = NON_DIGITS().replace_all(major_raw, "").into_owned();
let suffix_str = DIGITS().replace_all(minor_raw, "").into_owned();
let suffix = if suffix_str.is_empty() {
None
} else {
Some(suffix_str)
};
let minor_str = NON_DIGITS().replace_all(minor_raw, "").into_owned();
Some(TmuxVersionInfo {
major: major_str.parse().ok()?,
minor: minor_str.parse().ok()?,
suffix,
})
}
#[cfg(test)]
pub(crate) static POWERLINE_TMUX_EXE_ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_tmux_executable_name_defaults_to_tmux() {
let _guard = POWERLINE_TMUX_EXE_ENV_LOCK
.lock()
.unwrap_or_else(|p| p.into_inner());
let prev = std::env::var("POWERLINE_TMUX_EXE").ok();
std::env::remove_var("POWERLINE_TMUX_EXE");
assert_eq!(get_tmux_executable_name(), "tmux");
if let Some(p) = prev {
std::env::set_var("POWERLINE_TMUX_EXE", p);
}
}
#[test]
fn get_tmux_executable_name_uses_env_var() {
let _guard = POWERLINE_TMUX_EXE_ENV_LOCK
.lock()
.unwrap_or_else(|p| p.into_inner());
std::env::set_var("POWERLINE_TMUX_EXE", "/usr/local/bin/tmux");
assert_eq!(get_tmux_executable_name(), "/usr/local/bin/tmux");
std::env::remove_var("POWERLINE_TMUX_EXE");
}
#[test]
fn version_regexes_strip_correctly() {
assert_eq!(NON_DIGITS().replace_all("2", "").into_owned(), "2");
assert_eq!(DIGITS().replace_all("9a", "").into_owned(), "a");
assert_eq!(NON_DIGITS().replace_all("9a", "").into_owned(), "9");
}
}