feat(cli): /stylize: change TrueColor to Rgb and improve docs

This commit is contained in:
Lucas Colombo 2024-03-31 11:24:44 -03:00
parent baef445169
commit 917b763b45
Signed by: lucas
GPG Key ID: EF34786CFEFFAE35
5 changed files with 85 additions and 42 deletions

View File

@ -47,5 +47,17 @@ fn main() -> Result<()> {
println!("pre {} post", "[.dim()]".dim());
println!("pre {} post", "[.blue().dim()]".blue().dim());
println!("pre {} post", "[.rgb(\"#af7cbf\")]".rgb("#af7cbf"));
println!(
"pre {} post",
"[.rgb(\"#af7cbf\").bold()]".rgb("#af7cbf").bold()
);
println!("pre {} post", "[.on_rgb(\"#af7cbf\")".on_rgb("#af7cbf"));
println!(
"pre {} post",
"[.on_rgb(\"#af7cbf\").bold()]".on_rgb("#af7cbf").bold()
);
Ok(())
}

View File

@ -1,6 +1,6 @@
use {bitflags::bitflags, eyre::Context, std::borrow::Cow};
/// The 8 standard colors.
/// Standard terminal colors + RGB
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Color {
Black,
@ -19,12 +19,13 @@ pub enum Color {
BrightMagenta,
BrightCyan,
BrightWhite,
TrueColor { r: u8, g: u8, b: u8 },
Rgb { r: u8, g: u8, b: u8 },
}
impl Color {
pub fn to_fg_str(&self) -> Cow<'static, str> {
match *self {
/// converts a color to a string that can be used in an ANSI foreground escape sequence
pub fn to_fg_str(self) -> Cow<'static, str> {
match self {
Color::Black => "30".into(),
Color::Red => "31".into(),
Color::Green => "32".into(),
@ -41,12 +42,13 @@ impl Color {
Color::BrightMagenta => "95".into(),
Color::BrightCyan => "96".into(),
Color::BrightWhite => "97".into(),
Color::TrueColor { r, g, b } => format!("38;2;{};{};{}", r, g, b).into(),
Color::Rgb { r, g, b } => format!("38;2;{};{};{}", r, g, b).into(),
}
}
pub fn to_bg_str(&self) -> Cow<'static, str> {
match *self {
/// converts a color to a string that can be used in an ANSI background escape sequence
pub fn to_bg_str(self) -> Cow<'static, str> {
match self {
Color::Black => "40".into(),
Color::Red => "41".into(),
Color::Green => "42".into(),
@ -63,10 +65,11 @@ impl Color {
Color::BrightMagenta => "105".into(),
Color::BrightCyan => "106".into(),
Color::BrightWhite => "107".into(),
Color::TrueColor { r, g, b } => format!("48;2;{};{};{}", r, g, b).into(),
Color::Rgb { r, g, b } => format!("48;2;{};{};{}", r, g, b).into(),
}
}
/// creates a `Color` from a string
pub fn from_str(s: &str) -> eyre::Result<Color> {
let color = match s {
"" => None,
@ -91,7 +94,7 @@ impl Color {
let r = u8::from_str_radix(&s[0..2], 16).context("Error parsing RGB color")?;
let g = u8::from_str_radix(&s[2..4], 16).context("Error parsing RGB color")?;
let b = u8::from_str_radix(&s[4..6], 16).context("Error parsing RGB color")?;
Some(Color::TrueColor { r, g, b })
Some(Color::Rgb { r, g, b })
}
_ => None,
};
@ -102,6 +105,7 @@ impl Color {
bitflags! {
#[derive(Clone, PartialEq, Eq, Debug)]
/// style attributes bitflags
pub struct StyleAttributes: u8 {
const BOLD = 0b00000001;
const DIM = 0b00000010;
@ -115,6 +119,7 @@ bitflags! {
}
impl StyleAttributes {
/// converts the style attributes to ANSI codes
pub fn to_ansi_codes(&self) -> Vec<&'static str> {
let mut v = Vec::new();
if self.contains(StyleAttributes::BOLD) {

View File

@ -9,6 +9,7 @@ pub mod instructions {
bitflags::parser::{from_str, ParseError},
};
/// struct that holds the style information
pub struct StyledString {
pub fg: Option<Color>,
pub bg: Option<Color>,
@ -25,7 +26,7 @@ pub mod instructions {
}
}
/// parses the instruction into a StyledString
/// parses the instruction into a `StyledString`
pub fn parse(instructions: &str) -> Result<StyledString> {
let mut styled_string = StyledString::default();
@ -61,11 +62,10 @@ pub mod instructions {
Ok(styled_string)
}
/// Parses the color instruction into a tuple of fg and bg colors.
/// parses the color part of an instruction into a tuple of fg and bg colors.
pub fn parse_color_instruction(instruction: &str) -> Result<(Option<Color>, Option<Color>)> {
if instruction.starts_with("on ") {
// If instruction starts with "on ", bg color is provided
return Ok((None, Some(Color::from_str(&instruction[3..])?)));
if let Some(prefix) = instruction.strip_prefix("on ") {
return Ok((None, Some(Color::from_str(prefix)?)));
}
let colors: Vec<&str> = instruction.split(" on ").collect();
@ -100,47 +100,89 @@ pub trait Stylize {
/// Basic styling method, receives a styling instruction
/// see the `stylize` function for more information
fn stl(&self, instruction: &str) -> String;
/// 🧉 » makes the text **black**
fn black(&self) -> String { self.stl("black") }
/// 🧉 » makes the text **red**
fn red(&self) -> String { self.stl("red") }
/// 🧉 » makes the text **green**
fn green(&self) -> String { self.stl("green") }
/// 🧉 » makes the text **yellow**
fn yellow(&self) -> String { self.stl("yellow") }
/// 🧉 » makes the text **blue**
fn blue(&self) -> String { self.stl("blue") }
/// 🧉 » makes the text **magenta**
fn magenta(&self) -> String { self.stl("magenta") }
/// 🧉 » makes the text **cyan**
fn cyan(&self) -> String { self.stl("cyan") }
/// 🧉 » makes the text **white**
fn white(&self) -> String { self.stl("white") }
/// 🧉 » makes the text **bright black**
fn bright_black(&self) -> String { self.stl("bright-black") }
/// 🧉 » makes the text **bright red**
fn bright_red(&self) -> String { self.stl("bright-red") }
/// 🧉 » makes the text **bright green**
fn bright_green(&self) -> String { self.stl("bright-green") }
/// 🧉 » makes the text **bright yellow**
fn bright_yellow(&self) -> String { self.stl("bright-yellow") }
/// 🧉 » makes the text **bright blue**
fn bright_blue(&self) -> String { self.stl("bright-blue") }
/// 🧉 » makes the text **bright magenta**
fn bright_magenta(&self) -> String { self.stl("bright-magenta") }
/// 🧉 » makes the text **bright cyan**
fn bright_cyan(&self) -> String { self.stl("bright-cyan") }
/// 🧉 » makes the text **bright white**
fn bright_white(&self) -> String { self.stl("bright-white") }
fn rgb(&self, r: u8, g: u8, b: u8) -> String { self.stl(&format!("#{:02X}{:02X}{:02X}", r, g, b)) }
/// 🧉 » makes the text colored after the **`rgb`** param (`#RRGGBB` format)
fn rgb(&self, rgb: &str) -> String { self.stl(rgb) }
/// 🧉 » makes the background of the text **black**
fn on_black(&self) -> String { self.stl("on black") }
/// 🧉 » makes the background of the text **red**
fn on_red(&self) -> String { self.stl("on red") }
/// 🧉 » makes the background of the text **green**
fn on_green(&self) -> String { self.stl("on green") }
/// 🧉 » makes the background of the text **yellow**
fn on_yellow(&self) -> String { self.stl("on yellow") }
/// 🧉 » makes the background of the text **blue**
fn on_blue(&self) -> String { self.stl("on blue") }
/// 🧉 » makes the background of the text **magenta**
fn on_magenta(&self) -> String { self.stl("on magenta") }
/// 🧉 » makes the background of the text **cyan**
fn on_cyan(&self) -> String { self.stl("on cyan") }
/// 🧉 » makes the background of the text **white**
fn on_white(&self) -> String { self.stl("on white") }
/// 🧉 » makes the background of the text **bright black**
fn on_bright_black(&self) -> String { self.stl("on bright-black") }
/// 🧉 » makes the background of the text **bright red**
fn on_bright_red(&self) -> String { self.stl("on bright-red") }
/// 🧉 » makes the background of the text **bright green**
fn on_bright_green(&self) -> String { self.stl("on bright-green") }
/// 🧉 » makes the background of the text **bright yellow**
fn on_bright_yellow(&self) -> String { self.stl("on bright-yellow") }
/// 🧉 » makes the background of the text **bright blue**
fn on_bright_blue(&self) -> String { self.stl("on bright-blue") }
/// 🧉 » makes the background of the text **bright magenta**
fn on_bright_magenta(&self) -> String { self.stl("on bright-magenta") }
/// 🧉 » makes the background of the text **bright cyan**
fn on_bright_cyan(&self) -> String { self.stl("on bright-cyan") }
/// 🧉 » makes the background of the text **bright white**
fn on_bright_white(&self) -> String { self.stl("on bright-white") }
fn on_rgb(&self, r: u8, g: u8, b: u8) -> String { self.stl(&format!("on #{:02X}{:02X}{:02X}", r, g, b)) }
/// 🧉 » makes the background color = **`rgb`** param (`#RRGGBB` format)
fn on_rgb(&self, rgb: &str) -> String { self.stl(&format!("on {}", rgb)) }
/// 🧉 » makes the text **bold**
fn bold(&self) -> String { self.stl("+bold") }
/// 🧉 » makes the text **dim**
fn dim(&self) -> String { self.stl("+dim") }
/// 🧉 » makes the text **italic**
fn italic(&self) -> String { self.stl("+italic") }
/// 🧉 » makes the text **underline**
fn underline(&self) -> String { self.stl("+underline") }
/// 🧉 » makes the text **blink**
fn blink(&self) -> String { self.stl("+blink") }
/// 🧉 » makes the text **reverse**
fn reverse(&self) -> String { self.stl("+reverse") }
/// 🧉 » makes the text **hidden**
fn hidden(&self) -> String { self.stl("+hidden") }
/// 🧉 » makes the text **strikethrough**
fn strikethrough(&self) -> String { self.stl("+strikethrough") }
}
@ -160,7 +202,6 @@ impl Stylize for String {
/// --
///
/// Stylizes a string with optional ANSI color and attributes.
///
pub fn stylize<S: AsRef<str>>(s: S, instructions: &str) -> String {
let styled_string = instructions::parse(instructions);

View File

@ -1 +1 @@
mod stylizo;
mod stylize;

View File

@ -19,7 +19,7 @@ mod parse_instruction {
assert_eq!(parse_color_instruction("red")?, (Some(Color::Red), None));
assert_eq!(
parse_color_instruction("#FF0000")?,
(Some(Color::TrueColor { r: 255, g: 0, b: 0 }), None)
(Some(Color::Rgb { r: 255, g: 0, b: 0 }), None)
);
assert_eq!(
parse_color_instruction("on blue")?,
@ -27,7 +27,7 @@ mod parse_instruction {
);
assert_eq!(
parse_color_instruction("on #0000FF")?,
(None, Some(Color::TrueColor { r: 0, g: 0, b: 255 }))
(None, Some(Color::Rgb { r: 0, g: 0, b: 255 }))
);
assert_eq!(
parse_color_instruction("red on blue")?,
@ -36,8 +36,8 @@ mod parse_instruction {
assert_eq!(
parse_color_instruction("#FF0000 on #0000FF")?,
(
Some(Color::TrueColor { r: 255, g: 0, b: 0 }),
Some(Color::TrueColor { r: 0, g: 0, b: 255 })
Some(Color::Rgb { r: 255, g: 0, b: 0 }),
Some(Color::Rgb { r: 0, g: 0, b: 255 })
)
);
assert!(parse_color_instruction("red on blue on green").is_err());
@ -72,14 +72,8 @@ mod parse_instruction {
// ##RRGGBB
let styled_string = parse("#FF0000 on #0000FF")?;
assert_eq!(
styled_string.fg,
Some(Color::TrueColor { r: 255, g: 0, b: 0 })
);
assert_eq!(
styled_string.bg,
Some(Color::TrueColor { r: 0, g: 0, b: 255 })
);
assert_eq!(styled_string.fg, Some(Color::Rgb { r: 255, g: 0, b: 0 }));
assert_eq!(styled_string.bg, Some(Color::Rgb { r: 0, g: 0, b: 255 }));
assert_eq!(styled_string.attrs, StyleAttributes::empty());
let styled_string = parse("red on blue+bold")?;
@ -89,14 +83,8 @@ mod parse_instruction {
// ##RRGGBB
let styled_string = parse("#FF0000 on #0000FF+bold")?;
assert_eq!(
styled_string.fg,
Some(Color::TrueColor { r: 255, g: 0, b: 0 })
);
assert_eq!(
styled_string.bg,
Some(Color::TrueColor { r: 0, g: 0, b: 255 })
);
assert_eq!(styled_string.fg, Some(Color::Rgb { r: 255, g: 0, b: 0 }));
assert_eq!(styled_string.bg, Some(Color::Rgb { r: 0, g: 0, b: 255 }));
assert_eq!(styled_string.attrs, StyleAttributes::BOLD);
let styled_string = parse("red on blue+bold|underline")?;
@ -109,10 +97,7 @@ mod parse_instruction {
let styled_string = parse("red on #0000FF+bold|underline|italic")?;
assert_eq!(styled_string.fg, Some(Color::Red));
assert_eq!(
styled_string.bg,
Some(Color::TrueColor { r: 0, g: 0, b: 255 })
);
assert_eq!(styled_string.bg, Some(Color::Rgb { r: 0, g: 0, b: 255 }));
assert_eq!(
styled_string.attrs,
StyleAttributes::BOLD | StyleAttributes::UNDERLINE | StyleAttributes::ITALIC