debug_tree 0.4.0

Build a tree one element at a time and output it as a pretty string.
Documentation
# 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.

<!--{ fibonacci.rs | code: rust }-->
```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!");
}
```
<!--{ end }-->

<!--{ out/fibonacci.txt | code }-->
```
A Fibonacci Tree
├╼ 6
│ ├╼ 1
│ ├╼ 2
│ │ └╼ 1
│ └╼ 3
│   └╼ 1
└╼ That's All Folks!
```
<!--{ end }-->

## 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.

<!--{ multiple_trees.rs | code: rust }-->
```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);
}
```
<!--{ end }-->
<!--{ out/multiple_trees_A.txt | code }-->
```
A TREE
├╼ A TREE
│ └╼ A TREE
└╼ A TREE
  └╼ A TREE
```
<!--{ end }-->
<!--{ out/multiple_trees_B.txt | code }-->
```
B TREE
├──> B TREE
│   ╰──> B TREE
├──> B TREE
│   ╰──> B TREE
╰──> B TREE
    ╰──> B TREE
```
<!--{ end }-->

### Nested Functions

Branches also make nested function calls a lot easier to follow.

<!--{ nested.rs | code: rust }-->
```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();
}
```
<!--{ end }-->
<!--{ out/nested.txt | code }-->
```
a
├╼ b
│ └╼ c
│   └╼ Nothing to see here
└╼ c
  └╼ Nothing to see here
```
<!--{ end }-->

### Line Breaks

Newlines in multi-line strings are automatically indented.

<!--{ multi_line.rs | code: rust }-->
```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");
}
```
<!--{ end }-->

<!--{ out/multi_line.txt | code }-->
```
1
├╼ 1.1
│  Another line...
│  ... and one more line
└╼ 1.2
```
<!--{ end }-->

### 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.

<!--{ panic.rs | code: rust }-->
```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();
}
```
<!--{ end }-->

<!--{ out/panic.txt | code }-->
```
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
```
<!--{ end }-->


### Without Macros

If you prefer not using macros, you can construct `TreeBuilder`s manually.

<!--{ no_macros.rs | code: rust }-->
```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.
}
```
<!--{ end }-->
<!--{ out/no_macros.txt | code }-->
```
1 Branch
└╼ 1.1 Child
2 Sibling
```
<!--{ end }-->