1 unstable release

0.1.0 Aug 8, 2023

#924 in Procedural macros

MIT license

14KB
299 lines

pprint

A Rust library for pretty ✨ printing using a document model. Automatically derive Pretty for structs, enums, and primitive types; vector and map types are also supported by default; very similar to the derive(Debug) macro, just prettier and more configurable.

Usage

use pprint::{Doc, Printer, PRINTER};

let doc = Doc::from(vec![1, 2, 3])
    .wrap("[", "]")
    .join(", ");

print!("{}", PRINTER.pretty(doc));
// prints:
// [
//   1,
//   2,
//   3
// ]

Document Model

The document model provides a rich set of building blocks:

  • Primitive values like strings, numbers
  • Containers like vectors, tuples, maps, sets
  • Formatting like concat, join, wrap, group
  • Indentation control with indent and dedent
  • Conditional formatting with if_break
  • Line breaks like hardline, softline

The Printer handles pretty printing a Doc to a string with configurable options:

  • max_width - maximum width of each line
  • indent - number of spaces for each indentation level
  • break_long_text - insert line breaks for long text
  • use_tabs - use tabs instead of spaces for indentation

Derive Macro

Half of the library's development time was spent on the derive macro, allowing for easy pretty printing of essentially any type. Here's a trivial example:

#[derive(Pretty)]
struct Point {
    x: f64,
    y: f64
}

let point = Point { x: 1.0, y: 2.0 };
print!("{}", Doc::from(point)); // prints "(x: 1, y: 2)"

Pretty supports an additional attribute, pprint, which is used to customize an object's pretty printing definition. The following options are available:

  • skip: bool: Skip this field - don't include it in the output
  • indent: bool: Indent this field - add a newline and indent before and after
  • rename: Option: Rename this field - use the given string as the field name
  • getter: Option: Use the given function to get the value of this field
  • verbose: bool: Verbose output - include field names in output
#[derive(Pretty)]
#[pprint(verbose)]
struct Point {
    #[pprint(rename = "x-coordinate")]
    x: f64,
    #[pprint(rename = "y-coordinate")]
    y: f64
    #[pprint(skip)]
    _skip_me: bool,
}

let point = Point { x: 1.0, y: 2.0, _skip_me: true };
print!("{}", Doc::from(point));
// prints:
// Point {
//   x-coordinate: 1,
//   y-coordinate: 2
// }

Structures can be arbitrarily nested, & c. & c. More involved examples can be found in the tests file.

Dependencies

~1.5MB
~35K SLoC