use crate::config::ThemeColors; use crate::theme::Theme; pub const RESET: &str = "\x1b[0m"; pub const BOLD: &str = "\x1b[1m"; pub const DIM: &str = "\x1b[2m"; pub const RED: &str = "\x1b[31m"; pub const GREEN: &str = "\x1b[32m"; pub const YELLOW: &str = "\x1b[33m"; pub const BLUE: &str = "\x1b[34m"; pub const MAGENTA: &str = "\x1b[35m"; pub const CYAN: &str = "\x1b[36m"; pub const WHITE: &str = "\x1b[37m"; /// Resolve a color name to ANSI escape sequence(s). pub fn resolve_color(name: &str, theme: Theme, palette: &ThemeColors) -> String { if let Some(key) = name.strip_prefix("p:") { let map = match theme { Theme::Dark => &palette.dark, Theme::Light => &palette.light, }; if let Some(resolved) = map.get(key) { return resolve_color(resolved, theme, palette); } return RESET.to_string(); } let mut result = String::new(); for part in name.split_whitespace() { result.push_str(match part { "red" => RED, "green" => GREEN, "yellow" => YELLOW, "blue" => BLUE, "magenta" => MAGENTA, "cyan" => CYAN, "white" => WHITE, "dim" => DIM, "bold" => BOLD, _ => "", }); } if result.is_empty() { RESET.to_string() } else { result } } /// Determine whether color output should be used. pub fn should_use_color(cli_color: Option<&str>, config_color: &crate::config::ColorMode) -> bool { if std::env::var("NO_COLOR").is_ok() { return false; } if let Some(flag) = cli_color { return match flag { "always" => true, "never" => false, _ => atty_stdout(), }; } match config_color { crate::config::ColorMode::Always => true, crate::config::ColorMode::Never => false, crate::config::ColorMode::Auto => { atty_stdout() && std::env::var("TERM").map_or(true, |t| t != "dumb") } } } fn atty_stdout() -> bool { unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } }