use core::fmt::{Display, Formatter, Result};
use crate::{
AppliedTo, Style, StyleAttribute, StyleElement, StyleSet as _, ToStyle, ToStyleSet,
color::Color,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TargetedColor {
color: Color,
target: ColorTarget,
}
impl TargetedColor {
#[must_use]
pub fn new(color: impl Into<Color>, target: ColorTarget) -> Self {
let color = color.into();
Self { color, target }
}
#[must_use]
pub fn new_for_fg(color: impl Into<Color>) -> Self {
Self::new(color, ColorTarget::Foreground)
}
#[must_use]
pub fn new_for_bg(color: impl Into<Color>) -> Self {
Self::new(color, ColorTarget::Background)
}
#[must_use]
pub fn new_for_underline(color: impl Into<Color>) -> Self {
Self::new(color, ColorTarget::Underline)
}
#[must_use]
pub const fn get_color(self) -> Color {
self.color
}
#[must_use]
pub const fn get_target(self) -> ColorTarget {
self.target
}
}
impl StyleElement for TargetedColor {
fn add_to_style(self, style: Style) -> Style {
style.set_color(self.target, Some(self.color))
}
}
impl ToStyleSet for TargetedColor {
type StyleSet = Style;
fn to_style_set(self) -> Self::StyleSet {
self.to_style()
}
}
impl ToStyle for TargetedColor {
fn to_style(self) -> Style {
self.into()
}
}
impl AppliedTo for TargetedColor {}
impl Display for TargetedColor {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
self.to_style().fmt(f)
}
}
impl<C: Into<Color>> From<C> for TargetedColor {
fn from(value: C) -> Self {
Self::new(value, ColorTarget::Foreground)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ColorTarget {
Foreground,
Background,
Underline,
}
impl StyleAttribute for ColorTarget {
type Value = Option<Color>;
fn set_in_style(self, style: Style, value: Self::Value) -> Style {
match self {
ColorTarget::Foreground => Style { fg: value, ..style },
ColorTarget::Background => Style { bg: value, ..style },
ColorTarget::Underline => Style {
underline_color: value,
..style
},
}
}
fn get_from_style(self, style: &Style) -> Self::Value {
match self {
ColorTarget::Foreground => style.fg,
ColorTarget::Background => style.bg,
ColorTarget::Underline => style.underline_color,
}
}
}
#[cfg(test)]
mod tests {
use crate::{
StyleSet as _, assert_display,
color::{BasicColor, ColorKind as _, IndexedColor, RGBColor, SimpleColor},
test_to_style_set_methods,
};
use super::*;
#[test]
fn targeted_color() {
let cp = TargetedColor::new(BasicColor::Red, ColorTarget::Foreground);
assert_eq!(cp.get_color(), BasicColor::Red.to_color());
assert_eq!(cp.get_target(), ColorTarget::Foreground);
assert_eq!(
cp.to_style_set(),
Style::new().set_color(ColorTarget::Foreground, Some(BasicColor::Red))
);
assert_eq!(
cp.to_style(),
Style::new().set_color(ColorTarget::Foreground, Some(BasicColor::Red))
);
}
test_to_style_set_methods!(red_fg; TargetedColor::new_for_fg(BasicColor::Red), Style::new().fg(BasicColor::Red));
test_to_style_set_methods!(green_fg; TargetedColor::new_for_fg(BasicColor::Green), Style::new().fg(BasicColor::Green));
test_to_style_set_methods!(red_bg; TargetedColor::new_for_fg(BasicColor::Red), Style::new().fg(BasicColor::Red));
test_to_style_set_methods!(green_bg; TargetedColor::new_for_fg(BasicColor::Green), Style::new().fg(BasicColor::Green));
test_to_style_set_methods!(red_underline; TargetedColor::new_for_underline(BasicColor::Red), Style::new().underline_color(BasicColor::Red));
test_to_style_set_methods!(green_underline; TargetedColor::new_for_underline(BasicColor::Green), Style::new().underline_color(BasicColor::Green));
#[test]
fn applied_to() {
let stld = BasicColor::Red.for_fg().applied_to("CONTENT");
assert_eq!(stld.get_content(), &"CONTENT");
assert_eq!(stld.get_style(), Style::new().fg(BasicColor::Red));
}
#[test]
fn to_style() {
assert_eq!(
BasicColor::Red.for_fg().to_style(),
Style::new().fg(BasicColor::Red)
);
assert_eq!(
BasicColor::Green.for_bg().to_style(),
Style::new().bg(BasicColor::Green)
);
}
#[test]
fn basic_color_display() {
assert_display!(BasicColor::Black.for_fg(), "\x1b[30m");
assert_display!(BasicColor::Red.for_fg(), "\x1b[31m");
assert_display!(BasicColor::Green.for_fg(), "\x1b[32m");
assert_display!(BasicColor::Yellow.for_fg(), "\x1b[33m");
assert_display!(BasicColor::Blue.for_fg(), "\x1b[34m");
assert_display!(BasicColor::Magenta.for_fg(), "\x1b[35m");
assert_display!(BasicColor::Cyan.for_fg(), "\x1b[36m");
assert_display!(BasicColor::White.for_fg(), "\x1b[37m");
assert_display!(BasicColor::Black.for_bg(), "\x1b[40m");
assert_display!(BasicColor::Red.for_bg(), "\x1b[41m");
assert_display!(BasicColor::Green.for_bg(), "\x1b[42m");
assert_display!(BasicColor::Yellow.for_bg(), "\x1b[43m");
assert_display!(BasicColor::Blue.for_bg(), "\x1b[44m");
assert_display!(BasicColor::Magenta.for_bg(), "\x1b[45m");
assert_display!(BasicColor::Cyan.for_bg(), "\x1b[46m");
assert_display!(BasicColor::White.for_bg(), "\x1b[47m");
assert_display!(BasicColor::Black.for_underline(), "\x1b[58;5;0m");
assert_display!(BasicColor::Red.for_underline(), "\x1b[58;5;1m");
assert_display!(BasicColor::Green.for_underline(), "\x1b[58;5;2m");
assert_display!(BasicColor::Yellow.for_underline(), "\x1b[58;5;3m");
assert_display!(BasicColor::Blue.for_underline(), "\x1b[58;5;4m");
assert_display!(BasicColor::Magenta.for_underline(), "\x1b[58;5;5m");
assert_display!(BasicColor::Cyan.for_underline(), "\x1b[58;5;6m");
assert_display!(BasicColor::White.for_underline(), "\x1b[58;5;7m");
}
#[test]
fn simple_color_display() {
assert_display!(SimpleColor::new(BasicColor::Black).for_fg(), "\x1b[30m");
assert_display!(SimpleColor::new(BasicColor::Red).for_fg(), "\x1b[31m");
assert_display!(SimpleColor::new(BasicColor::White).for_fg(), "\x1b[37m");
assert_display!(SimpleColor::new(BasicColor::Black).for_bg(), "\x1b[40m");
assert_display!(SimpleColor::new(BasicColor::Red).for_bg(), "\x1b[41m");
assert_display!(SimpleColor::new(BasicColor::White).for_bg(), "\x1b[47m");
assert_display!(
SimpleColor::new(BasicColor::Black).for_underline(),
"\x1b[58;5;0m"
);
assert_display!(
SimpleColor::new(BasicColor::Red).for_underline(),
"\x1b[58;5;1m"
);
assert_display!(
SimpleColor::new(BasicColor::White).for_underline(),
"\x1b[58;5;7m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::Black).for_fg(),
"\x1b[90m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::Red).for_fg(),
"\x1b[91m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::White).for_fg(),
"\x1b[97m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::Black).for_bg(),
"\x1b[100m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::Red).for_bg(),
"\x1b[101m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::White).for_bg(),
"\x1b[107m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::Black).for_underline(),
"\x1b[58;5;8m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::Red).for_underline(),
"\x1b[58;5;9m"
);
assert_display!(
SimpleColor::new_bright(BasicColor::White).for_underline(),
"\x1b[58;5;15m"
);
}
#[test]
fn indexed_color_display() {
assert_display!(IndexedColor(0).for_fg(), "\x1b[38;5;0m");
assert_display!(IndexedColor(7).for_fg(), "\x1b[38;5;7m");
assert_display!(IndexedColor(255).for_fg(), "\x1b[38;5;255m");
assert_display!(IndexedColor(0).for_bg(), "\x1b[48;5;0m");
assert_display!(IndexedColor(7).for_bg(), "\x1b[48;5;7m");
assert_display!(IndexedColor(255).for_bg(), "\x1b[48;5;255m");
assert_display!(IndexedColor(0).for_underline(), "\x1b[58;5;0m");
assert_display!(IndexedColor(7).for_underline(), "\x1b[58;5;7m");
assert_display!(IndexedColor(255).for_underline(), "\x1b[58;5;255m");
}
#[test]
fn rgb_color_display() {
assert_display!(RGBColor::new(0, 128, 255).for_fg(), "\x1b[38;2;0;128;255m");
assert_display!(RGBColor::new(128, 255, 0).for_fg(), "\x1b[38;2;128;255;0m");
assert_display!(RGBColor::new(255, 0, 128).for_fg(), "\x1b[38;2;255;0;128m");
assert_display!(RGBColor::new(0, 128, 255).for_bg(), "\x1b[48;2;0;128;255m");
assert_display!(RGBColor::new(128, 255, 0).for_bg(), "\x1b[48;2;128;255;0m");
assert_display!(RGBColor::new(255, 0, 128).for_bg(), "\x1b[48;2;255;0;128m");
assert_display!(
RGBColor::new(0, 128, 255).for_underline(),
"\x1b[58;2;0;128;255m"
);
assert_display!(
RGBColor::new(128, 255, 0).for_underline(),
"\x1b[58;2;128;255;0m"
);
assert_display!(
RGBColor::new(255, 0, 128).for_underline(),
"\x1b[58;2;255;0;128m"
);
}
}