Refactor the Style Module (#291)

This commit is contained in:
ebroto 2019-10-27 21:07:09 +01:00 committed by Timon
parent 0479d68f50
commit ea7130a419
11 changed files with 217 additions and 194 deletions

View File

@ -14,6 +14,11 @@
- Rename `ResetPos` to `ResetPosition`
- Rename `SavePos` to `SavePosition`
- Remove re-export cursor module types at root level, are now accessible from `crossterm::cursor`
- `style module`
- Rename `ObjectStyle` to `ContentStyle`. Now full names are used for methods.
- Rename `StyledObject` to `StyledContent` and made members private.
- Rename `attr` method to `attribute`.
- Rename `Attribute::NoInverse` to `NoReverse`
# Version 0.12.1

View File

@ -20,7 +20,6 @@ see [Tested Terminals](#tested-terminals) for more info).
* [Tested Terminals](#tested-terminals)
* [Getting Started](#getting-started)
* [Feature Flags](#feature-flags)
* [`crossterm` vs `crossterm_*` crates](#crossterm-vs-crossterm_-crates)
* [Other Resources](#other-resources)
* [Used By](#used-by)
* [Contributing](#contributing)

View File

@ -28,12 +28,12 @@ impl Crossterm {
crate::style::TerminalColor::new()
}
/// Creates a new `StyledObject`.
/// Creates a new `StyledContent`.
#[cfg(feature = "style")]
pub fn style<D>(&self, val: D) -> crate::style::StyledObject<D>
pub fn style<D>(&self, val: D) -> crate::style::StyledContent<D>
where
D: Display + Clone,
{
crate::style::ObjectStyle::new().apply_to(val)
crate::style::ContentStyle::new().apply(val)
}
}

View File

@ -177,8 +177,8 @@ pub use screen::{
};
#[cfg(feature = "style")]
pub use style::{
color, style, Attribute, Color, Colored, Colorize, ObjectStyle, PrintStyledFont, ResetColor,
SetAttr, SetBg, SetFg, StyledObject, Styler, TerminalColor,
color, style, Attribute, Color, Colored, Colorize, ContentStyle, PrintStyledFont, ResetColor,
SetAttr, SetBg, SetFg, StyledContent, Styler, TerminalColor,
};
#[cfg(feature = "terminal")]
pub use terminal::{terminal, Clear, ClearType, ScrollDown, ScrollUp, SetSize, Terminal};

View File

@ -115,41 +115,41 @@ use crate::impl_display;
use crate::utils::supports_ansi;
use crate::utils::{Command, Result};
pub use self::contentstyle::ContentStyle;
pub use self::enums::{Attribute, Color, Colored};
pub use self::objectstyle::ObjectStyle;
pub use self::styledobject::StyledObject;
pub use self::styledcontent::StyledContent;
pub use self::traits::{Colorize, Styler};
#[macro_use]
mod macros;
mod contentstyle;
mod enums;
mod objectstyle;
mod style;
mod styledobject;
mod styledcontent;
mod traits;
/// Creates a `StyledObject`.
/// Creates a `StyledContent`.
///
/// This could be used to style any type that implements `Display` with colors and text attributes.
///
/// See [`StyledObject`](struct.StyledObject.html) for more info.
/// See [`StyledContent`](struct.StyledContent.html) for more info.
///
/// # Examples
///
/// ```no_run
/// use crossterm::{style, Color};
///
/// let styled_object = style("Blue colored text on yellow background")
/// let styled_content = style("Blue colored text on yellow background")
/// .with(Color::Blue)
/// .on(Color::Yellow);
///
/// println!("{}", styled_object);
/// println!("{}", styled_content);
/// ```
pub fn style<'a, D: 'a>(val: D) -> StyledObject<D>
pub fn style<'a, D: 'a>(val: D) -> StyledContent<D>
where
D: Display + Clone,
{
ObjectStyle::new().apply_to(val)
ContentStyle::new().apply(val)
}
impl Colorize<&'static str> for &'static str {
@ -365,20 +365,20 @@ impl Command for SetAttr {
}
}
/// A command to print the styled object.
/// A command to print the styled content.
///
/// See [`StyledObject`](struct.StyledObject.html) for more info.
/// See [`StyledContent`](struct.StyledContent.html) for more info.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
pub struct PrintStyledFont<D: Display + Clone>(pub StyledObject<D>);
pub struct PrintStyledFont<D: Display + Clone>(pub StyledContent<D>);
impl<D> Command for PrintStyledFont<D>
where
D: Display + Clone,
{
type AnsiType = StyledObject<D>;
type AnsiType = StyledContent<D>;
fn ansi_code(&self) -> Self::AnsiType {
self.0.clone()

79
src/style/contentstyle.rs Normal file
View File

@ -0,0 +1,79 @@
//! This module contains the `content style` that can be applied to an `styled content`.
use std::fmt::Display;
use super::{Attribute, Color, StyledContent};
/// A content style.
#[derive(Debug, Clone, Default)]
pub struct ContentStyle {
/// The foreground color.
pub fg_color: Option<Color>,
/// The background color.
pub bg_color: Option<Color>,
/// List of attributes.
pub attrs: Vec<Attribute>,
}
impl ContentStyle {
/// Creates a `StyledContent` by applying the style to the given `val`.
pub fn apply<D: Display + Clone>(&self, val: D) -> StyledContent<D> {
StyledContent::new(self.clone(), val)
}
/// Creates a new `ContentStyle`.
pub fn new() -> ContentStyle {
ContentStyle::default()
}
/// Sets the background color.
pub fn background(mut self, color: Color) -> ContentStyle {
self.bg_color = Some(color);
self
}
/// Sets the foreground color.
pub fn foreground(mut self, color: Color) -> ContentStyle {
self.fg_color = Some(color);
self
}
/// Adds the attribute.
///
/// You can add more attributes by calling this method multiple times.
pub fn attribute(mut self, attr: Attribute) -> ContentStyle {
self.attrs.push(attr);
self
}
}
#[cfg(test)]
mod tests {
use crate::{Attribute, Color, ContentStyle};
#[test]
fn test_set_fg_bg_add_attr() {
let content_style = ContentStyle::new()
.foreground(Color::Blue)
.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);
}
#[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().fg_color, Some(Color::Blue));
assert_eq!(styled_content.style().bg_color, Some(Color::Red));
assert_eq!(styled_content.style().attrs[0], Attribute::Reset);
}
}

View File

@ -93,7 +93,7 @@ pub enum Attribute {
/// Turns off the text blinking (`SlowBlink` or `RapidBlink`).
NoBlink = 25,
/// Turns off the `Reverse` attribute.
NoInverse = 27, // TODO Shouldn't we rename this to `NoReverse`? Or `Reverse` to `Inverse`?
NoReverse = 27,
/// Turns off the `Hidden` attribute.
NoHidden = 28,
/// Turns off the `CrossedOut` attribute.

View File

@ -1,46 +1,46 @@
macro_rules! def_attr {
($name:ident => $attr:path) => {
fn $name(self) -> StyledObject<D> {
self.attr($attr)
fn $name(self) -> StyledContent<D> {
self.attribute($attr)
}
};
}
macro_rules! def_color {
($side:ident: $name:ident => $color:path) => {
fn $name(self) -> StyledObject<D> {
StyledObject {
object_style: ObjectStyle {
fn $name(self) -> StyledContent<D> {
StyledContent::new(
ContentStyle {
$side: Some($color),
..self.object_style
..self.style
},
..self
}
self.content
)
}
};
}
macro_rules! def_str_color {
($side:ident: $name:ident => $color:path) => {
fn $name(self) -> StyledObject< &'static str> {
StyledObject {
object_style: ObjectStyle {
fn $name(self) -> StyledContent< &'static str> {
StyledContent::new(
ContentStyle {
$side: Some($color),
..Default::default()
},
content: self
}
self
)
}
};
}
macro_rules! def_str_attr {
($name:ident => $color:path) => {
fn $name(self) -> StyledObject<&'static str> {
StyledObject {
object_style: Default::default(),
content: self,
}
fn $name(self) -> StyledContent<&'static str> {
StyledContent::new(
Default::default(),
self
)
}
}
}

View File

@ -1,77 +0,0 @@
//! This module contains the `object style` that can be applied to an `styled object`.
use std::fmt::Display;
use super::{Attribute, Color, StyledObject};
/// An object style.
#[derive(Debug, Clone, Default)]
pub struct ObjectStyle {
/// The foreground color.
pub fg_color: Option<Color>,
/// The background color.
pub bg_color: Option<Color>,
/// List of attributes.
pub attrs: Vec<Attribute>,
}
impl ObjectStyle {
/// Creates a `StyledObject` by applying the style to the given `val`.
pub fn apply_to<D: Display + Clone>(&self, val: D) -> StyledObject<D> {
StyledObject {
object_style: self.clone(),
content: val,
}
}
/// Creates a new `ObjectStyle`.
pub fn new() -> ObjectStyle {
ObjectStyle::default()
}
/// Sets the background color.
pub fn bg(mut self, color: Color) -> ObjectStyle {
self.bg_color = Some(color);
self
}
/// Sets the foreground color.
pub fn fg(mut self, color: Color) -> ObjectStyle {
self.fg_color = Some(color);
self
}
/// Adds the attribute.
///
/// You can add more attributes by calling this method multiple times.
pub fn add_attr(&mut self, attr: Attribute) {
self.attrs.push(attr);
}
}
#[cfg(test)]
mod tests {
use crate::{Attribute, Color, ObjectStyle};
#[test]
fn test_set_fg_bg_add_attr() {
let mut object_style = ObjectStyle::new().fg(Color::Blue).bg(Color::Red);
object_style.add_attr(Attribute::Reset);
assert_eq!(object_style.fg_color, Some(Color::Blue));
assert_eq!(object_style.bg_color, Some(Color::Red));
assert_eq!(object_style.attrs[0], Attribute::Reset);
}
#[test]
fn test_apply_object_style_to_text() {
let mut object_style = ObjectStyle::new().fg(Color::Blue).bg(Color::Red);
object_style.add_attr(Attribute::Reset);
let styled_object = object_style.apply_to("test");
assert_eq!(styled_object.object_style.fg_color, Some(Color::Blue));
assert_eq!(styled_object.object_style.bg_color, Some(Color::Red));
assert_eq!(styled_object.object_style.attrs[0], Attribute::Reset);
}
}

View File

@ -1,13 +1,13 @@
//! This module contains the logic to style an object that contains some 'content' which can be styled.
//! This module contains the logic to style some content.
use std::fmt::{self, Display, Formatter};
use std::result;
use crate::queue;
use super::{Attribute, Color, Colorize, ObjectStyle, ResetColor, SetAttr, SetBg, SetFg, Styler};
use super::{Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttr, SetBg, SetFg, Styler};
/// A styled object.
/// A styled content.
///
/// # Examples
///
@ -17,54 +17,69 @@ use super::{Attribute, Color, Colorize, ObjectStyle, ResetColor, SetAttr, SetBg,
/// let styled = style("Hello there")
/// .with(Color::Yellow)
/// .on(Color::Blue)
/// .attr(Attribute::Bold);
/// .attribute(Attribute::Bold);
///
/// println!("{}", styled);
/// ```
#[derive(Clone)]
pub struct StyledObject<D: Display + Clone> {
/// The object style (colors, content attributes).
pub object_style: ObjectStyle,
/// An object to apply the style on.
pub content: D,
pub struct StyledContent<D: Display + Clone> {
/// The style (colors, content attributes).
style: ContentStyle,
/// A content to apply the style on.
content: D,
}
impl<'a, D: Display + 'a + Clone> StyledObject<D> {
impl<'a, D: Display + 'a + Clone> StyledContent<D> {
/// Creates a new `StyledContent`.
pub fn new(style: ContentStyle, content: D) -> StyledContent<D> {
StyledContent { style, content }
}
/// Sets the foreground color.
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.fg(foreground_color);
pub fn with(mut self, foreground_color: Color) -> StyledContent<D> {
self.style = self.style.foreground(foreground_color);
self
}
/// Sets the background color.
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.bg(background_color);
pub fn on(mut self, background_color: Color) -> StyledContent<D> {
self.style = self.style.background(background_color);
self
}
/// Adds the attribute.
///
/// You can add more attributes by calling this method multiple times.
pub fn attr(mut self, attr: Attribute) -> StyledObject<D> {
self.object_style.add_attr(attr);
pub fn attribute(mut self, attr: Attribute) -> StyledContent<D> {
self.style = self.style.attribute(attr);
self
}
/// Returns the content.
pub fn content(&self) -> &D {
&self.content
}
/// Returns the style.
pub fn style(&self) -> &ContentStyle {
&self.style
}
}
impl<D: Display + Clone> Display for StyledObject<D> {
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.object_style.bg_color {
if let Some(bg) = self.style.bg_color {
queue!(f, SetBg(bg)).map_err(|_| fmt::Error)?;
reset = true;
}
if let Some(fg) = self.object_style.fg_color {
if let Some(fg) = self.style.fg_color {
queue!(f, SetFg(fg)).map_err(|_| fmt::Error)?;
reset = true;
}
for attr in self.object_style.attrs.iter() {
for attr in self.style.attrs.iter() {
queue!(f, SetAttr(*attr)).map_err(|_| fmt::Error)?;
reset = true;
}
@ -79,7 +94,7 @@ impl<D: Display + Clone> Display for StyledObject<D> {
}
}
impl<D: Display + Clone> Colorize<D> for StyledObject<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);
@ -117,7 +132,7 @@ impl<D: Display + Clone> Colorize<D> for StyledObject<D> {
def_color!(bg_color: on_grey => Color::Grey);
}
impl<D: Display + Clone> Styler<D> for StyledObject<D> {
impl<D: Display + Clone> Styler<D> for StyledContent<D> {
def_attr!(reset => Attribute::Reset);
def_attr!(bold => Attribute::Bold);
def_attr!(underlined => Attribute::Underlined);
@ -133,24 +148,26 @@ impl<D: Display + Clone> Styler<D> for StyledObject<D> {
#[cfg(test)]
mod tests {
use super::{Attribute, Color, ObjectStyle};
use super::{Attribute, Color, ContentStyle};
#[test]
fn test_set_fg_bg_add_attr() {
let mut object_style = ObjectStyle::new().fg(Color::Blue).bg(Color::Red);
object_style.add_attr(Attribute::Reset);
let style = ContentStyle::new()
.foreground(Color::Blue)
.background(Color::Red)
.attribute(Attribute::Reset);
let mut styled_object = object_style.apply_to("test");
let mut styled_content = style.apply("test");
styled_object = styled_object
styled_content = styled_content
.with(Color::Green)
.on(Color::Magenta)
.attr(Attribute::NoItalic);
.attribute(Attribute::NoItalic);
assert_eq!(styled_object.object_style.fg_color, Some(Color::Green));
assert_eq!(styled_object.object_style.bg_color, Some(Color::Magenta));
assert_eq!(styled_object.object_style.attrs.len(), 2);
assert_eq!(styled_object.object_style.attrs[0], Attribute::Reset);
assert_eq!(styled_object.object_style.attrs[1], 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);
}
}

View File

@ -1,6 +1,6 @@
use std::fmt::Display;
use super::StyledObject;
use super::StyledContent;
/// Provides a set of methods to set the colors.
///
@ -18,39 +18,39 @@ use super::StyledObject;
/// println!("{}", styled_text);
/// ```
pub trait Colorize<D: Display + Clone> {
fn black(self) -> StyledObject<D>;
fn dark_grey(self) -> StyledObject<D>;
fn red(self) -> StyledObject<D>;
fn dark_red(self) -> StyledObject<D>;
fn green(self) -> StyledObject<D>;
fn dark_green(self) -> StyledObject<D>;
fn yellow(self) -> StyledObject<D>;
fn dark_yellow(self) -> StyledObject<D>;
fn blue(self) -> StyledObject<D>;
fn dark_blue(self) -> StyledObject<D>;
fn magenta(self) -> StyledObject<D>;
fn dark_magenta(self) -> StyledObject<D>;
fn cyan(self) -> StyledObject<D>;
fn dark_cyan(self) -> StyledObject<D>;
fn white(self) -> StyledObject<D>;
fn grey(self) -> StyledObject<D>;
fn black(self) -> StyledContent<D>;
fn dark_grey(self) -> StyledContent<D>;
fn red(self) -> StyledContent<D>;
fn dark_red(self) -> StyledContent<D>;
fn green(self) -> StyledContent<D>;
fn dark_green(self) -> StyledContent<D>;
fn yellow(self) -> StyledContent<D>;
fn dark_yellow(self) -> StyledContent<D>;
fn blue(self) -> StyledContent<D>;
fn dark_blue(self) -> StyledContent<D>;
fn magenta(self) -> StyledContent<D>;
fn dark_magenta(self) -> StyledContent<D>;
fn cyan(self) -> StyledContent<D>;
fn dark_cyan(self) -> StyledContent<D>;
fn white(self) -> StyledContent<D>;
fn grey(self) -> StyledContent<D>;
fn on_black(self) -> StyledObject<D>;
fn on_dark_grey(self) -> StyledObject<D>;
fn on_red(self) -> StyledObject<D>;
fn on_dark_red(self) -> StyledObject<D>;
fn on_green(self) -> StyledObject<D>;
fn on_dark_green(self) -> StyledObject<D>;
fn on_yellow(self) -> StyledObject<D>;
fn on_dark_yellow(self) -> StyledObject<D>;
fn on_blue(self) -> StyledObject<D>;
fn on_dark_blue(self) -> StyledObject<D>;
fn on_magenta(self) -> StyledObject<D>;
fn on_dark_magenta(self) -> StyledObject<D>;
fn on_cyan(self) -> StyledObject<D>;
fn on_dark_cyan(self) -> StyledObject<D>;
fn on_white(self) -> StyledObject<D>;
fn on_grey(self) -> StyledObject<D>;
fn on_black(self) -> StyledContent<D>;
fn on_dark_grey(self) -> StyledContent<D>;
fn on_red(self) -> StyledContent<D>;
fn on_dark_red(self) -> StyledContent<D>;
fn on_green(self) -> StyledContent<D>;
fn on_dark_green(self) -> StyledContent<D>;
fn on_yellow(self) -> StyledContent<D>;
fn on_dark_yellow(self) -> StyledContent<D>;
fn on_blue(self) -> StyledContent<D>;
fn on_dark_blue(self) -> StyledContent<D>;
fn on_magenta(self) -> StyledContent<D>;
fn on_dark_magenta(self) -> StyledContent<D>;
fn on_cyan(self) -> StyledContent<D>;
fn on_dark_cyan(self) -> StyledContent<D>;
fn on_white(self) -> StyledContent<D>;
fn on_grey(self) -> StyledContent<D>;
}
/// Provides a set of methods to set the text attributes.
@ -67,15 +67,15 @@ pub trait Colorize<D: Display + Clone> {
/// println!("{}", "Negative text".negative());
/// ```
pub trait Styler<D: Display + Clone> {
fn reset(self) -> StyledObject<D>;
fn bold(self) -> StyledObject<D>;
fn underlined(self) -> StyledObject<D>;
fn reverse(self) -> StyledObject<D>;
fn dim(self) -> StyledObject<D>;
fn italic(self) -> StyledObject<D>;
fn negative(self) -> StyledObject<D>;
fn slow_blink(self) -> StyledObject<D>;
fn rapid_blink(self) -> StyledObject<D>;
fn hidden(self) -> StyledObject<D>;
fn crossed_out(self) -> StyledObject<D>;
fn reset(self) -> StyledContent<D>;
fn bold(self) -> StyledContent<D>;
fn underlined(self) -> StyledContent<D>;
fn reverse(self) -> StyledContent<D>;
fn dim(self) -> StyledContent<D>;
fn italic(self) -> StyledContent<D>;
fn negative(self) -> StyledContent<D>;
fn slow_blink(self) -> StyledContent<D>;
fn rapid_blink(self) -> StyledContent<D>;
fn hidden(self) -> StyledContent<D>;
fn crossed_out(self) -> StyledContent<D>;
}