use std::borrow::Cow;
use std::env;
use std::sync::LazyLock;
#[cfg(not(tarpaulin_include))]
#[allow(unreachable_code)]
pub static NO_COLOR: LazyLock<bool> = LazyLock::new(|| {
#[cfg(test)]
{
return false;
}
env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty())
});
pub const GREEN: &str = "\x1b[0;92m";
pub const YELLOW: &str = "\x1b[0;93m";
pub const RED: &str = "\x1b[0;91m";
pub const BLUE: &str = "\x1b[0;94m";
pub const BOLD_PURPLE: &str = "\x1b[1;95m";
pub const CYAN: &str = "\x1b[0;96m";
pub const RESET: &str = "\x1b[0m";
pub const HIGHLIGHT: &str = GREEN;
pub const ATTENUATE: &str = "\x1b[0;90m";
pub const ITALIC: &str = "\x1b[3m";
pub const UNDERLINE: &str = "\x1b[4m";
pub struct Color;
impl Color {
#[must_use]
pub fn error(string: &str) -> Cow<'_, str> {
Self::color(RED, string)
}
#[must_use]
pub fn warning(string: &str) -> Cow<'_, str> {
Self::color(YELLOW, string)
}
#[must_use]
pub fn in_sync(string: &str) -> Cow<'_, str> {
Self::color(GREEN, string)
}
#[must_use]
pub fn modified(string: &str) -> Cow<'_, str> {
Self::color(YELLOW, string)
}
#[must_use]
pub fn missing(string: &str) -> Cow<'_, str> {
Self::color(RED, string)
}
#[must_use]
pub fn symlink(string: &str) -> Cow<'_, str> {
Self::color(BLUE, string)
}
#[must_use]
pub fn file_name(string: &str) -> Cow<'_, str> {
Self::color(BOLD_PURPLE, string)
}
#[must_use]
pub fn line_range(string: &str) -> Cow<'_, str> {
Self::color(CYAN, string)
}
#[must_use]
pub fn added(string: &str) -> Cow<'_, str> {
Self::color(GREEN, string)
}
#[must_use]
pub fn removed(string: &str) -> Cow<'_, str> {
Self::color(RED, string)
}
#[must_use]
pub fn none(string: &str) -> Cow<'_, str> {
Cow::Borrowed(string)
}
#[must_use]
fn color<'a>(color: &str, string: &'a str) -> Cow<'a, str> {
if *NO_COLOR {
#[cfg(not(tarpaulin_include))] return Cow::Borrowed(string);
}
Cow::Owned(format!("{color}{string}{RESET}"))
}
#[must_use]
pub fn maybe_color(color: &str) -> &str {
if *NO_COLOR {
#[cfg(not(tarpaulin_include))] return "";
}
color
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn color_error_is_red() {
assert_eq!(
Color::error("this is an error"),
"\x1b[0;91mthis is an error\x1b[0m"
);
}
#[test]
fn color_warning_is_yellow() {
assert_eq!(
Color::warning("this is a warning"),
"\x1b[0;93mthis is a warning\x1b[0m"
);
}
#[test]
fn color_in_sync_is_green() {
assert_eq!(
Color::in_sync("this is in sync"),
"\x1b[0;92mthis is in sync\x1b[0m"
);
}
#[test]
fn color_modified_is_yellow() {
assert_eq!(
Color::modified("this is marked as modified"),
"\x1b[0;93mthis is marked as modified\x1b[0m"
);
}
#[test]
fn color_missing_is_red() {
assert_eq!(
Color::missing("this is marked as missing"),
"\x1b[0;91mthis is marked as missing\x1b[0m"
);
}
#[test]
fn color_symlink_is_blue() {
assert_eq!(
Color::missing("this is a symlink"),
"\x1b[0;91mthis is a symlink\x1b[0m"
);
}
#[test]
fn color_file_name_is_bold_purple() {
assert_eq!(
Color::file_name("this is bold, and purple"),
"\x1b[1;95mthis is bold, and purple\x1b[0m"
);
}
#[test]
fn color_line_range_is_cyan() {
assert_eq!(
Color::line_range("this is cyan"),
"\x1b[0;96mthis is cyan\x1b[0m"
);
}
#[test]
fn color_added_is_green() {
assert_eq!(
Color::added("+this is has been added"),
"\x1b[0;92m+this is has been added\x1b[0m"
);
}
#[test]
fn color_removed_is_red() {
assert_eq!(
Color::removed("+this is has been removed"),
"\x1b[0;91m+this is has been removed\x1b[0m"
);
}
#[test]
fn color_none_has_no_effect() {
assert_eq!(Color::none("same as input"), "same as input");
}
}