use std::fmt;
use std::io::Write;
use crate::Command;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Color {
Reset,
Black,
DarkGrey,
Red,
DarkRed,
Green,
DarkGreen,
Yellow,
DarkYellow,
Blue,
DarkBlue,
Magenta,
DarkMagenta,
Cyan,
DarkCyan,
White,
Grey,
Rgb { r: u8, g: u8, b: u8 },
AnsiValue(u8),
}
impl Color {
fn fg_ansi(self) -> ColorAnsi {
match self {
Color::Reset => ColorAnsi::Sgr(39),
Color::Black => ColorAnsi::Sgr(30),
Color::DarkGrey => ColorAnsi::Sgr(90),
Color::Red => ColorAnsi::Sgr(31),
Color::DarkRed => ColorAnsi::Sgr(91),
Color::Green => ColorAnsi::Sgr(32),
Color::DarkGreen => ColorAnsi::Sgr(92),
Color::Yellow => ColorAnsi::Sgr(33),
Color::DarkYellow => ColorAnsi::Sgr(93),
Color::Blue => ColorAnsi::Sgr(34),
Color::DarkBlue => ColorAnsi::Sgr(94),
Color::Magenta => ColorAnsi::Sgr(35),
Color::DarkMagenta => ColorAnsi::Sgr(95),
Color::Cyan => ColorAnsi::Sgr(36),
Color::DarkCyan => ColorAnsi::Sgr(96),
Color::White => ColorAnsi::Sgr(37),
Color::Grey => ColorAnsi::Sgr(97),
Color::Rgb { r, g, b } => ColorAnsi::Rgb(38, r, g, b),
Color::AnsiValue(n) => ColorAnsi::Ansi256(38, n),
}
}
fn bg_ansi(self) -> ColorAnsi {
match self {
Color::Reset => ColorAnsi::Sgr(49),
Color::Black => ColorAnsi::Sgr(40),
Color::DarkGrey => ColorAnsi::Sgr(100),
Color::Red => ColorAnsi::Sgr(41),
Color::DarkRed => ColorAnsi::Sgr(101),
Color::Green => ColorAnsi::Sgr(42),
Color::DarkGreen => ColorAnsi::Sgr(102),
Color::Yellow => ColorAnsi::Sgr(43),
Color::DarkYellow => ColorAnsi::Sgr(103),
Color::Blue => ColorAnsi::Sgr(44),
Color::DarkBlue => ColorAnsi::Sgr(104),
Color::Magenta => ColorAnsi::Sgr(45),
Color::DarkMagenta => ColorAnsi::Sgr(105),
Color::Cyan => ColorAnsi::Sgr(46),
Color::DarkCyan => ColorAnsi::Sgr(106),
Color::White => ColorAnsi::Sgr(47),
Color::Grey => ColorAnsi::Sgr(107),
Color::Rgb { r, g, b } => ColorAnsi::Rgb(48, r, g, b),
Color::AnsiValue(n) => ColorAnsi::Ansi256(48, n),
}
}
}
enum ColorAnsi {
Sgr(u8),
Rgb(u8, u8, u8, u8),
Ansi256(u8, u8),
}
impl ColorAnsi {
fn write(self, w: &mut impl Write) -> std::io::Result<()> {
match self {
ColorAnsi::Sgr(code) => write!(w, "\x1b[{code}m"),
ColorAnsi::Rgb(base, r, g, b) => write!(w, "\x1b[{base};2;{r};{g};{b}m"),
ColorAnsi::Ansi256(base, n) => write!(w, "\x1b[{base};5;{n}m"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Attribute {
Reset,
Bold,
Dim,
Italic,
Underlined,
SlowBlink,
RapidBlink,
Reverse,
Hidden,
CrossedOut,
}
impl Attribute {
fn sgr(self) -> u8 {
match self {
Attribute::Reset => 0,
Attribute::Bold => 1,
Attribute::Dim => 2,
Attribute::Italic => 3,
Attribute::Underlined => 4,
Attribute::SlowBlink => 5,
Attribute::RapidBlink => 6,
Attribute::Reverse => 7,
Attribute::Hidden => 8,
Attribute::CrossedOut => 9,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SetForegroundColor(pub Color);
impl Command for SetForegroundColor {
fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
self.0.fg_ansi().write(w)
}
}
#[derive(Debug, Clone, Copy)]
pub struct SetBackgroundColor(pub Color);
impl Command for SetBackgroundColor {
fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
self.0.bg_ansi().write(w)
}
}
#[derive(Debug, Clone, Copy)]
pub struct SetAttribute(pub Attribute);
impl Command for SetAttribute {
fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
write!(w, "\x1b[{}m", self.0.sgr())
}
}
#[derive(Debug, Clone, Copy)]
pub struct ResetColor;
impl Command for ResetColor {
fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
w.write_all(b"\x1b[0m")
}
}
#[derive(Debug, Clone)]
pub struct Print<T: fmt::Display>(pub T);
impl<T: fmt::Display> Command for Print<T> {
fn write_ansi(&self, w: &mut impl Write) -> std::io::Result<()> {
write!(w, "{}", self.0)
}
}