diff --git a/CHANGELOG.md b/CHANGELOG.md index dfe3a33..1a6afbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,18 @@ - Rename `PrintStyledFont` to `PrintStyledContent` - Rename `attr` method to `attribute`. - Rename `Attribute::NoInverse` to `NoReverse` + - `Crossterm::style()` and `Crossterm::color()` + - Remove re-exports from style module at at root and only expose those in the `crossterm::style` module. + - Remove `TerminalColor` (/style.rs), + - Remove `color` (style.rs) + - Update documentation + - Made `Colored` private, user should use commands instead. + - Rename `SetFg` -> `SetForegroundColor` + - Rename `SetBg` -> `SetBackgroundColor` + - Rename `SetAttr` -> `SetAttribute` + - Rename `ContentStyle::fg_color` -> `ContentStyle::foreground_color` + - Rename `ContentStyle::bg_color` -> `ContentStyle::background_color` + - Rename `ContentStyle::attrs` -> `ContentStyle::attributes` # Version 0.12.1 diff --git a/src/crossterm.rs b/src/crossterm.rs index b55da1f..dc22233 100644 --- a/src/crossterm.rs +++ b/src/crossterm.rs @@ -1,7 +1,3 @@ -#[cfg(feature = "style")] -use std::fmt::Display; - -// TODO Should be removed? This adds just another way to achieve the same thing. /// A crossterm functionality wrapper. pub struct Crossterm; @@ -16,19 +12,4 @@ impl Crossterm { pub fn input(&self) -> crate::input::TerminalInput { crate::input::TerminalInput::new() } - - /// Creates a new `TerminalColor`. - #[cfg(feature = "style")] - pub fn color(&self) -> crate::style::TerminalColor { - crate::style::TerminalColor::new() - } - - /// Creates a new `StyledContent`. - #[cfg(feature = "style")] - pub fn style(&self, val: D) -> crate::style::StyledContent - where - D: Display + Clone, - { - crate::style::ContentStyle::new().apply(val) - } } diff --git a/src/lib.rs b/src/lib.rs index 89ff1fb..b45c06f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,8 +118,8 @@ //! ```no_run //! use std::io::{stdout, Write}; //! use crossterm::{ -//! ExecutableCommand, QueueableCommand, Color, -//! Colorize, terminal, cursor, style, Result +//! ExecutableCommand, QueueableCommand, +//! terminal, cursor, style::{self, Colorize}, Result //! }; //! //! fn main() -> Result<()> { @@ -146,8 +146,8 @@ //! ```no_run //! use std::io::{stdout, Write}; //! use crossterm::{ -//! execute, queue, Color, PrintStyledContent, -//! Colorize, cursor, terminal, style, Result +//! execute, queue, +//! style::{self, Colorize}, cursor, terminal, Result //! }; //! //! fn main() -> Result<()> { @@ -176,11 +176,6 @@ pub use input::{ pub use screen::{ AlternateScreen, EnterAlternateScreen, IntoRawMode, LeaveAlternateScreen, RawScreen, }; -#[cfg(feature = "style")] -pub use style::{ - color, style, Attribute, Color, Colored, Colorize, ContentStyle, PrintStyledContent, - ResetColor, SetAttr, SetBg, SetFg, StyledContent, Styler, TerminalColor, -}; pub use utils::{Command, ErrorKind, ExecutableCommand, Output, QueueableCommand, Result}; pub use self::crossterm::Crossterm; diff --git a/src/style.rs b/src/style.rs index f535bf0..0e3cca8 100644 --- a/src/style.rs +++ b/src/style.rs @@ -25,15 +25,16 @@ //! use std::io::{stdout, Write}; //! //! use crossterm::{execute, Result, Output}; -//! use crossterm::{SetBg, SetFg, ResetColor, Color, Attribute}; +//! use crossterm::style::{SetForegroundColor, SetBackgroundColor, ResetColor, Color, Attribute}; //! //! fn main() -> Result<()> { //! execute!( //! stdout(), //! // Blue foreground -//! SetFg(Color::Blue), +//! SetForegroundColor(Color::Blue), //! // Red background -//! SetBg(Color::Red), +//! SetBackgroundColor(Color::Red), +//! // output text //! Output("Styled text here.".to_string()), //! // Reset to default colors //! ResetColor @@ -41,19 +42,10 @@ //! } //! ``` //! -//! The [`Colored`](enum.Colored.html) & [`Color`](enum.Color.html) enums: -//! -//! ```no_run -//! use crossterm::{Colored, Color}; -//! -//! println!("{} Red foreground", Colored::Fg(Color::Red)); -//! println!("{} Blue background", Colored::Bg(Color::Blue)); -//! ``` -//! //! The [`Colorize`](trait.Colorize.html) trait: //! //! ```no_run -//! use crossterm::Colorize; +//! use crossterm::style::Colorize; //! //! println!("{}", "Red foreground color & blue background.".red().on_blue()); //! ``` @@ -66,16 +58,16 @@ //! use std::io::{stdout, Write}; //! //! use crossterm::{execute, Result, Output}; -//! use crossterm::{SetAttr, Attribute}; +//! use crossterm::style::{SetAttribute, Attribute}; //! //! fn main() -> Result<()> { //! execute!( //! stdout(), //! // Set to bold -//! SetAttr(Attribute::Bold), +//! SetAttribute(Attribute::Bold), //! Output("Styled text here.".to_string()), //! // Reset all attributes -//! SetAttr(Attribute::Reset) +//! SetAttribute(Attribute::Reset) //! ) //! } //! ``` @@ -83,7 +75,7 @@ //! The [`Styler`](trait.Styler.html) trait: //! //! ```no_run -//! use crossterm::Styler; +//! use crossterm::style::Styler; //! //! println!("{}", "Bold".bold()); //! println!("{}", "Underlined".underlined()); @@ -93,7 +85,7 @@ //! The [`Attribute`](enum.Attribute.html) enum: //! //! ```no_run -//! use crossterm::Attribute; +//! use crossterm::style::Attribute; //! //! println!( //! "{} Underlined {} No Underline", @@ -105,27 +97,25 @@ use std::env; use std::fmt::Display; -use style::ansi::{self, AnsiColor}; -#[cfg(windows)] -use style::winapi::WinApiColor; -use style::Style; - use crate::impl_display; -#[cfg(windows)] -use crate::utils::supports_ansi; -use crate::utils::{Command, Result}; +use crate::utils::Command; -pub use self::contentstyle::ContentStyle; -pub use self::enums::{Attribute, Color, Colored}; -pub use self::styledcontent::StyledContent; +#[cfg(windows)] +use crate::Result; + +pub use self::content_style::ContentStyle; +pub(crate) use self::enums::Colored; +pub use self::enums::{Attribute, Color}; +pub use self::styled_content::StyledContent; pub use self::traits::{Colorize, Styler}; #[macro_use] mod macros; -mod contentstyle; +mod ansi; +mod content_style; mod enums; -mod style; -mod styledcontent; +mod styled_content; +mod sys; mod traits; /// Creates a `StyledContent`. @@ -137,7 +127,7 @@ mod traits; /// # Examples /// /// ```no_run -/// use crossterm::{style, Color}; +/// use crossterm::style::{style, Color}; /// /// let styled_content = style("Blue colored text on yellow background") /// .with(Color::Blue) @@ -154,40 +144,40 @@ where impl Colorize<&'static str> for &'static str { // foreground colors - def_str_color!(fg_color: black => Color::Black); - def_str_color!(fg_color: dark_grey => Color::DarkGrey); - def_str_color!(fg_color: red => Color::Red); - def_str_color!(fg_color: dark_red => Color::DarkRed); - def_str_color!(fg_color: green => Color::Green); - def_str_color!(fg_color: dark_green => Color::DarkGreen); - def_str_color!(fg_color: yellow => Color::Yellow); - def_str_color!(fg_color: dark_yellow => Color::DarkYellow); - def_str_color!(fg_color: blue => Color::Blue); - def_str_color!(fg_color: dark_blue => Color::DarkBlue); - def_str_color!(fg_color: magenta => Color::Magenta); - def_str_color!(fg_color: dark_magenta => Color::DarkMagenta); - def_str_color!(fg_color: cyan => Color::Cyan); - def_str_color!(fg_color: dark_cyan => Color::DarkCyan); - def_str_color!(fg_color: white => Color::White); - def_str_color!(fg_color: grey => Color::Grey); + def_str_color!(foreground_color: black => Color::Black); + def_str_color!(foreground_color: dark_grey => Color::DarkGrey); + def_str_color!(foreground_color: red => Color::Red); + def_str_color!(foreground_color: dark_red => Color::DarkRed); + def_str_color!(foreground_color: green => Color::Green); + def_str_color!(foreground_color: dark_green => Color::DarkGreen); + def_str_color!(foreground_color: yellow => Color::Yellow); + def_str_color!(foreground_color: dark_yellow => Color::DarkYellow); + def_str_color!(foreground_color: blue => Color::Blue); + def_str_color!(foreground_color: dark_blue => Color::DarkBlue); + def_str_color!(foreground_color: magenta => Color::Magenta); + def_str_color!(foreground_color: dark_magenta => Color::DarkMagenta); + def_str_color!(foreground_color: cyan => Color::Cyan); + def_str_color!(foreground_color: dark_cyan => Color::DarkCyan); + def_str_color!(foreground_color: white => Color::White); + def_str_color!(foreground_color: grey => Color::Grey); // background colors - def_str_color!(bg_color: on_black => Color::Black); - def_str_color!(bg_color: on_dark_grey => Color::DarkGrey); - def_str_color!(bg_color: on_red => Color::Red); - def_str_color!(bg_color: on_dark_red => Color::DarkRed); - def_str_color!(bg_color: on_green => Color::Green); - def_str_color!(bg_color: on_dark_green => Color::DarkGreen); - def_str_color!(bg_color: on_yellow => Color::Yellow); - def_str_color!(bg_color: on_dark_yellow => Color::DarkYellow); - def_str_color!(bg_color: on_blue => Color::Blue); - def_str_color!(bg_color: on_dark_blue => Color::DarkBlue); - def_str_color!(bg_color: on_magenta => Color::Magenta); - def_str_color!(bg_color: on_dark_magenta => Color::DarkMagenta); - def_str_color!(bg_color: on_cyan => Color::Cyan); - def_str_color!(bg_color: on_dark_cyan => Color::DarkCyan); - def_str_color!(bg_color: on_white => Color::White); - def_str_color!(bg_color: on_grey => Color::Grey); + def_str_color!(background_color: on_black => Color::Black); + def_str_color!(background_color: on_dark_grey => Color::DarkGrey); + def_str_color!(background_color: on_red => Color::Red); + def_str_color!(background_color: on_dark_red => Color::DarkRed); + def_str_color!(background_color: on_green => Color::Green); + def_str_color!(background_color: on_dark_green => Color::DarkGreen); + def_str_color!(background_color: on_yellow => Color::Yellow); + def_str_color!(background_color: on_dark_yellow => Color::DarkYellow); + def_str_color!(background_color: on_blue => Color::Blue); + def_str_color!(background_color: on_dark_blue => Color::DarkBlue); + def_str_color!(background_color: on_magenta => Color::Magenta); + def_str_color!(background_color: on_dark_magenta => Color::DarkMagenta); + def_str_color!(background_color: on_cyan => Color::Cyan); + def_str_color!(background_color: on_dark_cyan => Color::DarkCyan); + def_str_color!(background_color: on_white => Color::White); + def_str_color!(background_color: on_grey => Color::Grey); } impl Styler<&'static str> for &'static str { @@ -204,110 +194,27 @@ impl Styler<&'static str> for &'static str { def_str_attr!(crossed_out => Attribute::CrossedOut); } -/// A terminal color. +/// Returns available color count. /// -/// # Examples +/// # Notes /// -/// Basic usage: -/// -/// ```no_run -/// // You can replace the following line with `use crossterm::TerminalColor;` -/// // if you're using the `crossterm` crate with the `style` feature enabled. -/// use crossterm::{Result, TerminalColor, Color}; -/// -/// fn main() -> Result<()> { -/// let color = TerminalColor::new(); -/// // Set foreground color -/// color.set_fg(Color::Blue)?; -/// // Set background color -/// color.set_bg(Color::Red)?; -/// // Reset to the default colors -/// color.reset() -/// } -/// ``` -pub struct TerminalColor { - #[cfg(windows)] - color: Box<(dyn Style + Sync + Send)>, - #[cfg(unix)] - color: AnsiColor, +/// This does not always provide a good result. +pub fn available_color_count() -> u16 { + env::var("TERM") + .map(|x| if x.contains("256color") { 256 } else { 8 }) + .unwrap_or(8) } -impl TerminalColor { - /// Creates a new `TerminalColor`. - pub fn new() -> TerminalColor { - #[cfg(windows)] - let color = if supports_ansi() { - Box::from(AnsiColor::new()) as Box<(dyn Style + Sync + Send)> - } else { - WinApiColor::new() as Box<(dyn Style + Sync + Send)> - }; - - #[cfg(unix)] - let color = AnsiColor::new(); - - TerminalColor { color } - } - - /// Sets the foreground color. - pub fn set_fg(&self, color: Color) -> Result<()> { - self.color.set_fg(color) - } - - /// Sets the background color. - pub fn set_bg(&self, color: Color) -> Result<()> { - self.color.set_bg(color) - } - - /// Resets the terminal colors and attributes to the default ones. - pub fn reset(&self) -> Result<()> { - self.color.reset() - } - - /// Returns available color count. - /// - /// # Notes - /// - /// This does not always provide a good result. - pub fn available_color_count(&self) -> u16 { - env::var("TERM") - .map(|x| if x.contains("256color") { 256 } else { 8 }) - .unwrap_or(8) - } -} - -/// Creates a new `TerminalColor`. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ```no_run -/// use crossterm::{color, Color, Result}; -/// -/// fn main() -> Result<()> { -/// let color = color(); -/// // Set foreground color -/// color.set_fg(Color::Blue)?; -/// // Set background color -/// color.set_bg(Color::Red)?; -/// // Reset to the default colors -/// color.reset() -/// } -/// ``` -pub fn color() -> TerminalColor { - TerminalColor::new() -} - -/// A command to set the foreground color. +/// A command that sets the the foreground color. /// /// See [`Color`](enum.Color.html) for more info. /// /// # Notes /// /// Commands must be executed/queued for execution otherwise they do nothing. -pub struct SetFg(pub Color); +pub struct SetForegroundColor(pub Color); -impl Command for SetFg { +impl Command for SetForegroundColor { type AnsiType = String; fn ansi_code(&self) -> Self::AnsiType { @@ -316,20 +223,20 @@ impl Command for SetFg { #[cfg(windows)] fn execute_winapi(&self) -> Result<()> { - WinApiColor::new().set_fg(self.0) + sys::windows::set_foreground_color(self.0) } } -/// A command to set the background color. +/// A command that sets the the background color. /// /// See [`Color`](enum.Color.html) for more info. /// /// # Notes /// /// Commands must be executed/queued for execution otherwise they do nothing. -pub struct SetBg(pub Color); +pub struct SetBackgroundColor(pub Color); -impl Command for SetBg { +impl Command for SetBackgroundColor { type AnsiType = String; fn ansi_code(&self) -> Self::AnsiType { @@ -338,20 +245,20 @@ impl Command for SetBg { #[cfg(windows)] fn execute_winapi(&self) -> Result<()> { - WinApiColor::new().set_bg(self.0) + sys::windows::set_background_color(self.0) } } -/// A command to set the text attribute. +/// A command that sets an attribute. /// /// See [`Attribute`](enum.Attribute.html) for more info. /// /// # Notes /// /// Commands must be executed/queued for execution otherwise they do nothing. -pub struct SetAttr(pub Attribute); +pub struct SetAttribute(pub Attribute); -impl Command for SetAttr { +impl Command for SetAttribute { type AnsiType = String; fn ansi_code(&self) -> Self::AnsiType { @@ -365,7 +272,7 @@ impl Command for SetAttr { } } -/// A command to print the styled content. +/// A command that prints styled content. /// /// See [`StyledContent`](struct.StyledContent.html) for more info. /// @@ -390,7 +297,7 @@ where } } -/// A command to reset the colors back to default ones. +/// A command that resets the colors back to default. /// /// # Notes /// @@ -406,13 +313,13 @@ impl Command for ResetColor { #[cfg(windows)] fn execute_winapi(&self) -> Result<()> { - WinApiColor::new().reset() + sys::windows::reset() } } -impl_display!(for SetFg); -impl_display!(for SetBg); -impl_display!(for SetAttr); +impl_display!(for SetForegroundColor); +impl_display!(for SetBackgroundColor); +impl_display!(for SetAttribute); impl_display!(for PrintStyledContent); impl_display!(for PrintStyledContent<&'static str>); impl_display!(for ResetColor); diff --git a/src/style/style/ansi.rs b/src/style/ansi.rs similarity index 70% rename from src/style/style/ansi.rs rename to src/style/ansi.rs index 2637b1a..0ff4b90 100644 --- a/src/style/style/ansi.rs +++ b/src/style/ansi.rs @@ -1,17 +1,21 @@ //! This is a ANSI specific implementation for styling related action. //! This module is used for Windows 10 terminals and Unix terminals by default. -use crate::utils::Result; -use crate::{csi, write_cout}; - -use super::super::{Attribute, Color, Colored, Style}; +use crate::csi; +use crate::style::{Attribute, Color, Colored}; pub(crate) fn set_fg_csi_sequence(fg_color: Color) -> String { - format!(csi!("{}m"), Into::::into(Colored::Fg(fg_color))) + format!( + csi!("{}m"), + Into::::into(Colored::ForegroundColor(fg_color)) + ) } pub(crate) fn set_bg_csi_sequence(bg_color: Color) -> String { - format!(csi!("{}m"), Into::::into(Colored::Bg(bg_color))) + format!( + csi!("{}m"), + Into::::into(Colored::BackgroundColor(bg_color)) + ) } pub(crate) fn set_attr_csi_sequence(attribute: Attribute) -> String { @@ -20,32 +24,6 @@ pub(crate) fn set_attr_csi_sequence(attribute: Attribute) -> String { pub(crate) static RESET_CSI_SEQUENCE: &'static str = csi!("0m"); -/// This struct is an ANSI escape code implementation for color related actions. -pub(crate) struct AnsiColor; - -impl AnsiColor { - pub fn new() -> AnsiColor { - AnsiColor - } -} - -impl Style for AnsiColor { - fn set_fg(&self, fg_color: Color) -> Result<()> { - write_cout!(set_fg_csi_sequence(fg_color))?; - Ok(()) - } - - fn set_bg(&self, bg_color: Color) -> Result<()> { - write_cout!(set_bg_csi_sequence(bg_color))?; - Ok(()) - } - - fn reset(&self) -> Result<()> { - write_cout!(RESET_CSI_SEQUENCE)?; - Ok(()) - } -} - impl From for String { fn from(colored: Colored) -> Self { let mut ansi_value = String::new(); @@ -53,7 +31,7 @@ impl From for String { let color; match colored { - Colored::Fg(new_color) => { + Colored::ForegroundColor(new_color) => { if new_color == Color::Reset { ansi_value.push_str("39"); return ansi_value; @@ -62,7 +40,7 @@ impl From for String { color = new_color; } } - Colored::Bg(new_color) => { + Colored::BackgroundColor(new_color) => { if new_color == Color::Reset { ansi_value.push_str("49"); return ansi_value; @@ -108,41 +86,41 @@ impl From for String { #[cfg(test)] mod tests { - use crate::{Color, Colored}; + use crate::style::{Color, Colored}; #[test] fn test_parse_fg_color() { - let colored = Colored::Fg(Color::Red); + let colored = Colored::ForegroundColor(Color::Red); assert_eq!(Into::::into(colored), "38;5;9"); } #[test] fn test_parse_bg_color() { - let colored = Colored::Bg(Color::Red); + let colored = Colored::BackgroundColor(Color::Red); assert_eq!(Into::::into(colored), "48;5;9"); } #[test] fn test_parse_reset_fg_color() { - let colored = Colored::Fg(Color::Reset); + let colored = Colored::ForegroundColor(Color::Reset); assert_eq!(Into::::into(colored), "39"); } #[test] fn test_parse_reset_bg_color() { - let colored = Colored::Bg(Color::Reset); + let colored = Colored::BackgroundColor(Color::Reset); assert_eq!(Into::::into(colored), "49"); } #[test] fn test_parse_fg_rgb_color() { - let colored = Colored::Bg(Color::Rgb { r: 1, g: 2, b: 3 }); + let colored = Colored::BackgroundColor(Color::Rgb { r: 1, g: 2, b: 3 }); assert_eq!(Into::::into(colored), "48;2;1;2;3"); } #[test] fn test_parse_fg_ansi_color() { - let colored = Colored::Fg(Color::AnsiValue(255)); + let colored = Colored::ForegroundColor(Color::AnsiValue(255)); assert_eq!(Into::::into(colored), "38;5;255"); } } diff --git a/src/style/contentstyle.rs b/src/style/content_style.rs similarity index 66% rename from src/style/contentstyle.rs rename to src/style/content_style.rs index 25fe843..693e745 100644 --- a/src/style/contentstyle.rs +++ b/src/style/content_style.rs @@ -2,17 +2,17 @@ use std::fmt::Display; -use super::{Attribute, Color, StyledContent}; +use crate::style::{Attribute, Color, StyledContent}; /// A content style. #[derive(Debug, Clone, Default)] pub struct ContentStyle { /// The foreground color. - pub fg_color: Option, + pub foreground_color: Option, /// The background color. - pub bg_color: Option, + pub background_color: Option, /// List of attributes. - pub attrs: Vec, + pub attributes: Vec, } impl ContentStyle { @@ -28,13 +28,13 @@ impl ContentStyle { /// Sets the background color. pub fn background(mut self, color: Color) -> ContentStyle { - self.bg_color = Some(color); + self.background_color = Some(color); self } /// Sets the foreground color. pub fn foreground(mut self, color: Color) -> ContentStyle { - self.fg_color = Some(color); + self.foreground_color = Some(color); self } @@ -42,14 +42,14 @@ impl ContentStyle { /// /// You can add more attributes by calling this method multiple times. pub fn attribute(mut self, attr: Attribute) -> ContentStyle { - self.attrs.push(attr); + self.attributes.push(attr); self } } #[cfg(test)] mod tests { - use crate::{Attribute, Color, ContentStyle}; + use crate::style::{Attribute, Color, ContentStyle}; #[test] fn test_set_fg_bg_add_attr() { @@ -58,9 +58,9 @@ mod tests { .background(Color::Red) .attribute(Attribute::Reset); - assert_eq!(content_style.fg_color, Some(Color::Blue)); - assert_eq!(content_style.bg_color, Some(Color::Red)); - assert_eq!(content_style.attrs[0], Attribute::Reset); + assert_eq!(content_style.foreground_color, Some(Color::Blue)); + assert_eq!(content_style.background_color, Some(Color::Red)); + assert_eq!(content_style.attributes[0], Attribute::Reset); } #[test] @@ -72,8 +72,8 @@ mod tests { let styled_content = content_style.apply("test"); - assert_eq!(styled_content.style().fg_color, Some(Color::Blue)); - assert_eq!(styled_content.style().bg_color, Some(Color::Red)); - assert_eq!(styled_content.style().attrs[0], Attribute::Reset); + assert_eq!(styled_content.style().foreground_color, Some(Color::Blue)); + assert_eq!(styled_content.style().background_color, Some(Color::Red)); + assert_eq!(styled_content.style().attributes[0], Attribute::Reset); } } diff --git a/src/style/enums.rs b/src/style/enums.rs index e790c64..b7df3d4 100644 --- a/src/style/enums.rs +++ b/src/style/enums.rs @@ -1,4 +1,5 @@ -pub use self::{attribute::Attribute, color::Color, colored::Colored}; +pub(crate) use self::colored::Colored; +pub use self::{attribute::Attribute, color::Color}; mod attribute; mod color; diff --git a/src/style/enums/attribute.rs b/src/style/enums/attribute.rs index b130d7f..3c60e38 100644 --- a/src/style/enums/attribute.rs +++ b/src/style/enums/attribute.rs @@ -3,7 +3,7 @@ use std::fmt::Display; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use super::super::SetAttr; +use super::super::SetAttribute; /// Represents an attribute. /// @@ -37,7 +37,7 @@ use super::super::SetAttr; /// Basic usage: /// /// ```no_run -/// use crossterm::Attribute; +/// use crossterm::style::Attribute; /// /// println!( /// "{} Underlined {} No Underline", @@ -49,7 +49,7 @@ use super::super::SetAttr; /// Style existing text: /// /// ```no_run -/// use crossterm::Styler; +/// use crossterm::style::Styler; /// /// println!("{}", "Bold text".bold()); /// println!("{}", "Underlined text".underlined()); @@ -115,7 +115,7 @@ pub enum Attribute { impl Display for Attribute { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - write!(f, "{}", SetAttr(*self))?; + write!(f, "{}", SetAttribute(*self))?; Ok(()) } } diff --git a/src/style/enums/colored.rs b/src/style/enums/colored.rs index e77cc80..38b51cb 100644 --- a/src/style/enums/colored.rs +++ b/src/style/enums/colored.rs @@ -1,46 +1,10 @@ -use std::fmt::Display; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -use super::{super::color, color::Color}; +use crate::style::Color; /// Represents a foreground or a background color. -/// -/// Can be used to easily change the text colors. -/// -/// # Examples -/// -/// `Colored` implements `Display` therefore you can use it in any `write` operation. -/// -/// ```no_run -/// use crossterm::{Colored, Color}; -/// -/// println!("{} Red foreground color", Colored::Fg(Color::Red)); -/// println!("{} Blue background color", Colored::Bg(Color::Blue)); -/// ``` -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub enum Colored { +pub(crate) enum Colored { /// A foreground color. - Fg(Color), + ForegroundColor(Color), /// A background color. - Bg(Color), -} - -impl Display for Colored { - fn fmt(&self, _f: &mut ::std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - let colored_terminal = color(); - - match *self { - Colored::Fg(color) => colored_terminal - .set_fg(color) - .map_err(|_| std::fmt::Error)?, - Colored::Bg(color) => colored_terminal - .set_bg(color) - .map_err(|_| std::fmt::Error)?, - } - - Ok(()) - } + BackgroundColor(Color), } diff --git a/src/style/style.rs b/src/style/style.rs deleted file mode 100644 index b4699f9..0000000 --- a/src/style/style.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! A module that contains all the actions related to the styling of the terminal. -//! Like applying attributes to text and changing the foreground and background. - -use crate::utils::Result; - -use super::Color; - -pub(crate) mod ansi; -#[cfg(windows)] -pub(crate) mod winapi; - -/// This trait defines the actions that can be performed with terminal colors. -/// This trait can be implemented so that a concrete implementation of the ITerminalColor can fulfill -/// the wishes to work on a specific platform. -/// -/// ## For example: -/// -/// This trait is implemented for `WinApi` (Windows specific) and `ANSI` (Unix specific), -/// so that color-related actions can be performed on both UNIX and Windows systems. -pub(crate) trait Style: Sync + Send { - /// Set the foreground color to the given color. - fn set_fg(&self, fg_color: Color) -> Result<()>; - /// Set the background color to the given color. - fn set_bg(&self, fg_color: Color) -> Result<()>; - /// Reset the terminal color to default. - fn reset(&self) -> Result<()>; -} diff --git a/src/style/styledcontent.rs b/src/style/styled_content.rs similarity index 52% rename from src/style/styledcontent.rs rename to src/style/styled_content.rs index 55ec0df..c6b7282 100644 --- a/src/style/styledcontent.rs +++ b/src/style/styled_content.rs @@ -5,14 +5,17 @@ use std::result; use crate::queue; -use super::{Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttr, SetBg, SetFg, Styler}; +use crate::style::{ + Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttribute, SetBackgroundColor, + SetForegroundColor, Styler, +}; /// A styled content. /// /// # Examples /// /// ```rust -/// use crossterm::{style, Color, Attribute}; +/// use crossterm::style::{style, Color, Attribute}; /// /// let styled = style("Hello there") /// .with(Color::Yellow) @@ -70,17 +73,17 @@ impl Display for StyledContent { fn fmt(&self, f: &mut Formatter<'_>) -> result::Result<(), fmt::Error> { let mut reset = false; - if let Some(bg) = self.style.bg_color { - queue!(f, SetBg(bg)).map_err(|_| fmt::Error)?; + if let Some(bg) = self.style.background_color { + queue!(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?; reset = true; } - if let Some(fg) = self.style.fg_color { - queue!(f, SetFg(fg)).map_err(|_| fmt::Error)?; + if let Some(fg) = self.style.foreground_color { + queue!(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?; reset = true; } - for attr in self.style.attrs.iter() { - queue!(f, SetAttr(*attr)).map_err(|_| fmt::Error)?; + for attr in self.style.attributes.iter() { + queue!(f, SetAttribute(*attr)).map_err(|_| fmt::Error)?; reset = true; } @@ -96,40 +99,40 @@ impl Display for StyledContent { impl Colorize for StyledContent { // foreground colors - def_color!(fg_color: black => Color::Black); - def_color!(fg_color: dark_grey => Color::DarkGrey); - def_color!(fg_color: red => Color::Red); - def_color!(fg_color: dark_red => Color::DarkRed); - def_color!(fg_color: green => Color::Green); - def_color!(fg_color: dark_green => Color::DarkGreen); - def_color!(fg_color: yellow => Color::Yellow); - def_color!(fg_color: dark_yellow => Color::DarkYellow); - def_color!(fg_color: blue => Color::Blue); - def_color!(fg_color: dark_blue => Color::DarkBlue); - def_color!(fg_color: magenta => Color::Magenta); - def_color!(fg_color: dark_magenta => Color::DarkMagenta); - def_color!(fg_color: cyan => Color::Cyan); - def_color!(fg_color: dark_cyan => Color::DarkCyan); - def_color!(fg_color: white => Color::White); - def_color!(fg_color: grey => Color::Grey); + 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!(bg_color: on_black => Color::Black); - def_color!(bg_color: on_dark_grey => Color::DarkGrey); - def_color!(bg_color: on_red => Color::Red); - def_color!(bg_color: on_dark_red => Color::DarkRed); - def_color!(bg_color: on_green => Color::Green); - def_color!(bg_color: on_dark_green => Color::DarkGreen); - def_color!(bg_color: on_yellow => Color::Yellow); - def_color!(bg_color: on_dark_yellow => Color::DarkYellow); - def_color!(bg_color: on_blue => Color::Blue); - def_color!(bg_color: on_dark_blue => Color::DarkBlue); - def_color!(bg_color: on_magenta => Color::Magenta); - def_color!(bg_color: on_dark_magenta => Color::DarkMagenta); - def_color!(bg_color: on_cyan => Color::Cyan); - def_color!(bg_color: on_dark_cyan => Color::DarkCyan); - def_color!(bg_color: on_white => Color::White); - def_color!(bg_color: on_grey => Color::Grey); + 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 { @@ -164,10 +167,10 @@ mod tests { .on(Color::Magenta) .attribute(Attribute::NoItalic); - assert_eq!(styled_content.style.fg_color, Some(Color::Green)); - assert_eq!(styled_content.style.bg_color, Some(Color::Magenta)); - assert_eq!(styled_content.style.attrs.len(), 2); - assert_eq!(styled_content.style.attrs[0], Attribute::Reset); - assert_eq!(styled_content.style.attrs[1], 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); } } diff --git a/src/style/sys.rs b/src/style/sys.rs new file mode 100644 index 0000000..5a54276 --- /dev/null +++ b/src/style/sys.rs @@ -0,0 +1,2 @@ +#[cfg(windows)] +pub(crate) mod windows; diff --git a/src/style/style/winapi.rs b/src/style/sys/windows.rs similarity index 66% rename from src/style/style/winapi.rs rename to src/style/sys/windows.rs index c114c7c..65bd12b 100644 --- a/src/style/style/winapi.rs +++ b/src/style/sys/windows.rs @@ -1,6 +1,3 @@ -//! This is a `WinApi` specific implementation for styling related action. -//! This module is used for non supporting `ANSI` Windows terminals. - use std::sync::Mutex; use crossterm_winapi::{Console, Handle, HandleType, ScreenBuffer}; @@ -10,7 +7,7 @@ use lazy_static::lazy_static; use crate::utils::Result; -use super::super::{Color, Colored, Style}; +use super::super::{Color, Colored}; const FG_GREEN: u16 = wincon::FOREGROUND_GREEN; const FG_RED: u16 = wincon::FOREGROUND_RED; @@ -22,80 +19,98 @@ const BG_RED: u16 = wincon::BACKGROUND_RED; const BG_BLUE: u16 = wincon::BACKGROUND_BLUE; const BG_INTENSITY: u16 = wincon::BACKGROUND_INTENSITY; -/// This struct is a WinApi implementation for color related actions. -pub(crate) struct WinApiColor; +pub(crate) fn set_foreground_color(fg_color: Color) -> Result<()> { + init_console_color()?; -impl WinApiColor { - pub fn new() -> Box { - init_console_color().unwrap(); - Box::from(WinApiColor) + let color_value: u16 = Colored::ForegroundColor(fg_color).into(); + + let screen_buffer = ScreenBuffer::current()?; + let csbi = screen_buffer.info()?; + + // Notice that the color values are stored in wAttribute. + // So we need to use bitwise operators to check if the values exists or to get current console colors. + let mut color: u16; + let attrs = csbi.attributes(); + let bg_color = attrs & 0x0070; + color = color_value | bg_color; + + // background intensity is a separate value in attrs, + // wee need to check if this was applied to the current bg color. + if (attrs & wincon::BACKGROUND_INTENSITY as u16) != 0 { + color = color | wincon::BACKGROUND_INTENSITY as u16; } + + Console::from(**screen_buffer.handle()).set_text_attribute(color)?; + + Ok(()) } -impl Style for WinApiColor { - fn set_fg(&self, fg_color: Color) -> Result<()> { - let color_value: u16 = Colored::Fg(fg_color).into(); +pub(crate) fn set_background_color(bg_color: Color) -> Result<()> { + init_console_color()?; + let color_value: u16 = Colored::BackgroundColor(bg_color).into(); + + let screen_buffer = ScreenBuffer::current()?; + let csbi = screen_buffer.info()?; + + // Notice that the color values are stored in wAttribute. + // So wee need to use bitwise operators to check if the values exists or to get current console colors. + let mut color: u16; + let attrs = csbi.attributes(); + let fg_color = attrs & 0x0007; + color = fg_color | color_value; + + // Foreground intensity is a separate value in attrs, + // So we need to check if this was applied to the current fg color. + if (attrs & wincon::FOREGROUND_INTENSITY as u16) != 0 { + color = color | wincon::FOREGROUND_INTENSITY as u16; + } + + Console::from(**screen_buffer.handle()).set_text_attribute(color)?; + + Ok(()) +} + +pub(crate) fn reset() -> Result<()> { + let original_color = original_console_color(); + + Console::from(Handle::new(HandleType::CurrentOutputHandle)?) + .set_text_attribute(original_color)?; + + Ok(()) +} + +/// Initializes the default console color. It will will be skipped if it has already been initialized. +pub(crate) fn init_console_color() -> Result<()> { + let mut locked_pos = ORIGINAL_CONSOLE_COLOR.lock().unwrap(); + + if locked_pos.is_none() { let screen_buffer = ScreenBuffer::current()?; - let csbi = screen_buffer.info()?; - - // Notice that the color values are stored in wAttribute. - // So we need to use bitwise operators to check if the values exists or to get current console colors. - let mut color: u16; - let attrs = csbi.attributes(); - let bg_color = attrs & 0x0070; - color = color_value | bg_color; - - // background intensity is a separate value in attrs, - // wee need to check if this was applied to the current bg color. - if (attrs & wincon::BACKGROUND_INTENSITY as u16) != 0 { - color = color | wincon::BACKGROUND_INTENSITY as u16; - } - - Console::from(**screen_buffer.handle()).set_text_attribute(color)?; - - Ok(()) + let attr = screen_buffer.info()?.attributes(); + *locked_pos = Some(attr); } - fn set_bg(&self, bg_color: Color) -> Result<()> { - let color_value: u16 = Colored::Bg(bg_color).into(); + Ok(()) +} - let screen_buffer = ScreenBuffer::current()?; - let csbi = screen_buffer.info()?; +/// Returns the original console color, make sure to call `init_console_color` before calling this function. Otherwise this function will panic. +pub(crate) fn original_console_color() -> u16 { + // safe unwrap, initial console color was set with `init_console_color` in `WinApiColor::new()` + ORIGINAL_CONSOLE_COLOR + .lock() + .unwrap() + .expect("Initial console color not set") +} - // Notice that the color values are stored in wAttribute. - // So wee need to use bitwise operators to check if the values exists or to get current console colors. - let mut color: u16; - let attrs = csbi.attributes(); - let fg_color = attrs & 0x0007; - color = fg_color | color_value; - - // Foreground intensity is a separate value in attrs, - // So we need to check if this was applied to the current fg color. - if (attrs & wincon::FOREGROUND_INTENSITY as u16) != 0 { - color = color | wincon::FOREGROUND_INTENSITY as u16; - } - - Console::from(**screen_buffer.handle()).set_text_attribute(color)?; - - Ok(()) - } - - fn reset(&self) -> Result<()> { - let original_color = original_console_color(); - - Console::from(Handle::new(HandleType::CurrentOutputHandle)?) - .set_text_attribute(original_color)?; - - Ok(()) - } +lazy_static! { + static ref ORIGINAL_CONSOLE_COLOR: Mutex> = Mutex::new(None); } impl From for u16 { /// Returns the WinApi color value (u16) from the `Colored` struct. fn from(colored: Colored) -> Self { match colored { - Colored::Fg(color) => { + Colored::ForegroundColor(color) => { match color { Color::Black => 0, Color::DarkGrey => FG_INTENSITY, @@ -128,7 +143,7 @@ impl From for u16 { Color::AnsiValue(_val) => 0, } } - Colored::Bg(color) => { + Colored::BackgroundColor(color) => { match color { Color::Black => 0, Color::DarkGrey => BG_INTENSITY, @@ -163,48 +178,22 @@ impl From for u16 { } } -/// Initializes the default console color. It will will be skipped if it has already been initialized. -fn init_console_color() -> Result<()> { - let mut locked_pos = ORIGINAL_CONSOLE_COLOR.lock().unwrap(); - - if locked_pos.is_none() { - let screen_buffer = ScreenBuffer::current()?; - let attr = screen_buffer.info()?.attributes(); - *locked_pos = Some(attr); - } - - Ok(()) -} - -/// Returns the original console color, make sure to call `init_console_color` before calling this function. Otherwise this function will panic. -fn original_console_color() -> u16 { - // safe unwrap, initial console color was set with `init_console_color` in `WinApiColor::new()` - ORIGINAL_CONSOLE_COLOR - .lock() - .unwrap() - .expect("Initial console color not set") -} - -lazy_static! { - static ref ORIGINAL_CONSOLE_COLOR: Mutex> = Mutex::new(None); -} - #[cfg(test)] mod tests { use super::{ - Color, Colored, WinApiColor, BG_INTENSITY, BG_RED, FG_INTENSITY, FG_RED, - ORIGINAL_CONSOLE_COLOR, + Color, Colored, BG_INTENSITY, BG_RED, FG_INTENSITY, FG_RED, ORIGINAL_CONSOLE_COLOR, }; + use crate::style::sys::windows::set_foreground_color; #[test] fn test_parse_fg_color() { - let colored = Colored::Fg(Color::Red); + let colored = Colored::ForegroundColor(Color::Red); assert_eq!(Into::::into(colored), FG_INTENSITY | FG_RED); } #[test] fn test_parse_bg_color() { - let colored = Colored::Bg(Color::Red); + let colored = Colored::BackgroundColor(Color::Red); assert_eq!(Into::::into(colored), BG_INTENSITY | BG_RED); } @@ -213,7 +202,7 @@ mod tests { assert!(ORIGINAL_CONSOLE_COLOR.lock().unwrap().is_none()); // will call `init_console_color` - let _ = WinApiColor::new(); + set_foreground_color(Color::Blue).unwrap(); assert!(ORIGINAL_CONSOLE_COLOR.lock().unwrap().is_some()); } diff --git a/src/style/traits.rs b/src/style/traits.rs index ad408d5..b8d7653 100644 --- a/src/style/traits.rs +++ b/src/style/traits.rs @@ -12,7 +12,7 @@ use super::StyledContent; /// # Examples /// /// ```no_run -/// use crossterm::Colorize; +/// use crossterm::style::Colorize; /// /// let styled_text = "Red foreground color on blue background.".red().on_blue(); /// println!("{}", styled_text); @@ -60,7 +60,7 @@ pub trait Colorize { /// # Examples /// /// ```no_run -/// use crossterm::Styler; +/// use crossterm::style::Styler; /// /// println!("{}", "Bold text".bold()); /// println!("{}", "Underlined text".underlined());