use std::io::IsTerminal;
#[derive(Clone, Copy)]
pub(crate) enum Role {
Fg,
Dim,
Clay,
Info,
Ok,
Error,
}
#[derive(Clone, Copy)]
enum Stream {
Stdout,
Stderr,
}
pub(crate) fn stdout(role: Role, text: impl AsRef<str>) -> String {
style(Stream::Stdout, role, text.as_ref(), false)
}
pub(crate) fn stdout_bold(role: Role, text: impl AsRef<str>) -> String {
style(Stream::Stdout, role, text.as_ref(), true)
}
pub(crate) fn stderr(role: Role, text: impl AsRef<str>) -> String {
style(Stream::Stderr, role, text.as_ref(), false)
}
pub(crate) fn stderr_bold(role: Role, text: impl AsRef<str>) -> String {
style(Stream::Stderr, role, text.as_ref(), true)
}
fn style(stream: Stream, role: Role, text: &str, bold: bool) -> String {
if !color_enabled(stream) {
return text.to_owned();
}
if bold {
format!("\x1b[1;{}m{}\x1b[0m", ansi_code(role), text)
} else {
format!("\x1b[{}m{}\x1b[0m", ansi_code(role), text)
}
}
fn color_enabled(stream: Stream) -> bool {
if std::env::var_os("NO_COLOR").is_some() {
return false;
}
if let Some(force) = std::env::var_os("CLICOLOR_FORCE") {
return force.to_string_lossy() != "0";
}
if std::env::var_os("CLICOLOR").as_deref() == Some(std::ffi::OsStr::new("0")) {
return false;
}
match stream {
Stream::Stdout => std::io::stdout().is_terminal(),
Stream::Stderr => std::io::stderr().is_terminal(),
}
}
fn ansi_code(role: Role) -> &'static str {
match role {
Role::Fg => "38;2;227;223;216",
Role::Dim => "38;2;144;139;132",
Role::Clay => "38;2;232;135;97",
Role::Info => "38;2;94;182;230",
Role::Ok => "38;2;97;203;124",
Role::Error => "38;2;246;109;100",
}
}