1 use std::collections::VecDeque;
2 use std::fmt::{self, Display};
3 use std::rc::Rc;
4
5 /// a simple recursive type which is able to render its
6 /// components in a tree-like format
7 #[derive(Debug)]
8 pub struct Tree<D: Display> {
9 root: D,
10 leaves: Vec<Tree<D>>,
11 multiline: bool,
12 glyphs: GlyphPalette,
13 }
14
15 impl<D: Display> Tree<D> {
new(root: D, leaves: Vec<Tree<D>>) -> Tree<D>16 pub fn new(root: D, leaves: Vec<Tree<D>>) -> Tree<D> {
17 Tree {
18 root,
19 leaves,
20 multiline: false,
21 glyphs: GlyphPalette::new(),
22 }
23 }
24
root(root: D) -> Tree<D>25 pub fn root(root: D) -> Tree<D> {
26 Tree {
27 root,
28 leaves: Vec::new(),
29 multiline: false,
30 glyphs: GlyphPalette::new(),
31 }
32 }
33
34 /// Ensure all lines for `root` are indented
with_multiline(mut self, yes: bool) -> Self35 pub fn with_multiline(mut self, yes: bool) -> Self {
36 self.multiline = yes;
37 self
38 }
39
40 /// Ensure all lines for `root` are indented
set_multiline(&mut self, yes: bool) -> &mut Self41 pub fn set_multiline(&mut self, yes: bool) -> &mut Self {
42 self.multiline = yes;
43 self
44 }
45
46 /// Customize the rendering of this node
with_glyphs(mut self, glyphs: GlyphPalette) -> Self47 pub fn with_glyphs(mut self, glyphs: GlyphPalette) -> Self {
48 self.glyphs = glyphs;
49 self
50 }
51
52 /// Customize the rendering of this node
set_glyphs(&mut self, glyphs: GlyphPalette) -> &mut Self53 pub fn set_glyphs(&mut self, glyphs: GlyphPalette) -> &mut Self {
54 self.glyphs = glyphs;
55 self
56 }
57
push(&mut self, leaf: Tree<D>) -> &mut Self58 pub fn push(&mut self, leaf: Tree<D>) -> &mut Self {
59 self.leaves.push(leaf);
60 self
61 }
62 }
63
64 impl<D: Display> Extend<D> for Tree<D> {
extend<T: IntoIterator<Item = D>>(&mut self, iter: T)65 fn extend<T: IntoIterator<Item = D>>(&mut self, iter: T) {
66 self.leaves.extend(iter.into_iter().map(Tree::root))
67 }
68 }
69
70 impl<D: Display> Extend<Tree<D>> for Tree<D> {
extend<T: IntoIterator<Item = Tree<D>>>(&mut self, iter: T)71 fn extend<T: IntoIterator<Item = Tree<D>>>(&mut self, iter: T) {
72 self.leaves.extend(iter)
73 }
74 }
75
76 impl<D: Display> Display for Tree<D> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 writeln!(f, "{}", self.root)?;
79 let mut queue = DisplauQueue::new();
80 let no_space = Rc::new(Vec::new());
81 enqueue_leaves(&mut queue, self, no_space);
82 while let Some((last, leaf, spaces)) = queue.pop_front() {
83 let mut prefix = (
84 if last {
85 leaf.glyphs.last_item
86 } else {
87 leaf.glyphs.middle_item
88 },
89 leaf.glyphs.item_indent,
90 );
91
92 if leaf.multiline {
93 let rest_prefix = (
94 if last {
95 leaf.glyphs.last_skip
96 } else {
97 leaf.glyphs.middle_skip
98 },
99 leaf.glyphs.skip_indent,
100 );
101 debug_assert_eq!(prefix.0.chars().count(), rest_prefix.0.chars().count());
102 debug_assert_eq!(prefix.1.chars().count(), rest_prefix.1.chars().count());
103
104 let root = leaf.root.to_string();
105 for line in root.lines() {
106 // print single line
107 for s in spaces.as_slice() {
108 if *s {
109 write!(f, "{}{}", self.glyphs.last_skip, self.glyphs.skip_indent)?;
110 } else {
111 write!(f, "{}{}", self.glyphs.middle_skip, self.glyphs.skip_indent)?;
112 }
113 }
114 writeln!(f, "{}{}{}", prefix.0, prefix.1, line)?;
115 prefix = rest_prefix;
116 }
117 } else {
118 // print single line
119 for s in spaces.as_slice() {
120 if *s {
121 write!(f, "{}{}", self.glyphs.last_skip, self.glyphs.skip_indent)?;
122 } else {
123 write!(f, "{}{}", self.glyphs.middle_skip, self.glyphs.skip_indent)?;
124 }
125 }
126 writeln!(f, "{}{}{}", prefix.0, prefix.1, leaf.root)?;
127 }
128
129 // recurse
130 if !leaf.leaves.is_empty() {
131 let s: &Vec<bool> = &spaces;
132 let mut child_spaces = s.clone();
133 child_spaces.push(last);
134 let child_spaces = Rc::new(child_spaces);
135 enqueue_leaves(&mut queue, leaf, child_spaces);
136 }
137 }
138 Ok(())
139 }
140 }
141
142 type DisplauQueue<'t, D> = VecDeque<(bool, &'t Tree<D>, Rc<Vec<bool>>)>;
143
enqueue_leaves<'t, D: Display>( queue: &mut DisplauQueue<'t, D>, parent: &'t Tree<D>, spaces: Rc<Vec<bool>>, )144 fn enqueue_leaves<'t, D: Display>(
145 queue: &mut DisplauQueue<'t, D>,
146 parent: &'t Tree<D>,
147 spaces: Rc<Vec<bool>>,
148 ) {
149 for (i, leaf) in parent.leaves.iter().rev().enumerate() {
150 let last = i == 0;
151 queue.push_front((last, leaf, spaces.clone()));
152 }
153 }
154
155 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
156 pub struct GlyphPalette {
157 pub middle_item: &'static str,
158 pub last_item: &'static str,
159 pub item_indent: &'static str,
160
161 pub middle_skip: &'static str,
162 pub last_skip: &'static str,
163 pub skip_indent: &'static str,
164 }
165
166 impl GlyphPalette {
new() -> Self167 pub const fn new() -> Self {
168 Self {
169 middle_item: "├",
170 last_item: "└",
171 item_indent: "── ",
172
173 middle_skip: "│",
174 last_skip: " ",
175 skip_indent: " ",
176 }
177 }
178 }
179
180 impl Default for GlyphPalette {
default() -> Self181 fn default() -> Self {
182 Self::new()
183 }
184 }
185
186 #[cfg(test)]
187 mod tests {
188 use super::Tree;
189 #[test]
render_tree_root()190 fn render_tree_root() {
191 let tree = Tree::root("foo");
192 assert_eq!(format!("{}", tree), "foo\n")
193 }
194
195 #[test]
render_tree_with_leaves()196 fn render_tree_with_leaves() {
197 let tree = Tree::new("foo", vec![Tree::new("bar", vec![Tree::root("baz")])]);
198 assert_eq!(
199 format!("{}", tree),
200 r#"foo
201 └── bar
202 └── baz
203 "#
204 )
205 }
206
207 #[test]
render_tree_with_multiple_leaves()208 fn render_tree_with_multiple_leaves() {
209 let tree = Tree::new("foo", vec![Tree::root("bar"), Tree::root("baz")]);
210 assert_eq!(
211 format!("{}", tree),
212 r#"foo
213 ├── bar
214 └── baz
215 "#
216 )
217 }
218
219 #[test]
render_tree_with_multiline_leaf()220 fn render_tree_with_multiline_leaf() {
221 let tree = Tree::new(
222 "foo",
223 vec![
224 Tree::root("hello\nworld").with_multiline(true),
225 Tree::root("goodbye\nworld").with_multiline(true),
226 ],
227 );
228 assert_eq!(
229 format!("{}", tree),
230 r#"foo
231 ├── hello
232 │ world
233 └── goodbye
234 world
235 "#
236 )
237 }
238 }
239