use numtoa::NumToA;
use std::fmt;
use std::fmt::Debug;
pub trait Color: Debug {
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result;
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
macro_rules! derive_color {
($doc:expr, $name:ident, $value:expr) => {
#[doc = $doc]
#[derive(Copy, Clone, Debug)]
pub struct $name;
impl Color for $name {
#[inline]
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.fg_str())
}
#[inline]
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.bg_str())
}
}
impl $name {
#[inline]
pub fn fg_str(&self) -> &'static str {
csi!("38;5;", $value, "m")
}
#[inline]
pub fn bg_str(&self) -> &'static str {
csi!("48;5;", $value, "m")
}
}
};
}
derive_color!("Black.", Black, "0");
derive_color!("Red.", Red, "1");
derive_color!("Green.", Green, "2");
derive_color!("Yellow.", Yellow, "3");
derive_color!("Blue.", Blue, "4");
derive_color!("Magenta.", Magenta, "5");
derive_color!("Cyan.", Cyan, "6");
derive_color!("White.", White, "7");
derive_color!("High-intensity light black.", LightBlack, "8");
derive_color!("High-intensity light red.", LightRed, "9");
derive_color!("High-intensity light green.", LightGreen, "10");
derive_color!("High-intensity light yellow.", LightYellow, "11");
derive_color!("High-intensity light blue.", LightBlue, "12");
derive_color!("High-intensity light magenta.", LightMagenta, "13");
derive_color!("High-intensity light cyan.", LightCyan, "14");
derive_color!("High-intensity light white.", LightWhite, "15");
impl<'a> Color for &'a dyn Color {
#[inline]
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
(*self).write_fg(f)
}
#[inline]
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
(*self).write_bg(f)
}
}
#[derive(Clone, Copy, Debug)]
pub struct AnsiValue(pub u8);
impl AnsiValue {
pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
debug_assert!(
r <= 5,
"Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.",
r
);
debug_assert!(
g <= 5,
"Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.",
g
);
debug_assert!(
b <= 5,
"Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.",
b
);
AnsiValue(16 + 36 * r + 6 * g + b)
}
pub fn grayscale(shade: u8) -> AnsiValue {
debug_assert!(
shade < 24,
"Grayscale out of bound (shade = {}). There are only 24 shades of \
gray.",
shade
);
AnsiValue(0xE8 + shade)
}
}
impl AnsiValue {
pub fn fg_string(self) -> String {
let mut x = [0u8; 20];
let x = self.0.numtoa_str(10, &mut x);
[csi!("38;5;"), x, "m"].concat()
}
pub fn bg_string(self) -> String {
let mut x = [0u8; 20];
let x = self.0.numtoa_str(10, &mut x);
[csi!("48;5;"), x, "m"].concat()
}
}
impl Color for AnsiValue {
#[inline]
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.fg_string())
}
#[inline]
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.bg_string())
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Rgb(pub u8, pub u8, pub u8);
impl Rgb {
pub fn fg_string(self) -> String {
let (mut x, mut y, mut z) = ([0u8; 20], [0u8; 20], [0u8; 20]);
let (x, y, z) = (
self.0.numtoa_str(10, &mut x),
self.1.numtoa_str(10, &mut y),
self.2.numtoa_str(10, &mut z),
);
[csi!("38;2;"), x, ";", y, ";", z, "m"].concat()
}
pub fn bg_string(self) -> String {
let (mut x, mut y, mut z) = ([0u8; 20], [0u8; 20], [0u8; 20]);
let (x, y, z) = (
self.0.numtoa_str(10, &mut x),
self.1.numtoa_str(10, &mut y),
self.2.numtoa_str(10, &mut z),
);
[csi!("48;2;"), x, ";", y, ";", z, "m"].concat()
}
}
impl Color for Rgb {
#[inline]
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.fg_string())
}
#[inline]
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.bg_string())
}
}
#[derive(Debug, Clone, Copy)]
pub struct Reset;
const RESET_FG: &str = csi!("39m");
const RESET_BG: &str = csi!("49m");
impl Reset {
pub fn fg_str(self) -> &'static str {
RESET_FG
}
pub fn bg_str(self) -> &'static str {
RESET_BG
}
}
impl Color for Reset {
#[inline]
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(RESET_FG)
}
#[inline]
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(RESET_BG)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Fg<C: Color>(pub C);
impl<C: Color> fmt::Display for Fg<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.write_fg(f)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Bg<C: Color>(pub C);
impl<C: Color> fmt::Display for Bg<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.write_bg(f)
}
}