Removed old api Style Module (#299)

This commit is contained in:
Timon 2019-10-31 21:02:04 +01:00 committed by GitHub
parent 5c36790187
commit 3e82d6ae1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 273 additions and 468 deletions

View File

@ -26,6 +26,18 @@
- Rename `PrintStyledFont` to `PrintStyledContent` - Rename `PrintStyledFont` to `PrintStyledContent`
- Rename `attr` method to `attribute`. - Rename `attr` method to `attribute`.
- Rename `Attribute::NoInverse` to `NoReverse` - 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 # Version 0.12.1

View File

@ -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. /// A crossterm functionality wrapper.
pub struct Crossterm; pub struct Crossterm;
@ -16,19 +12,4 @@ impl Crossterm {
pub fn input(&self) -> crate::input::TerminalInput { pub fn input(&self) -> crate::input::TerminalInput {
crate::input::TerminalInput::new() 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<D>(&self, val: D) -> crate::style::StyledContent<D>
where
D: Display + Clone,
{
crate::style::ContentStyle::new().apply(val)
}
} }

View File

@ -118,8 +118,8 @@
//! ```no_run //! ```no_run
//! use std::io::{stdout, Write}; //! use std::io::{stdout, Write};
//! use crossterm::{ //! use crossterm::{
//! ExecutableCommand, QueueableCommand, Color, //! ExecutableCommand, QueueableCommand,
//! Colorize, terminal, cursor, style, Result //! terminal, cursor, style::{self, Colorize}, Result
//! }; //! };
//! //!
//! fn main() -> Result<()> { //! fn main() -> Result<()> {
@ -146,8 +146,8 @@
//! ```no_run //! ```no_run
//! use std::io::{stdout, Write}; //! use std::io::{stdout, Write};
//! use crossterm::{ //! use crossterm::{
//! execute, queue, Color, PrintStyledContent, //! execute, queue,
//! Colorize, cursor, terminal, style, Result //! style::{self, Colorize}, cursor, terminal, Result
//! }; //! };
//! //!
//! fn main() -> Result<()> { //! fn main() -> Result<()> {
@ -176,11 +176,6 @@ pub use input::{
pub use screen::{ pub use screen::{
AlternateScreen, EnterAlternateScreen, IntoRawMode, LeaveAlternateScreen, RawScreen, 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 utils::{Command, ErrorKind, ExecutableCommand, Output, QueueableCommand, Result};
pub use self::crossterm::Crossterm; pub use self::crossterm::Crossterm;

View File

@ -25,15 +25,16 @@
//! use std::io::{stdout, Write}; //! use std::io::{stdout, Write};
//! //!
//! use crossterm::{execute, Result, Output}; //! use crossterm::{execute, Result, Output};
//! use crossterm::{SetBg, SetFg, ResetColor, Color, Attribute}; //! use crossterm::style::{SetForegroundColor, SetBackgroundColor, ResetColor, Color, Attribute};
//! //!
//! fn main() -> Result<()> { //! fn main() -> Result<()> {
//! execute!( //! execute!(
//! stdout(), //! stdout(),
//! // Blue foreground //! // Blue foreground
//! SetFg(Color::Blue), //! SetForegroundColor(Color::Blue),
//! // Red background //! // Red background
//! SetBg(Color::Red), //! SetBackgroundColor(Color::Red),
//! // output text
//! Output("Styled text here.".to_string()), //! Output("Styled text here.".to_string()),
//! // Reset to default colors //! // Reset to default colors
//! ResetColor //! 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: //! The [`Colorize`](trait.Colorize.html) trait:
//! //!
//! ```no_run //! ```no_run
//! use crossterm::Colorize; //! use crossterm::style::Colorize;
//! //!
//! println!("{}", "Red foreground color & blue background.".red().on_blue()); //! println!("{}", "Red foreground color & blue background.".red().on_blue());
//! ``` //! ```
@ -66,16 +58,16 @@
//! use std::io::{stdout, Write}; //! use std::io::{stdout, Write};
//! //!
//! use crossterm::{execute, Result, Output}; //! use crossterm::{execute, Result, Output};
//! use crossterm::{SetAttr, Attribute}; //! use crossterm::style::{SetAttribute, Attribute};
//! //!
//! fn main() -> Result<()> { //! fn main() -> Result<()> {
//! execute!( //! execute!(
//! stdout(), //! stdout(),
//! // Set to bold //! // Set to bold
//! SetAttr(Attribute::Bold), //! SetAttribute(Attribute::Bold),
//! Output("Styled text here.".to_string()), //! Output("Styled text here.".to_string()),
//! // Reset all attributes //! // Reset all attributes
//! SetAttr(Attribute::Reset) //! SetAttribute(Attribute::Reset)
//! ) //! )
//! } //! }
//! ``` //! ```
@ -83,7 +75,7 @@
//! The [`Styler`](trait.Styler.html) trait: //! The [`Styler`](trait.Styler.html) trait:
//! //!
//! ```no_run //! ```no_run
//! use crossterm::Styler; //! use crossterm::style::Styler;
//! //!
//! println!("{}", "Bold".bold()); //! println!("{}", "Bold".bold());
//! println!("{}", "Underlined".underlined()); //! println!("{}", "Underlined".underlined());
@ -93,7 +85,7 @@
//! The [`Attribute`](enum.Attribute.html) enum: //! The [`Attribute`](enum.Attribute.html) enum:
//! //!
//! ```no_run //! ```no_run
//! use crossterm::Attribute; //! use crossterm::style::Attribute;
//! //!
//! println!( //! println!(
//! "{} Underlined {} No Underline", //! "{} Underlined {} No Underline",
@ -105,27 +97,25 @@
use std::env; use std::env;
use std::fmt::Display; use std::fmt::Display;
use style::ansi::{self, AnsiColor};
#[cfg(windows)]
use style::winapi::WinApiColor;
use style::Style;
use crate::impl_display; use crate::impl_display;
#[cfg(windows)] use crate::utils::Command;
use crate::utils::supports_ansi;
use crate::utils::{Command, Result};
pub use self::contentstyle::ContentStyle; #[cfg(windows)]
pub use self::enums::{Attribute, Color, Colored}; use crate::Result;
pub use self::styledcontent::StyledContent;
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}; pub use self::traits::{Colorize, Styler};
#[macro_use] #[macro_use]
mod macros; mod macros;
mod contentstyle; mod ansi;
mod content_style;
mod enums; mod enums;
mod style; mod styled_content;
mod styledcontent; mod sys;
mod traits; mod traits;
/// Creates a `StyledContent`. /// Creates a `StyledContent`.
@ -137,7 +127,7 @@ mod traits;
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// use crossterm::{style, Color}; /// use crossterm::style::{style, Color};
/// ///
/// let styled_content = style("Blue colored text on yellow background") /// let styled_content = style("Blue colored text on yellow background")
/// .with(Color::Blue) /// .with(Color::Blue)
@ -154,40 +144,40 @@ where
impl Colorize<&'static str> for &'static str { impl Colorize<&'static str> for &'static str {
// foreground colors // foreground colors
def_str_color!(fg_color: black => Color::Black); def_str_color!(foreground_color: black => Color::Black);
def_str_color!(fg_color: dark_grey => Color::DarkGrey); def_str_color!(foreground_color: dark_grey => Color::DarkGrey);
def_str_color!(fg_color: red => Color::Red); def_str_color!(foreground_color: red => Color::Red);
def_str_color!(fg_color: dark_red => Color::DarkRed); def_str_color!(foreground_color: dark_red => Color::DarkRed);
def_str_color!(fg_color: green => Color::Green); def_str_color!(foreground_color: green => Color::Green);
def_str_color!(fg_color: dark_green => Color::DarkGreen); def_str_color!(foreground_color: dark_green => Color::DarkGreen);
def_str_color!(fg_color: yellow => Color::Yellow); def_str_color!(foreground_color: yellow => Color::Yellow);
def_str_color!(fg_color: dark_yellow => Color::DarkYellow); def_str_color!(foreground_color: dark_yellow => Color::DarkYellow);
def_str_color!(fg_color: blue => Color::Blue); def_str_color!(foreground_color: blue => Color::Blue);
def_str_color!(fg_color: dark_blue => Color::DarkBlue); def_str_color!(foreground_color: dark_blue => Color::DarkBlue);
def_str_color!(fg_color: magenta => Color::Magenta); def_str_color!(foreground_color: magenta => Color::Magenta);
def_str_color!(fg_color: dark_magenta => Color::DarkMagenta); def_str_color!(foreground_color: dark_magenta => Color::DarkMagenta);
def_str_color!(fg_color: cyan => Color::Cyan); def_str_color!(foreground_color: cyan => Color::Cyan);
def_str_color!(fg_color: dark_cyan => Color::DarkCyan); def_str_color!(foreground_color: dark_cyan => Color::DarkCyan);
def_str_color!(fg_color: white => Color::White); def_str_color!(foreground_color: white => Color::White);
def_str_color!(fg_color: grey => Color::Grey); def_str_color!(foreground_color: grey => Color::Grey);
// background colors // background colors
def_str_color!(bg_color: on_black => Color::Black); def_str_color!(background_color: on_black => Color::Black);
def_str_color!(bg_color: on_dark_grey => Color::DarkGrey); def_str_color!(background_color: on_dark_grey => Color::DarkGrey);
def_str_color!(bg_color: on_red => Color::Red); def_str_color!(background_color: on_red => Color::Red);
def_str_color!(bg_color: on_dark_red => Color::DarkRed); def_str_color!(background_color: on_dark_red => Color::DarkRed);
def_str_color!(bg_color: on_green => Color::Green); def_str_color!(background_color: on_green => Color::Green);
def_str_color!(bg_color: on_dark_green => Color::DarkGreen); def_str_color!(background_color: on_dark_green => Color::DarkGreen);
def_str_color!(bg_color: on_yellow => Color::Yellow); def_str_color!(background_color: on_yellow => Color::Yellow);
def_str_color!(bg_color: on_dark_yellow => Color::DarkYellow); def_str_color!(background_color: on_dark_yellow => Color::DarkYellow);
def_str_color!(bg_color: on_blue => Color::Blue); def_str_color!(background_color: on_blue => Color::Blue);
def_str_color!(bg_color: on_dark_blue => Color::DarkBlue); def_str_color!(background_color: on_dark_blue => Color::DarkBlue);
def_str_color!(bg_color: on_magenta => Color::Magenta); def_str_color!(background_color: on_magenta => Color::Magenta);
def_str_color!(bg_color: on_dark_magenta => Color::DarkMagenta); def_str_color!(background_color: on_dark_magenta => Color::DarkMagenta);
def_str_color!(bg_color: on_cyan => Color::Cyan); def_str_color!(background_color: on_cyan => Color::Cyan);
def_str_color!(bg_color: on_dark_cyan => Color::DarkCyan); def_str_color!(background_color: on_dark_cyan => Color::DarkCyan);
def_str_color!(bg_color: on_white => Color::White); def_str_color!(background_color: on_white => Color::White);
def_str_color!(bg_color: on_grey => Color::Grey); def_str_color!(background_color: on_grey => Color::Grey);
} }
impl Styler<&'static str> for &'static str { 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); def_str_attr!(crossed_out => Attribute::CrossedOut);
} }
/// A terminal color.
///
/// # Examples
///
/// 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,
}
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. /// Returns available color count.
/// ///
/// # Notes /// # Notes
/// ///
/// This does not always provide a good result. /// This does not always provide a good result.
pub fn available_color_count(&self) -> u16 { pub fn available_color_count() -> u16 {
env::var("TERM") env::var("TERM")
.map(|x| if x.contains("256color") { 256 } else { 8 }) .map(|x| if x.contains("256color") { 256 } else { 8 })
.unwrap_or(8) .unwrap_or(8)
} }
}
/// Creates a new `TerminalColor`. /// A command that sets the the foreground color.
///
/// # 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.
/// ///
/// See [`Color`](enum.Color.html) for more info. /// See [`Color`](enum.Color.html) for more info.
/// ///
/// # Notes /// # Notes
/// ///
/// Commands must be executed/queued for execution otherwise they do nothing. /// 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; type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType { fn ansi_code(&self) -> Self::AnsiType {
@ -316,20 +223,20 @@ impl Command for SetFg {
#[cfg(windows)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { 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. /// See [`Color`](enum.Color.html) for more info.
/// ///
/// # Notes /// # Notes
/// ///
/// Commands must be executed/queued for execution otherwise they do nothing. /// 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; type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType { fn ansi_code(&self) -> Self::AnsiType {
@ -338,20 +245,20 @@ impl Command for SetBg {
#[cfg(windows)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { 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. /// See [`Attribute`](enum.Attribute.html) for more info.
/// ///
/// # Notes /// # Notes
/// ///
/// Commands must be executed/queued for execution otherwise they do nothing. /// 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; type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType { 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. /// 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 /// # Notes
/// ///
@ -406,13 +313,13 @@ impl Command for ResetColor {
#[cfg(windows)] #[cfg(windows)]
fn execute_winapi(&self) -> Result<()> { fn execute_winapi(&self) -> Result<()> {
WinApiColor::new().reset() sys::windows::reset()
} }
} }
impl_display!(for SetFg); impl_display!(for SetForegroundColor);
impl_display!(for SetBg); impl_display!(for SetBackgroundColor);
impl_display!(for SetAttr); impl_display!(for SetAttribute);
impl_display!(for PrintStyledContent<String>); impl_display!(for PrintStyledContent<String>);
impl_display!(for PrintStyledContent<&'static str>); impl_display!(for PrintStyledContent<&'static str>);
impl_display!(for ResetColor); impl_display!(for ResetColor);

View File

@ -1,17 +1,21 @@
//! This is a ANSI specific implementation for styling related action. //! This is a ANSI specific implementation for styling related action.
//! This module is used for Windows 10 terminals and Unix terminals by default. //! This module is used for Windows 10 terminals and Unix terminals by default.
use crate::utils::Result; use crate::csi;
use crate::{csi, write_cout}; use crate::style::{Attribute, Color, Colored};
use super::super::{Attribute, Color, Colored, Style};
pub(crate) fn set_fg_csi_sequence(fg_color: Color) -> String { pub(crate) fn set_fg_csi_sequence(fg_color: Color) -> String {
format!(csi!("{}m"), Into::<String>::into(Colored::Fg(fg_color))) format!(
csi!("{}m"),
Into::<String>::into(Colored::ForegroundColor(fg_color))
)
} }
pub(crate) fn set_bg_csi_sequence(bg_color: Color) -> String { pub(crate) fn set_bg_csi_sequence(bg_color: Color) -> String {
format!(csi!("{}m"), Into::<String>::into(Colored::Bg(bg_color))) format!(
csi!("{}m"),
Into::<String>::into(Colored::BackgroundColor(bg_color))
)
} }
pub(crate) fn set_attr_csi_sequence(attribute: Attribute) -> String { 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"); 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<Colored> for String { impl From<Colored> for String {
fn from(colored: Colored) -> Self { fn from(colored: Colored) -> Self {
let mut ansi_value = String::new(); let mut ansi_value = String::new();
@ -53,7 +31,7 @@ impl From<Colored> for String {
let color; let color;
match colored { match colored {
Colored::Fg(new_color) => { Colored::ForegroundColor(new_color) => {
if new_color == Color::Reset { if new_color == Color::Reset {
ansi_value.push_str("39"); ansi_value.push_str("39");
return ansi_value; return ansi_value;
@ -62,7 +40,7 @@ impl From<Colored> for String {
color = new_color; color = new_color;
} }
} }
Colored::Bg(new_color) => { Colored::BackgroundColor(new_color) => {
if new_color == Color::Reset { if new_color == Color::Reset {
ansi_value.push_str("49"); ansi_value.push_str("49");
return ansi_value; return ansi_value;
@ -108,41 +86,41 @@ impl From<Colored> for String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Color, Colored}; use crate::style::{Color, Colored};
#[test] #[test]
fn test_parse_fg_color() { fn test_parse_fg_color() {
let colored = Colored::Fg(Color::Red); let colored = Colored::ForegroundColor(Color::Red);
assert_eq!(Into::<String>::into(colored), "38;5;9"); assert_eq!(Into::<String>::into(colored), "38;5;9");
} }
#[test] #[test]
fn test_parse_bg_color() { fn test_parse_bg_color() {
let colored = Colored::Bg(Color::Red); let colored = Colored::BackgroundColor(Color::Red);
assert_eq!(Into::<String>::into(colored), "48;5;9"); assert_eq!(Into::<String>::into(colored), "48;5;9");
} }
#[test] #[test]
fn test_parse_reset_fg_color() { fn test_parse_reset_fg_color() {
let colored = Colored::Fg(Color::Reset); let colored = Colored::ForegroundColor(Color::Reset);
assert_eq!(Into::<String>::into(colored), "39"); assert_eq!(Into::<String>::into(colored), "39");
} }
#[test] #[test]
fn test_parse_reset_bg_color() { fn test_parse_reset_bg_color() {
let colored = Colored::Bg(Color::Reset); let colored = Colored::BackgroundColor(Color::Reset);
assert_eq!(Into::<String>::into(colored), "49"); assert_eq!(Into::<String>::into(colored), "49");
} }
#[test] #[test]
fn test_parse_fg_rgb_color() { 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::<String>::into(colored), "48;2;1;2;3"); assert_eq!(Into::<String>::into(colored), "48;2;1;2;3");
} }
#[test] #[test]
fn test_parse_fg_ansi_color() { fn test_parse_fg_ansi_color() {
let colored = Colored::Fg(Color::AnsiValue(255)); let colored = Colored::ForegroundColor(Color::AnsiValue(255));
assert_eq!(Into::<String>::into(colored), "38;5;255"); assert_eq!(Into::<String>::into(colored), "38;5;255");
} }
} }

View File

@ -2,17 +2,17 @@
use std::fmt::Display; use std::fmt::Display;
use super::{Attribute, Color, StyledContent}; use crate::style::{Attribute, Color, StyledContent};
/// A content style. /// A content style.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct ContentStyle { pub struct ContentStyle {
/// The foreground color. /// The foreground color.
pub fg_color: Option<Color>, pub foreground_color: Option<Color>,
/// The background color. /// The background color.
pub bg_color: Option<Color>, pub background_color: Option<Color>,
/// List of attributes. /// List of attributes.
pub attrs: Vec<Attribute>, pub attributes: Vec<Attribute>,
} }
impl ContentStyle { impl ContentStyle {
@ -28,13 +28,13 @@ impl ContentStyle {
/// Sets the background color. /// Sets the background color.
pub fn background(mut self, color: Color) -> ContentStyle { pub fn background(mut self, color: Color) -> ContentStyle {
self.bg_color = Some(color); self.background_color = Some(color);
self self
} }
/// Sets the foreground color. /// Sets the foreground color.
pub fn foreground(mut self, color: Color) -> ContentStyle { pub fn foreground(mut self, color: Color) -> ContentStyle {
self.fg_color = Some(color); self.foreground_color = Some(color);
self self
} }
@ -42,14 +42,14 @@ impl ContentStyle {
/// ///
/// You can add more attributes by calling this method multiple times. /// You can add more attributes by calling this method multiple times.
pub fn attribute(mut self, attr: Attribute) -> ContentStyle { pub fn attribute(mut self, attr: Attribute) -> ContentStyle {
self.attrs.push(attr); self.attributes.push(attr);
self self
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Attribute, Color, ContentStyle}; use crate::style::{Attribute, Color, ContentStyle};
#[test] #[test]
fn test_set_fg_bg_add_attr() { fn test_set_fg_bg_add_attr() {
@ -58,9 +58,9 @@ mod tests {
.background(Color::Red) .background(Color::Red)
.attribute(Attribute::Reset); .attribute(Attribute::Reset);
assert_eq!(content_style.fg_color, Some(Color::Blue)); assert_eq!(content_style.foreground_color, Some(Color::Blue));
assert_eq!(content_style.bg_color, Some(Color::Red)); assert_eq!(content_style.background_color, Some(Color::Red));
assert_eq!(content_style.attrs[0], Attribute::Reset); assert_eq!(content_style.attributes[0], Attribute::Reset);
} }
#[test] #[test]
@ -72,8 +72,8 @@ mod tests {
let styled_content = content_style.apply("test"); let styled_content = content_style.apply("test");
assert_eq!(styled_content.style().fg_color, Some(Color::Blue)); assert_eq!(styled_content.style().foreground_color, Some(Color::Blue));
assert_eq!(styled_content.style().bg_color, Some(Color::Red)); assert_eq!(styled_content.style().background_color, Some(Color::Red));
assert_eq!(styled_content.style().attrs[0], Attribute::Reset); assert_eq!(styled_content.style().attributes[0], Attribute::Reset);
} }
} }

View File

@ -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 attribute;
mod color; mod color;

View File

@ -3,7 +3,7 @@ use std::fmt::Display;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::super::SetAttr; use super::super::SetAttribute;
/// Represents an attribute. /// Represents an attribute.
/// ///
@ -37,7 +37,7 @@ use super::super::SetAttr;
/// Basic usage: /// Basic usage:
/// ///
/// ```no_run /// ```no_run
/// use crossterm::Attribute; /// use crossterm::style::Attribute;
/// ///
/// println!( /// println!(
/// "{} Underlined {} No Underline", /// "{} Underlined {} No Underline",
@ -49,7 +49,7 @@ use super::super::SetAttr;
/// Style existing text: /// Style existing text:
/// ///
/// ```no_run /// ```no_run
/// use crossterm::Styler; /// use crossterm::style::Styler;
/// ///
/// println!("{}", "Bold text".bold()); /// println!("{}", "Bold text".bold());
/// println!("{}", "Underlined text".underlined()); /// println!("{}", "Underlined text".underlined());
@ -115,7 +115,7 @@ pub enum Attribute {
impl Display for Attribute { impl Display for Attribute {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
write!(f, "{}", SetAttr(*self))?; write!(f, "{}", SetAttribute(*self))?;
Ok(()) Ok(())
} }
} }

View File

@ -1,46 +1,10 @@
use std::fmt::Display; use crate::style::Color;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::{super::color, color::Color};
/// Represents a foreground or a background 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)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub enum Colored { pub(crate) enum Colored {
/// A foreground color. /// A foreground color.
Fg(Color), ForegroundColor(Color),
/// A background color. /// A background color.
Bg(Color), BackgroundColor(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(())
}
} }

View File

@ -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<()>;
}

View File

@ -5,14 +5,17 @@ use std::result;
use crate::queue; 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. /// A styled content.
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use crossterm::{style, Color, Attribute}; /// use crossterm::style::{style, Color, Attribute};
/// ///
/// let styled = style("Hello there") /// let styled = style("Hello there")
/// .with(Color::Yellow) /// .with(Color::Yellow)
@ -70,17 +73,17 @@ impl<D: Display + Clone> Display for StyledContent<D> {
fn fmt(&self, f: &mut Formatter<'_>) -> result::Result<(), fmt::Error> { fn fmt(&self, f: &mut Formatter<'_>) -> result::Result<(), fmt::Error> {
let mut reset = false; let mut reset = false;
if let Some(bg) = self.style.bg_color { if let Some(bg) = self.style.background_color {
queue!(f, SetBg(bg)).map_err(|_| fmt::Error)?; queue!(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
reset = true; reset = true;
} }
if let Some(fg) = self.style.fg_color { if let Some(fg) = self.style.foreground_color {
queue!(f, SetFg(fg)).map_err(|_| fmt::Error)?; queue!(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
reset = true; reset = true;
} }
for attr in self.style.attrs.iter() { for attr in self.style.attributes.iter() {
queue!(f, SetAttr(*attr)).map_err(|_| fmt::Error)?; queue!(f, SetAttribute(*attr)).map_err(|_| fmt::Error)?;
reset = true; reset = true;
} }
@ -96,40 +99,40 @@ impl<D: Display + Clone> Display for StyledContent<D> {
impl<D: Display + Clone> Colorize<D> for StyledContent<D> { impl<D: Display + Clone> Colorize<D> for StyledContent<D> {
// foreground colors // foreground colors
def_color!(fg_color: black => Color::Black); def_color!(foreground_color: black => Color::Black);
def_color!(fg_color: dark_grey => Color::DarkGrey); def_color!(foreground_color: dark_grey => Color::DarkGrey);
def_color!(fg_color: red => Color::Red); def_color!(foreground_color: red => Color::Red);
def_color!(fg_color: dark_red => Color::DarkRed); def_color!(foreground_color: dark_red => Color::DarkRed);
def_color!(fg_color: green => Color::Green); def_color!(foreground_color: green => Color::Green);
def_color!(fg_color: dark_green => Color::DarkGreen); def_color!(foreground_color: dark_green => Color::DarkGreen);
def_color!(fg_color: yellow => Color::Yellow); def_color!(foreground_color: yellow => Color::Yellow);
def_color!(fg_color: dark_yellow => Color::DarkYellow); def_color!(foreground_color: dark_yellow => Color::DarkYellow);
def_color!(fg_color: blue => Color::Blue); def_color!(foreground_color: blue => Color::Blue);
def_color!(fg_color: dark_blue => Color::DarkBlue); def_color!(foreground_color: dark_blue => Color::DarkBlue);
def_color!(fg_color: magenta => Color::Magenta); def_color!(foreground_color: magenta => Color::Magenta);
def_color!(fg_color: dark_magenta => Color::DarkMagenta); def_color!(foreground_color: dark_magenta => Color::DarkMagenta);
def_color!(fg_color: cyan => Color::Cyan); def_color!(foreground_color: cyan => Color::Cyan);
def_color!(fg_color: dark_cyan => Color::DarkCyan); def_color!(foreground_color: dark_cyan => Color::DarkCyan);
def_color!(fg_color: white => Color::White); def_color!(foreground_color: white => Color::White);
def_color!(fg_color: grey => Color::Grey); def_color!(foreground_color: grey => Color::Grey);
// background colors // background colors
def_color!(bg_color: on_black => Color::Black); def_color!(background_color: on_black => Color::Black);
def_color!(bg_color: on_dark_grey => Color::DarkGrey); def_color!(background_color: on_dark_grey => Color::DarkGrey);
def_color!(bg_color: on_red => Color::Red); def_color!(background_color: on_red => Color::Red);
def_color!(bg_color: on_dark_red => Color::DarkRed); def_color!(background_color: on_dark_red => Color::DarkRed);
def_color!(bg_color: on_green => Color::Green); def_color!(background_color: on_green => Color::Green);
def_color!(bg_color: on_dark_green => Color::DarkGreen); def_color!(background_color: on_dark_green => Color::DarkGreen);
def_color!(bg_color: on_yellow => Color::Yellow); def_color!(background_color: on_yellow => Color::Yellow);
def_color!(bg_color: on_dark_yellow => Color::DarkYellow); def_color!(background_color: on_dark_yellow => Color::DarkYellow);
def_color!(bg_color: on_blue => Color::Blue); def_color!(background_color: on_blue => Color::Blue);
def_color!(bg_color: on_dark_blue => Color::DarkBlue); def_color!(background_color: on_dark_blue => Color::DarkBlue);
def_color!(bg_color: on_magenta => Color::Magenta); def_color!(background_color: on_magenta => Color::Magenta);
def_color!(bg_color: on_dark_magenta => Color::DarkMagenta); def_color!(background_color: on_dark_magenta => Color::DarkMagenta);
def_color!(bg_color: on_cyan => Color::Cyan); def_color!(background_color: on_cyan => Color::Cyan);
def_color!(bg_color: on_dark_cyan => Color::DarkCyan); def_color!(background_color: on_dark_cyan => Color::DarkCyan);
def_color!(bg_color: on_white => Color::White); def_color!(background_color: on_white => Color::White);
def_color!(bg_color: on_grey => Color::Grey); def_color!(background_color: on_grey => Color::Grey);
} }
impl<D: Display + Clone> Styler<D> for StyledContent<D> { impl<D: Display + Clone> Styler<D> for StyledContent<D> {
@ -164,10 +167,10 @@ mod tests {
.on(Color::Magenta) .on(Color::Magenta)
.attribute(Attribute::NoItalic); .attribute(Attribute::NoItalic);
assert_eq!(styled_content.style.fg_color, Some(Color::Green)); assert_eq!(styled_content.style.foreground_color, Some(Color::Green));
assert_eq!(styled_content.style.bg_color, Some(Color::Magenta)); assert_eq!(styled_content.style.background_color, Some(Color::Magenta));
assert_eq!(styled_content.style.attrs.len(), 2); assert_eq!(styled_content.style.attributes.len(), 2);
assert_eq!(styled_content.style.attrs[0], Attribute::Reset); assert_eq!(styled_content.style.attributes[0], Attribute::Reset);
assert_eq!(styled_content.style.attrs[1], Attribute::NoItalic); assert_eq!(styled_content.style.attributes[1], Attribute::NoItalic);
} }
} }

2
src/style/sys.rs Normal file
View File

@ -0,0 +1,2 @@
#[cfg(windows)]
pub(crate) mod windows;

View File

@ -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 std::sync::Mutex;
use crossterm_winapi::{Console, Handle, HandleType, ScreenBuffer}; use crossterm_winapi::{Console, Handle, HandleType, ScreenBuffer};
@ -10,7 +7,7 @@ use lazy_static::lazy_static;
use crate::utils::Result; use crate::utils::Result;
use super::super::{Color, Colored, Style}; use super::super::{Color, Colored};
const FG_GREEN: u16 = wincon::FOREGROUND_GREEN; const FG_GREEN: u16 = wincon::FOREGROUND_GREEN;
const FG_RED: u16 = wincon::FOREGROUND_RED; const FG_RED: u16 = wincon::FOREGROUND_RED;
@ -22,19 +19,10 @@ const BG_RED: u16 = wincon::BACKGROUND_RED;
const BG_BLUE: u16 = wincon::BACKGROUND_BLUE; const BG_BLUE: u16 = wincon::BACKGROUND_BLUE;
const BG_INTENSITY: u16 = wincon::BACKGROUND_INTENSITY; const BG_INTENSITY: u16 = wincon::BACKGROUND_INTENSITY;
/// This struct is a WinApi implementation for color related actions. pub(crate) fn set_foreground_color(fg_color: Color) -> Result<()> {
pub(crate) struct WinApiColor; init_console_color()?;
impl WinApiColor { let color_value: u16 = Colored::ForegroundColor(fg_color).into();
pub fn new() -> Box<WinApiColor> {
init_console_color().unwrap();
Box::from(WinApiColor)
}
}
impl Style for WinApiColor {
fn set_fg(&self, fg_color: Color) -> Result<()> {
let color_value: u16 = Colored::Fg(fg_color).into();
let screen_buffer = ScreenBuffer::current()?; let screen_buffer = ScreenBuffer::current()?;
let csbi = screen_buffer.info()?; let csbi = screen_buffer.info()?;
@ -57,8 +45,10 @@ impl Style for WinApiColor {
Ok(()) Ok(())
} }
fn set_bg(&self, bg_color: Color) -> Result<()> { pub(crate) fn set_background_color(bg_color: Color) -> Result<()> {
let color_value: u16 = Colored::Bg(bg_color).into(); init_console_color()?;
let color_value: u16 = Colored::BackgroundColor(bg_color).into();
let screen_buffer = ScreenBuffer::current()?; let screen_buffer = ScreenBuffer::current()?;
let csbi = screen_buffer.info()?; let csbi = screen_buffer.info()?;
@ -81,7 +71,7 @@ impl Style for WinApiColor {
Ok(()) Ok(())
} }
fn reset(&self) -> Result<()> { pub(crate) fn reset() -> Result<()> {
let original_color = original_console_color(); let original_color = original_console_color();
Console::from(Handle::new(HandleType::CurrentOutputHandle)?) Console::from(Handle::new(HandleType::CurrentOutputHandle)?)
@ -89,13 +79,38 @@ impl Style for WinApiColor {
Ok(()) 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 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.
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")
}
lazy_static! {
static ref ORIGINAL_CONSOLE_COLOR: Mutex<Option<u16>> = Mutex::new(None);
} }
impl From<Colored> for u16 { impl From<Colored> for u16 {
/// Returns the WinApi color value (u16) from the `Colored` struct. /// Returns the WinApi color value (u16) from the `Colored` struct.
fn from(colored: Colored) -> Self { fn from(colored: Colored) -> Self {
match colored { match colored {
Colored::Fg(color) => { Colored::ForegroundColor(color) => {
match color { match color {
Color::Black => 0, Color::Black => 0,
Color::DarkGrey => FG_INTENSITY, Color::DarkGrey => FG_INTENSITY,
@ -128,7 +143,7 @@ impl From<Colored> for u16 {
Color::AnsiValue(_val) => 0, Color::AnsiValue(_val) => 0,
} }
} }
Colored::Bg(color) => { Colored::BackgroundColor(color) => {
match color { match color {
Color::Black => 0, Color::Black => 0,
Color::DarkGrey => BG_INTENSITY, Color::DarkGrey => BG_INTENSITY,
@ -163,48 +178,22 @@ impl From<Colored> 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<Option<u16>> = Mutex::new(None);
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{ use super::{
Color, Colored, WinApiColor, BG_INTENSITY, BG_RED, FG_INTENSITY, FG_RED, Color, Colored, BG_INTENSITY, BG_RED, FG_INTENSITY, FG_RED, ORIGINAL_CONSOLE_COLOR,
ORIGINAL_CONSOLE_COLOR,
}; };
use crate::style::sys::windows::set_foreground_color;
#[test] #[test]
fn test_parse_fg_color() { fn test_parse_fg_color() {
let colored = Colored::Fg(Color::Red); let colored = Colored::ForegroundColor(Color::Red);
assert_eq!(Into::<u16>::into(colored), FG_INTENSITY | FG_RED); assert_eq!(Into::<u16>::into(colored), FG_INTENSITY | FG_RED);
} }
#[test] #[test]
fn test_parse_bg_color() { fn test_parse_bg_color() {
let colored = Colored::Bg(Color::Red); let colored = Colored::BackgroundColor(Color::Red);
assert_eq!(Into::<u16>::into(colored), BG_INTENSITY | BG_RED); assert_eq!(Into::<u16>::into(colored), BG_INTENSITY | BG_RED);
} }
@ -213,7 +202,7 @@ mod tests {
assert!(ORIGINAL_CONSOLE_COLOR.lock().unwrap().is_none()); assert!(ORIGINAL_CONSOLE_COLOR.lock().unwrap().is_none());
// will call `init_console_color` // will call `init_console_color`
let _ = WinApiColor::new(); set_foreground_color(Color::Blue).unwrap();
assert!(ORIGINAL_CONSOLE_COLOR.lock().unwrap().is_some()); assert!(ORIGINAL_CONSOLE_COLOR.lock().unwrap().is_some());
} }

View File

@ -12,7 +12,7 @@ use super::StyledContent;
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// use crossterm::Colorize; /// use crossterm::style::Colorize;
/// ///
/// let styled_text = "Red foreground color on blue background.".red().on_blue(); /// let styled_text = "Red foreground color on blue background.".red().on_blue();
/// println!("{}", styled_text); /// println!("{}", styled_text);
@ -60,7 +60,7 @@ pub trait Colorize<D: Display + Clone> {
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// use crossterm::Styler; /// use crossterm::style::Styler;
/// ///
/// println!("{}", "Bold text".bold()); /// println!("{}", "Bold text".bold());
/// println!("{}", "Underlined text".underlined()); /// println!("{}", "Underlined text".underlined());