Expand description
§Pretty 🌸 Pretty
Prettypretty brings 2020s color science to 1970 terminals.
This version of the API documentation covers both Rust and Python
interfaces. You can find a version without Python integration, with the pyffi
feature disabled, on Docs.rs.
The user guide provides a
comprehensive overview and several deep dives covering both languages. There
also are the type
stubs
and API documentation
for Python as well as the shared source
repository, Rust
crate, and Python
package.
§1. Overview
Prettypretty’s main abstractions are:
Colorimplements high-resolution colors by combining aColorSpacewith threeFloatcoordinates. Its methods expose much of prettypretty’s functionality, including conversion between color spaces, interpolation between colors, calculation of perceptual contrast, as well as gamut testing, clipping, and mapping.- The
termcomodule offers a choice of terminal-specific color formatsAnsiColor,EmbeddedRgb,GrayGradient,EightBitColor,Rgb, as well as the wrapperColorant. - The
stylemodule defines terminalStyles as a textFormatUpdatecombined with foreground and backgroundColorants. It also definesLayerto distinguish between the two colors andFidelityto represent a terminal’s styling capabilities. Translatorimplements translation between color formats. To ensure high quality results, its preferred algorithms leverage the perceptually uniform Oklab/Oklch color space. For conversion to the 16 ANSI colors, it also reqires the terminal’s current colorTheme.- The optional
gamutandspectrumsubmodules enable the traversal of color space gamuts and the human visual gamut, respectively. The plot.py and viz3d.py scripts leverage the additional functionality for generating helpful color visualizations.
§2. One-Two-Three: Styles!
Prettypretty’s three-step workflow for awesome terminal styles works like this.
§i. Assemble Your Styles
First, assemble your application’s styles by modifying the empty
Style::default().
// 1. Assemble application styles
let chic = Style::default()
.bold()
.underlined()
.with_foreground(Rgb::new(215, 40, 39));Style::with_foreground and
Style::with_background accept any of
prettypretty’s color representations, i.e.,
AnsiColor, EmbeddedRgb,
GrayGradient,
EightBitColor, Rgb or
high-resolution Color.
§ii. Adjust Your Styles
Second, determine the terminal’s current color theme with
Theme::query and its color support with
Fidelity::from_environment.
// 2a. Determine terminal's color support and theme
let options = Options::with_log();
let (has_tty, theme) = match Connection::with_options(options) {
Ok(tty) => (true, Theme::query(&tty)?),
Err(_) => (false, VGA_COLORS),
};
let fidelity = Fidelity::from_environment(has_tty);Use the theme to instantiate a Translator, which
specializes in complex color conversions and then adjust your application’s
styles to the current color theme and fidelity.
Style::cap puts a cap on styles with the help of
Translator::cap, which takes care of colors.
// 2b. Actually adjust styles
let translator = Translator::new(OkVersion::Revised, theme);
let effective_chic = &chic.cap(fidelity, &translator);§iii. Apply Your Styles
Third, to apply a style, just write its display. To undo the style again, just write the negation’s display.
// 3. Apply and revert styles
println!("{}Wow!{}", effective_chic, -effective_chic);And the terminal exclaims:
🎉
§3. Optional Features
Prettypretty supports four feature flags:
f64selects the eponymous type as floating point typeFloatandu64asBitsinstead off32asFloatandu32asBits. This feature is enabled by default.ttycontrolsTheme::queryand its implementation with the prettytty terminal crate. This feature is enabled by default.gamutcontrols support for tracing the boundaries of color spaces (mod gamut,ColorSpace::gamut) and the human visual gamut (mod spectrum). This feature is disabled by default.pyfficontrols prettypretty’s Python integration through PyO3. This feature is disabled by default.
Prettypretty’s Python extension module is built with
Maturin, PyO3’s dedicated build tool. Since Python
packages typically come with “batteries included,” the gamut feature is
also enabled when building the Python extension module. However, the tty
feature is disabled, and prettypretty’s Python package includes its own
terminal abstraction.
Throughout the API documentation, items that are only available in Rust are
decorated with Rust only!.
Items that are only available in Python are decorated with Python only!.
Similarly, items only available with the tty feature are decorated with TTY only! and items only available with the gamut
feature are decorated with Gamut only!.
§4. Acknowledgements
Implementing prettypretty’s color support was a breeze. In part, that was because I had been toying with different approaches to terminal styling for a while and knew what I wanted to build. In part, that was because I benefitted from Lea Verou’s and Chris Lilley’s work on the Color.js library and CSS Color 4 specification. Prettypretty directly reuses Color.js’ formulae for conversion between color spaces and implements several CSS Color 4 algorithms. Thank you! 🌸
Modules§
- error
- Utility module with prettypretty’s errors.
- gamut
- Optional module implementing the traversal of RGB gamut boundaries with
ColorSpace::gamut. - spectrum
- Optional module implementing the traversal of the human visual gamut.
- style
- Terminal-specific text fromatting and styles.
- termco
- Terminal color representations.
- theme
- Utility module implementing terminal color themes.
Macros§
- assert_
close_ enough - Test macro for asserting the equality of floating point numbers.
- assert_
same_ color - Test macro for asserting the equality of colors.
- rgb
- Create a new sRGB color from 24-bit integer coordinates.
Structs§
- Color
- A high-resolution color object.
- Interpolator
- Helper struct returned by
Color::interpolate. - Translator
- A color translator.
Enums§
- Color
Space - The enumeration of supported color spaces.
- HueInterpolation
- A choice of strategy for interpolating hues.
- OkVersion
- A choice of Oklab versions.
Functions§
- close_
enough - Determine whether the two floats are close enough to be considered equal. Python only!