blob: 17922f7b9e5e0878475451d0bf419dea20e5727d [file] [log] [blame] [edit]
//! Popular color palettes for [`anstyle::AnsiColor`]
//!
//! Based on [wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit)
use anstyle::RgbColor as Rgb;
/// A color palette for rendering 4-bit [`anstyle::AnsiColor`]
#[allow(clippy::exhaustive_structs)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Palette(pub RawPalette);
type RawPalette = [Rgb; 16];
impl Palette {
/// Look up the [`anstyle::RgbColor`] in the palette
pub const fn get(&self, color: anstyle::AnsiColor) -> Rgb {
let color = anstyle::Ansi256Color::from_ansi(color);
*self.get_ansi256_ref(color)
}
const fn get_ansi256_ref(&self, color: anstyle::Ansi256Color) -> &Rgb {
let index = color.index() as usize;
&self.0[index]
}
pub(crate) const fn rgb_from_ansi(&self, color: anstyle::AnsiColor) -> anstyle::RgbColor {
self.get(color)
}
pub(crate) const fn rgb_from_index(&self, index: u8) -> Option<anstyle::RgbColor> {
let index = index as usize;
if index < self.0.len() {
Some(self.0[index])
} else {
None
}
}
pub(crate) const fn find_match(&self, color: anstyle::RgbColor) -> anstyle::AnsiColor {
let mut best_index = 0;
let mut best_distance = crate::distance(color, self.0[best_index]);
let mut index = best_index + 1;
while index < self.0.len() {
let distance = crate::distance(color, self.0[index]);
if distance < best_distance {
best_index = index;
best_distance = distance;
}
index += 1;
}
if let Some(color) = anstyle::Ansi256Color(best_index as u8).into_ansi() {
color
} else {
// Panic
#[allow(clippy::no_effect)]
["best_index is out of bounds"][best_index];
// Make compiler happy
anstyle::AnsiColor::Black
}
}
}
impl Default for Palette {
fn default() -> Self {
DEFAULT
}
}
impl std::ops::Index<anstyle::AnsiColor> for Palette {
type Output = Rgb;
#[inline]
fn index(&self, color: anstyle::AnsiColor) -> &Rgb {
let color = anstyle::Ansi256Color::from_ansi(color);
self.get_ansi256_ref(color)
}
}
impl From<RawPalette> for Palette {
fn from(raw: RawPalette) -> Self {
Self(raw)
}
}
/// Platform-specific default
#[cfg(not(windows))]
pub use VGA as DEFAULT;
/// Platform-specific default
#[cfg(windows)]
pub use WIN10_CONSOLE as DEFAULT;
/// Typical colors that are used when booting PCs and leaving them in text mode
pub const VGA: Palette = Palette([
Rgb(0, 0, 0),
Rgb(170, 0, 0),
Rgb(0, 170, 0),
Rgb(170, 85, 0),
Rgb(0, 0, 170),
Rgb(170, 0, 170),
Rgb(0, 170, 170),
Rgb(170, 170, 170),
Rgb(85, 85, 85),
Rgb(255, 85, 85),
Rgb(85, 255, 85),
Rgb(255, 255, 85),
Rgb(85, 85, 255),
Rgb(255, 85, 255),
Rgb(85, 255, 255),
Rgb(255, 255, 255),
]);
/// Campbell theme, used as of Windows 10 version 1709.
pub const WIN10_CONSOLE: Palette = Palette([
Rgb(12, 12, 12),
Rgb(197, 15, 31),
Rgb(19, 161, 14),
Rgb(193, 156, 0),
Rgb(0, 55, 218),
Rgb(136, 23, 152),
Rgb(58, 150, 221),
Rgb(204, 204, 204),
Rgb(118, 118, 118),
Rgb(231, 72, 86),
Rgb(22, 198, 12),
Rgb(249, 241, 165),
Rgb(59, 120, 255),
Rgb(180, 0, 158),
Rgb(97, 214, 214),
Rgb(242, 242, 242),
]);