use std::io::IsTerminal;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ColorChoice {
#[default]
Auto,
Always,
Never,
}
impl ColorChoice {
pub fn should_color(self, is_terminal: bool) -> bool {
match self {
Self::Always => true,
Self::Never => false,
Self::Auto => Self::detect_auto(is_terminal),
}
}
pub fn detect_auto(is_terminal: bool) -> bool {
Self::detect_with(is_terminal, |k| std::env::var(k).ok())
}
pub fn detect_with(is_terminal: bool, get_var: impl Fn(&str) -> Option<String>) -> bool {
if let Some(val) = get_var("NO_COLOR") {
if !val.is_empty() {
return false;
}
}
if let Some(val) = get_var("FORCE_COLOR") {
if !val.is_empty() && val != "0" {
return true;
}
}
if let Some(term) = get_var("TERM") {
if term == "dumb" {
return false;
}
}
is_terminal
}
pub fn resolve_stdout(self) -> bool {
self.should_color(std::io::stdout().is_terminal())
}
pub fn resolve_stderr(self) -> bool {
self.should_color(std::io::stderr().is_terminal())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum ColorLevel {
#[default]
Auto,
Truecolor,
Ansi256,
Ansi16,
None,
}
impl ColorLevel {
pub fn detect() -> Self {
Self::detect_with(|k| std::env::var(k).ok())
}
pub fn detect_with(get_var: impl Fn(&str) -> Option<String>) -> Self {
if let Some(val) = get_var("NO_COLOR") {
if !val.is_empty() {
return Self::None;
}
}
if let Some(term) = get_var("TERM") {
if term == "dumb" {
return Self::None;
}
}
if let Some(colorterm) = get_var("COLORTERM") {
if colorterm == "truecolor" || colorterm == "24bit" {
return Self::Truecolor;
}
}
if let Some(term) = get_var("TERM") {
let term_lower = term.to_lowercase();
if term_lower.contains("direct")
|| term_lower.contains("truecolor")
|| term_lower.contains("kitty")
|| term_lower.contains("alacritty")
|| term_lower.contains("wezterm")
|| term_lower.contains("ghostty")
{
return Self::Truecolor;
}
if term_lower.contains("256color") || term_lower.contains("xterm") {
return Self::Ansi256;
}
}
Self::Ansi16
}
}