Skip to main content

tree_display/
lib.rs

1//! A library for displaying Rust data structures as syntax-highlighted trees.
2//!
3//! `tree-display` provides a simple derive macro (`#[derive(TreeDisplay)]`)
4//! to render any data structure as a beautifully formatted tree in the terminal.
5//! Features include syntax highlighting, custom value mapping, and full theming support.
6//!
7//! ## Quick Start
8//! ```no_run
9//! use tree_display::{TreeDisplay, Formatter};
10//!
11//! #[derive(Debug, TreeDisplay)]
12//! struct Person {
13//!     name: String,
14//!     age: u32,
15//! }
16//!
17//! let person = Person {
18//!     name: "Alice".to_string(),
19//!     age: 30,
20//! };
21//!
22//! println!("{}", Formatter::of(&person).format());
23//! ```
24//!
25//! ## Features
26//! - **Derive macro**: `#[derive(TreeDisplay)]` for automatic tree generation
27//! - **Field attributes**: Control rendering of individual fields:
28//!   - `#[tree(map)]` - Apply a custom mapper from [`Context`]
29//!   - `#[tree(ignore)]` - Exclude a field from the tree
30//!   - `#[tree(label = "...")]` - Override the field's display label
31//!   - `#[tree(unlabeled)]` - Display the field without a label
32//! - **Custom mapping**: Transform values with [`Context`] mappers
33//! - **Theming**: Predefined themes (VS Code Dark+, Solarized, etc.)
34//! - **Color support**: Optional ANSI color highlighting
35//! - **Line styles**: ASCII or Unicode box-drawing characters
36//! - **Formatting**: Labels, alignment, and custom content types
37
38pub mod color;
39pub mod context;
40pub mod format;
41pub mod graphics;
42pub mod support;
43pub mod theme;
44
45use format::Content;
46
47// Re-export the most commonly used types at root
48pub use color::Colors;
49pub use context::Context;
50pub use derive::TreeDisplay;
51pub use format::Formatter;
52pub use graphics::Graphics;
53pub use theme::Theme;
54
55// ──── API ───────────────────────────────────────────────────────────────────────────────────────
56
57/// A type that can be displayed as a tree.
58///
59/// This trait is automatically implemented by `#[derive(TreeDisplay)]`
60/// and is also implemented for many standard library types.
61pub trait TreeDisplay {
62  /// Converts the value into a tree structure using the given context.
63  ///
64  /// The context provides custom mappers that can transform values before they are displayed.
65  fn tree(&self, context: &Context) -> Tree;
66}
67
68/// A tree node containing content and child subtrees.
69///
70/// Trees are built from a root node with zero or more child nodes,
71/// each of which can have their own children. Nodes can optionally
72/// have labels that appear alongside their content.
73///
74/// ## Example
75/// ```
76/// use tree_display::{Tree, format::Member};
77///
78/// let tree = Tree::leaf("root")
79///     .labeled(Member::new("label"));
80/// ```
81pub struct Tree {
82  /// Optional label displayed next to the content
83  pub label: Option<Box<dyn Content>>,
84  /// The main content of this node
85  pub content: Box<dyn Content>,
86  /// Child subtrees
87  pub subtrees: Vec<Tree>,
88}
89
90// ──── Utility ───────────────────────────────────────────────────────────────────────────────────
91
92impl Tree {
93  /// Creates a new tree node with content and children.
94  pub fn new(content: impl Content, subtrees: Vec<Tree>) -> Tree {
95    Tree {
96      label: None,
97      content: Box::new(content),
98      subtrees,
99    }
100  }
101
102  /// Creates a leaf node (a node with no children).
103  pub fn leaf(content: impl Content) -> Tree {
104    Tree {
105      label: None,
106      content: Box::new(content),
107      subtrees: Vec::new(),
108    }
109  }
110
111  /// Adds a label to the node.
112  ///
113  /// Labels appear before the content, typically as a key or name.
114  pub fn labeled(mut self, label: impl Content) -> Self {
115    self.label = Some(Box::new(label));
116    self
117  }
118
119  /// Returns whether this node is a leaf (has no children).
120  pub fn is_leaf(&self) -> bool {
121    self.subtrees.is_empty()
122  }
123}