//! This module contains the logic to style some content. use std::{ fmt::{self, Display, Formatter}, result, }; use crate::{ queue, style::{ Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttribute, SetBackgroundColor, SetForegroundColor, Styler, }, }; /// The style with the content to be styled. /// /// # Examples /// /// ```rust /// use crossterm::style::{style, Color, Attribute}; /// /// let styled = style("Hello there") /// .with(Color::Yellow) /// .on(Color::Blue) /// .attribute(Attribute::Bold); /// /// println!("{}", styled); /// ``` #[derive(Clone)] pub struct StyledContent { /// The style (colors, content attributes). style: ContentStyle, /// A content to apply the style on. content: D, } impl<'a, D: Display + 'a + Clone> StyledContent { /// Creates a new `StyledContent`. pub fn new(style: ContentStyle, content: D) -> StyledContent { StyledContent { style, content } } /// Sets the foreground color. pub fn with(mut self, foreground_color: Color) -> StyledContent { self.style = self.style.foreground(foreground_color); self } /// Sets the background color. pub fn on(mut self, background_color: Color) -> StyledContent { self.style = self.style.background(background_color); self } /// Adds the attribute. /// /// You can add more attributes by calling this method multiple times. pub fn attribute(mut self, attr: Attribute) -> StyledContent { self.style = self.style.attribute(attr); self } /// Returns the content. pub fn content(&self) -> &D { &self.content } /// Returns the style. pub fn style(&self) -> &ContentStyle { &self.style } } impl Display for StyledContent { fn fmt(&self, f: &mut Formatter<'_>) -> result::Result<(), fmt::Error> { let mut reset = false; if let Some(bg) = self.style.background_color { queue!(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?; reset = true; } if let Some(fg) = self.style.foreground_color { queue!(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?; reset = true; } for attr in self.style.attributes.iter() { queue!(f, SetAttribute(*attr)).map_err(|_| fmt::Error)?; reset = true; } fmt::Display::fmt(&self.content, f)?; if reset { queue!(f, ResetColor).map_err(|_| fmt::Error)?; } Ok(()) } } impl Colorize for StyledContent { // foreground colors def_color!(foreground_color: black => Color::Black); def_color!(foreground_color: dark_grey => Color::DarkGrey); def_color!(foreground_color: red => Color::Red); def_color!(foreground_color: dark_red => Color::DarkRed); def_color!(foreground_color: green => Color::Green); def_color!(foreground_color: dark_green => Color::DarkGreen); def_color!(foreground_color: yellow => Color::Yellow); def_color!(foreground_color: dark_yellow => Color::DarkYellow); def_color!(foreground_color: blue => Color::Blue); def_color!(foreground_color: dark_blue => Color::DarkBlue); def_color!(foreground_color: magenta => Color::Magenta); def_color!(foreground_color: dark_magenta => Color::DarkMagenta); def_color!(foreground_color: cyan => Color::Cyan); def_color!(foreground_color: dark_cyan => Color::DarkCyan); def_color!(foreground_color: white => Color::White); def_color!(foreground_color: grey => Color::Grey); // background colors def_color!(background_color: on_black => Color::Black); def_color!(background_color: on_dark_grey => Color::DarkGrey); def_color!(background_color: on_red => Color::Red); def_color!(background_color: on_dark_red => Color::DarkRed); def_color!(background_color: on_green => Color::Green); def_color!(background_color: on_dark_green => Color::DarkGreen); def_color!(background_color: on_yellow => Color::Yellow); def_color!(background_color: on_dark_yellow => Color::DarkYellow); def_color!(background_color: on_blue => Color::Blue); def_color!(background_color: on_dark_blue => Color::DarkBlue); def_color!(background_color: on_magenta => Color::Magenta); def_color!(background_color: on_dark_magenta => Color::DarkMagenta); def_color!(background_color: on_cyan => Color::Cyan); def_color!(background_color: on_dark_cyan => Color::DarkCyan); def_color!(background_color: on_white => Color::White); def_color!(background_color: on_grey => Color::Grey); } impl Styler for StyledContent { def_attr!(reset => Attribute::Reset); def_attr!(bold => Attribute::Bold); def_attr!(underlined => Attribute::Underlined); def_attr!(reverse => Attribute::Reverse); def_attr!(dim => Attribute::Dim); def_attr!(italic => Attribute::Italic); def_attr!(negative => Attribute::Reverse); def_attr!(slow_blink => Attribute::SlowBlink); def_attr!(rapid_blink => Attribute::RapidBlink); def_attr!(hidden => Attribute::Hidden); def_attr!(crossed_out => Attribute::CrossedOut); } #[cfg(test)] mod tests { use super::{Attribute, Color, ContentStyle}; #[test] fn test_set_fg_bg_add_attr() { let style = ContentStyle::new() .foreground(Color::Blue) .background(Color::Red) .attribute(Attribute::Reset); let mut styled_content = style.apply("test"); styled_content = styled_content .with(Color::Green) .on(Color::Magenta) .attribute(Attribute::NoItalic); assert_eq!(styled_content.style.foreground_color, Some(Color::Green)); assert_eq!(styled_content.style.background_color, Some(Color::Magenta)); assert_eq!(styled_content.style.attributes.len(), 2); assert_eq!(styled_content.style.attributes[0], Attribute::Reset); assert_eq!(styled_content.style.attributes[1], Attribute::NoItalic); } }