minicrossterm/src/style.rs

369 lines
10 KiB
Rust
Raw Normal View History

//! # Style
//!
//! The `style` module provides a functionality to apply attributes and colors on your text.
//!
//! This documentation does not contain a lot of examples. The reason is that it's fairly
//! obvious how to use this crate. Although, we do provide
//! [examples](https://github.com/crossterm-rs/examples) repository
//! to demonstrate the capabilities.
//!
//! ## Platform-specific Notes
//!
//! Not all features are supported on all terminals/platforms. You should always consult
//! platform-specific notes of the following types:
//!
//! * [Color](enum.Color.html#platform-specific-notes)
//! * [Attribute](enum.Attribute.html#platform-specific-notes)
//!
//! ## Examples
2019-11-19 07:50:57 +11:00
//!
//! A few examples of how to use the style module.
//!
//! ### Colors
2019-11-19 07:50:57 +11:00
//!
//! How to change the terminal text color.
//!
2019-11-19 07:50:57 +11:00
//! Command API:
//!
//! Using the Command API to color text.
//!
//! ```no_run
//! use std::io::{stdout, Write};
//!
//! use crossterm::{execute, Result};
//! use crossterm::style::{Print, SetForegroundColor, SetBackgroundColor, ResetColor, Color, Attribute};
//!
//! fn main() -> Result<()> {
//! execute!(
//! stdout(),
//! // Blue foreground
2019-11-01 07:02:04 +11:00
//! SetForegroundColor(Color::Blue),
//! // Red background
2019-11-01 07:02:04 +11:00
//! SetBackgroundColor(Color::Red),
//! // Print text
//! Print("Blue text on Red.".to_string()),
//! // Reset to default colors
//! ResetColor
//! )
//! }
//! ```
//!
2019-11-19 07:50:57 +11:00
//! Functions:
//!
//! Using functions from [`Colorize`](trait.Colorize.html) on a `String` or `&'static str` to color it.
//!
//! ```no_run
2019-11-01 07:02:04 +11:00
//! use crossterm::style::Colorize;
//!
//! println!("{}", "Red foreground color & blue background.".red().on_blue());
//! ```
//!
//! ### Attributes
2019-11-19 07:50:57 +11:00
//!
//! How to appy terminal attributes to text.
//!
2019-11-19 07:50:57 +11:00
//! Command API:
//!
//! Using the Command API to set attributes.
//!
//! ```no_run
//! use std::io::{stdout, Write};
//!
//! use crossterm::{execute, Result, style::Print};
2019-11-01 07:02:04 +11:00
//! use crossterm::style::{SetAttribute, Attribute};
//!
//! fn main() -> Result<()> {
//! execute!(
//! stdout(),
//! // Set to bold
2019-11-01 07:02:04 +11:00
//! SetAttribute(Attribute::Bold),
//! Print("Bold text here.".to_string()),
//! // Reset all attributes
2019-11-01 07:02:04 +11:00
//! SetAttribute(Attribute::Reset)
//! )
//! }
//! ```
//!
2019-11-19 07:50:57 +11:00
//! Functions:
//!
//! Using [`Styler`](trait.Styler.html) functions on a `String` or `&'static str` to set attributes to it.
//!
//! ```no_run
2019-11-01 07:02:04 +11:00
//! use crossterm::style::Styler;
//!
//! println!("{}", "Bold".bold());
//! println!("{}", "Underlined".underlined());
//! println!("{}", "Negative".negative());
//! ```
//!
2019-11-19 07:50:57 +11:00
//! Displayable:
//!
//! [`Attribute`](enum.Attribute.html) implements [Display](https://doc.rust-lang.org/beta/std/fmt/trait.Display.html) and therefore it can be formatted like:
//!
//! ```no_run
2019-11-01 07:02:04 +11:00
//! use crossterm::style::Attribute;
//!
//! println!(
//! "{} Underlined {} No Underline",
//! Attribute::Underlined,
//! Attribute::NoUnderline
//! );
//! ```
2019-11-19 07:50:57 +11:00
use std::{env, fmt::Display};
#[cfg(windows)]
2019-11-01 07:02:04 +11:00
use crate::Result;
2019-11-19 07:50:57 +11:00
use crate::{impl_display, utils::Command};
2019-11-01 07:02:04 +11:00
pub(crate) use self::enums::Colored;
2019-11-19 07:50:57 +11:00
pub use self::{
content_style::ContentStyle,
enums::{Attribute, Color},
styled_content::StyledContent,
traits::{Colorize, Styler},
};
#[macro_use]
mod macros;
2019-11-01 07:02:04 +11:00
mod ansi;
mod content_style;
mod enums;
2019-11-01 07:02:04 +11:00
mod styled_content;
mod sys;
mod traits;
2019-10-28 07:07:09 +11:00
/// Creates a `StyledContent`.
///
/// This could be used to style any type that implements `Display` with colors and text attributes.
///
2019-10-28 07:07:09 +11:00
/// See [`StyledContent`](struct.StyledContent.html) for more info.
///
/// # Examples
///
/// ```no_run
2019-11-01 07:02:04 +11:00
/// use crossterm::style::{style, Color};
///
2019-10-28 07:07:09 +11:00
/// let styled_content = style("Blue colored text on yellow background")
/// .with(Color::Blue)
/// .on(Color::Yellow);
///
2019-10-28 07:07:09 +11:00
/// println!("{}", styled_content);
/// ```
2019-10-28 07:07:09 +11:00
pub fn style<'a, D: 'a>(val: D) -> StyledContent<D>
where
D: Display + Clone,
{
2019-10-28 07:07:09 +11:00
ContentStyle::new().apply(val)
}
impl Colorize<&'static str> for &'static str {
// foreground colors
2019-11-01 07:02:04 +11:00
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
2019-11-01 07:02:04 +11:00
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 {
def_str_attr!(reset => Attribute::Reset);
def_str_attr!(bold => Attribute::Bold);
def_str_attr!(underlined => Attribute::Underlined);
def_str_attr!(reverse => Attribute::Reverse);
def_str_attr!(dim => Attribute::Dim);
def_str_attr!(italic => Attribute::Italic);
def_str_attr!(negative => Attribute::Reverse);
def_str_attr!(slow_blink => Attribute::SlowBlink);
def_str_attr!(rapid_blink => Attribute::RapidBlink);
def_str_attr!(hidden => Attribute::Hidden);
def_str_attr!(crossed_out => Attribute::CrossedOut);
}
2019-11-01 07:02:04 +11:00
/// Returns available color count.
///
2019-11-01 07:02:04 +11:00
/// # Notes
///
2019-11-01 07:02:04 +11:00
/// This does not always provide a good result.
pub fn available_color_count() -> u16 {
env::var("TERM")
.map(|x| if x.contains("256color") { 256 } else { 8 })
.unwrap_or(8)
}
2019-11-01 07:02:04 +11:00
/// 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.
2019-11-01 07:02:04 +11:00
pub struct SetForegroundColor(pub Color);
2019-11-01 07:02:04 +11:00
impl Command for SetForegroundColor {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
ansi::set_fg_csi_sequence(self.0)
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
2019-11-01 07:02:04 +11:00
sys::windows::set_foreground_color(self.0)
}
}
2019-11-01 07:02:04 +11:00
/// 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.
2019-11-01 07:02:04 +11:00
pub struct SetBackgroundColor(pub Color);
2019-11-01 07:02:04 +11:00
impl Command for SetBackgroundColor {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
ansi::set_bg_csi_sequence(self.0)
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
2019-11-01 07:02:04 +11:00
sys::windows::set_background_color(self.0)
}
}
2019-11-01 07:02:04 +11:00
/// 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.
2019-11-01 07:02:04 +11:00
pub struct SetAttribute(pub Attribute);
2019-11-01 07:02:04 +11:00
impl Command for SetAttribute {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
ansi::set_attr_csi_sequence(self.0)
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
// attributes are not supported by WinAPI.
Ok(())
}
}
2019-11-01 07:02:04 +11:00
/// A command that prints styled content.
///
2019-10-28 07:07:09 +11:00
/// See [`StyledContent`](struct.StyledContent.html) for more info.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
pub struct PrintStyledContent<D: Display + Clone>(pub StyledContent<D>);
impl<D> Command for PrintStyledContent<D>
where
D: Display + Clone,
{
2019-10-28 07:07:09 +11:00
type AnsiType = StyledContent<D>;
fn ansi_code(&self) -> Self::AnsiType {
self.0.clone()
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
Ok(())
}
}
2019-11-01 07:02:04 +11:00
/// A command that resets the colors back to default.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
pub struct ResetColor;
impl Command for ResetColor {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
ansi::RESET_CSI_SEQUENCE.to_string()
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
2019-11-01 07:02:04 +11:00
sys::windows::reset()
}
}
/// A command that prints the given displayable type.
///
/// Commands must be executed/queued for execution otherwise they do nothing.
pub struct Print<T: Display + Clone>(pub T);
impl<T: Display + Clone> Command for Print<T> {
type AnsiType = T;
fn ansi_code(&self) -> Self::AnsiType {
self.0.clone()
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
print!("{}", self.0);
Ok(())
}
}
impl<T: Display + Clone> Display for Print<T> {
fn fmt(
&self,
f: &mut ::std::fmt::Formatter<'_>,
) -> ::std::result::Result<(), ::std::fmt::Error> {
write!(f, "{}", self.ansi_code())
}
}
2019-11-01 07:02:04 +11:00
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);