From 917b763b4540e1d545dea77f2a803e10c622fbe0 Mon Sep 17 00:00:00 2001 From: Lucas Colombo Date: Sun, 31 Mar 2024 11:24:44 -0300 Subject: [PATCH] =?UTF-8?q?feat(cli):=20=E2=9C=A8=20/stylize:=20change=20T?= =?UTF-8?q?rueColor=20to=20Rgb=20and=20improve=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/stylizer.rs | 12 ++++ lib/cli/stylize/style.rs | 23 +++++--- lib/cli/stylize/stylizer.rs | 57 ++++++++++++++++--- lib/cli/stylize/tests/mod.rs | 2 +- .../stylize/tests/{stylizo.rs => stylize.rs} | 33 +++-------- 5 files changed, 85 insertions(+), 42 deletions(-) rename lib/cli/stylize/tests/{stylizo.rs => stylize.rs} (83%) diff --git a/examples/stylizer.rs b/examples/stylizer.rs index 6b721bc..d40132a 100644 --- a/examples/stylizer.rs +++ b/examples/stylizer.rs @@ -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(()) } diff --git a/lib/cli/stylize/style.rs b/lib/cli/stylize/style.rs index bc0524d..5a97881 100644 --- a/lib/cli/stylize/style.rs +++ b/lib/cli/stylize/style.rs @@ -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 { 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) { diff --git a/lib/cli/stylize/stylizer.rs b/lib/cli/stylize/stylizer.rs index e717c20..72d3ce4 100644 --- a/lib/cli/stylize/stylizer.rs +++ b/lib/cli/stylize/stylizer.rs @@ -9,6 +9,7 @@ pub mod instructions { bitflags::parser::{from_str, ParseError}, }; + /// struct that holds the style information pub struct StyledString { pub fg: Option, pub bg: Option, @@ -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 { 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, Option)> { - 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: S, instructions: &str) -> String { let styled_string = instructions::parse(instructions); diff --git a/lib/cli/stylize/tests/mod.rs b/lib/cli/stylize/tests/mod.rs index 3fac3d8..72bd02a 100644 --- a/lib/cli/stylize/tests/mod.rs +++ b/lib/cli/stylize/tests/mod.rs @@ -1 +1 @@ -mod stylizo; +mod stylize; diff --git a/lib/cli/stylize/tests/stylizo.rs b/lib/cli/stylize/tests/stylize.rs similarity index 83% rename from lib/cli/stylize/tests/stylizo.rs rename to lib/cli/stylize/tests/stylize.rs index 679f448..d3eb7d2 100644 --- a/lib/cli/stylize/tests/stylizo.rs +++ b/lib/cli/stylize/tests/stylize.rs @@ -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