coloriz 0.2.0

A simple library for colorful temrinal
Documentation
//! Text styles

use crate::{Color, Gradient, StyledText, HSL, RGB};

/// Represents the style of coloring
#[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)
    }
}

/// Represents styles
#[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<_>>()
    }
}

/// The trait that can be styled
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)
    }
}