use crate::enums::rgb::RGB;
#[derive(Debug, Default, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Color {
Black,
DarkRed,
DarkGreen,
DarkYellow,
DarkBlue,
DarkMagenta,
DarkCyan,
LightGray,
Gray,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
Indexed(u8),
Rgb(u8, u8, u8),
Hsl(f64, f64, f64),
Hex(u32),
#[default]
Default,
}
impl Color {
pub fn to_fg(&self) -> String {
match self {
Color::Black => "\x1b[30m".to_string(),
Color::DarkRed => "\x1b[31m".to_string(),
Color::DarkGreen => "\x1b[32m".to_string(),
Color::DarkYellow => "\x1b[33m".to_string(),
Color::DarkBlue => "\x1b[34m".to_string(),
Color::DarkMagenta => "\x1b[35m".to_string(),
Color::DarkCyan => "\x1b[36m".to_string(),
Color::LightGray => "\x1b[37m".to_string(),
Color::Gray => "\x1b[90m".to_string(),
Color::Red => "\x1b[91m".to_string(),
Color::Green => "\x1b[92m".to_string(),
Color::Yellow => "\x1b[93m".to_string(),
Color::Blue => "\x1b[94m".to_string(),
Color::Magenta => "\x1b[95m".to_string(),
Color::Cyan => "\x1b[96m".to_string(),
Color::White => "\x1b[97m".to_string(),
Color::Indexed(i) => format!("\x1b[38;5;{i}m"),
Color::Rgb(r, g, b) => format!("\x1b[38;2;{r};{g};{b}m"),
Color::Hsl(h, s, l) => {
let rgb = RGB::from_hsl(*h, *s, *l);
format!("\x1b[38;2;{};{};{}m", rgb.r, rgb.g, rgb.b)
}
Color::Hex(val) => {
let rgb = RGB::from_hex(*val);
format!("\x1b[38;2;{};{};{}m", rgb.r, rgb.g, rgb.b)
}
Color::Default => "\x1b[39m".to_string(),
}
}
pub fn to_bg(&self) -> String {
match self {
Color::Black => "\x1b[40m".to_string(),
Color::DarkRed => "\x1b[41m".to_string(),
Color::DarkGreen => "\x1b[42m".to_string(),
Color::DarkYellow => "\x1b[43m".to_string(),
Color::DarkBlue => "\x1b[44m".to_string(),
Color::DarkMagenta => "\x1b[45m".to_string(),
Color::DarkCyan => "\x1b[46m".to_string(),
Color::LightGray => "\x1b[47m".to_string(),
Color::Gray => "\x1b[100m".to_string(),
Color::Red => "\x1b[101m".to_string(),
Color::Green => "\x1b[102m".to_string(),
Color::Yellow => "\x1b[103m".to_string(),
Color::Blue => "\x1b[104m".to_string(),
Color::Magenta => "\x1b[105m".to_string(),
Color::Cyan => "\x1b[106m".to_string(),
Color::White => "\x1b[107m".to_string(),
Color::Indexed(i) => format!("\x1b[48;5;{i}m"),
Color::Rgb(r, g, b) => format!("\x1b[48;2;{r};{g};{b}m"),
Color::Hsl(h, s, l) => {
let rgb = RGB::from_hsl(*h, *s, *l);
format!("\x1b[48;2;{};{};{}m", rgb.r, rgb.g, rgb.b)
}
Color::Hex(val) => {
let rgb = RGB::from_hex(*val);
format!("\x1b[48;2;{};{};{}m", rgb.r, rgb.g, rgb.b)
}
Color::Default => "\x1b[49m".to_string(),
}
}
fn str_to_hex(value: &str) -> Option<u32> {
let value = value.trim_start_matches('#');
let Ok(radix) = u32::from_str_radix(value, 16) else {
return None;
};
let hex = match value.len() {
1 => {
let val = radix | (radix << 4);
(val << 16) | (val << 8) | val
}
2 => (radix << 16) | (radix << 8) | radix,
3 => {
let r = (radix & 0xf00) << 12 | (radix & 0xf00) << 8;
let g = (radix & 0x0f0) << 8 | (radix & 0x0f0) << 4;
let b = (radix & 0x00f) << 4 | (radix & 0x00f);
r | g | b
}
6 => radix,
_ => return None,
};
Some(hex)
}
}
impl From<u32> for Color {
fn from(value: u32) -> Self {
Self::Hex(value)
}
}
impl From<(u8, u8, u8)> for Color {
fn from((r, g, b): (u8, u8, u8)) -> Self {
Self::Rgb(r, g, b)
}
}
impl From<(f64, f64, f64)> for Color {
fn from((h, s, l): (f64, f64, f64)) -> Self {
Self::Hsl(h, s, l)
}
}
impl From<&str> for Color {
fn from(value: &str) -> Self {
match value {
"black" | "bl" => Self::Black,
"dark_red" | "dr" => Self::DarkRed,
"dark_green" | "dg" => Self::DarkGreen,
"dark_yellow" | "dy" => Self::DarkYellow,
"dark_blue" | "db" => Self::DarkBlue,
"dark_magenta" | "dm" => Self::DarkMagenta,
"dark_cyan" | "dc" => Self::DarkCyan,
"light_gray" | "light_grey" | "lg" => Self::LightGray,
"gray" | "grey" | "gr" => Self::Gray,
"red" | "r" => Self::Red,
"green" | "g" => Self::Green,
"yellow" | "y" => Self::Yellow,
"blue" | "b" => Self::Blue,
"magenta" | "m" => Self::Magenta,
"cyan" | "c" => Self::Cyan,
"white" | "w" => Self::White,
"default" | "d" => Self::Default,
hex if hex.starts_with('#') => {
let Some(hex) = Self::str_to_hex(hex) else {
panic!("invalid hex color provided");
};
Self::Hex(hex)
}
_ => panic!("unknown color"),
}
}
}