use std::io::IsTerminal;
use std::sync::atomic::{AtomicBool, Ordering};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, clap::ValueEnum)]
pub enum ColorChoice {
#[default]
Auto,
Always,
Never,
}
static COLOR_ENABLED: AtomicBool = AtomicBool::new(true);
pub fn init(choice: ColorChoice) {
let enabled = match choice {
ColorChoice::Always => true,
ColorChoice::Never => false,
ColorChoice::Auto => auto_detect(),
};
colored::control::set_override(enabled);
COLOR_ENABLED.store(enabled, Ordering::Relaxed);
}
pub fn colorize_enabled() -> bool {
COLOR_ENABLED.load(Ordering::Relaxed)
}
fn auto_detect() -> bool {
if env_truthy("CLICOLOR_FORCE") {
return true;
}
if std::env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty()) {
return false;
}
if std::env::var("CLICOLOR").is_ok_and(|v| v == "0") {
return false;
}
std::io::stdout().is_terminal()
}
fn env_truthy(name: &str) -> bool {
std::env::var(name).is_ok_and(|v| !v.is_empty() && v != "0")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_choice_is_auto() {
assert_eq!(ColorChoice::default(), ColorChoice::Auto);
}
#[test]
fn test_env_truthy() {
std::env::set_var("COLGREP_TEST_TRUTHY", "1");
assert!(env_truthy("COLGREP_TEST_TRUTHY"));
std::env::set_var("COLGREP_TEST_TRUTHY", "0");
assert!(!env_truthy("COLGREP_TEST_TRUTHY"));
std::env::set_var("COLGREP_TEST_TRUTHY", "");
assert!(!env_truthy("COLGREP_TEST_TRUTHY"));
std::env::remove_var("COLGREP_TEST_TRUTHY");
assert!(!env_truthy("COLGREP_TEST_TRUTHY"));
}
#[test]
fn test_always_and_never_set_global() {
init(ColorChoice::Always);
assert!(colorize_enabled());
init(ColorChoice::Never);
assert!(!colorize_enabled());
init(ColorChoice::Always);
}
}