# Debug Tree This library allows you to build a tree one element at a time and output it as a pretty string. The tree can easily be output to a `String`, `stdout` or a file. This is particularly convenient for generating clean output from nested and recursive functions. * [Recursive Fibonacci Example](#recursive-fibonacci-example) * [Overview](#overview) * [More Examples](#more-examples) * [Multiple Tagged Trees](#multiple-tagged-trees) * [Nested Functions](#nested-functions) * [Panic](#panics) * [Without Macros](#without-macros) ## Recursive Fibonacci Example Using the `add_branch!()` macro at the start of the `factors()` function, you can generate an entire call tree, with minimal effort. ```rust use debug_tree::*; fn factors(x: usize) { add_branch!("{}", x); // <~ THE MAGIC LINE for i in 1..x { if x % i == 0 { factors(i); } } } fn main() { // output to file at the end of this block defer_write!("examples/out/fibonacci.txt"); add_branch!("A Fibonacci Tree"); factors(6); add_leaf!("That's All Folks!"); } ``` ``` A Fibonacci Tree ├╼ 6 │ ├╼ 1 │ ├╼ 2 │ │ └╼ 1 │ └╼ 3 │ └╼ 1 └╼ That's All Folks! ``` ## Overview - Add a branch - `add_branch!("Hello, {}", "World")` - The branch will exit at the end of the current block - Add a leaf - `add_leaf!("I am a {}", "leaf")` - Added to the current scoped branch - Print a tree, or write it to file at the end of a block - `defer_print!()` - `defer_write!("filename.txt")` - The tree will be empty after these calls - To prevent clearing, use `defer_peek_print!` and `defer_peek_write!` - Handle multiple trees using named trees - `add_branch_to!("A", "I'm a branch on tree 'A'")` - `add_leaf_to!("A", "I'm a leaf on tree 'A'")` - `defer_print!("A")` - `defer_write!("A", "filename.txt")` - Get a named tree - `tree("TREE_NAME")` - Retrieve the pretty-string from a tree - `tree("TREE_NAME").string()` - Usage across threads - `default_tree()` is local to each thread - Named trees are shared between threads ## More Examples ### Multiple Tagged Trees If you need multiple, separated trees you can use a name tag. ```rust use debug_tree::*; fn populate(tree_name: &str, n_children: usize) { add_branch_to!(tree_name, "{} TREE", tree_name); for _ in 0..n_children { populate(tree_name, n_children / 2); } } fn main() { // Override tree config (just for "B") let b_tree = tree("B"); b_tree.set_config_override( TreeConfig::new() .indent(4) .symbols(TreeSymbols::with_rounded().leaf("> ")), ); defer_write!(b_tree, "examples/out/multiple_trees_B.txt"); defer_write!("A", "examples/out/multiple_trees_A.txt"); populate("A", 2); populate("B", 3); } ``` ``` A TREE ├╼ A TREE │ └╼ A TREE └╼ A TREE └╼ A TREE ``` ``` B TREE ├──> B TREE │ ╰──> B TREE ├──> B TREE │ ╰──> B TREE ╰──> B TREE ╰──> B TREE ``` ### Nested Functions Branches also make nested function calls a lot easier to follow. ```rust use debug_tree::*; fn a() { add_branch!("a"); b(); c(); } fn b() { add_branch!("b"); c(); } fn c() { add_branch!("c"); add_leaf!("Nothing to see here"); } fn main() { defer_write!("examples/out/nested.txt"); a(); } ``` ``` a ├╼ b │ └╼ c │ └╼ Nothing to see here └╼ c └╼ Nothing to see here ``` ### Line Breaks Newlines in multi-line strings are automatically indented. ```rust use debug_tree::*; fn main() { // output to file at the end of this block defer_write!("examples/out/multi_line.txt"); add_branch!("1"); add_leaf!("1.1\nAnother line...\n... and one more line"); add_leaf!("1.2"); } ``` ``` 1 ├╼ 1.1 │ Another line... │ ... and one more line └╼ 1.2 ``` ### Panics Even if there is a panic, the tree is not lost! The `defer_` functions were introduced to allow the tree to be printed our written to file in the case of a `panic!` or early return. ```rust use debug_tree::*; fn i_will_panic() { add_branch!("Here are my last words"); add_leaf!("Stay calm, and try not to panic"); panic!("I told you so...") } fn main() { // output to file at the end of this block defer_write!("examples/out/panic.txt"); // print at the end of this block { add_branch!("By using the 'defer_' functions"); add_branch!("Output will still be generated"); add_branch!("Otherwise you might lose your valuable tree!"); } add_branch!("Now for something crazy..."); i_will_panic(); } ``` ``` By using the 'defer_' functions └╼ Output will still be generated └╼ Otherwise you might lose your valuable tree! Now for something crazy... └╼ Here are my last words └╼ Stay calm, and try not to panic ``` ### Without Macros If you prefer not using macros, you can construct `TreeBuilder`s manually. ```rust use debug_tree::TreeBuilder; fn main() { // Make a new tree. let tree = TreeBuilder::new(); // Add a scoped branch. The next item added will belong to the branch. let mut branch = tree.add_branch("1 Branch"); // Add a leaf to the current branch tree.add_leaf("1.1 Child"); // Leave scope early branch.release(); tree.add_leaf("2 Sibling"); // output to file tree.write("examples/out/no_macros.txt").ok(); // Write and flush. } ``` ``` 1 Branch └╼ 1.1 Child 2 Sibling ```