
A customizable tree rendering library for Rust
Provides low-level and high-level APIs for rendering hierarchical data structures, similar to tree, npm ls, or cargo tree.
Installation • Quick Start • Documentation • Examples
Core Features
- Multiple Styles - Unicode, ASCII, Box drawing, and custom styles
- Macro DSL - Declarative syntax for easy tree construction
- Builder API - Fluent interface for easy tree construction
- Iterator Support - Stream large trees without materializing
- Custom Formatters - Format nodes and leaves to your needs
- Optimized - Pre-computed prefixes and efficient rendering
- Zero Dependencies - Lightweight and fast
Analysis & Statistics
- Tree Statistics - Get depth, width, node/leaf counts, and more
- Tree Traversal - Pre-order, post-order, level-order, and filtered iterators
- Tree Search - Find nodes/leaves by label or content, get paths
Transformation & Manipulation
- Tree Transformation - Map, filter, and prune trees functionally
- Tree Sorting - Sort children by label, depth, or custom comparison
- Tree Merging - Merge trees with different strategies (replace, append, merge-by-label)
Utilities
- Path Utilities - Navigate trees by path, flatten to lists
- Tree Comparison - Compare structure, compute diffs, check subtrees
- Export Formats - Export to HTML, SVG, and Graphviz DOT format
- Tree Validation - Validate tree structure
Installation
Add this to your Cargo.toml:
[]
= "0.0.4"
Quick Start
use ;
let tree = Node;
let mut output = Stringnew;
write_tree.unwrap;
println!;
Output:
root
├─ item1
└─ sub
├─ subitem1
└─ subitem2
Usage
use ;
let tree = Node;
let mut output = Stringnew;
write_tree.unwrap;
// root
// └─ item
The tree! macro provides a clean, declarative syntax for constructing trees:
use tree;
let tree = tree! ;
println!;
The macro supports:
- Nodes:
identifier { ... }or"string" { ... } - Leaves:
"string"or bare identifiers (converted to strings) - Nested structures: Arbitrary nesting depth
- Comma-separated: Children separated by commas (trailing comma optional)
use TreeBuilder;
let mut builder = new;
builder.node.leaf.node.leaf.leaf.end.leaf;
let tree = builder.build;
println!;
use Tree;
let tree = Node;
println!;
use ;
let tree = Node;
// Stream lines
for line in lines
// Or collect all at once
let lines: = tree.to_lines;
Styles:
use ;
let tree = Node;
// Predefined styles
tree.render_to_string_with_config;
// Custom style
let style = custom;
tree.render_to_string_with_config;
Formatters (requires formatters feature):
use ;
let tree = Node;
let config = default
.with_node_formatter
.with_leaf_formatter;
tree.render_to_string_with_config;
use ;
use Write;
let tree = Node;
let mut stdout = stdout;
for line in lines
Advanced Features
Get detailed statistics about your tree:
use Tree;
let tree = Node;
// Individual statistics
println!;
println!;
println!;
println!;
// Or get all at once
let stats = tree.stats;
println!;
Iterate over trees in different orders:
use Tree;
let tree = Node;
// Pre-order: root, then children
for node in tree.pre_order
// Post-order: children, then root
for node in tree.post_order
// Level-order: breadth-first
for node in tree.level_order
// Iterate only over nodes or leaves
for node in tree.nodes
for leaf in tree.leaves
Find nodes and leaves in your tree:
use Tree;
let tree = Node;
// Find first node with label
if let Some = tree.find_node
// Find all nodes with label
let all_nodes = tree.find_all_nodes;
// Find leaf containing content
if let Some = tree.find_leaf
// Check if tree contains label/content
if tree.contains
// Get path to a node
if let Some = tree.path_to
Transform trees functionally:
use Tree;
let tree = Node;
// Map node labels
let transformed = tree.map_nodes;
// Map leaf lines
let transformed = tree.map_leaves;
// Filter tree
let filtered = tree.filter;
// Prune tree (inverse of filter)
let pruned = tree.prune;
Sort tree children:
use Tree;
let mut tree = Node;
// Sort by label alphabetically
tree.sort_by_label;
// Sort by depth
tree.sort_by_depth; // deepest first
// Custom sort
let mut compare = ;
tree.sort_children;
Navigate and manipulate trees by path:
use Tree;
let tree = Node;
// Get path to a node
let child = &tree.children.unwrap;
if let Some = tree.get_path
// Get node by path
if let Some = tree.get_by_path
// Modify node by path
let mut tree = tree.clone;
if let Some = tree.get_by_path_mut
// Flatten tree to list
let flattened = tree.flatten;
for entry in flattened
Compare trees and find differences:
use Tree;
let tree1 = Node;
let tree2 = Node;
// Compare structure (ignoring content)
if tree1.eq_structure
// Compute differences
let diffs = tree1.diff;
for diff in diffs
// Check if subtree
let subtree = Leaf;
if subtree.is_subtree_of
Merge trees with different strategies:
use ;
let tree1 = Node;
let tree2 = Node;
// Replace: replace first tree with second
let merged = tree1.merge;
// Append: append all children
let merged = tree1.merge;
// MergeByLabel: merge nodes with matching labels
let merged = tree1.merge;
Export trees to various formats:
use Tree;
use fs;
let tree = Node;
// Create exports directory
create_dir_all.unwrap;
// Export to HTML (with collapsible nodes)
let html = tree.to_html;
write.unwrap;
// Export to SVG
let svg = tree.to_svg;
write.unwrap;
// Export to Graphviz DOT format
let dot = tree.to_dot;
write.unwrap;
// Render with: dot -Tpng exports/tree.dot -o exports/tree.png
Most advanced features are behind feature flags to keep the core library lightweight:
[]
= { = "0.0.4", = ["traversal", "transform", "path", "comparison", "merge", "export"] }
Available features:
traversal- Tree traversal iterators (pre-order, post-order, level-order)transform- Tree transformation operations (map, filter, prune)path- Tree path utilities (get by path, flatten)comparison- Tree comparison and diff operationsmerge- Tree merging with different strategiesexport- Export to HTML, SVG, and DOT formatsbuilder- Builder API for constructing treesiterator- Iterator API for streaming treesmacro- Macro DSL for tree constructionformatters- Custom formatters for nodes and leavescolor- Color output support
Use all feature to enable everything:
= { = "0.0.4", = ["all"] }
- Pre-computed prefixes - Efficient string buffer capacity estimation
- Iterator API - Stream large trees without materializing the entire structure
- Stack-based traversal - Memory-efficient tree walking
- Zero-copy operations - Most operations work with references where possible
Examples
The repository includes comprehensive examples demonstrating all features:
Core Examples:
basic- Basic tree construction and renderingbuilder- Using the builder APIiterator- Streaming large treesmacro- Using the macro DSLcustomization- Custom styles and formatterscomplex- Complex tree structuresfile_tree- File system tree example
Advanced Examples:
statistics- Tree statistics and analysistraversal- Tree traversal iteratorssearch- Tree search and query operationstransform- Tree transformation operationssorting- Tree sorting operationspath- Tree path utilitiescomparison- Tree comparison and diffmerge- Tree merging strategiesexport- Export to HTML, SVG, and DOT formats
Run any example with:
Development
Real-time feedback: This project includes VS Code/Cursor settings (.vscode/settings.json) that configure rust-analyzer to provide real-time feedback:
- Formatting: Automatically formats on save (matches
cargo fmt) - Clippy: Shows clippy warnings/errors as you type (matches pre-commit hook settings)
- Tests: Displays test failures in the editor
Git hooks available via pre-commit (see .pre-commit-config.yaml).
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.