use std::sync::atomic::{AtomicU8, Ordering};
static COLOR_MODE: AtomicU8 = AtomicU8::new(0); static ASCII_MODE: AtomicU8 = AtomicU8::new(0);
const GREEN: &str = "\x1b[32m";
const RED: &str = "\x1b[31m";
const YELLOW: &str = "\x1b[33m";
#[allow(dead_code)]
const BOLD: &str = "\x1b[1m";
const RESET: &str = "\x1b[0m";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ColorMode {
Auto,
Always,
Never,
}
pub fn init(cli_color: Option<&str>) {
let mode = match cli_color {
Some("always") => ColorMode::Always,
Some("never") => ColorMode::Never,
_ => ColorMode::Auto,
};
let mode_val = match mode {
ColorMode::Auto => 0,
ColorMode::Always => 1,
ColorMode::Never => 2,
};
COLOR_MODE.store(mode_val, Ordering::Relaxed);
let ascii = std::env::var("TKT_ASCII").is_ok_and(|v| v == "1" || v == "true");
ASCII_MODE.store(if ascii { 1 } else { 0 }, Ordering::Relaxed);
}
pub fn is_color_enabled() -> bool {
match COLOR_MODE.load(Ordering::Relaxed) {
1 => true, 2 => false, _ => {
if std::env::var("NO_COLOR").is_ok() {
return false;
}
stdout_is_tty()
}
}
}
fn is_ascii() -> bool {
ASCII_MODE.load(Ordering::Relaxed) == 1
}
fn stdout_is_tty() -> bool {
use std::io::IsTerminal;
std::io::stdout().is_terminal()
}
pub fn sym_ok() -> String {
if is_ascii() {
if is_color_enabled() {
format!("{}[ok]{}", GREEN, RESET)
} else {
"[ok]".to_string()
}
} else if is_color_enabled() {
format!("{}✓{}", GREEN, RESET)
} else {
"✓".to_string()
}
}
pub fn sym_err() -> String {
if is_ascii() {
if is_color_enabled() {
format!("{}[err]{}", RED, RESET)
} else {
"[err]".to_string()
}
} else if is_color_enabled() {
format!("{}✗{}", RED, RESET)
} else {
"✗".to_string()
}
}
pub fn sym_warn() -> String {
if is_ascii() {
if is_color_enabled() {
format!("{}[warn]{}", YELLOW, RESET)
} else {
"[warn]".to_string()
}
} else if is_color_enabled() {
format!("{}⚠{}", YELLOW, RESET)
} else {
"⚠".to_string()
}
}
pub fn sym_arrow() -> String {
if is_ascii() {
"->".to_string()
} else {
"→".to_string()
}
}
#[allow(dead_code)]
pub fn bold(text: &str) -> String {
if is_color_enabled() {
format!("{}{}{}", BOLD, text, RESET)
} else {
text.to_string()
}
}
#[allow(dead_code)]
pub fn green(text: &str) -> String {
if is_color_enabled() {
format!("{}{}{}", GREEN, text, RESET)
} else {
text.to_string()
}
}
#[allow(dead_code)]
pub fn red(text: &str) -> String {
if is_color_enabled() {
format!("{}{}{}", RED, text, RESET)
} else {
text.to_string()
}
}
#[allow(dead_code)]
pub fn yellow(text: &str) -> String {
if is_color_enabled() {
format!("{}{}{}", YELLOW, text, RESET)
} else {
text.to_string()
}
}