1# Debug Tree 2 3This library allows you to build a tree one element at a time and output it as a pretty string. 4 5The tree can easily be output to a `String`, `stdout` or a file. 6 7This is particularly convenient for generating clean output from nested and recursive functions. 8 9* [Recursive Fibonacci Example](#recursive-fibonacci-example) 10* [Overview](#overview) 11* [More Examples](#more-examples) 12 * [Multiple Tagged Trees](#multiple-tagged-trees) 13 * [Nested Functions](#nested-functions) 14 * [Panic](#panics) 15 * [Without Macros](#without-macros) 16 17 18## Recursive Fibonacci Example 19 20Using the `add_branch!()` macro at the start of the `factors()` function, you can generate an entire call tree, with minimal effort. 21 22<!--{ fibonacci.rs | code: rust }--> 23```rust 24use debug_tree::*; 25 26fn factors(x: usize) { 27 add_branch!("{}", x); // <~ THE MAGIC LINE 28 for i in 1..x { 29 if x % i == 0 { 30 factors(i); 31 } 32 } 33} 34 35fn main() { 36 // output to file at the end of this block 37 defer_write!("examples/out/fibonacci.txt"); 38 add_branch!("A Fibonacci Tree"); 39 factors(6); 40 add_leaf!("That's All Folks!"); 41} 42``` 43<!--{ end }--> 44 45<!--{ out/fibonacci.txt | code }--> 46``` 47A Fibonacci Tree 48├╼ 6 49│ ├╼ 1 50│ ├╼ 2 51│ │ └╼ 1 52│ └╼ 3 53│ └╼ 1 54└╼ That's All Folks! 55``` 56<!--{ end }--> 57 58## Overview 59 60- Add a branch 61 - `add_branch!("Hello, {}", "World")` 62 - The branch will exit at the end of the current block 63 64- Add a leaf 65 - `add_leaf!("I am a {}", "leaf")` 66 - Added to the current scoped branch 67 68- Print a tree, or write it to file at the end of a block 69 - `defer_print!()` 70 - `defer_write!("filename.txt")` 71 - The tree will be empty after these calls 72 - To prevent clearing, use `defer_peek_print!` and `defer_peek_write!` 73 74 75- Handle multiple trees using named trees 76 - `add_branch_to!("A", "I'm a branch on tree 'A'")` 77 - `add_leaf_to!("A", "I'm a leaf on tree 'A'")` 78 - `defer_print!("A")` 79 - `defer_write!("A", "filename.txt")` 80 81- Get a named tree 82 - `tree("TREE_NAME")` 83 84- Retrieve the pretty-string from a tree 85 - `tree("TREE_NAME").string()` 86 87 88- Usage across threads 89 - `default_tree()` is local to each thread 90 - Named trees are shared between threads 91 92## More Examples 93 94### Multiple Tagged Trees 95 96If you need multiple, separated trees you can use a name tag. 97 98<!--{ multiple_trees.rs | code: rust }--> 99```rust 100use debug_tree::*; 101 102fn populate(tree_name: &str, n_children: usize) { 103 add_branch_to!(tree_name, "{} TREE", tree_name); 104 for _ in 0..n_children { 105 populate(tree_name, n_children / 2); 106 } 107} 108fn main() { 109 // Override tree config (just for "B") 110 let b_tree = tree("B"); 111 b_tree.set_config_override( 112 TreeConfig::new() 113 .indent(4) 114 .symbols(TreeSymbols::with_rounded().leaf("> ")), 115 ); 116 defer_write!(b_tree, "examples/out/multiple_trees_B.txt"); 117 defer_write!("A", "examples/out/multiple_trees_A.txt"); 118 119 populate("A", 2); 120 populate("B", 3); 121} 122``` 123<!--{ end }--> 124<!--{ out/multiple_trees_A.txt | code }--> 125``` 126A TREE 127├╼ A TREE 128│ └╼ A TREE 129└╼ A TREE 130 └╼ A TREE 131``` 132<!--{ end }--> 133<!--{ out/multiple_trees_B.txt | code }--> 134``` 135B TREE 136├──> B TREE 137│ ╰──> B TREE 138├──> B TREE 139│ ╰──> B TREE 140╰──> B TREE 141 ╰──> B TREE 142``` 143<!--{ end }--> 144 145### Nested Functions 146 147Branches also make nested function calls a lot easier to follow. 148 149<!--{ nested.rs | code: rust }--> 150```rust 151use debug_tree::*; 152fn a() { 153 add_branch!("a"); 154 b(); 155 c(); 156} 157fn b() { 158 add_branch!("b"); 159 c(); 160} 161fn c() { 162 add_branch!("c"); 163 add_leaf!("Nothing to see here"); 164} 165 166fn main() { 167 defer_write!("examples/out/nested.txt"); 168 a(); 169} 170``` 171<!--{ end }--> 172<!--{ out/nested.txt | code }--> 173``` 174a 175├╼ b 176│ └╼ c 177│ └╼ Nothing to see here 178└╼ c 179 └╼ Nothing to see here 180``` 181<!--{ end }--> 182 183### Line Breaks 184 185Newlines in multi-line strings are automatically indented. 186 187<!--{ multi_line.rs | code: rust }--> 188```rust 189use debug_tree::*; 190fn main() { 191 // output to file at the end of this block 192 defer_write!("examples/out/multi_line.txt"); 193 add_branch!("1"); 194 add_leaf!("1.1\nAnother line...\n... and one more line"); 195 add_leaf!("1.2"); 196} 197``` 198<!--{ end }--> 199 200<!--{ out/multi_line.txt | code }--> 201``` 2021 203├╼ 1.1 204│ Another line... 205│ ... and one more line 206└╼ 1.2 207``` 208<!--{ end }--> 209 210### Panics 211Even if there is a panic, the tree is not lost! 212The `defer_` functions were introduced to allow the tree 213to be printed our written to file in the case of a `panic!` or early return. 214 215<!--{ panic.rs | code: rust }--> 216```rust 217use debug_tree::*; 218 219fn i_will_panic() { 220 add_branch!("Here are my last words"); 221 add_leaf!("Stay calm, and try not to panic"); 222 panic!("I told you so...") 223} 224 225fn main() { 226 // output to file at the end of this block 227 defer_write!("examples/out/panic.txt"); 228 // print at the end of this block 229 { 230 add_branch!("By using the 'defer_' functions"); 231 add_branch!("Output will still be generated"); 232 add_branch!("Otherwise you might lose your valuable tree!"); 233 } 234 add_branch!("Now for something crazy..."); 235 i_will_panic(); 236} 237``` 238<!--{ end }--> 239 240<!--{ out/panic.txt | code }--> 241``` 242By using the 'defer_' functions 243└╼ Output will still be generated 244 └╼ Otherwise you might lose your valuable tree! 245Now for something crazy... 246└╼ Here are my last words 247 └╼ Stay calm, and try not to panic 248``` 249<!--{ end }--> 250 251 252### Without Macros 253 254If you prefer not using macros, you can construct `TreeBuilder`s manually. 255 256<!--{ no_macros.rs | code: rust }--> 257```rust 258use debug_tree::TreeBuilder; 259 260fn main() { 261 // Make a new tree. 262 let tree = TreeBuilder::new(); 263 264 // Add a scoped branch. The next item added will belong to the branch. 265 let mut branch = tree.add_branch("1 Branch"); 266 267 // Add a leaf to the current branch 268 tree.add_leaf("1.1 Child"); 269 270 // Leave scope early 271 branch.release(); 272 tree.add_leaf("2 Sibling"); 273 // output to file 274 tree.write("examples/out/no_macros.txt").ok(); // Write and flush. 275} 276``` 277<!--{ end }--> 278<!--{ out/no_macros.txt | code }--> 279``` 2801 Branch 281└╼ 1.1 Child 2822 Sibling 283``` 284<!--{ end }-->