Crate term_painter [] [src]

This is a crate for coloring and formatting terminal output. Simple example:

extern crate term_painter;

use term_painter::ToStyle;
use term_painter::Color::*;
use term_painter::Attr::*;

fn main() {
    println!("{} or {} or {}",
        Red.paint("Red"),
        Bold.paint("Bold"),
        Red.bold().paint("Both!")
    );
}

This crate uses rust-lang/term to do the formatting. Of course, you can use term directly, but it's kinda clumsy. Hence this library.

How to use it

Formatting is done in two steps:

  1. Creating a style
  2. Use this style to "paint" something and get a Painted object

1. Creating a style

To create a style a startpoint is needed: This can either be a startpoint with an attached modifier (like Red: modifies the fg-color) or the Plain startpoint, which does not modify anything. After that, the startpoint can be modified with modifiers like bold() or fg().

extern crate term_painter;

use term_painter::ToStyle;
use term_painter::Color::*;
use term_painter::Attr::*;

fn main() {
    let x = 5;

    // These two are equivalent: nothing is formatted/painted
    println!("{} | {}", x, Plain.paint(x));

    // These two are equivalent, too
    println!("{} | {}", Red.paint(x), Plain.fg(Red).paint(x));
}

You can chain as many modifiers as you want. Every modifier overrides preceding modifier:


// blue, not red
println!("{}", Plain.fg(Red).fg(Blue).paint("Apple"));

2. Use the style

After building the style, you can use it in two different ways.

One way is to call paint to use it on some object. paint will return the wrapper object Painted that holds your object and the specified style. Painted implements any formatting trait (like Display and Debug) if and only if the type of the given Object, T, does. So a Painted object can be printed via println! or similar macros. When it gets printed, it will apply the given style before printing the object of type T and will reset the style after printing.

Note: paint will consume the passed object. This is no problem when passing constant literals (like paint("cheesecake")) or types that are Copy. Otherwise it could be confusing because just printing should not consume a variable. To prevent consuming, just pass a reference to the object (with &). Example:

extern crate term_painter;

use term_painter::ToStyle;
use term_painter::Color::*;
use term_painter::Attr::*;

fn main() {
    let non_copy = "cake".to_string();  // String is *not* Copy
    let copy = 27;  // i32 *is* Copy

    println!("{}", Plain.paint(&non_copy));
    println!("{}", Plain.paint(&copy));
    // non_copy is still usable here...
    // copy is still usable here...

    println!("{}", Plain.paint(non_copy));
    println!("{}", Plain.paint(copy));
    // non_copy was moved into `paint`, so it not usable anymore...
    // copy is still usable here...
}

Another way is to call with. with takes another function (usually a closure) and everything that is printed within that closure is formatted with the given style. Specifically, with() sets the given style, calls the given function and resets the style afterwards. It can be chained and used together with paint(). Inner calls will overwrite outer calls of with.

extern crate term_painter;

use term_painter::ToStyle;
use term_painter::Color::*;
use term_painter::Attr::*;

fn main() {
    Red.with(|| {
        print!("JustRed");
        Bold.with(|| {
            print!(" BoldRed {} BoldRed ", Underline.paint("Underline"));
        });
        print!("JustRed ");

         print!("{}", Blue.paint("Blue (overwrite) "));
         Green.with(|| {
             println!("Green (overwrite)");
         });
    });
}

Some Notes

If you don't want to pollute your namespace with Color and Attr names, you can use a more qualified name (Color::Red.paint(..)) and remove these use statements:

  • use term_painter::Color::*;
  • use term_painter::Attr::*;

Please note that global state is changed when printing a Painted object. This means that some state is set before and reset after printing. This means that, for example, using this library in format! or write! won't work. The color formatting is not stored in the resulting string. Although Unix terminals do modify color and formatting by printing special control characters, Windows and others do not. This library uses the plattform independent library term, thus saving formatted text in a string not possible. This was a design choice.

This crate also assumes that the terminal state is not altered by anything else. Calling term function directly might result in strange behaviour. This is due to the fact that one can not read the current terminal state. In order to work like this, this crate needs to track terminal state itself. However, there shouldn't be any problems when the terminal state is completely reset in between using those two different methods.

Another possible source of confusion might be multithreading. Terminal state and handles are hold in thread local variables. If two terminal handles would reference the same physical terminal, those two threads could interfere with each other. I have not tested it, though. Usually, you don't want to print to the same Terminal in two threads simultanously anyway.

Functions of term sometimes return a Result that is Err when the function fails to set the state. However, this crate silently ignores those failures. To check the capabilities of the terminal, use term directly.

Structs

Painted

Wraps an object of type T and a style. When attempting to print it, the given style is applied before printing and reset afterwards. All formatting traits (Display, Debug, ...) that are implemented for T are also implemented the wrapper type Painted<T>.

Style

Saves all properties of a style. Implements ToStyle, so you can call style modifiers on it.

Enums

Attr

Lists possible attributes. It implements ToStyle so it's possible to call ToStyle's methods directly on a Attr variant like:

Color

Lists all possible Colors. It implements ToStyle so it's possible to call ToStyle's methods directly on a Color variant like:

Traits

ToStyle

Everything that can be seen as part of a style. This is the core of this crate. All functions ("style modifier") consume self and return a modified version of the style.