use core::fmt::{Display, Formatter, Result};
use enum_iterator::Sequence;
use crate::{AppliedTo, Style, StyleAttribute, StyleElement, StyleSet, ToStyle, ToStyleSet};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Sequence)]
pub enum Flag {
Bold,
Faint,
Italic,
Underline,
SlowBlink,
RapidBlink,
Reverse,
Conceal,
CrossedOut,
DoubleUnderline,
Overline,
}
impl Flag {
#[must_use]
pub(crate) const fn get_code(self) -> u8 {
match self {
Flag::Bold => 1,
Flag::Faint => 2,
Flag::Italic => 3,
Flag::Underline => 4,
Flag::SlowBlink => 5,
Flag::RapidBlink => 6,
Flag::Reverse => 7,
Flag::Conceal => 8,
Flag::CrossedOut => 9,
Flag::DoubleUnderline => 21,
Flag::Overline => 53,
}
}
#[must_use]
const fn bit_mask(self) -> u16 {
let bit_index = self as u16;
1 << bit_index
}
}
impl StyleElement for Flag {
fn add_to_style(self, style: Style) -> Style {
style.set_flag(self, true)
}
}
impl StyleAttribute for Flag {
type Value = bool;
fn set_in_style(self, style: Style, value: Self::Value) -> Style {
let flags = if value {
style.flags | self.bit_mask()
} else {
style.flags & !self.bit_mask()
};
Style { flags, ..style }
}
fn get_from_style(self, style: &Style) -> Self::Value {
style.flags & self.bit_mask() != 0
}
}
impl ToStyleSet for Flag {
type StyleSet = Style;
fn to_style_set(self) -> Self::StyleSet {
self.to_style()
}
}
impl ToStyle for Flag {
fn to_style(self) -> Style {
self.into()
}
}
impl AppliedTo for Flag {}
impl Display for Flag {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
self.to_style().fmt(f)
}
}
#[cfg(test)]
mod tests {
use crate::{
ToStyleSet as _, assert_display,
color::{BasicColor, ColorKind as _},
};
use super::*;
#[test]
fn add_flag() {
let flag = Flag::Bold;
assert_eq!(flag.bold(), Style::new().bold());
assert_eq!(flag.italic(), Style::new().bold().italic());
assert_eq!(flag.flag(Flag::Italic), Style::new().bold().italic());
assert_eq!(flag.add(Flag::Italic), Style::new().bold().italic());
}
#[test]
fn add_color() {
let flag = Flag::Bold;
assert_eq!(
flag.fg(BasicColor::Green),
Style::new().bold().fg(BasicColor::Green)
);
assert_eq!(
flag.color(BasicColor::Green.in_bg()),
Style::new().bold().bg(BasicColor::Green)
);
assert_eq!(
flag.add(BasicColor::Green.in_bg()),
Style::new().bold().bg(BasicColor::Green)
);
}
#[test]
fn applied_to() {
let stld = Flag::Bold.applied_to("CONTENT");
assert_eq!(stld.get_content(), &"CONTENT");
assert_eq!(stld.get_style(), Style::new().bold());
}
#[test]
fn to_style() {
assert_eq!(Flag::Bold.to_style(), Style::new().bold());
}
#[test]
fn to_style_set() {
assert_eq!(Flag::Bold.to_style_set(), Style::new().bold());
}
#[test]
fn display() {
assert_display!(Flag::Bold, "\x1b[1m");
assert_display!(Flag::Faint, "\x1b[2m");
assert_display!(Flag::Italic, "\x1b[3m");
assert_display!(Flag::Underline, "\x1b[4m");
assert_display!(Flag::SlowBlink, "\x1b[5m");
assert_display!(Flag::RapidBlink, "\x1b[6m");
assert_display!(Flag::Reverse, "\x1b[7m");
assert_display!(Flag::Conceal, "\x1b[8m");
assert_display!(Flag::CrossedOut, "\x1b[9m");
assert_display!(Flag::DoubleUnderline, "\x1b[21m");
assert_display!(Flag::Overline, "\x1b[53m");
}
}