Crate yansi

source ·
Expand description

A dead simple ANSI terminal color painting library.

Usage

Usage is best illustrated via a quick example:

use yansi::{Paint, Color};

println!("Testing, {}, {}, {}!",
    Paint::red(1),
    Paint::green(2).bold().underline(),
    Paint::blue("3").bg(Color::White).italic());

Paint

The main entry point into this library is the Paint type. Paint encapsulates a value of any type that implements the Display or Debug trait. When a Paint is Displayed or Debuged, the appropriate ANSI escape characters are emitted before and after the wrapped type’s fmt implementation.

Paint can be constructed via a myriad of methods. In addition to these constructors, you can also use the color.paint() method on a given Color value to construct a Paint type. Both of these approaches are shown below:

use yansi::Paint;
use yansi::Color::Red;

println!("I'm {}!", Paint::red("red").bold());
println!("I'm also {}!", Red.paint("red").bold());

Styling

Modifications to the styling of an item can be made via a number of chainable methods on Paint.

use yansi::Paint;

Paint::new("hi").underline().invert().italic().dimmed().bold();

Styling can also be created independently from a Paint structure via the Style structure. This allows common styling to be stored and reused. A Style can be applied via the style.paint() method or the paint.with_style() method:

use yansi::{Paint, Color, Style};

// A bold, itatlic style with red foreground.
let alert = Style::new(Color::Red).bold().italic();

// Using `style.paint()`; this is preferred.
println!("Alert! {}", alert.paint("This is serious business!"));
println!("Hi! {}", alert.underline().paint("Super serious!"));

// Using `paint.with_style()`.
println!("Alert! {}", Paint::new("Yet another.").with_style(alert));

Disabling

Painting can be disabled globally via the Paint::disable() method. When painting is disabled, the Display and Debug implementations for Paint will emit the Display or Debug of the contained object and nothing else. Painting can be reenabled via the Paint::enable() method.

One potential use of this feature is to allow users to control color ouput via an environment variable. For instance, to disable coloring if the CLICOLOR variable is set to 0, you might write:

use yansi::Paint;

if let Ok(true) = std::env::var("CLICOLOR").map(|v| v == "0") {
    Paint::disable();
}

Masking

Items can be arbitrarily masked. When an item is masked and painting is disabled, the Display and Debug implementations of Paint write nothing. This allows you to selectively omit output when painting is disabled. Values can be masked using the Paint::masked() constructor or paint.mask() and style.mask() style setters.

One use for this feature is to print certain characters only when painting is enabled. For instance, you might wish to emit the 🎨 emoji when coloring is enabled but not otherwise. This can be accomplished by masking the emoji:

use yansi::Paint;

println!("I like colors!{}", Paint::masked(" 🎨"));

This will print “I like colors! 🎨” when painting is enabled and “I like colors!” when painting is disabled.

Wrapping

Styling can be set to wrap existing styles using either the Paint::wrapping() constructor or the paint.wrap() and style.wrap() style setters. When a style is wrapping, all color resets written out by the internal item’s Display or Debug implementation are set to the styling of the wrapping style itself. In other words, the “default” style of the wrapped item is modified to be the wrapping style. This allows for easy wrapping of other colored text. Without this feature, the console would reset styling to the terminal’s default style instead of the wrapping style.

One use for this feature is to ensure that styling is consistently set across items that may already be styled, such as when logging.

use yansi::{Paint, Color};

let inner = format!("{} and {}", Paint::red("Stop"), Paint::green("Go"));
println!("Hey! {}", Paint::wrapping(inner).fg(Color::Blue));

This will print ‘Hey!’ unstyled, “Stop” in red, “and” in blue, and “Go” in green. Without wrapping, “and” would be unstyled as Paint::red() resets the style after printing the internal item.

Windows

Coloring is supported on Windows beginning with the Windows 10 anniversary update. Since this update, Windows consoles support ANSI escape sequences. This support, however, must be explicitly enabled. yansi provides the Paint::enable_windows_ascii() method to enable ASCII support on Windows consoles when available.

use yansi::Paint;

// Enable ASCII escape sequence support on Windows consoles.
Paint::enable_windows_ascii();

You may wish to disable coloring on unsupported Windows consoles to avoid emitting unrecognized ASCII escape sequences:

use yansi::Paint;

if cfg!(windows) && !Paint::enable_windows_ascii() {
    Paint::disable();
}

Why?

Several terminal coloring libraries exist (ansi_term, colored, term_painter, to name a few), begging the question: why yet another? Here are a few reasons:

  • This library is much simpler: there are three types!
  • Unlike ansi_term or colored, any type implementing Display or Debug can be stylized, not only strings.
  • Styling can be enabled and disabled globally, on the fly.
  • Arbitrary items can be masked for selective disabling.
  • Styling can wrap any arbitrarily styled item.
  • Typically only one type needs to be imported: Paint.
  • Zero dependencies. It really is simple.
  • The name yansi is pretty short.

All that being said, this library borrows API ideas from the three libraries as well as implementation details from ansi_term.

Structs

  • A structure encapsulating an item and styling.
  • Represents a set of styling options.

Enums

  • An enum representing an ANSI color code.