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. You can of course
use term directly, but it's kinda clumsy. Hence this library.
How to use it
Formatting works in two steps mainly:
- Creating a style
Use this style to "paint" something and reviece a
Paintedobject
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 by 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 println!("{} | {}", x, Plain.paint(x)); // These two are equivalent, too println!("{} | {}", Red.paint(x), Plain.fg(Red).paint(x)); }
You can chain as many modifier as you want. Every modifier overrides preceding modifier:
println("{}", Plain.fg(Red).fg(Blue).paint("Apple")); // blue, not red
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 borrow 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; // usize/isize *is* Copy println!("{}", Plain.paint(&non_copy)); println!("{}", Plain.paint(©)); // 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. 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::*; and
use term_painter::Attr::*;.
And 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. And since this library uses
the plattform independent library term. 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 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.
Functions of term sometimes return a Result that is Err when the
function fails to set 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 |
| Style |
Saves all properties of a style. Implements |
Enums
| Attr |
Lists possible attributes. It implements |
| Color |
Lists all possible Colors. It implements |
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. |