use std::io::IsTerminal;
use std::sync::OnceLock;
use nu_ansi_term::{Color, Style};
fn evaluate(no_color: bool, force_color: bool, is_tty: bool) -> bool {
if no_color {
return false;
}
if force_color {
return true;
}
is_tty
}
fn check_decorate(is_tty: bool) -> bool {
evaluate(
std::env::var_os("NO_COLOR").is_some(),
std::env::var_os("FORCE_COLOR").is_some(),
is_tty,
)
}
pub fn decorate() -> bool {
static V: OnceLock<bool> = OnceLock::new();
*V.get_or_init(|| check_decorate(std::io::stdout().is_terminal()))
}
pub fn decorate_stderr() -> bool {
static V: OnceLock<bool> = OnceLock::new();
*V.get_or_init(|| check_decorate(std::io::stderr().is_terminal()))
}
pub fn green(s: &str) -> String {
if decorate() {
Color::Green.paint(s).to_string()
} else {
s.to_string()
}
}
pub fn red(s: &str) -> String {
if decorate_stderr() {
Color::Red.paint(s).to_string()
} else {
s.to_string()
}
}
pub fn yellow(s: &str) -> String {
if decorate() {
Color::Yellow.paint(s).to_string()
} else {
s.to_string()
}
}
pub fn cyan(s: &str) -> String {
if decorate() {
Color::Cyan.paint(s).to_string()
} else {
s.to_string()
}
}
pub fn dim(s: &str) -> String {
if decorate() {
Style::new().dimmed().paint(s).to_string()
} else {
s.to_string()
}
}
pub fn bold(s: &str) -> String {
if decorate() {
Style::new().bold().paint(s).to_string()
} else {
s.to_string()
}
}
pub fn cyan_stderr(s: &str) -> String {
if decorate_stderr() {
Color::Cyan.paint(s).to_string()
} else {
s.to_string()
}
}
pub fn dim_stderr(s: &str) -> String {
if decorate_stderr() {
Style::new().dimmed().paint(s).to_string()
} else {
s.to_string()
}
}
pub fn icon_ok() -> &'static str {
if decorate() { "✓" } else { "[ok]" }
}
pub fn icon_fail() -> &'static str {
if decorate_stderr() { "✗" } else { "[fail]" }
}
pub fn icon_warn() -> &'static str {
if decorate() { "⚠" } else { "[!]" }
}
pub fn icon_active() -> &'static str {
if decorate() { "🎯" } else { "*" }
}
pub fn icon_folder() -> &'static str {
if decorate() { "📁 " } else { "" }
}
pub fn icon_check() -> &'static str {
if decorate() { "🔍 " } else { "" }
}
pub fn icon_init() -> &'static str {
if decorate() { "📝 " } else { "" }
}
pub fn icon_info() -> &'static str {
if decorate() { "📊 " } else { "" }
}
pub fn icon_prune() -> &'static str {
if decorate() { "🧹 " } else { "" }
}
pub fn icon_clear() -> &'static str {
if decorate() { "🗑 " } else { "" }
}
#[cfg(test)]
mod tests {
use super::evaluate;
#[test]
fn no_color_disables_even_when_tty() {
assert!(!evaluate(true, false, true), "NO_COLOR must override TTY");
assert!(!evaluate(true, false, false));
}
#[test]
fn force_color_overrides_non_tty() {
assert!(
evaluate(false, true, false),
"FORCE_COLOR must enable when piped"
);
assert!(evaluate(false, true, true));
}
#[test]
fn no_color_beats_force_color() {
assert!(!evaluate(true, true, true));
assert!(!evaluate(true, true, false));
}
#[test]
fn falls_back_to_tty_when_neither_env_set() {
assert!(evaluate(false, false, true));
assert!(!evaluate(false, false, false));
}
}