| 1 | use std::fmt::Display;
|
| 2 |
|
| 3 | use super::{style, Attribute, Color, ContentStyle, StyledContent};
|
| 4 |
|
| 5 | macro_rules! stylize_method {
|
| 6 | ($method_name:ident Attribute::$attribute:ident) => {
|
| 7 | calculated_docs! {
|
| 8 | #[doc = concat!(
|
| 9 | "Applies the [`" ,
|
| 10 | stringify!($attribute),
|
| 11 | "`](Attribute::" ,
|
| 12 | stringify!($attribute),
|
| 13 | ") attribute to the text." ,
|
| 14 | )]
|
| 15 | fn $method_name(self) -> Self::Styled {
|
| 16 | self.attribute(Attribute::$attribute)
|
| 17 | }
|
| 18 | }
|
| 19 | };
|
| 20 | ($method_name_fg:ident, $method_name_bg:ident, $method_name_ul:ident Color::$color:ident) => {
|
| 21 | calculated_docs! {
|
| 22 | #[doc = concat!(
|
| 23 | "Sets the foreground color to [`" ,
|
| 24 | stringify!($color),
|
| 25 | "`](Color::" ,
|
| 26 | stringify!($color),
|
| 27 | ")."
|
| 28 | )]
|
| 29 | fn $method_name_fg(self) -> Self::Styled {
|
| 30 | self.with(Color::$color)
|
| 31 | }
|
| 32 |
|
| 33 | #[doc = concat!(
|
| 34 | "Sets the background color to [`" ,
|
| 35 | stringify!($color),
|
| 36 | "`](Color::" ,
|
| 37 | stringify!($color),
|
| 38 | ")."
|
| 39 | )]
|
| 40 | fn $method_name_bg(self) -> Self::Styled {
|
| 41 | self.on(Color::$color)
|
| 42 | }
|
| 43 |
|
| 44 | #[doc = concat!(
|
| 45 | "Sets the underline color to [`" ,
|
| 46 | stringify!($color),
|
| 47 | "`](Color::" ,
|
| 48 | stringify!($color),
|
| 49 | ")."
|
| 50 | )]
|
| 51 | fn $method_name_ul(self) -> Self::Styled {
|
| 52 | self.underline(Color::$color)
|
| 53 | }
|
| 54 | }
|
| 55 | };
|
| 56 | }
|
| 57 |
|
| 58 | /// Provides a set of methods to set attributes and colors.
|
| 59 | ///
|
| 60 | /// # Examples
|
| 61 | ///
|
| 62 | /// ```no_run
|
| 63 | /// use crossterm::style::Stylize;
|
| 64 | ///
|
| 65 | /// println!("{}" , "Bold text" .bold());
|
| 66 | /// println!("{}" , "Underlined text" .underlined());
|
| 67 | /// println!("{}" , "Negative text" .negative());
|
| 68 | /// println!("{}" , "Red on blue" .red().on_blue());
|
| 69 | /// ```
|
| 70 | pub trait Stylize: Sized {
|
| 71 | /// This type with styles applied.
|
| 72 | type Styled: AsRef<ContentStyle> + AsMut<ContentStyle>;
|
| 73 |
|
| 74 | /// Styles this type.
|
| 75 | fn stylize(self) -> Self::Styled;
|
| 76 |
|
| 77 | /// Sets the foreground color.
|
| 78 | fn with(self, color: Color) -> Self::Styled {
|
| 79 | let mut styled = self.stylize();
|
| 80 | styled.as_mut().foreground_color = Some(color);
|
| 81 | styled
|
| 82 | }
|
| 83 |
|
| 84 | /// Sets the background color.
|
| 85 | fn on(self, color: Color) -> Self::Styled {
|
| 86 | let mut styled = self.stylize();
|
| 87 | styled.as_mut().background_color = Some(color);
|
| 88 | styled
|
| 89 | }
|
| 90 |
|
| 91 | /// Sets the underline color.
|
| 92 | fn underline(self, color: Color) -> Self::Styled {
|
| 93 | let mut styled = self.stylize();
|
| 94 | styled.as_mut().underline_color = Some(color);
|
| 95 | styled
|
| 96 | }
|
| 97 |
|
| 98 | /// Styles the content with the attribute.
|
| 99 | fn attribute(self, attr: Attribute) -> Self::Styled {
|
| 100 | let mut styled = self.stylize();
|
| 101 | styled.as_mut().attributes.set(attr);
|
| 102 | styled
|
| 103 | }
|
| 104 |
|
| 105 | stylize_method!(reset Attribute::Reset);
|
| 106 | stylize_method!(bold Attribute::Bold);
|
| 107 | stylize_method!(underlined Attribute::Underlined);
|
| 108 | stylize_method!(reverse Attribute::Reverse);
|
| 109 | stylize_method!(dim Attribute::Dim);
|
| 110 | stylize_method!(italic Attribute::Italic);
|
| 111 | stylize_method!(negative Attribute::Reverse);
|
| 112 | stylize_method!(slow_blink Attribute::SlowBlink);
|
| 113 | stylize_method!(rapid_blink Attribute::RapidBlink);
|
| 114 | stylize_method!(hidden Attribute::Hidden);
|
| 115 | stylize_method!(crossed_out Attribute::CrossedOut);
|
| 116 |
|
| 117 | stylize_method!(black, on_black, underline_black Color::Black);
|
| 118 | stylize_method!(dark_grey, on_dark_grey, underline_dark_grey Color::DarkGrey);
|
| 119 | stylize_method!(red, on_red, underline_red Color::Red);
|
| 120 | stylize_method!(dark_red, on_dark_red, underline_dark_red Color::DarkRed);
|
| 121 | stylize_method!(green, on_green, underline_green Color::Green);
|
| 122 | stylize_method!(dark_green, on_dark_green, underline_dark_green Color::DarkGreen);
|
| 123 | stylize_method!(yellow, on_yellow, underline_yellow Color::Yellow);
|
| 124 | stylize_method!(dark_yellow, on_dark_yellow, underline_dark_yellow Color::DarkYellow);
|
| 125 | stylize_method!(blue, on_blue, underline_blue Color::Blue);
|
| 126 | stylize_method!(dark_blue, on_dark_blue, underline_dark_blue Color::DarkBlue);
|
| 127 | stylize_method!(magenta, on_magenta, underline_magenta Color::Magenta);
|
| 128 | stylize_method!(dark_magenta, on_dark_magenta, underline_dark_magenta Color::DarkMagenta);
|
| 129 | stylize_method!(cyan, on_cyan, underline_cyan Color::Cyan);
|
| 130 | stylize_method!(dark_cyan, on_dark_cyan, underline_dark_cyan Color::DarkCyan);
|
| 131 | stylize_method!(white, on_white, underline_white Color::White);
|
| 132 | stylize_method!(grey, on_grey, underline_grey Color::Grey);
|
| 133 | }
|
| 134 |
|
| 135 | macro_rules! impl_stylize_for_display {
|
| 136 | ($($t:ty),*) => { $(
|
| 137 | impl Stylize for $t {
|
| 138 | type Styled = StyledContent<Self>;
|
| 139 | #[inline]
|
| 140 | fn stylize(self) -> Self::Styled {
|
| 141 | style(self)
|
| 142 | }
|
| 143 | }
|
| 144 | )* }
|
| 145 | }
|
| 146 | impl_stylize_for_display!(String, char, &str);
|
| 147 |
|
| 148 | impl Stylize for ContentStyle {
|
| 149 | type Styled = Self;
|
| 150 | #[inline ]
|
| 151 | fn stylize(self) -> Self::Styled {
|
| 152 | self
|
| 153 | }
|
| 154 | }
|
| 155 | impl<D: Display> Stylize for StyledContent<D> {
|
| 156 | type Styled = StyledContent<D>;
|
| 157 | fn stylize(self) -> Self::Styled {
|
| 158 | self
|
| 159 | }
|
| 160 | }
|
| 161 |
|
| 162 | // Workaround for https://github.com/rust-lang/rust/issues/78835
|
| 163 | macro_rules! calculated_docs {
|
| 164 | ($(#[doc = $doc:expr] $item:item)*) => { $(#[doc = $doc] $item)* };
|
| 165 | }
|
| 166 | // Remove once https://github.com/rust-lang/rust-clippy/issues/7106 stabilizes.
|
| 167 | #[allow (clippy::single_component_path_imports)]
|
| 168 | #[allow (clippy::useless_attribute)]
|
| 169 | use calculated_docs;
|
| 170 |
|
| 171 | #[cfg (test)]
|
| 172 | mod tests {
|
| 173 | use super::super::{Attribute, Color, ContentStyle, Stylize};
|
| 174 |
|
| 175 | #[test ]
|
| 176 | fn set_fg_bg_add_attr() {
|
| 177 | let style = ContentStyle::new()
|
| 178 | .with(Color::Blue)
|
| 179 | .on(Color::Red)
|
| 180 | .attribute(Attribute::Bold);
|
| 181 |
|
| 182 | assert_eq!(style.foreground_color, Some(Color::Blue));
|
| 183 | assert_eq!(style.background_color, Some(Color::Red));
|
| 184 | assert!(style.attributes.has(Attribute::Bold));
|
| 185 |
|
| 186 | let mut styled_content = style.apply("test" );
|
| 187 |
|
| 188 | styled_content = styled_content
|
| 189 | .with(Color::Green)
|
| 190 | .on(Color::Magenta)
|
| 191 | .attribute(Attribute::NoItalic);
|
| 192 |
|
| 193 | let style = styled_content.style();
|
| 194 |
|
| 195 | assert_eq!(style.foreground_color, Some(Color::Green));
|
| 196 | assert_eq!(style.background_color, Some(Color::Magenta));
|
| 197 | assert!(style.attributes.has(Attribute::Bold));
|
| 198 | assert!(style.attributes.has(Attribute::NoItalic));
|
| 199 | }
|
| 200 | }
|
| 201 | |