#[cfg(feature = "color")]
pub use anstyle::{Ansi256Color, AnsiColor, Color, Effects, Reset, RgbColor};
#[cfg(not(feature = "color"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AnsiColor {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
BrightBlack,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Style {
#[cfg(feature = "color")]
inner: anstyle::Style,
}
impl Style {
#[inline]
pub const fn new() -> Self {
#[cfg(feature = "color")]
{
Self { inner: anstyle::Style::new() }
}
#[cfg(not(feature = "color"))]
{
Self {}
}
}
#[inline]
#[allow(unused_mut)]
pub const fn bold(mut self) -> Self {
#[cfg(feature = "color")]
{
self.inner = self.inner.bold();
}
self
}
#[inline]
#[allow(unused_mut)]
pub const fn dimmed(mut self) -> Self {
#[cfg(feature = "color")]
{
self.inner = self.inner.dimmed();
}
self
}
#[inline]
#[allow(unused_mut)]
pub const fn italic(mut self) -> Self {
#[cfg(feature = "color")]
{
self.inner = self.inner.italic();
}
self
}
#[inline]
#[allow(unused_mut)]
pub const fn underline(mut self) -> Self {
#[cfg(feature = "color")]
{
self.inner = self.inner.underline();
}
self
}
#[inline]
#[allow(unused_mut)]
pub const fn fg_rgb(mut self, r: u8, g: u8, b: u8) -> Self {
#[cfg(feature = "color")]
{
self.inner = self.inner.fg_color(Some(anstyle::Color::Rgb(anstyle::RgbColor(r, g, b))));
}
let _ = (r, g, b);
self
}
#[inline]
#[allow(unused_mut)]
pub const fn fg_ansi256(mut self, code: u8) -> Self {
#[cfg(feature = "color")]
{
self.inner =
self.inner.fg_color(Some(anstyle::Color::Ansi256(anstyle::Ansi256Color(code))));
}
let _ = code;
self
}
#[inline]
#[allow(unused_mut)]
pub const fn fg_ansi(mut self, color: AnsiColor) -> Self {
#[cfg(feature = "color")]
{
self.inner = self.inner.fg_color(Some(anstyle::Color::Ansi(color)));
}
let _ = color;
self
}
#[inline]
pub fn is_plain(&self) -> bool {
#[cfg(feature = "color")]
{
self.inner == anstyle::Style::new()
}
#[cfg(not(feature = "color"))]
{
true
}
}
#[inline]
pub fn render(&self) -> impl core::fmt::Display {
#[cfg(feature = "color")]
{
self.inner.render()
}
#[cfg(not(feature = "color"))]
{
""
}
}
#[inline]
pub fn render_reset(&self) -> impl core::fmt::Display {
#[cfg(feature = "color")]
{
self.inner.render_reset()
}
#[cfg(not(feature = "color"))]
{
""
}
}
#[cfg(feature = "color")]
pub const fn inner(&self) -> anstyle::Style {
self.inner
}
pub fn to_ansi256(self) -> Self {
#[cfg(feature = "color")]
{
let mut styled = self.inner;
if let Some(color) = styled.get_fg_color() {
let converted = match color {
anstyle::Color::Rgb(rgb) => anstyle::Color::Ansi256(anstyle::Ansi256Color(
rgb_to_ansi256(rgb.0, rgb.1, rgb.2),
)),
other => other,
};
styled = styled.fg_color(Some(converted));
}
Self { inner: styled }
}
#[cfg(not(feature = "color"))]
{
self
}
}
pub fn to_ansi16(self) -> Self {
#[cfg(feature = "color")]
{
let mut styled = self.inner;
if let Some(color) = styled.get_fg_color() {
let converted = match color {
anstyle::Color::Rgb(rgb) => {
anstyle::Color::Ansi(rgb_to_ansi16(rgb.0, rgb.1, rgb.2))
}
anstyle::Color::Ansi256(code) => {
let (r, g, b) = ansi256_to_rgb(code.0);
anstyle::Color::Ansi(rgb_to_ansi16(r, g, b))
}
anstyle::Color::Ansi(ansi) => anstyle::Color::Ansi(ansi),
};
styled = styled.fg_color(Some(converted));
}
Self { inner: styled }
}
#[cfg(not(feature = "color"))]
{
self
}
}
pub fn to_monochrome(self) -> Self {
#[cfg(feature = "color")]
{
let styled = self.inner.fg_color(None).bg_color(None);
Self { inner: styled }
}
#[cfg(not(feature = "color"))]
{
self
}
}
}
#[cfg(feature = "color")]
impl From<anstyle::Style> for Style {
fn from(inner: anstyle::Style) -> Self {
Self { inner }
}
}
#[cfg(feature = "color")]
impl From<Style> for anstyle::Style {
fn from(style: Style) -> Self {
style.inner
}
}
pub fn rgb_to_ansi256(r: u8, g: u8, b: u8) -> u8 {
if r == g && g == b {
if r < 8 {
16
} else if r > 248 {
231
} else {
(((r as u16 - 8) * 24) / 240) as u8 + 232
}
} else {
let r_idx = ((r as u16 * 5) + 127) / 255;
let g_idx = ((g as u16 * 5) + 127) / 255;
let b_idx = ((b as u16 * 5) + 127) / 255;
(16 + 36 * r_idx + 6 * g_idx + b_idx) as u8
}
}
pub fn ansi256_to_rgb(code: u8) -> (u8, u8, u8) {
if code < 16 {
ANSI16_PALETTE[code as usize].1
} else if code < 232 {
let idx = code - 16;
let b = (idx % 6) * 51;
let g = ((idx / 6) % 6) * 51;
let r = (idx / 36) * 51;
(r, g, b)
} else {
let gray = (code - 232) * 10 + 8;
(gray, gray, gray)
}
}
static ANSI16_PALETTE: [(AnsiColor, (u8, u8, u8)); 16] = [
(AnsiColor::Black, (0, 0, 0)),
(AnsiColor::Red, (205, 49, 49)),
(AnsiColor::Green, (13, 188, 121)),
(AnsiColor::Yellow, (229, 229, 16)),
(AnsiColor::Blue, (36, 114, 200)),
(AnsiColor::Magenta, (188, 63, 188)),
(AnsiColor::Cyan, (17, 168, 205)),
(AnsiColor::White, (229, 229, 229)),
(AnsiColor::BrightBlack, (102, 102, 102)),
(AnsiColor::BrightRed, (241, 76, 76)),
(AnsiColor::BrightGreen, (35, 209, 139)),
(AnsiColor::BrightYellow, (245, 245, 67)),
(AnsiColor::BrightBlue, (59, 142, 234)),
(AnsiColor::BrightMagenta, (214, 112, 214)),
(AnsiColor::BrightCyan, (41, 184, 219)),
(AnsiColor::BrightWhite, (255, 255, 255)),
];
pub fn rgb_to_ansi16(r: u8, g: u8, b: u8) -> AnsiColor {
let mut closest = AnsiColor::White;
let mut min_dist = u32::MAX;
for (color, (pr, pg, pb)) in ANSI16_PALETTE {
let dr = (r as i32) - (pr as i32);
let dg = (g as i32) - (pg as i32);
let db = (b as i32) - (pb as i32);
let dist = (dr * dr + dg * dg + db * db) as u32;
if dist < min_dist {
min_dist = dist;
closest = color;
}
}
closest
}