use std::io::IsTerminal;
pub struct Palette {
pub red: &'static str,
pub green: &'static str,
pub cyan: &'static str,
pub bold: &'static str,
pub dim: &'static str,
pub reset: &'static str,
}
impl Palette {
pub fn ansi() -> Self {
Self {
red: "\x1b[31m",
green: "\x1b[32m",
cyan: "\x1b[36m",
bold: "\x1b[1m",
dim: "\x1b[2m",
reset: "\x1b[0m",
}
}
pub fn none() -> Self {
Self {
red: "",
green: "",
cyan: "",
bold: "",
dim: "",
reset: "",
}
}
pub fn for_stderr() -> Self {
if no_color() || !std::io::stderr().is_terminal() {
Self::none()
} else {
Self::ansi()
}
}
pub fn for_stdout() -> Self {
if no_color() || !std::io::stdout().is_terminal() {
Self::none()
} else {
Self::ansi()
}
}
}
fn no_color() -> bool {
std::env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ansi_and_none_have_matching_field_shapes() {
let a = Palette::ansi();
let n = Palette::none();
for (field_a, field_n) in [
(a.red, n.red),
(a.green, n.green),
(a.cyan, n.cyan),
(a.bold, n.bold),
(a.dim, n.dim),
(a.reset, n.reset),
] {
assert!(!field_a.is_empty(), "ansi field unexpectedly empty");
assert!(field_n.is_empty(), "none field unexpectedly populated");
}
}
}