diff --git a/README.md b/README.md index c6abf7f..cab3ba5 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,18 @@ Red.normal().paint("yet another red string"); Style::default().paint("a completely regular string"); ``` +Sometimes it is desirable to hard-reset a style/color just before +applying a new one. To reset and apply, the `reset_before_style` method can +be used on either `Color` or `Style` structs. + +```rust +use nu_ansi_term::Style; + +println!("\x1b[33mHow about some {} \x1b[33mand {}?\x1b[0m", + Style::new().reset_before_style().bold().paint("bold"), + Style::new().reset_before_style().underline().paint("underline")); +``` + ## Extended colors You can access the extended range of 256 colors by using the `Color::Fixed` variant, which takes an argument of the color number to use. diff --git a/examples/basic_colors.rs b/examples/basic_colors.rs index 6b8917b..a446a19 100644 --- a/examples/basic_colors.rs +++ b/examples/basic_colors.rs @@ -17,4 +17,18 @@ fn main() { println!("{} {}", Purple.paint("Purple"), Purple.bold().paint("bold")); println!("{} {}", Cyan.paint("Cyan"), Cyan.bold().paint("bold")); println!("{} {}", White.paint("White"), White.bold().paint("bold")); + println!("\nreset_before_style at work:"); + println!( + "\x1b[33mReset {} \x1b[33mand {}\x1b[0m", + Style::new().reset_before_style().bold().paint("bold"), + Style::new() + .reset_before_style() + .underline() + .paint("underline") + ); + println!( + "\x1b[33mDo not reset {} \x1b[33mand {}\x1b[0m", + Style::new().bold().paint("bold"), + Style::new().underline().paint("underline") + ); } diff --git a/src/ansi.rs b/src/ansi.rs index 2a32d9c..901e160 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -13,6 +13,11 @@ impl Style { return Ok(()); } + // Prefix everything with reset characters if needed + if self.with_reset { + write!(f, "\x1B[0m")? + } + // Write the codes’ prefix, then write numbers, separated by // semicolons, for each text style we want to apply. write!(f, "\x1B[")?; @@ -407,6 +412,8 @@ mod test { test!(magenta_on_white: Magenta.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(magenta_on_white_2: Magenta.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(yellow_on_blue_reset: Cyan.on(Blue).reset_before_style().fg(Yellow); "hi" => "\x1B[0m\x1B[44;33mhi\x1B[0m"); + test!(yellow_on_blue_reset_2: Cyan.on(Blue).fg(Yellow).reset_before_style(); "hi" => "\x1B[0m\x1B[44;33mhi\x1B[0m"); test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[1;47;36mhi\x1B[0m"); test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[4;47;36mhi\x1B[0m"); test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); @@ -419,6 +426,8 @@ mod test { test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m"); + test!(bold_with_reset: Style::new().reset_before_style().bold(); "hi" => "\x1B[0m\x1B[1mhi\x1B[0m"); + test!(bold_with_reset_2: Style::new().bold().reset_before_style(); "hi" => "\x1B[0m\x1B[1mhi\x1B[0m"); test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m"); test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m"); test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[2mhi\x1B[0m"); @@ -462,6 +471,8 @@ mod gnu_legacy_test { test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(yellow_on_blue_reset: Cyan.on(Blue).reset_before_style().fg(Yellow); "hi" => "\x1B[0m\x1B[44;33mhi\x1B[0m"); + test!(yellow_on_blue_reset_2: Cyan.on(Blue).fg(Yellow).reset_before_style(); "hi" => "\x1B[0m\x1B[44;33mhi\x1B[0m"); test!(magenta_on_white: Magenta.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(magenta_on_white_2: Magenta.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); @@ -477,6 +488,8 @@ mod gnu_legacy_test { test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); test!(bold: Style::new().bold(); "hi" => "\x1B[01mhi\x1B[0m"); + test!(bold_with_reset: Style::new().reset_before_style().bold(); "hi" => "\x1B[0m\x1B[01mhi\x1B[0m"); + test!(bold_with_reset_2: Style::new().bold().reset_before_style(); "hi" => "\x1B[0m\x1B[01mhi\x1B[0m"); test!(underline: Style::new().underline(); "hi" => "\x1B[04mhi\x1B[0m"); test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[01;04mhi\x1B[0m"); test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[02mhi\x1B[0m"); diff --git a/src/style.rs b/src/style.rs index 1201a85..154028d 100644 --- a/src/style.rs +++ b/src/style.rs @@ -44,6 +44,9 @@ pub struct Style { /// Whether this style is struckthrough. pub is_strikethrough: bool, + + /// Wether this style starts with reset code + pub with_reset: bool, } impl Style { @@ -61,6 +64,23 @@ impl Style { Style::default() } + /// Returns a `Style` with the reset_before_style property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().reset_before_style(); + /// println!("{}", style.paint("hey")); + /// ``` + pub const fn reset_before_style(&self) -> Style { + Style { + with_reset: true, + ..*self + } + } + /// Returns a `Style` with the bold property set. /// /// # Examples @@ -269,6 +289,7 @@ impl Default for Style { is_reverse: false, is_hidden: false, is_strikethrough: false, + with_reset: false, } } } @@ -542,6 +563,25 @@ impl Color { } } + /// Returns a `Style` thats resets all styling before applying + /// the foreground color set to this color. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Fixed(244).reset_before_style(); + /// println!("{}", style.paint("yo")); + /// ``` + pub fn reset_before_style(self) -> Style { + Style { + foreground: Some(self), + with_reset: true, + ..Style::default() + } + } + /// Returns a `Style` with the foreground color set to this color and the /// background color property set to the given color. /// @@ -619,6 +659,6 @@ mod serde_json_tests { fn style_serialization() { let style = Style::default(); - assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false}".to_string()); + assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false,\"with_reset\":false}".to_string()); } }