diff --git a/src/ansi.rs b/src/ansi.rs index 430e036..c10c491 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -59,23 +59,17 @@ impl Style { // All the codes end with an `m`, because reasons. write!(f, "m")?; - if let Some(url) = self.hyperlink_url.as_deref() { - write!(f, "\x1B]8;;{}\x1B\\", url)?; - } - Ok(()) } /// Write any bytes that go *after* a piece of text to the given writer. fn write_suffix(&self, f: &mut W) -> Result<(), W::Error> { if self.is_plain() { - return Ok(()); + Ok(()) } - if self.hyperlink_url.is_some() { - write!(f, "{}", RESET_HYPERLINK)?; + else { + write!(f, "{}", RESET) } - write!(f, "{}", RESET)?; - Ok(()) } } @@ -83,8 +77,6 @@ impl Style { /// The code to send to reset all styles and return to `Style::default()`. pub static RESET: &str = "\x1B[0m"; -/// The code to reset hyperlinks. -pub static RESET_HYPERLINK: &str = "\x1B]8;;\x1B\\"; impl Colour { @@ -143,7 +135,7 @@ impl Colour { /// `std::fmt` formatting without doing any extra allocation, and written to a /// string with the `.to_string()` method. For examples, see /// [`Style::prefix`](struct.Style.html#method.prefix). -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct Prefix(Style); /// Like `ANSIString`, but only displays the difference between two @@ -153,7 +145,7 @@ pub struct Prefix(Style); /// `std::fmt` formatting without doing any extra allocation, and written to a /// string with the `.to_string()` method. For examples, see /// [`Style::infix`](struct.Style.html#method.infix). -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct Infix(Style, Style); /// Like `ANSIString`, but only displays the style suffix. @@ -162,7 +154,7 @@ pub struct Infix(Style, Style); /// `std::fmt` formatting without doing any extra allocation, and written to a /// string with the `.to_string()` method. For examples, see /// [`Style::suffix`](struct.Style.html#method.suffix). -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct Suffix(Style); @@ -188,8 +180,8 @@ impl Style { /// assert_eq!("", /// style.prefix().to_string()); /// ``` - pub fn prefix(&self) -> Prefix { - Prefix(self.clone()) + pub fn prefix(self) -> Prefix { + Prefix(self) } /// The infix bytes between this style and `next` style. These are the bytes @@ -203,18 +195,18 @@ impl Style { /// /// let style = Style::default().bold(); /// assert_eq!("\x1b[32m", - /// style.infix(&Green.bold()).to_string()); + /// style.infix(Green.bold()).to_string()); /// /// let style = Green.normal(); /// assert_eq!("\x1b[1m", - /// style.infix(&Green.bold()).to_string()); + /// style.infix(Green.bold()).to_string()); /// /// let style = Style::default(); /// assert_eq!("", - /// style.infix(&style).to_string()); + /// style.infix(style).to_string()); /// ``` - pub fn infix(&self, next: &Style) -> Infix { - Infix(self.clone(), next.clone()) + pub fn infix(self, next: Style) -> Infix { + Infix(self, next) } /// The suffix for this style. These are the bytes that tell the terminal @@ -237,8 +229,8 @@ impl Style { /// assert_eq!("", /// style.suffix().to_string()); /// ``` - pub fn suffix(&self) -> Suffix { - Suffix(self.clone()) + pub fn suffix(self) -> Suffix { + Suffix(self) } } @@ -318,10 +310,6 @@ impl fmt::Display for Infix { let f: &mut dyn fmt::Write = f; write!(f, "{}{}", RESET, self.1.prefix()) }, - Difference::ResetHyperlink => { - let f: &mut dyn fmt::Write = f; - write!(f, "{}{}{}", RESET_HYPERLINK, RESET, self.1.prefix()) - }, Difference::NoDifference => { Ok(()) // nothing to write }, @@ -470,31 +458,15 @@ mod test { test!(reverse: Style::new().reverse(); "hi" => "\x1B[7mhi\x1B[0m"); test!(hidden: Style::new().hidden(); "hi" => "\x1B[8mhi\x1B[0m"); test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[9mhi\x1B[0m"); - test!(hyperlink_plain: Style::new().hyperlink("url"); "hi" => "\x1B[m\x1B]8;;url\x1B\\hi\x1B]8;;\x1B\\\x1B[0m"); - test!(hyperlink_color: Blue.hyperlink("url"); "hi" => "\x1B[34m\x1B]8;;url\x1B\\hi\x1B]8;;\x1B\\\x1B[0m"); - test!(hyperlink_style: Blue.underline().hyperlink("url"); "hi" => "\x1B[4;34m\x1B]8;;url\x1B\\hi\x1B]8;;\x1B\\\x1B[0m"); test!(brightgreen: BrightGreen; "hi" => "\x1B[92mhi\x1B[0m"); test!(brightred_on_brightblue: BrightRed.on(BrightBlue); "hi" => "\x1B[104;91mhi\x1B[0m"); #[test] fn test_infix() { - assert_eq!(Style::new().dimmed().infix(&Style::new()).to_string(), "\x1B[0m"); - assert_eq!(White.dimmed().infix(&White.normal()).to_string(), "\x1B[0m\x1B[37m"); - assert_eq!(White.normal().infix(&White.bold()).to_string(), "\x1B[1m"); - assert_eq!(White.normal().infix(&Blue.normal()).to_string(), "\x1B[34m"); - assert_eq!(Blue.bold().infix(&Blue.bold()).to_string(), ""); - } - - #[test] - fn test_infix_hyperlink() { - assert_eq!(Blue.hyperlink("url1").infix(&Style::new()).to_string(), "\x1B]8;;\x1B\\\x1B[0m"); - assert_eq!(Blue.hyperlink("url1").infix(&Red.normal()).to_string(), "\x1B]8;;\x1B\\\x1B[0m\x1B[31m"); - assert_eq!(Blue.normal().infix(&Red.hyperlink("url2")).to_string(), "\x1B[31m\x1B]8;;url2\x1B\\"); - assert_eq!(Blue.hyperlink("url1").infix(&Red.hyperlink("url2")).to_string(), "\x1B[31m\x1B]8;;url2\x1B\\"); - assert_eq!(Blue.underline().hyperlink("url1").infix(&Red.italic().hyperlink("url2")).to_string(), "\x1B[0m\x1B[3;31m\x1B]8;;url2\x1B\\"); - - assert_eq!(Style::new().hyperlink("url1").infix(&Style::new().hyperlink("url1")).to_string(), ""); - assert_eq!(Blue.hyperlink("url1").infix(&Red.hyperlink("url1")).to_string(), "\x1B[31m"); - assert_eq!(Blue.underline().hyperlink("url1").infix(&Red.underline().hyperlink("url1")).to_string(), "\x1B[31m"); + assert_eq!(Style::new().dimmed().infix(Style::new()).to_string(), "\x1B[0m"); + assert_eq!(White.dimmed().infix(White.normal()).to_string(), "\x1B[0m\x1B[37m"); + assert_eq!(White.normal().infix(White.bold()).to_string(), "\x1B[1m"); + assert_eq!(White.normal().infix(Blue.normal()).to_string(), "\x1B[34m"); + assert_eq!(Blue.bold().infix(Blue.bold()).to_string(), ""); } } diff --git a/src/difference.rs b/src/difference.rs index 4683634..d2208f4 100644 --- a/src/difference.rs +++ b/src/difference.rs @@ -3,7 +3,7 @@ use super::Style; /// When printing out one coloured string followed by another, use one of /// these rules to figure out which *extra* control codes need to be sent. -#[derive(PartialEq, Clone, Debug)] +#[derive(PartialEq, Clone, Copy, Debug)] pub enum Difference { /// Print out the control codes specified by this style to end up looking @@ -14,11 +14,6 @@ pub enum Difference { /// command and then the second string's styles. Reset, - /// Converting between these two is impossible, and the first includes a - /// hyperlink, so send a reset and a hyperlink reset, then the second - /// string's styles. - ResetHyperlink, - /// The before style is exactly the same as the after style, so no further /// control codes need to be printed. NoDifference, @@ -52,10 +47,6 @@ impl Difference { return NoDifference; } - if first.hyperlink_url.is_some() && next.hyperlink_url.is_none() { - return ResetHyperlink; - } - // Cannot un-bold, so must Reset. if first.is_bold && !next.is_bold { return Reset; @@ -142,10 +133,6 @@ impl Difference { extra_styles.background = next.background; } - if first.hyperlink_url != next.hyperlink_url { - extra_styles.hyperlink_url = next.hyperlink_url.clone(); - } - ExtraStyles(extra_styles) } } @@ -183,14 +170,10 @@ mod test { test!(addition_of_hidden: style(); style().hidden() => ExtraStyles(style().hidden())); test!(addition_of_reverse: style(); style().reverse() => ExtraStyles(style().reverse())); test!(addition_of_strikethrough: style(); style().strikethrough() => ExtraStyles(style().strikethrough())); - test!(addition_of_hyperlink: style(); style().hyperlink("x") => ExtraStyles(style().hyperlink("x"))); test!(removal_of_strikethrough: style().strikethrough(); style() => Reset); test!(removal_of_reverse: style().reverse(); style() => Reset); test!(removal_of_hidden: style().hidden(); style() => Reset); test!(removal_of_dimmed: style().dimmed(); style() => Reset); test!(removal_of_blink: style().blink(); style() => Reset); - test!(removal_of_hyperlink: style().hyperlink("x"); style() => ResetHyperlink); - - test!(change_of_hyperlink: style().hyperlink("url1"); style().hyperlink("url2") => ExtraStyles(style().hyperlink("url2"))); } diff --git a/src/display.rs b/src/display.rs index 2054f7e..27b535a 100644 --- a/src/display.rs +++ b/src/display.rs @@ -3,7 +3,7 @@ use std::fmt; use std::io; use std::ops::Deref; -use crate::ansi::{RESET, RESET_HYPERLINK}; +use crate::ansi::RESET; use crate::difference::Difference; use crate::style::{Style, Colour}; use crate::write::AnyWrite; @@ -35,7 +35,7 @@ impl<'a, S: 'a + ToOwned + ?Sized> Clone for ANSIGenericString<'a, S> where ::Owned: fmt::Debug { fn clone(&self) -> ANSIGenericString<'a, S> { ANSIGenericString { - style: self.style.clone(), + style: self.style, string: self.string.clone(), } } @@ -161,12 +161,12 @@ impl Style { /// Paints the given text with this colour, returning an ANSI string. #[must_use] - pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(&self, input: I) -> ANSIGenericString<'a, S> + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S> where I: Into>, ::Owned: fmt::Debug { ANSIGenericString { string: input.into(), - style: self.clone(), + style: self, } } } @@ -258,19 +258,19 @@ where ::Owned: fmt::Debug, &'a S: AsRef<[u8]> { match Difference::between(&window[0].style, &window[1].style) { ExtraStyles(style) => write!(w, "{}", style.prefix())?, Reset => write!(w, "{}{}", RESET, window[1].style.prefix())?, - ResetHyperlink => { - write!(w, "{}{}{}", RESET_HYPERLINK, RESET, window[1].style.prefix())?; - } NoDifference => {/* Do nothing! */}, } w.write_str(&window[1].string)?; } - // Write any final reset strings needed after all of the ANSIStrings - // have been written. + // Write the final reset string after all of the ANSIStrings have been + // written, *except* if the last one has no styles, because it would + // have already been written by this point. if let Some(last) = self.0.last() { - write!(w, "{}", last.style.suffix())?; + if !last.style.is_plain() { + write!(w, "{}", RESET)?; + } } Ok(()) diff --git a/src/style.rs b/src/style.rs index e07ce60..536c226 100644 --- a/src/style.rs +++ b/src/style.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - /// A style is a collection of properties that can format a string /// using ANSI escape codes. /// @@ -11,7 +9,7 @@ use std::rc::Rc; /// let style = Style::new().bold().on(Colour::Black); /// println!("{}", style.paint("Bold on black")); /// ``` -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Copy)] #[cfg_attr(feature = "derive_serde_style", derive(serde::Deserialize, serde::Serialize))] pub struct Style { @@ -43,10 +41,7 @@ pub struct Style { pub is_hidden: bool, /// Whether this style is struckthrough. - pub is_strikethrough: bool, - - /// Hyperlink target for this style - pub hyperlink_url: Option>, + pub is_strikethrough: bool } impl Style { @@ -76,7 +71,7 @@ impl Style { /// println!("{}", style.paint("hey")); /// ``` pub fn bold(&self) -> Style { - Style { is_bold: true, ..self.clone() } + Style { is_bold: true, .. *self } } /// Returns a `Style` with the dimmed property set. @@ -90,7 +85,7 @@ impl Style { /// println!("{}", style.paint("sup")); /// ``` pub fn dimmed(&self) -> Style { - Style { is_dimmed: true, ..self.clone() } + Style { is_dimmed: true, .. *self } } /// Returns a `Style` with the italic property set. @@ -104,7 +99,7 @@ impl Style { /// println!("{}", style.paint("greetings")); /// ``` pub fn italic(&self) -> Style { - Style { is_italic: true, ..self.clone() } + Style { is_italic: true, .. *self } } /// Returns a `Style` with the underline property set. @@ -118,7 +113,7 @@ impl Style { /// println!("{}", style.paint("salutations")); /// ``` pub fn underline(&self) -> Style { - Style { is_underline: true, ..self.clone() } + Style { is_underline: true, .. *self } } /// Returns a `Style` with the blink property set. @@ -131,7 +126,7 @@ impl Style { /// println!("{}", style.paint("wazzup")); /// ``` pub fn blink(&self) -> Style { - Style { is_blink: true, ..self.clone() } + Style { is_blink: true, .. *self } } /// Returns a `Style` with the reverse property set. @@ -145,7 +140,7 @@ impl Style { /// println!("{}", style.paint("aloha")); /// ``` pub fn reverse(&self) -> Style { - Style { is_reverse: true, ..self.clone() } + Style { is_reverse: true, .. *self } } /// Returns a `Style` with the hidden property set. @@ -159,7 +154,7 @@ impl Style { /// println!("{}", style.paint("ahoy")); /// ``` pub fn hidden(&self) -> Style { - Style { is_hidden: true, ..self.clone() } + Style { is_hidden: true, .. *self } } /// Returns a `Style` with the strikethrough property set. @@ -173,7 +168,7 @@ impl Style { /// println!("{}", style.paint("yo")); /// ``` pub fn strikethrough(&self) -> Style { - Style { is_strikethrough: true, ..self.clone() } + Style { is_strikethrough: true, .. *self } } /// Returns a `Style` with the foreground colour property set. @@ -187,7 +182,7 @@ impl Style { /// println!("{}", style.paint("hi")); /// ``` pub fn fg(&self, foreground: Colour) -> Style { - Style { foreground: Some(foreground), ..self.clone() } + Style { foreground: Some(foreground), .. *self } } /// Returns a `Style` with the background colour property set. @@ -201,21 +196,7 @@ impl Style { /// println!("{}", style.paint("eyyyy")); /// ``` pub fn on(&self, background: Colour) -> Style { - Style { background: Some(background), ..self.clone() } - } - - /// Returns a `Style` with the hyperlink URL set. You can pass the - /// hyperlink as either a `String` or a `&str`. - /// - /// # Examples - /// - /// ``` - /// use ansi_term::Style; - /// let style = Style::new().hyperlink("https://example.org/"); - /// println!("{}", style.paint("example link")); - /// ``` - pub fn hyperlink>>(&self, url: U) -> Style { - Style { hyperlink_url: Some(url.into()), ..self.clone() } + Style { background: Some(background), .. *self } } /// Return true if this `Style` has no actual styles, and can be written @@ -229,8 +210,8 @@ impl Style { /// assert_eq!(true, Style::default().is_plain()); /// assert_eq!(false, Style::default().bold().is_plain()); /// ``` - pub fn is_plain(&self) -> bool { - self == &Style::default() + pub fn is_plain(self) -> bool { + self == Style::default() } } @@ -258,7 +239,6 @@ impl Default for Style { is_reverse: false, is_hidden: false, is_strikethrough: false, - hyperlink_url: None, } } } @@ -508,23 +488,7 @@ impl Colour { pub fn on(self, background: Colour) -> Style { Style { foreground: Some(self), background: Some(background), .. Style::default() } } - - /// Returns a `Style` with the foreground colour set to this colour and the - /// hyperlink URL set. You can pass the hyperlink as either a `String` or a - /// `&str`. - /// - /// # Examples - /// - /// ``` - /// use ansi_term::Colour; - /// - /// let style = Colour::Blue.hyperlink("https://example.org/"); - /// println!("{}", style.paint("example link")); - /// ``` - pub fn hyperlink>>(self, url: U) -> Style { - Style { foreground: Some(self), hyperlink_url: Some(url.into()), ..Style::default() } - } - + /// Returns index in 256-colour ANSI palette or red, green and blue /// components of the colour. ///