//! Colorized status output (NO_COLOR-aware). use std::io::IsTerminal; use std::sync::OnceLock; /// Honors NO_COLOR (), dumb terminals, and redirected output. fn color_enabled() -> bool { static ENABLED: OnceLock = OnceLock::new(); *ENABLED.get_or_init(|| { std::env::var_os("NO_COLOR").is_none() && std::env::var("TERM").map(|t| t != "dumb").unwrap_or(true) && std::io::stdout().is_terminal() && std::io::stderr().is_terminal() }) } fn paint(code: &str, s: &str) -> String { if color_enabled() { format!("\x1b[{code}m{s}\x1b[0m") } else { s.to_string() } } pub fn red(s: &str) -> String { paint("31", s) } pub fn yellow(s: &str) -> String { paint("33", s) } pub fn green(s: &str) -> String { paint("32", s) } pub fn blue(s: &str) -> String { paint("34", s) } pub fn cyan(s: &str) -> String { paint("36", s) } pub fn err(msg: &str) { eprintln!("{}", red(&format!("Error: {msg}"))); } pub fn warn(msg: &str) { eprintln!("{}", yellow(&format!("Warning: {msg}"))); } pub fn info(msg: &str) { println!("{}", blue(msg)); } pub fn ok(msg: &str) { println!("{}", green(msg)); }