Skip to content

Commit

Permalink
Unify Colorize and Styler as Stylize (#571)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kestrer authored Jun 10, 2021
1 parent e126044 commit 0e8be6a
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 454 deletions.
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
//! use std::io::{stdout, Write};
//! use crossterm::{
//! ExecutableCommand, QueueableCommand,
//! terminal, cursor, style::{self, Colorize}, Result
//! terminal, cursor, style::{self, Stylize}, Result
//! };
//!
//! fn main() -> Result<()> {
Expand Down Expand Up @@ -204,7 +204,7 @@
//! use std::io::{stdout, Write};
//! use crossterm::{
//! execute, queue,
//! style::{self, Colorize}, cursor, terminal, Result
//! style::{self, Stylize}, cursor, terminal, Result
//! };
//!
//! fn main() -> Result<()> {
Expand Down
76 changes: 48 additions & 28 deletions src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@
//!
//! Functions:
//!
//! Using functions from [`Colorize`](trait.Colorize.html) on a `String` or `&'static str` to color it.
//! Using functions from [`Stylize`](crate::style::Stylize) on a `String` or `&'static str` to color
//! it.
//!
//! ```no_run
//! use crossterm::style::Colorize;
//! use crossterm::style::Stylize;
//!
//! println!("{}", "Red foreground color & blue background.".red().on_blue());
//! ```
Expand Down Expand Up @@ -86,10 +87,11 @@
//!
//! Functions:
//!
//! Using [`Styler`](trait.Styler.html) functions on a `String` or `&'static str` to set attributes to it.
//! Using [`Stylize`](crate::style::Stylize) functions on a `String` or `&'static str` to set
//! attributes to it.
//!
//! ```no_run
//! use crossterm::style::Styler;
//! use crossterm::style::Stylize;
//!
//! println!("{}", "Bold".bold());
//! println!("{}", "Underlined".underlined());
Expand All @@ -115,6 +117,7 @@ use std::{
fmt::{self, Display},
};

use crate::command::execute_fmt;
#[cfg(windows)]
use crate::Result;
use crate::{csi, impl_display, Command};
Expand All @@ -123,17 +126,15 @@ pub use self::{
attributes::Attributes,
content_style::ContentStyle,
styled_content::StyledContent,
traits::{Colorize, Styler},
stylize::Stylize,
types::{Attribute, Color, Colored, Colors},
};

#[macro_use]
mod macros;
mod attributes;
mod content_style;
mod styled_content;
mod stylize;
mod sys;
mod traits;
mod types;

/// Creates a `StyledContent`.
Expand All @@ -145,7 +146,7 @@ mod types;
/// # Examples
///
/// ```no_run
/// use crossterm::style::{style, Color};
/// use crossterm::style::{style, Stylize, Color};
///
/// let styled_content = style("Blue colored text on yellow background")
/// .with(Color::Blue)
Expand All @@ -157,24 +158,6 @@ pub fn style<D: Display>(val: D) -> StyledContent<D> {
ContentStyle::new().apply(val)
}

impl_colorize!(String);
impl_colorize!(char);

// We do actually need the parentheses here because the macro doesn't work without them otherwise
// This is probably a bug somewhere in the compiler, but it isn't that big a deal.
#[allow(unused_parens)]
impl<'a> Colorize<&'a str> for &'a str {
impl_colorize_callback!(def_color_base!((&'a str)));
}

impl_styler!(String);
impl_styler!(char);

#[allow(unused_parens)]
impl<'a> Styler<&'a str> for &'a str {
impl_styler_callback!(def_attr_base!((&'a str)));
}

/// Returns available color count.
///
/// # Notes
Expand Down Expand Up @@ -342,7 +325,44 @@ pub struct PrintStyledContent<D: Display>(pub StyledContent<D>);

impl<D: Display> Command for PrintStyledContent<D> {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
write!(f, "{}", self.0)
let style = self.0.style();

let mut reset_background = false;
let mut reset_foreground = false;
let mut reset = false;

if let Some(bg) = style.background_color {
execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
reset_background = true;
}
if let Some(fg) = style.foreground_color {
execute_fmt(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
reset_foreground = true;
}

if !style.attributes.is_empty() {
execute_fmt(f, SetAttributes(style.attributes)).map_err(|_| fmt::Error)?;
reset = true;
}

write!(f, "{}", self.0.content())?;

if reset {
// NOTE: This will reset colors even though self has no colors, hence produce unexpected
// resets.
// TODO: reset the set attributes only.
execute_fmt(f, ResetColor).map_err(|_| fmt::Error)?;
} else {
// NOTE: Since the above bug, we do not need to reset colors when we reset attributes.
if reset_background {
execute_fmt(f, SetBackgroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
}
if reset_foreground {
execute_fmt(f, SetForegroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
}
}

Ok(())
}

#[cfg(windows)]
Expand Down
61 changes: 7 additions & 54 deletions src/style/content_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::fmt::Display;

use crate::style::{Attribute, Attributes, Color, StyledContent};
use crate::style::{Attributes, Color, StyledContent};

/// The style that can be put on content.
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
Expand All @@ -27,62 +27,15 @@ impl ContentStyle {
pub fn new() -> ContentStyle {
ContentStyle::default()
}
}

/// Sets the background color.
#[inline]
pub fn background(self, color: Color) -> ContentStyle {
Self {
background_color: Some(color),
..self
}
}

/// Sets the foreground color.
#[inline]
pub fn foreground(self, color: Color) -> ContentStyle {
Self {
foreground_color: Some(color),
..self
}
}

/// Adds the attribute.
///
/// You can add more attributes by calling this method multiple times.
#[inline]
pub fn attribute(mut self, attr: Attribute) -> ContentStyle {
self.attributes.set(attr);
impl AsRef<ContentStyle> for ContentStyle {
fn as_ref(&self) -> &Self {
self
}
}

#[cfg(test)]
mod tests {
use crate::style::{Attribute, Color, ContentStyle};

#[test]
fn test_set_fg_bg_add_attr() {
let content_style = ContentStyle::new()
.foreground(Color::Blue)
.background(Color::Red)
.attribute(Attribute::Bold);

assert_eq!(content_style.foreground_color, Some(Color::Blue));
assert_eq!(content_style.background_color, Some(Color::Red));
assert!(content_style.attributes.has(Attribute::Bold));
}

#[test]
fn test_apply_content_style_to_text() {
let content_style = ContentStyle::new()
.foreground(Color::Blue)
.background(Color::Red)
.attribute(Attribute::Reset);

let styled_content = content_style.apply("test");

assert_eq!(styled_content.style().foreground_color, Some(Color::Blue));
assert_eq!(styled_content.style().background_color, Some(Color::Red));
assert!(styled_content.style().attributes.has(Attribute::Reset));
impl AsMut<ContentStyle> for ContentStyle {
fn as_mut(&mut self) -> &mut Self {
self
}
}
Loading

0 comments on commit 0e8be6a

Please sign in to comment.