Bluegum
A beautiful tree printer for Rust that renders trees in a single pass with rich formatting and customization options.
Initially designed to handle concrete and abstract syntax trees, it excels at complex data structures with nested nodes and fields.
For Bullion, we use it to visualize the compiler and runtime internals, at various states.
The output is a good balance between readability and diff-friendliness, with line numbers, indentation guides, and ANSI colors.
Features
- Single pass rendering with low memory usage
- Line numbers and indentation guides
- Rich ANSI color formatting
- Customizable styles
- Support for alternate values and debug info
- Tree structure visualization with flexible node types
Usage
Add to your Cargo.toml:
[]
= "0.0.1"
Examples
Basic Tree Structure
Bluegum can represent any tree structure by implementing the Bluegum trait. Here's a simple example:
use Bluegum;
Output:
00│◈─▣ Node
01│ │ · name: root
02│ └─○ children [len=2]
03│ ├─▣ Leaf
04│ │ · value: a
05│ │
06│ └─▣ Node
07│ │ · name: branch
08│ └─○ children [len=2]
09│ ├─▣ Leaf
10│ │ · value: b
11│ │
12│ └─▣ Leaf
13│ · value: c
AST Visualization
Bluegum is particularly useful for visualizing ASTs and other complex tree structures:
use Bluegum;
Customization
Bluegum provides extensive style customization:
use ;
// Assume we have some tree to render
;
let tree = SimpleTree;
let mut styles = default;
styles.hide_line_numbers = true;
styles.new_line_after_node = false;
styles.verbose = true;
let mut printer = new;
printer.render.to_stdout;
Features
- Single Pass: Renders the tree in a single top-down pass for memory efficiency
- Rich Formatting:
- Line numbers
- Indentation guides with Unicode box-drawing characters
- ANSI colors (can be disabled)
- Alternate views and debug information
- Flexible Node Types:
- Regular nodes with fields and children
- Fragment nodes (children only)
- Leaf nodes (fields only)
- Customization:
- Colors and styles
- Line numbers
- Indentation guides
- Debug information
- Spacing and layout
State-Based Tree Printing
The BluegumWithState trait is designed for trees that need external context to render their values. This is particularly useful for:
- Syntax trees with symbol tables
- Trees with interned strings
- ASTs with type information
- Any tree where nodes reference shared data
// Example: A syntax tree with interned strings
use ;
; // Holds index into symbol table
// Regular Bluegum implementation falls back to debug printing indices
// BluegumWithState allows looking up the actual strings
// Usage example fn main() { let symbols = SymbolTable { strings: vec![ "add".to_string(), "1".to_string(), "2".to_string(), ] };
let expr = Expr::Binary {
op: Ident(0), // "add"
left: Box::new(Expr::Literal(Ident(1))), // "1"
right: Box::new(Expr::Literal(Ident(2))), // "2"
};
let mut printer = bluegum::Printer::default();
// Regular printing - shows indices
printer.render(&expr);
printer.to_stdout();
// Print with symbol resolution
let mut printer = bluegum::Printer::default();
printer.render_with_state(&expr, &symbols);
printer.to_stdout();
}
Output without state:
```plaintext
00│◈─▣ Binary
01│ │ · op: 0
02│ ├─○ left
03│ │ └─▣ Literal
04│ │ · value: 1
05│ │
06│ └─○ right
07│ └─▣ Literal
08│ · value: 2
Output with state:
00│◈─▣ Binary
01│ │ · op: add id:0
02│ ├─○ left
03│ │ └─▣ Literal
04│ │ · value: 1 id:1
05│ │
06│ └─○ right
07│ └─▣ Literal
08│ · value: 2 id:2
Type Information Example
Another common use case is printing ASTs with type information:
use HashMap;
use BluegumWithState;
// Simplified Expr for this example
This produces output showing both the AST structure and inferred types:
00│◈─▣ Binary type:int
01│ │ · op: +
02│ ├─○ left
03│ │ └─▣ Literal type:int
04│ │ · value: 1
05│ │
06│ └─○ right
07│ └─▣ Call type:int
08│ · name: add
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
Licensed under BlueOak-1.0.0.