#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Color {
Ansi(AnsiColor),
XTerm(XTermColor),
Rgb(RgbColor),
}
impl Color {
pub fn render_fg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: false,
}
}
pub fn render_bg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: true,
}
}
pub(crate) fn ansi_fmt(
&self,
f: &mut dyn core::fmt::Write,
is_background: bool,
) -> core::fmt::Result {
match self {
Self::Ansi(color) => color.ansi_fmt(f, is_background),
Self::XTerm(color) => color.ansi_fmt(f, is_background),
Self::Rgb(color) => color.ansi_fmt(f, is_background),
}
}
}
impl AnsiColorFmt for Color {
fn ansi_fmt(&self, f: &mut dyn core::fmt::Write, is_background: bool) -> core::fmt::Result {
self.ansi_fmt(f, is_background)
}
}
impl From<AnsiColor> for Color {
fn from(inner: AnsiColor) -> Self {
Self::Ansi(inner)
}
}
impl From<XTermColor> for Color {
fn from(inner: XTermColor) -> Self {
Self::XTerm(inner)
}
}
impl From<RgbColor> for Color {
fn from(inner: RgbColor) -> Self {
Self::Rgb(inner)
}
}
impl From<u8> for Color {
fn from(inner: u8) -> Self {
Self::XTerm(inner.into())
}
}
impl From<(u8, u8, u8)> for Color {
fn from(inner: (u8, u8, u8)) -> Self {
Self::Rgb(inner.into())
}
}
impl core::ops::BitOr<crate::Effects> for Color {
type Output = crate::Style;
#[inline(always)]
fn bitor(self, rhs: crate::Effects) -> Self::Output {
crate::Style::new().fg_color(Some(self)) | rhs
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AnsiColor {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
BrightBlack,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite,
}
impl AnsiColor {
pub fn render_fg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: false,
}
}
pub fn render_bg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: true,
}
}
fn is_bright(self) -> bool {
match self {
Self::Black => false,
Self::Red => false,
Self::Green => false,
Self::Yellow => false,
Self::Blue => false,
Self::Magenta => false,
Self::Cyan => false,
Self::White => false,
Self::BrightBlack => true,
Self::BrightRed => true,
Self::BrightGreen => true,
Self::BrightYellow => true,
Self::BrightBlue => true,
Self::BrightMagenta => true,
Self::BrightCyan => true,
Self::BrightWhite => true,
}
}
}
impl AnsiColorFmt for AnsiColor {
fn ansi_fmt(&self, f: &mut dyn core::fmt::Write, is_background: bool) -> core::fmt::Result {
match (is_background, self.is_bright()) {
(true, true) => write!(f, "10"),
(false, true) => write!(f, "9"),
(true, false) => write!(f, "4"),
(false, false) => write!(f, "3"),
}?;
match self {
Self::Black => write!(f, "0"),
Self::Red => write!(f, "1"),
Self::Green => write!(f, "2"),
Self::Yellow => write!(f, "3"),
Self::Blue => write!(f, "4"),
Self::Magenta => write!(f, "5"),
Self::Cyan => write!(f, "6"),
Self::White => write!(f, "7"),
Self::BrightBlack => write!(f, "0"),
Self::BrightRed => write!(f, "1"),
Self::BrightGreen => write!(f, "2"),
Self::BrightYellow => write!(f, "3"),
Self::BrightBlue => write!(f, "4"),
Self::BrightMagenta => write!(f, "5"),
Self::BrightCyan => write!(f, "6"),
Self::BrightWhite => write!(f, "7"),
}
}
}
impl core::ops::BitOr<crate::Effects> for AnsiColor {
type Output = crate::Style;
#[inline(always)]
fn bitor(self, rhs: crate::Effects) -> Self::Output {
crate::Style::new().fg_color(Some(self.into())) | rhs
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct XTermColor(pub u8);
impl XTermColor {
pub fn index(self) -> u8 {
self.0
}
pub fn render_fg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: false,
}
}
pub fn render_bg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: true,
}
}
}
impl AnsiColorFmt for XTermColor {
fn ansi_fmt(&self, f: &mut dyn core::fmt::Write, is_background: bool) -> core::fmt::Result {
if is_background {
write!(f, "48;")?;
} else {
write!(f, "38;")?;
}
write!(f, "5;{}", self.index())
}
}
impl From<u8> for XTermColor {
fn from(inner: u8) -> Self {
Self(inner)
}
}
impl core::ops::BitOr<crate::Effects> for XTermColor {
type Output = crate::Style;
#[inline(always)]
fn bitor(self, rhs: crate::Effects) -> Self::Output {
crate::Style::new().fg_color(Some(self.into())) | rhs
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RgbColor(pub u8, pub u8, pub u8);
impl RgbColor {
pub fn r(self) -> u8 {
self.0
}
pub fn g(self) -> u8 {
self.1
}
pub fn b(self) -> u8 {
self.2
}
pub fn render_fg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: false,
}
}
pub fn render_bg(self) -> impl core::fmt::Display {
DisplayColor {
color: self,
is_background: true,
}
}
}
impl AnsiColorFmt for RgbColor {
fn ansi_fmt(&self, f: &mut dyn core::fmt::Write, is_background: bool) -> core::fmt::Result {
if is_background {
write!(f, "48;")?;
} else {
write!(f, "38;")?;
}
write!(f, "2;{};{};{}", self.r(), self.g(), self.b())
}
}
impl From<(u8, u8, u8)> for RgbColor {
fn from(inner: (u8, u8, u8)) -> Self {
let (r, g, b) = inner;
Self(r, g, b)
}
}
impl core::ops::BitOr<crate::Effects> for RgbColor {
type Output = crate::Style;
#[inline(always)]
fn bitor(self, rhs: crate::Effects) -> Self::Output {
crate::Style::new().fg_color(Some(self.into())) | rhs
}
}
trait AnsiColorFmt {
fn ansi_fmt(&self, f: &mut dyn core::fmt::Write, is_background: bool) -> core::fmt::Result;
}
struct DisplayColor<C: AnsiColorFmt> {
color: C,
is_background: bool,
}
impl<C: AnsiColorFmt> core::fmt::Display for DisplayColor<C> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "\x1B[")?;
self.color.ansi_fmt(f, self.is_background)?;
write!(f, "m")?;
Ok(())
}
}