use crate::{Color, Gradient, StyledText, HSL, RGB};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ColorStyle {
Single(Color),
Gradient(Gradient),
Colorless,
}
impl From<Color> for ColorStyle {
fn from(color: Color) -> Self {
Self::Single(color)
}
}
impl From<(u8, u8, u8)> for ColorStyle {
fn from((r, g, b): (u8, u8, u8)) -> Self {
Self::Single(RGB::new(r, g, b).into())
}
}
impl From<RGB> for ColorStyle {
fn from(rgb: RGB) -> Self {
Self::Single(rgb.into())
}
}
impl From<HSL> for ColorStyle {
fn from(hsl: HSL) -> Self {
Self::Single(hsl.into())
}
}
impl From<Gradient> for ColorStyle {
fn from(gradient: Gradient) -> Self {
Self::Gradient(gradient)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum StyleMode {
Reset = 0b00000000,
Bold = 0b00000001,
Dim = 0b00000010,
Italic = 0b00000100,
Underline = 0b00001000,
Blinking = 0b00010000,
Reversed = 0b00100000,
Invisible = 0b01000000,
Strikethrough = 0b10000000,
}
impl StyleMode {
#[inline]
const fn from_u8(x: u8) -> Self {
match x {
1 => Self::Bold,
2 => Self::Dim,
3 => Self::Italic,
4 => Self::Underline,
5 => Self::Blinking,
6 => Self::Reversed,
7 => Self::Invisible,
8 => Self::Strikethrough,
_ => Self::Reset,
}
}
#[inline]
fn code(&self) -> String {
match self {
Self::Reset => "0".to_string(),
Self::Bold => "1".to_string(),
Self::Dim => "2".to_string(),
Self::Italic => "3".to_string(),
Self::Underline => "4".to_string(),
Self::Blinking => "5".to_string(),
Self::Reversed => "7".to_string(),
Self::Invisible => "8".to_string(),
Self::Strikethrough => "9".to_string(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Style {
modes: u8,
}
impl Style {
#[inline]
pub(crate) const fn new() -> Self {
Self { modes: 0 }
}
pub(crate) const fn add_style_mode(&self, mode: StyleMode) -> Self {
Self {
modes: self.modes | mode as u8,
}
}
pub(crate) fn ansi_code(&self) -> String {
if self.modes == 0 {
return String::new();
}
(0..8)
.filter_map(|i| {
(self.modes & 1 << i != 0).then(|| StyleMode::from_u8(i + 1).code())
})
.collect::<Vec<_>>()
.join(";")
}
pub(crate) fn styles(&self) -> Vec<StyleMode> {
if self.modes == 0 {
return vec![StyleMode::Reset];
}
(0..8)
.filter_map(|i| {
(self.modes & 1 << i != 0).then(|| StyleMode::from_u8(i + 1))
})
.collect::<Vec<_>>()
}
}
pub trait Styling: Into<StyledText> {
fn bold(&self) -> StyledText;
fn dim(&self) -> StyledText;
fn italic(&self) -> StyledText;
fn underline(&self) -> StyledText;
fn blinking(&self) -> StyledText;
fn reversed(&self) -> StyledText;
fn invisible(&self) -> StyledText;
fn strikethrough(&self) -> StyledText;
}
impl Styling for StyledText {
fn bold(&self) -> StyledText {
self.with_style_mode(StyleMode::Bold)
}
fn dim(&self) -> StyledText {
self.with_style_mode(StyleMode::Dim)
}
fn italic(&self) -> StyledText {
self.with_style_mode(StyleMode::Italic)
}
fn underline(&self) -> StyledText {
self.with_style_mode(StyleMode::Underline)
}
fn blinking(&self) -> StyledText {
self.with_style_mode(StyleMode::Blinking)
}
fn reversed(&self) -> StyledText {
self.with_style_mode(StyleMode::Reversed)
}
fn invisible(&self) -> StyledText {
self.with_style_mode(StyleMode::Invisible)
}
fn strikethrough(&self) -> StyledText {
self.with_style_mode(StyleMode::Strikethrough)
}
}
impl Styling for &str {
fn bold(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Bold)
}
fn dim(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Dim)
}
fn italic(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Italic)
}
fn underline(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Underline)
}
fn blinking(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Blinking)
}
fn reversed(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Reversed)
}
fn invisible(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Invisible)
}
fn strikethrough(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Strikethrough)
}
}
impl Styling for String {
fn bold(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Bold)
}
fn dim(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Dim)
}
fn italic(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Italic)
}
fn underline(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Underline)
}
fn blinking(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Blinking)
}
fn reversed(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Reversed)
}
fn invisible(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Invisible)
}
fn strikethrough(&self) -> StyledText {
StyledText::new(self).with_style_mode(StyleMode::Strikethrough)
}
}