Expand description
§Ansi Constants
A library for declaring nestable ANSI styles in const context.
§Motivation
The primary motivation of this crate is to provide the ability to use ANSI colors/effects in command-line programs by identifying them semantically rather than literally.
For example, when calling println!, instead of applying the style
Green, Bold to the output, it has more semantic meaning to apply
a style named Subheading that, when rendered (or “formatted” in Rust),
produces the output that activates the Green, Bold styling.
Furthermore, semantic styles should be nestable, like styling frameworks such as HTML’s CSS. For example, it should be possible to nest text styled with a name like Manufacturer inside text styled with a name like Product Details and have the literal styles that these semantic styles translate to applied automatically. The nested style’s attributes should temporarily layer on top of, or maybe replace, the parent style’s attributes as appropriate.
The second key motivation of this crate is to support the above at
compile-time. I.e. define semantic styles as const, and then use
them with minimal overhead throughout a command-line program.
There are other crates that provide terminal-styling functionality, but none appear to fully support the use-case outlined above. The API provided by this crate in support of this use-case is presented in the following section.
§Key Features
§Compile-Time
Declare ANSI codes as const. This means the compiler will inline them
wherever they are used, potentially improving runtime performance.
§Examples
use ansiconst::{Ansi, ansi, ansi_code};
// Define styles as Ansi structs:
const HEADING_ANSI: Ansi = ansi!(Green, Bold, Underline);
const SUBHEADING_ANSI: Ansi = ansi!(Blue, Italic);
const RESET_ANSI: Ansi = ansi!(Ansi::reset());
assert_eq!( HEADING_ANSI.to_string(), "\x1B[1;4;32m");
assert_eq!(SUBHEADING_ANSI.to_string(), "\x1B[3;34m");
assert_eq!( RESET_ANSI.to_string(), "\x1B[0m");
// Or, define styles as ANSI codes:
const HEADING_CODE: &str = ansi_code!(Green, Bold, Underline);
const SUBHEADING_CODE: &str = ansi_code!(Blue, Italic);
const RESET_CODE: &str = ansi_code!(Ansi::reset());
assert_eq!( HEADING_CODE, "\x1B[1;4;32m");
assert_eq!( SUBHEADING_CODE, "\x1B[3;34m");
assert_eq!( RESET_CODE, "\x1B[0m");§Small
Ansi instances are designed to be as small as possible. For example, Effects
are represented internally using bit flags rather than simple bools.
For this reason, the use of 8-bit and RGB colors
is gated behind feature flags, because supporting them means Ansi instances
must be ever so slightly bigger. Consider the memory sizes:
| Type | Bytes |
|---|---|
Ansi | 6 |
Ansi feature="color256" | 8 |
Ansi feature="rgb" | 12 |
&'static str | 16 |
§Simple Macros
Apply ANSI codes using macros:
styled!creates ANSI-styled values without interpolation (e.g.&'static str,u8).styled_format!,styled_format_args!are analogous toformat!,format_args!except that they create ANSI-styled results.styled_write!,styled_writeln!are analogous towrite!,writeln!except that they write ANSI-styled output.paint!,paintln!,epaint!,epaintln!are analogous toprint!,println!,eprint!,eprintln!except that they print ANSI-styled output.
§Examples
use ansiconst::{styled, styled_format, styled_format_args, styled_writeln};
use ansiconst::{paintln, epaintln};
// Notice how "Red" and "Bold" are automatically available inside the macros.
let pet = "cat";
let age = 5;
let string1 = styled!(Red, Bold, "My cat is 5 years old").to_string();
let string2 = styled_format!(Red, Bold, "My {} is {} years old", pet, age).to_string();
let string3 = styled_format_args!(Red, Bold, "My {} is {} years old", pet, age).to_string();
assert_eq!(string1, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m");
assert_eq!(string2, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m");
assert_eq!(string3, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m");
// Print "\x1B[1;31mMy cat is 5 years old\x1B[22;39m\n" to stdout and stderr:
paintln! (Red, Bold, "My {} is {} years old", pet, age);
epaintln!(Red, Bold, "My {} is {} years old", pet, age);
// Write "\x1B[1;31mMy cat is 5 years old\x1B[22;39m\n" to a writer:
use std::fmt::Write;
let mut buffer = String::new();
styled_writeln!(&mut buffer, Red, Bold, "My {} is {} years old", pet, age).unwrap();
assert_eq!(buffer, "\x1B[1;31mMy cat is 5 years old\x1B[22;39m\n");§Effortless Nesting
Nesting of ANSI codes is automatically handled, and uses the minimum ANSI code sequences when transitioning between nesting levels.
Additionally, nested ANSI codes can be effectively disabled by setting an
important modifier on the outer Ansi’s attributes.
This works similarly to HTML’s CSS !important
rule, in that an inner normal attribute is ignored if the same outer attribute
is important.
Furthermore, nested Ansis can prevent automatic inheriting of the style attributes
of enclosing Ansis by explicitly resetting them using only.
Finally, nested Ansis can be disabled entirely with no_ansi.
§Examples
use ansiconst::{Styled, styled, styled_format_args};
const INNER: Styled<&str> = styled!(Underline, "Inner");
const INNER_ONLY: Styled<&str> = styled!(Underline.only(), "Inner");
const INNER_IMPORTANT: Styled<&str> = styled!(Underline.important(), "Inner");
// Example 1: blended styles
assert_eq!(
styled_format_args!(Bold, "Bold {INNER} Bold again").to_string(),
// "Inner" is both Bold and Underline
"\x1B[1mBold \x1B[4mInner\x1B[24m Bold again\x1B[22m"
);
// Example 2: inner style only
assert_eq!(
styled_format_args!(Bold, "Bold {INNER_ONLY} Bold again").to_string(),
// "Inner" is not Bold, only Underline, due to inner's .only()
"\x1B[1mBold \x1B[22;4mInner\x1B[24;1m Bold again\x1B[22m"
);
// Example 3: outer style only + important
assert_eq!(
styled_format_args!(Bold.only().important(), "Bold {INNER_ONLY} Bold again").to_string(),
// Entire string is Bold, nested Underline was ignored due to .only().important()
"\x1B[0;1mBold Inner Bold again\x1B[22m"
);
// Example 4: both important
assert_eq!(
styled_format_args!(Bold.only().important(), "Bold {INNER_IMPORTANT} Bold again").to_string(),
// "Inner" is Bold and Underline, due to inner's .important()
"\x1B[0;1mBold \x1B[4mInner\x1B[24m Bold again\x1B[22m"
);
Note: automatic handling of nested styles is achieved by storing the last-applied
ANSI style in a thread_local! static variable, and therefore this library
requires std. See Styled<T> and StyledString for details.
§Examples
use ansiconst::{Ansi, ansi, paintln, styled_format_args};
const HEADING: Ansi = ansi!(Green, Bold, Underline);
const SUBHEADING: Ansi = ansi!(Cyan, Italic);
const STRONG: Ansi = ansi!(Yellow, Bold);
const STRONGER: Ansi = ansi!(Blink);
const STRONGEST: Ansi = ansi!(Purple, Bold.not());
// Styling with paintln!
paintln!(HEADING, "The Book of Rust");
paintln!();
paintln!(SUBHEADING, "Chapter 1");
paintln!();
// Styling with println!
println!("This sentence shows how {} as you would expect.",
styled_format_args!(STRONG, "styles can be {}, and they combine",
styled_format_args!(STRONGER, "nested to {} depths",
styled_format_args!(STRONGEST, "arbitrary")
)
)
);
println!("This sentence shows another {} colors/effects.",
styled_format_args!(Green, Italic, "way of styling {} i.e. with inline",
styled_format_args!(Yellow, Bold, "your text,")
)
);§Upgrading from v0.1.x
Required actions due to breaking changes:
- Rename
ansiconst::Colourtoansiconst::Color, or omit this import entirely, since color names (e.g.Red) are now automatically available inside API macros. - Rename
features = ["ansi256"]tofeatures = ["color256"]insideCargo.toml. - Rename
Colour::Ansi256(n)toColor::num(n). - Rename
Colour::Rgb(r,g,b)toColor::rgb(r,g,b). - Rename
Color::Unspecified,Effect::UnspecifiedtoAnsi::empty(). - Rename
Effect::NotBoldtoEffect::Bold.not()(same for other effects). - Rename
styled_format!(...)tostyled_format!(...).to_string()orstyled_format_args!(...).to_string().
Modules§
- introspect
- Obtain the properties of an
Ansi. - io
- Set default ANSI styles for writers and handles.
Macros§
- ansi
- Creates an ANSI style as an
Ansiconst. - ansi_
code - Creates an ANSI style as a
&'static str. - epaint
- Like
eprint!except with ANSI-styled output. - epaintln
- Like
eprintln!except with ANSI-styled output. - paint
- Like
print!except with ANSI-styled output. - paintln
- Like
println!except with ANSI-styled output. - styled
- Creates an ANSI-styled value.
- styled_
format - Like
format!except creates an ANSIStyledString. - styled_
format_ args - Like
format_args!except creates ANSI-styledArguments. - styled_
write - Like
write!except with ANSI-styled output. - styled_
writeln - Like
writeln!except with ANSI-styled output.
Structs§
- Ansi
- Represents an arbitrary combination of ANSI
Effects and foreground/backgroundColors. - Color
Reset - Represents the
resetColorcode (SGR parameters: foreground 39, background 49) - Styled
- Associates a
Displaytarget with anAnsistyle, such that formatting produces the result of formatting the target with the style’s ANSI codes wrapped around it. - Styled
String - A
StringcontainingAnsistyles, which can be overridden.
Enums§
- Color
- Represents the control sequences, named Select Graphic Rendition (SGR), that are used to set foreground and background colors on ANSI terminals.
- Coloree
- Represents the parts of an ANSI terminal that can have a color applied.
- Effect
- Represents the control sequences, named Select Graphic Rendition (SGR), that are used to enable various effects (e.g. italic) on ANSI terminals.