/prettypretty

Hello pretty 🌸 pretty, awesome terminal colors you have there!

Primary LanguageRustApache License 2.0Apache-2.0

Pretty 🌸 Pretty

Run Tests, Build Wheels, & Publish to PyPI (also builds wheels & publishes to PyPi) Publish to GitHub Pages

[ Documentation | Rust Crate | Python Package | Repository ]

🎖️ As featured on Real Python #211 🎖️ Inspired iTerm2's color preferences

Prettypretty is a Rust library with optional Python integration that brings 2020s color science to 1970s terminals for building awesome terminal user interfaces (TUIs). The intended benefits are twofold:

  • You get to design and build the TUI with all the expressivity and convenience of high-resolution color and color spaces, including the perceptually uniform Oklab whether in Cartesian or polar form, with original or revised lightness.
  • Prettypretty takes care of reconciling the intended appearance with the capabilities of the terminal, the current runtime context including light or dark mode, and the user's preferences, whether they lean FORCE_COLOR or NO_COLOR.

To make that possible, prettypretty provides simple abstractions for terminal and high-resolution colors alike, facilitates seamless conversion between them and common color spaces, and implements state-of-the-art algorithms for gamut-mapping, color interpolation, perceptual contrast, as well as its own hue- and lightness-based downsampling for optimal selection of ANSI colors.

Python Integration

The optional Python integration is enabled with the pyffi feature flag and relies on PyO3 and Maturin for building an extension module with the same functionality. Only where the Rust library uses trait implementations, the Python module uses dedicated methods. Also, where the Rust library currently is BYO(T)IO, that is, bring your own (terminal) I/O, the Python library comes with a powerful terminal abstraction that makes, say, querying the terminal for the current color theme a breeze.

The Python documentation covers the functionality that currently is Python-only. Over time, I expect to port those features to Rust as well.

Minimum Supported Rust and Python Versions

Prettypretty leverages both programming languages to their fullest and hence requires relatively recent versions:

  • According to cargo-msrv, the minimum supported Rust version is 1.77.2.
  • According to vermin, the minimum supported Python version is 3.11.0.

I expect that, as the project matures, the version lag between minimum and latest versions will grow, as it should.

Scripts Using Prettypretty

Besides the documentation, a good starting point for familiarizing yourself with prettypretty are the scripts:

  • prettypretty.progress illustrates the library's use on the example of a progress bar in less than 100 lines of Python. The finished progress bar is shown below for both light and dark themes.

    a complete, green progress bar under light mode a complete, green progress bar under dark mode

  • prettypretty.plot charts colors on the chroma/hue plane of Oklab, if you don't feed it colors defaulting to your terminal's current color scheme. Here's the one for the basic theme in Apple's Terminal.app:

    colors from the basic theme for Apple's Terminal.app in Oklch

  • prettypretty.grid visualizes perceptual contrast and color downsampling strategies, exhaustively for the 6x6x6 RGB cube embedded in 8-bit color and selectively for 32x32 slices through the much bigger 24-bit RGB cube.

    a grid visualizing the 6x6x6 embedded RGB cube

  • prettypretty.viz3d traces the boundaries of the visual gamut in 3D and saves the corresponding point cloud or mesh in PLY format. The screenshot below shows Vedo's rendering.

    a 3D visualization of the gamut for visible light,
somewhat shaped like a fat, squat hot pocket

Developing Prettypretty

Since prettypretty integrates Rust and Python, it not only requires tooling for both programming languages but also technology for integrating the two ecosystems. To keep development tasks nonetheless manageable, the runner or script in the repository root automates the most common ones. Its only argument is the task to perform:

  • install updates or installs necessary command line tools, including the Rust compiler and Python runtime, using either the APT or Homebrew package manager.
  • build compiles the Python extension module as prettypretty/color.pyd (on Windows) or prettypretty/color.abi3.so (on Unix).
  • check runs linters, type checkers, and tests for both languages. Test can be found at the end of Rust modules, embedded in the Rust API documentation, and the test directory.
  • doc builds the guide as well as the API documentation for both languages combining all three in the target/doc directory.

Acknowledgements

I wrote much of prettypretty over a two-month period in 2024. Twice. I first implemented the core color routines in Python and then I did so again in Rust. At this point, only the Rust version survives. But Python remains a tier-1 runtime target for prettypretty. Two things really helped with getting this project started. First, I had been toying with different approaches to terminal styles for a while and knew what I was looking for. Second, I benefitted tremendously 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.


Copyright 2024 Robert Grimm. The code in this repository has been released as open source under the Apache 2.0 license.