1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
//! Definitions for ANSI color codes used in terminals.
//!
//! This defines dedicated types for the foreground colors, background colors,
//! and underline colors used in terminals.
//!
//! Includes supports the following color sets:
//! * 3-bit colors: Black, Red, Green, Yellow, Blue, Magenta, Cyan, White.
//! * 4-bit colors: the "bright" versions of the above 3-bit colors.
//! * 8-bit colors: the 256 colors defined by the `xterm-256color` standard.
//! * 24-bit "TrueColor": full RGB colors, in which each channel has 8 bits.
//!
use alloc::borrow::Cow;
/// The set of colors that can be displayed by a terminal emulator.
///
/// * The first 8 variants are 3-bit colors, supported on every terminal emulator.
/// * The next 8 variants are 4-bit colors, which are brightened (or bold) versions of the first 8.
/// * After that, the 8-bit color variant accepts any value from 0 to 256,
/// in which values of 0-15 are the same as the first 16 variants of this enum
/// * Finally, the 24-bit color variant accepts standard RGB values.
///
/// See here for the set of colors: <https://en.wikipedia.org/wiki/ANSI_escape_code#Colors>
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum Color {
/////////////////////// 2-bit Colors //////////////////////
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
/// More of a light gray/grey. Use `BrightWhite` for true white.
White,
/////////////////////// 4-bit Colors //////////////////////
/// Gray/grey.
BrightBlack,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
/// True pure white.
BrightWhite,
/////////////////////// 8-bit Colors //////////////////////
/// 8-bit color, as introduced in xterm.
///
/// * Values of `0` through `15` are identical to the above 16 color variants.
/// * The next 216 colors `16` through `231` are arranged into a 6 x 6 x 6 color cube,
/// as shown here: <https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit>.
/// * The last 24 colors `232` through `255` are grayscale steps from dark gray to light.
///
/// This is sometimes referred to as a Palette color lookup table.
Color8Bit(u8),
/////////////////////// 24-bit Colors //////////////////////
/// True 24-bit RGB color, with 8 bits for each of the red, green, and blue channels.
RGB { red: u8, green: u8, blue: u8 },
/// The default color, which is generally unspecified
/// and depends on the context in which it is used.
#[default]
Default,
}
impl From<u8> for Color {
fn from(value: u8) -> Self {
match value {
0 => Self::Black,
1 => Self::Red,
2 => Self::Green,
3 => Self::Yellow,
4 => Self::Blue,
5 => Self::Magenta,
6 => Self::Cyan,
7 => Self::White,
8 => Self::BrightBlack,
9 => Self::BrightRed,
10 => Self::BrightGreen,
11 => Self::BrightYellow,
12 => Self::BrightBlue,
13 => Self::BrightMagenta,
14 => Self::BrightCyan,
15 => Self::BrightWhite,
x => Self::Color8Bit(x),
}
}
}
/// A wrapper type around [`Color`] that is used in [`crate::AnsiStyleCodes`]
/// to set the foreground color (for displayed text).
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct ForegroundColor(pub Color);
impl ForegroundColor {
const ANSI_ESCAPE_FOREGROUND_COLOR: &'static str = "38";
pub fn to_escape_code(self) -> Cow<'static, str> {
match self.0 {
Color::Black => "30".into(),
Color::Red => "31".into(),
Color::Green => "32".into(),
Color::Yellow => "33".into(),
Color::Blue => "34".into(),
Color::Magenta => "35".into(),
Color::Cyan => "36".into(),
Color::White => "37".into(),
// "38" is used by 8-bit and 24-bit colors
Color::Default => "39".into(),
Color::BrightBlack => "90".into(),
Color::BrightRed => "91".into(),
Color::BrightGreen => "92".into(),
Color::BrightYellow => "93".into(),
Color::BrightBlue => "94".into(),
Color::BrightMagenta => "95".into(),
Color::BrightCyan => "96".into(),
Color::BrightWhite => "97".into(),
// For better compatibility, reduce 8-bit color codes to their 4-bit representation if possible.
Color::Color8Bit(c_4bit) if c_4bit < 16 => Self(Color::from(c_4bit)).to_escape_code(),
Color::Color8Bit(c_8bit) => format!(
"{};{};{}",
Self::ANSI_ESCAPE_FOREGROUND_COLOR, ANSI_ESCAPE_8_BIT_COLOR, c_8bit
).into(),
Color::RGB { red, green, blue } => format!(
"{};{};{};{};{}",
Self::ANSI_ESCAPE_FOREGROUND_COLOR, ANSI_ESCAPE_24_BIT_COLOR, red, green, blue
).into(),
}
}
}
impl From<Color> for ForegroundColor {
fn from(c: Color) -> Self {
ForegroundColor(c)
}
}
/// A wrapper type around [`Color`] that is used in [`crate::AnsiStyleCodes`]
/// to set the background color (behind displayed text).
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct BackgroundColor(pub Color);
impl BackgroundColor {
const ANSI_ESCAPE_BACKGROUND_COLOR: &'static str = "48";
pub fn to_escape_code(self) -> Cow<'static, str> {
match self.0 {
Color::Black => "40".into(),
Color::Red => "41".into(),
Color::Green => "42".into(),
Color::Yellow => "43".into(),
Color::Blue => "44".into(),
Color::Magenta => "45".into(),
Color::Cyan => "46".into(),
Color::White => "47".into(),
// "48" is used by 8-bit and 24-bit colors
Color::Default => "49".into(),
Color::BrightBlack => "100".into(),
Color::BrightRed => "101".into(),
Color::BrightGreen => "102".into(),
Color::BrightYellow => "103".into(),
Color::BrightBlue => "104".into(),
Color::BrightMagenta => "105".into(),
Color::BrightCyan => "106".into(),
Color::BrightWhite => "107".into(),
// For better compatibility, reduce 8-bit color codes to their 4-bit representation if possible.
Color::Color8Bit(c_4bit) if c_4bit < 16 => Self(Color::from(c_4bit)).to_escape_code(),
Color::Color8Bit(c_8bit) => format!(
"{};{};{}",
Self::ANSI_ESCAPE_BACKGROUND_COLOR, ANSI_ESCAPE_8_BIT_COLOR, c_8bit
).into(),
Color::RGB { red, green, blue } => format!(
"{};{};{};{};{}",
Self::ANSI_ESCAPE_BACKGROUND_COLOR, ANSI_ESCAPE_24_BIT_COLOR, red, green, blue
).into(),
}
}
}
impl From<Color> for BackgroundColor {
fn from(c: Color) -> Self {
BackgroundColor(c)
}
}
/// A wrapper type around [`Color`] that is used in [`crate::AnsiStyleCodes`]
/// to set the color of the underline for underlined text.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct UnderlinedColor(pub Color);
impl UnderlinedColor {
const ANSI_ESCAPE_UDERLINED_COLOR: &'static str = "58";
pub fn to_escape_code(self) -> Cow<'static, str> {
match self.0 {
Color::Default => "59".into(),
Color::Color8Bit(c_8bit) => format!(
"{};{};{}",
Self::ANSI_ESCAPE_UDERLINED_COLOR, ANSI_ESCAPE_8_BIT_COLOR, c_8bit
).into(),
Color::RGB { red, green, blue } => format!(
"{};{};{};{};{}",
Self::ANSI_ESCAPE_UDERLINED_COLOR, ANSI_ESCAPE_24_BIT_COLOR, red, green, blue
).into(),
// This mode only supports parameters of 8-bit and 24-bit (RBG) colors,
// so we must convert 4-bit colors into 8-bit colors first.
Color::Black => Self(Color::Color8Bit(0)).to_escape_code(),
Color::Red => Self(Color::Color8Bit(1)).to_escape_code(),
Color::Green => Self(Color::Color8Bit(2)).to_escape_code(),
Color::Yellow => Self(Color::Color8Bit(3)).to_escape_code(),
Color::Blue => Self(Color::Color8Bit(4)).to_escape_code(),
Color::Magenta => Self(Color::Color8Bit(5)).to_escape_code(),
Color::Cyan => Self(Color::Color8Bit(6)).to_escape_code(),
Color::White => Self(Color::Color8Bit(7)).to_escape_code(),
Color::BrightBlack => Self(Color::Color8Bit(8)).to_escape_code(),
Color::BrightRed => Self(Color::Color8Bit(9)).to_escape_code(),
Color::BrightGreen => Self(Color::Color8Bit(10)).to_escape_code(),
Color::BrightYellow => Self(Color::Color8Bit(11)).to_escape_code(),
Color::BrightBlue => Self(Color::Color8Bit(12)).to_escape_code(),
Color::BrightMagenta => Self(Color::Color8Bit(13)).to_escape_code(),
Color::BrightCyan => Self(Color::Color8Bit(14)).to_escape_code(),
Color::BrightWhite => Self(Color::Color8Bit(15)).to_escape_code(),
}
}
}
impl From<Color> for UnderlinedColor {
fn from(c: Color) -> Self {
UnderlinedColor(c)
}
}
const ANSI_ESCAPE_8_BIT_COLOR: &str = "5";
const ANSI_ESCAPE_24_BIT_COLOR: &str = "2";