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 `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

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.
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<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
//! 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;

View File

@ -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.
///
/// # 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.
///
/// # Notes
///
/// This does not always provide a good result.
pub fn available_color_count(&self) -> u16 {
pub fn available_color_count() -> 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<String>);
impl_display!(for PrintStyledContent<&'static str>);
impl_display!(for ResetColor);

View File

@ -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::<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 {
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 {
@ -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<Colored> for String {
fn from(colored: Colored) -> Self {
let mut ansi_value = String::new();
@ -53,7 +31,7 @@ impl From<Colored> 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<Colored> 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<Colored> 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::<String>::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::<String>::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::<String>::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::<String>::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::<String>::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::<String>::into(colored), "38;5;255");
}
}

View File

@ -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<Color>,
pub foreground_color: Option<Color>,
/// The background color.
pub bg_color: Option<Color>,
pub background_color: Option<Color>,
/// List of attributes.
pub attrs: Vec<Attribute>,
pub attributes: Vec<Attribute>,
}
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);
}
}

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 color;

View File

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

View File

@ -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),
}

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 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<D: Display + Clone> Display for StyledContent<D> {
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<D: Display + Clone> Display for StyledContent<D> {
impl<D: Display + Clone> Colorize<D> for StyledContent<D> {
// 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<D: Display + Clone> Styler<D> for StyledContent<D> {
@ -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);
}
}

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 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,19 +19,10 @@ 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<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 color_value: u16 = Colored::ForegroundColor(fg_color).into();
let screen_buffer = ScreenBuffer::current()?;
let csbi = screen_buffer.info()?;
@ -57,8 +45,10 @@ impl Style for WinApiColor {
Ok(())
}
fn set_bg(&self, bg_color: Color) -> Result<()> {
let color_value: u16 = Colored::Bg(bg_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()?;
@ -81,7 +71,7 @@ impl Style for WinApiColor {
Ok(())
}
fn reset(&self) -> Result<()> {
pub(crate) fn reset() -> Result<()> {
let original_color = original_console_color();
Console::from(Handle::new(HandleType::CurrentOutputHandle)?)
@ -89,13 +79,38 @@ impl Style for WinApiColor {
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 {
/// 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<Colored> 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<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)]
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::<u16>::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::<u16>::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());
}

View File

@ -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<D: Display + Clone> {
/// # Examples
///
/// ```no_run
/// use crossterm::Styler;
/// use crossterm::style::Styler;
///
/// println!("{}", "Bold text".bold());
/// println!("{}", "Underlined text".underlined());