use std::fmt;
#[derive(Debug, Clone, Copy)]
pub enum Color {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
BrightBlack,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite,
ANSI(u8),
}
impl Color {
fn fg_code(self) -> u8 {
match self {
Color::Black => 30,
Color::Red => 31,
Color::Green => 32,
Color::Yellow => 33,
Color::Blue => 34,
Color::Magenta => 35,
Color::Cyan => 36,
Color::White => 37,
Color::BrightBlack => 90,
Color::BrightRed => 91,
Color::BrightGreen => 92,
Color::BrightYellow => 93,
Color::BrightBlue => 94,
Color::BrightMagenta => 95,
Color::BrightCyan => 96,
Color::BrightWhite => 97,
Color::ANSI(c) => c,
}
}
fn bg_code(self) -> u8 {
self.fg_code() + 10
}
}
pub struct StyledText<'a> {
text: &'a str,
fg: Option<Color>,
bg: Option<Color>,
bold: bool,
italic: bool,
underline: bool,
blink: bool,
reverse: bool,
strikethrough: bool,
}
impl<'a> StyledText<'a> {
pub fn new(text: &'a str) -> Self {
Self {
text,
fg: None,
bg: None,
bold: false,
italic: false,
underline: false,
blink: false,
reverse: false,
strikethrough: false,
}
}
pub fn fg(mut self, color: Color) -> Self {
self.fg = Some(color);
self
}
pub fn bg(mut self, color: Color) -> Self {
self.bg = Some(color);
self
}
pub fn bold(mut self) -> Self {
self.bold = true;
self
}
pub fn italic(mut self) -> Self {
self.italic = true;
self
}
pub fn underline(mut self) -> Self {
self.underline = true;
self
}
pub fn blink(mut self) -> Self {
self.blink = true;
self
}
pub fn reverse(mut self) -> Self {
self.reverse = true;
self
}
pub fn strikethrough(mut self) -> Self {
self.strikethrough = true;
self
}
pub fn format_sequence(&'a self) -> String {
let mut codes = Vec::new();
if let Some(fg) = self.fg {
codes.push(fg.fg_code());
}
if let Some(bg) = self.bg {
codes.push(bg.bg_code());
}
if self.bold {
codes.push(1);
}
if self.italic {
codes.push(3);
}
if self.underline {
codes.push(4);
}
if self.blink {
codes.push(5);
}
if self.reverse {
codes.push(7);
}
if self.strikethrough {
codes.push(9);
}
let codes_str = codes
.iter()
.map(|c| c.to_string())
.collect::<Vec<_>>()
.join(";");
if !codes.is_empty() {
format!("\x1B[{}m{}\x1B[0m", codes_str, self.text)
} else {
self.text.to_string()
}
}
}
impl fmt::Display for StyledText<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.format_sequence())
}
}