use core::fmt;
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
use crate::builder::builder_methods;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub struct Style {
pub fg: Color,
pub bg: Color,
pub underline: Color,
pub attributes: Attributes,
}
impl Style {
#[inline]
pub const fn new() -> Self {
Self {
fg: Color::Default,
bg: Color::Default,
underline: Color::Default,
attributes: Attributes::new(),
}
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.fg.is_default()
&& self.bg.is_default()
&& self.underline.is_default()
&& self.attributes.is_empty()
}
builder_methods! { s => s }
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Color {
#[default]
Default,
Basic(BasicColor),
Extended(u8),
Rgb(u8, u8, u8),
}
impl Color {
#[inline]
pub const fn is_default(&self) -> bool {
matches!(self, Self::Default)
}
#[inline]
pub const fn bright(self) -> Self {
match self {
Self::Basic(color) => Self::Basic(color.bright()),
_ => self,
}
}
#[inline]
pub const fn not_bright(self) -> Self {
match self {
Self::Basic(color) => Self::Basic(color.not_bright()),
_ => self,
}
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BasicColor {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
BrightBlack,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite,
}
impl From<BasicColor> for Color {
#[inline]
fn from(color: BasicColor) -> Self {
Self::Basic(color)
}
}
impl From<u8> for Color {
#[inline]
fn from(color: u8) -> Self {
Self::Extended(color)
}
}
impl From<(u8, u8, u8)> for Color {
#[inline]
fn from(color: (u8, u8, u8)) -> Self {
Self::Rgb(color.0, color.1, color.2)
}
}
impl BasicColor {
#[inline]
pub const fn bright(self) -> Self {
match self {
Self::Black => Self::BrightBlack,
Self::Red => Self::BrightRed,
Self::Green => Self::BrightGreen,
Self::Yellow => Self::BrightYellow,
Self::Blue => Self::BrightBlue,
Self::Magenta => Self::BrightMagenta,
Self::Cyan => Self::BrightCyan,
Self::White => Self::BrightWhite,
_ => self,
}
}
#[inline]
pub const fn not_bright(self) -> Self {
match self {
Self::BrightBlack => Self::Black,
Self::BrightRed => Self::Red,
Self::BrightGreen => Self::Green,
Self::BrightYellow => Self::Yellow,
Self::BrightBlue => Self::Blue,
Self::BrightMagenta => Self::Magenta,
Self::BrightCyan => Self::Cyan,
Self::BrightWhite => Self::White,
_ => self,
}
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Attributes(u8);
impl Attributes {
pub const BOLD: Self = Self(1 << 0);
pub const DIM: Self = Self(1 << 1);
pub const ITALIC: Self = Self(1 << 2);
pub const UNDERLINED: Self = Self(1 << 3);
pub const BLINK: Self = Self(1 << 4);
pub const INVERTED: Self = Self(1 << 5);
pub const HIDDEN: Self = Self(1 << 6);
pub const STRIKETHROUGH: Self = Self(1 << 7);
#[inline]
pub const fn new() -> Self {
Self(0)
}
#[inline]
pub(crate) const fn into_u8(self) -> u8 {
self.0
}
#[inline]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
#[inline]
pub const fn or(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
pub const fn and(self, other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
pub const fn not(self) -> Self {
Self(!self.0)
}
}
impl fmt::Debug for Attributes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_set();
macro_rules! impl_debug {
($($name:ident)*) => {
$(
if self.contains(Attributes::$name) {
f.entry(&format_args!("{}", stringify!($name)));
}
)*
};
}
impl_debug! {
BOLD
DIM
ITALIC
UNDERLINED
BLINK
INVERTED
HIDDEN
STRIKETHROUGH
}
f.finish()
}
}
impl BitOr<Attributes> for Attributes {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl BitOrAssign for Attributes {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl BitAnd<Attributes> for Attributes {
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl BitAndAssign for Attributes {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
impl Not for Attributes {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
Self(!self.0)
}
}
impl From<Attributes> for u8 {
#[inline]
fn from(value: Attributes) -> Self {
value.0
}
}