use crossterm::style as crossterm_style;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
BrightBlack,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite,
Rgb(u8, u8, u8),
}
impl From<Color> for crossterm_style::Color {
fn from(color: Color) -> Self {
match color {
Color::Black => crossterm_style::Color::Black,
Color::Red => crossterm_style::Color::Red,
Color::Green => crossterm_style::Color::Green,
Color::Yellow => crossterm_style::Color::Yellow,
Color::Blue => crossterm_style::Color::Blue,
Color::Magenta => crossterm_style::Color::Magenta,
Color::Cyan => crossterm_style::Color::Cyan,
Color::White => crossterm_style::Color::White,
Color::BrightBlack => crossterm_style::Color::AnsiValue(8),
Color::BrightRed => crossterm_style::Color::AnsiValue(9),
Color::BrightGreen => crossterm_style::Color::AnsiValue(10),
Color::BrightYellow => crossterm_style::Color::AnsiValue(11),
Color::BrightBlue => crossterm_style::Color::AnsiValue(12),
Color::BrightMagenta => crossterm_style::Color::AnsiValue(13),
Color::BrightCyan => crossterm_style::Color::AnsiValue(14),
Color::BrightWhite => crossterm_style::Color::AnsiValue(15),
Color::Rgb(r, g, b) => crossterm_style::Color::Rgb { r, g, b },
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Modifier {
bits: u8,
}
impl Modifier {
pub const NONE: Self = Self { bits: 0 };
pub const BOLD: Self = Self { bits: 1 };
pub const ITALIC: Self = Self { bits: 2 };
pub const UNDERLINED: Self = Self { bits: 4 };
pub const REVERSED: Self = Self { bits: 8 };
pub fn contains(&self, other: Self) -> bool {
(self.bits & other.bits) == other.bits
}
pub fn insert(&mut self, other: Self) {
self.bits |= other.bits;
}
pub fn remove(&mut self, other: Self) {
self.bits &= !other.bits;
}
}
impl std::ops::BitOr for Modifier {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Self { bits: self.bits | rhs.bits }
}
}
impl std::ops::BitOrAssign for Modifier {
fn bitor_assign(&mut self, rhs: Self) {
self.bits |= rhs.bits;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Style {
pub fg: Option<Color>,
pub bg: Option<Color>,
pub modifiers: Modifier,
}
impl Default for Style {
fn default() -> Self {
Self { fg: None, bg: None, modifiers: Modifier::NONE }
}
}
impl Style {
pub fn new() -> Self {
Self::default()
}
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.modifiers.insert(Modifier::BOLD);
self
}
pub fn italic(mut self) -> Self {
self.modifiers.insert(Modifier::ITALIC);
self
}
pub fn underlined(mut self) -> Self {
self.modifiers.insert(Modifier::UNDERLINED);
self
}
pub fn reversed(mut self) -> Self {
self.modifiers.insert(Modifier::REVERSED);
self
}
pub fn combine(&mut self, other: &Style) {
if other.fg.is_some() {
self.fg = other.fg;
}
if other.bg.is_some() {
self.bg = other.bg;
}
self.modifiers |= other.modifiers;
}
pub fn to_crossterm_style(&self) -> crossterm_style::ContentStyle {
let mut content_style = crossterm_style::ContentStyle::default();
if let Some(fg) = self.fg {
content_style.foreground_color = Some(crossterm_style::Color::from(fg));
}
if let Some(bg) = self.bg {
content_style.background_color = Some(crossterm_style::Color::from(bg));
}
if self.modifiers.contains(Modifier::BOLD) {
content_style.attributes.set(crossterm_style::Attribute::Bold);
}
if self.modifiers.contains(Modifier::ITALIC) {
content_style.attributes.set(crossterm_style::Attribute::Italic);
}
if self.modifiers.contains(Modifier::UNDERLINED) {
content_style.attributes.set(crossterm_style::Attribute::Underlined);
}
if self.modifiers.contains(Modifier::REVERSED) {
content_style.attributes.set(crossterm_style::Attribute::Reverse);
}
content_style
}
}