Import 'debug_tree' crate

Request Document: go/android-rust-importing-crates
For CL Reviewers: go/android3p#cl-review
For Build Team: go/ab-third-party-imports
Bug: http://b/328410074
Test: m libdebug_tree
Change-Id: I4283f42b85c79fe280d2eebe2be8f8283b6abe64

Change-Id: I537f1f12b44c56a83aa973b440271b19ca2bb40d
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..27bd387
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "5b709de2d8872102b20b566c408d31d0662d7a9f"
+  }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d4fe7bd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+/target
+**/*.rs.bk
+.idea
+*.lock
+test_out
+
+.DS_Store
diff --git a/.md-inc.toml b/.md-inc.toml
new file mode 100644
index 0000000..57b0690
--- /dev/null
+++ b/.md-inc.toml
@@ -0,0 +1,2 @@
+base_dir = "examples"
+files = ["README.md"]
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..ed34a1a
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,40 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file as changes will be overridden on upgrade.
+
+// TODO: Add license.
+rust_test {
+    name: "debug_tree_test_src_lib",
+    host_supported: true,
+    crate_name: "debug_tree",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.4.0",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
+    edition: "2018",
+    rustlibs: [
+        "libfutures",
+        "libonce_cell",
+        "libtokio",
+    ],
+}
+
+rust_library {
+    name: "libdebug_tree",
+    host_supported: true,
+    crate_name: "debug_tree",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.4.0",
+    srcs: ["src/lib.rs"],
+    edition: "2018",
+    rustlibs: ["libonce_cell"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    product_available: true,
+    vendor_available: true,
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..d6c6559
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,33 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "debug_tree"
+version = "0.4.0"
+authors = ["Marty Papamanolis <[email protected]>"]
+description = "Build a tree one element at a time and output it as a pretty string."
+readme = "README.md"
+license = "MIT"
+repository = "https://github.com/martypapa/debug-tree"
+
+[lib]
+name = "debug_tree"
+crate-type = ["lib"]
+[dependencies.once_cell]
+version = "1"
+[dev-dependencies.futures]
+version = "0.3.4"
+
+[dev-dependencies.tokio]
+version = "0.2.9"
+features = ["macros", "fs"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9cf1062
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..6537ff9
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "debug_tree"
+description: "Build a tree one element at a time and output it as a pretty string."
+third_party {
+  identifier {
+    type: "crates.io"
+    value: "debug_tree"
+  }
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/debug_tree/debug_tree-0.4.0.crate"
+    primary_source: true
+  }
+  version: "0.4.0"
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2024
+    month: 3
+    day: 21
+  }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..48bea6e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 688011
+include platform/prebuilts/rust:main:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..84511aa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,284 @@
+# 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 }-->
\ No newline at end of file
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..c8842d1
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,4 @@
+{
+  "run_cargo": false,
+  "tests": true
+}
diff --git a/doc/build/LICENSE.adoc b/doc/build/LICENSE.adoc
new file mode 100644
index 0000000..1d67901
--- /dev/null
+++ b/doc/build/LICENSE.adoc
@@ -0,0 +1,19 @@
+Copyright (C) 2014-2019 The Asciidoctor Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/doc/build/asciidoc-coalescer.rb b/doc/build/asciidoc-coalescer.rb
new file mode 100644
index 0000000..a4f9968
--- /dev/null
+++ b/doc/build/asciidoc-coalescer.rb
@@ -0,0 +1,66 @@
+#!/usr/bin/env ruby
+
+# This script coalesces the AsciiDoc content from a document master into a
+# single output file. It does so by resolving all preprocessor directives in
+# the document, and in any files which are included. The resolving of include
+# directives is likely of most interest to users of this script.
+#
+# This script works by using Asciidoctor's PreprocessorReader to read and
+# resolve all the lines in the specified input file. The script then writes the
+# result to the output.
+#
+# The script only recognizes attributes passed in as options or those defined
+# in the document header. It does not currently process attributes defined in
+# other, arbitrary locations within the document.
+#
+# You can find a similar extension written against AsciidoctorJ here:
+# https://github.com/hibernate/hibernate-asciidoctor-extensions/blob/master/src/main/java/org/hibernate/infra/asciidoctor/extensions/savepreprocessed/SavePreprocessedOutputPreprocessor.java
+
+# TODO
+# - add cli option to write attributes passed to cli to header of document
+# - escape all preprocessor directives after lines are processed (these are preprocessor directives that were escaped in the input)
+# - wrap in a custom converter so it can be used as an extension
+
+require 'asciidoctor'
+require 'optparse'
+
+options = { attributes: [], output: '-' }
+OptionParser.new do |opts|
+  opts.banner = 'Usage: ruby asciidoc-coalescer.rb [OPTIONS] FILE'
+  opts.on('-a', '--attribute key[=value]', 'A document attribute to set in the form of key[=value]') do |a|
+    options[:attributes] << a
+  end
+  opts.on('-o', '--output FILE', 'Write output to FILE instead of stdout.') do |o|
+    options[:output] = o
+  end
+end.parse!
+
+unless (source_file = ARGV.shift)
+  warn 'Please specify an AsciiDoc source file to coalesce.'
+  exit 1
+end
+
+unless (output_file = options[:output]) == '-'
+  if (output_file = File.expand_path output_file) == (File.expand_path source_file)
+    warn 'Source and output cannot be the same file.'
+    exit 1
+  end
+end
+
+# NOTE first, resolve attributes defined at the end of the document header
+# QUESTION can we do this in a single load?
+doc = Asciidoctor.load_file source_file, safe: :unsafe, header_only: true, attributes: options[:attributes]
+# NOTE quick and dirty way to get the attributes set or unset by the document header
+header_attr_names = (doc.instance_variable_get :@attributes_modified).to_a
+header_attr_names.each {|k| doc.attributes[%(#{k}!)] = '' unless doc.attr? k }
+
+doc = Asciidoctor.load_file source_file, safe: :unsafe, parse: false, attributes: doc.attributes
+# FIXME also escape ifdef, ifndef, ifeval and endif directives
+# FIXME do this more carefully by reading line by line; if input differs by output by leading backslash, restore original line
+lines = doc.reader.read.gsub(/^include::(?=.*\[\]$)/m, '\\include::')
+
+if output_file == '-'
+  puts lines
+else
+  File.open(output_file, 'w') {|f| f.write lines }
+end
\ No newline at end of file
diff --git a/doc/readme_template.adoc b/doc/readme_template.adoc
new file mode 100644
index 0000000..ec7cabb
--- /dev/null
+++ b/doc/readme_template.adoc
@@ -0,0 +1,127 @@
+:examples: ../examples/
+
+= 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.
+
+
+:toc:
+
+== 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.
+
+[source,rust]
+----
+include::{examples}fibonacci.rs[]
+----
+
+----
+include::{examples}out/fibonacci.txt[]
+----
+== 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!`
+
+* Get the trees pretty-string
+- 
+
+* 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.
+
+[source,rust]
+----
+include::{examples}multiple_trees.rs[]
+----
+----
+include::{examples}out/multiple_trees_A.txt[]
+----
+----
+include::{examples}out/multiple_trees_B.txt[]
+----
+
+=== Nested Functions
+
+Branches also make nested function calls a lot easier to follow.
+
+[source,rust]
+----
+include::{examples}nested.rs[]
+----
+----
+include::{examples}out/nested.txt[]
+----
+
+=== Line Breaks
+
+Newlines in multi-line strings are automatically indented.
+
+[source,rust]
+----
+include::{examples}multi_line.rs[]
+----
+----
+include::{examples}out/multi_line.txt[]
+----
+
+=== 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.
+
+[source,rust]
+----
+include::{examples}panic.rs[]
+----
+----
+include::{examples}out/panic.txt[]
+----
+
+
+=== Without Macros
+
+If you prefer not using macros, you can construct `TreeBuilder`s manually.
+
+[source,rust]
+----
+include::{examples}no_macros.rs[]
+----
+----
+include::{examples}out/no_macros.txt[]
+----
diff --git a/examples/fibonacci.rs b/examples/fibonacci.rs
new file mode 100644
index 0000000..1095592
--- /dev/null
+++ b/examples/fibonacci.rs
@@ -0,0 +1,18 @@
+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!");
+}
diff --git a/examples/multi_line.rs b/examples/multi_line.rs
new file mode 100644
index 0000000..fbe9c6c
--- /dev/null
+++ b/examples/multi_line.rs
@@ -0,0 +1,8 @@
+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");
+}
diff --git a/examples/multiple_trees.rs b/examples/multiple_trees.rs
new file mode 100644
index 0000000..01a4941
--- /dev/null
+++ b/examples/multiple_trees.rs
@@ -0,0 +1,22 @@
+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);
+}
diff --git a/examples/nested.rs b/examples/nested.rs
new file mode 100644
index 0000000..5315be5
--- /dev/null
+++ b/examples/nested.rs
@@ -0,0 +1,19 @@
+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();
+}
diff --git a/examples/no_macros.rs b/examples/no_macros.rs
new file mode 100644
index 0000000..1891bf4
--- /dev/null
+++ b/examples/no_macros.rs
@@ -0,0 +1,18 @@
+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.
+}
diff --git a/examples/out/fibonacci.txt b/examples/out/fibonacci.txt
new file mode 100644
index 0000000..40725b8
--- /dev/null
+++ b/examples/out/fibonacci.txt
@@ -0,0 +1,8 @@
+A Fibonacci Tree
+├╼ 6
+│ ├╼ 1
+│ ├╼ 2
+│ │ └╼ 1
+│ └╼ 3
+│   └╼ 1
+└╼ That's All Folks!
\ No newline at end of file
diff --git a/examples/out/multi_line.txt b/examples/out/multi_line.txt
new file mode 100644
index 0000000..93e17ff
--- /dev/null
+++ b/examples/out/multi_line.txt
@@ -0,0 +1,5 @@
+1
+├╼ 1.1
+│  Another line...
+│  ... and one more line
+└╼ 1.2
\ No newline at end of file
diff --git a/examples/out/multiple_trees_A.txt b/examples/out/multiple_trees_A.txt
new file mode 100644
index 0000000..d4b76d4
--- /dev/null
+++ b/examples/out/multiple_trees_A.txt
@@ -0,0 +1,5 @@
+A TREE
+├╼ A TREE
+│ └╼ A TREE
+└╼ A TREE
+  └╼ A TREE
\ No newline at end of file
diff --git a/examples/out/multiple_trees_B.txt b/examples/out/multiple_trees_B.txt
new file mode 100644
index 0000000..b2cce80
--- /dev/null
+++ b/examples/out/multiple_trees_B.txt
@@ -0,0 +1,7 @@
+B TREE
+├──> B TREE
+│   ╰──> B TREE
+├──> B TREE
+│   ╰──> B TREE
+╰──> B TREE
+    ╰──> B TREE
\ No newline at end of file
diff --git a/examples/out/nested.txt b/examples/out/nested.txt
new file mode 100644
index 0000000..f629559
--- /dev/null
+++ b/examples/out/nested.txt
@@ -0,0 +1,6 @@
+a
+├╼ b
+│ └╼ c
+│   └╼ Nothing to see here
+└╼ c
+  └╼ Nothing to see here
\ No newline at end of file
diff --git a/examples/out/no_macros.txt b/examples/out/no_macros.txt
new file mode 100644
index 0000000..9ee6b47
--- /dev/null
+++ b/examples/out/no_macros.txt
@@ -0,0 +1,3 @@
+1 Branch
+└╼ 1.1 Child
+2 Sibling
\ No newline at end of file
diff --git a/examples/out/panic.txt b/examples/out/panic.txt
new file mode 100644
index 0000000..3e5b29e
--- /dev/null
+++ b/examples/out/panic.txt
@@ -0,0 +1,6 @@
+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
\ No newline at end of file
diff --git a/examples/panic.rs b/examples/panic.rs
new file mode 100644
index 0000000..e1a9563
--- /dev/null
+++ b/examples/panic.rs
@@ -0,0 +1,20 @@
+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();
+}
diff --git a/src/default.rs b/src/default.rs
new file mode 100644
index 0000000..75efbb8
--- /dev/null
+++ b/src/default.rs
@@ -0,0 +1,167 @@
+use crate::TreeBuilder;
+
+/// Returns the default tree for the current thread
+///
+/// # Example
+///
+/// ```
+/// use debug_tree::default_tree;
+/// default_tree().add_leaf("A new leaf");
+/// assert_eq!("A new leaf", default_tree().peek_string());
+/// ```
+pub fn default_tree() -> TreeBuilder {
+    thread_local! {
+        static DEFAULT_BUILDER: TreeBuilder = TreeBuilder::new();
+    }
+    DEFAULT_BUILDER.with(|f| f.clone())
+}
+
+/// Adds a leaf to the default tree with the given text and formatting arguments
+///
+/// # Arguments
+/// * `text...` - Formatted text arguments, as per `format!(...)`.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// use debug_tree::{default_tree, add_leaf};
+/// fn main() {
+///     add_leaf!("A {} leaf", "new");
+///     assert_eq!("A new leaf", &default_tree().peek_string());
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_leaf {
+        ($($arg:tt)*) => {
+            if $crate::default::default_tree().is_enabled() {
+                $crate::default::default_tree().add_leaf(&format!($($arg)*))
+            }
+        };
+    }
+
+/// Adds the value as a leaf to the default tree.
+///
+/// Returns the given `value` argument.
+///
+/// # Arguments
+/// * `value` - An expression that implements the `Display` trait.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// use debug_tree::{default_tree, add_leaf_value};
+/// fn main() {
+///     let value = add_leaf_value!(10);
+///     assert_eq!("10", &default_tree().string());
+///     assert_eq!(10, value);
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_leaf_value {
+    ($value:expr) => {{
+        let v = $value;
+        if $crate::default::default_tree().is_enabled() {
+            $crate::default::default_tree().add_leaf(&format!("{}", &v));
+        }
+        v
+    }};
+}
+
+/// Adds a scoped branch to the default tree with the given text and formatting arguments
+/// The branch will be exited at the end of the current block.
+///
+/// # Arguments
+/// * `text...` - Formatted text arguments, as per `format!(...)`.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// use debug_tree::{default_tree, add_branch, add_leaf};
+/// fn main() {
+///     {
+///         add_branch!("New {}", "Branch"); // _branch enters scope
+///         // tree is now pointed inside new branch.
+///         add_leaf!("Child of {}", "Branch");
+///         // Block ends, so tree exits the current branch.
+///     }
+///     add_leaf!("Sibling of {}", "Branch");
+///     assert_eq!("\
+/// New Branch
+/// └╼ Child of Branch
+/// Sibling of Branch" , &default_tree().string());
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_branch {
+    () => {
+        let _debug_tree_branch = if $crate::default::default_tree().is_enabled() {
+            $crate::default::default_tree().enter_scoped()
+        } else {
+            $crate::scoped_branch::ScopedBranch::none()
+        };
+    };
+    ($($arg:tt)*) => {
+        let _debug_tree_branch = if $crate::default::default_tree().is_enabled() {
+            $crate::default::default_tree().add_branch(&format!($($arg)*))
+        } else {
+            $crate::scoped_branch::ScopedBranch::none()
+        };
+    };
+
+}
+
+#[cfg(test)]
+mod test {
+    use crate::default_tree;
+    use crate::*;
+
+    #[test]
+    fn unnamed_branch() {
+        add_leaf!("1");
+        add_branch!();
+        add_leaf!("1.1");
+        {
+            add_branch!();
+            add_leaf!("1.1.1");
+        }
+        add_leaf!("1.2");
+        default_tree().peek_print();
+        assert_eq!(
+            "\
+1
+├╼ 1.1
+│ └╼ 1.1.1
+└╼ 1.2",
+            default_tree().string()
+        );
+    }
+    #[test]
+    fn named_branch() {
+        add_branch!("11");
+        {
+            add_branch!("11.1");
+            add_leaf!("11.1.1");
+        }
+        add_leaf!("11.2");
+        default_tree().peek_print();
+        assert_eq!(
+            "\
+11
+├╼ 11.1
+│ └╼ 11.1.1
+└╼ 11.2",
+            default_tree().string()
+        );
+    }
+
+    #[test]
+    fn leaf_with_value() {
+        let value = add_leaf_value!(10);
+        default_tree().peek_print();
+        assert_eq!("10", default_tree().string());
+        assert_eq!(10, value);
+    }
+}
diff --git a/src/defer.rs b/src/defer.rs
new file mode 100644
index 0000000..2158a1d
--- /dev/null
+++ b/src/defer.rs
@@ -0,0 +1,46 @@
+use crate::TreeBuilder;
+
+/// A deferred function called with an argument, `TreeBuilder`
+pub struct DeferredFn<F: Fn(TreeBuilder) -> ()> {
+    tree: Option<TreeBuilder>,
+    action: Option<F>,
+}
+
+impl<F> DeferredFn<F>
+where
+    F: Fn(TreeBuilder) -> (),
+{
+    /// Create a new deferred function based on `tree`
+    pub fn new(tree: TreeBuilder, action: F) -> Self {
+        DeferredFn {
+            tree: Some(tree),
+            action: Some(action),
+        }
+    }
+    /// Create an empty deferred function
+    /// This does nothing when scope ends
+    pub fn none() -> Self {
+        DeferredFn {
+            tree: None,
+            action: None,
+        }
+    }
+
+    /// Disables the deferred function
+    /// This prevents the function from executing when the scope ends
+    pub fn cancel(&mut self) {
+        self.tree = None;
+        self.action = None;
+    }
+}
+
+impl<F> Drop for DeferredFn<F>
+where
+    F: Fn(TreeBuilder) -> (),
+{
+    fn drop(&mut self) {
+        if let (Some(x), Some(action)) = (&self.tree, &self.action) {
+            action(x.clone());
+        }
+    }
+}
diff --git a/src/internal.rs b/src/internal.rs
new file mode 100644
index 0000000..d8bf0a9
--- /dev/null
+++ b/src/internal.rs
@@ -0,0 +1,281 @@
+use crate::tree_config::{tree_config, TreeConfig};
+use std::cmp::max;
+use std::sync::{Arc, Mutex};
+
+/// Tree that holds `text` for the current leaf and a list of `children` that are the branches.
+#[derive(Debug)]
+pub struct Tree {
+    pub text: Option<String>,
+    pub children: Vec<Tree>,
+}
+
+/// Position of the element relative to its siblings
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Position {
+    Inside,
+    First,
+    Last,
+    Only,
+}
+
+impl Tree {
+    /// Create a new tree with some optional text.
+    pub fn new(text: Option<&str>) -> Tree {
+        Tree {
+            text: text.map(|x| x.to_string()),
+            children: Vec::new(),
+        }
+    }
+
+    /// Navigate to the branch at the given `path` relative to this tree.
+    /// If a valid branch is found by following the path, it is returned.
+    pub fn at_mut(&mut self, path: &[usize]) -> Option<&mut Tree> {
+        match path.first() {
+            Some(&i) => match self.children.get_mut(i) {
+                Some(x) => x.at_mut(&path[1..]),
+                _ => None,
+            },
+            _ => Some(self),
+        }
+    }
+
+    /// "Render" this tree as a list of `String`s.
+    /// Each string represents a line in the tree.
+    /// `does_continue` is a bool for each column indicating whether the tree continues.
+    pub fn lines(
+        &self,
+        does_continue: &Vec<bool>,
+        index: usize,
+        pool_size: usize,
+        config: &TreeConfig,
+    ) -> Vec<String> {
+        let does_continue = if config.show_first_level && does_continue.is_empty() {
+            vec![true]
+        } else {
+            does_continue.clone()
+        };
+        let position = match index {
+            _ if pool_size == 1 => Position::Only,
+            _ if (index + 1) == pool_size => Position::Last,
+            0 => Position::First,
+            _ => Position::Inside,
+        };
+        let mut next_continue = does_continue.clone();
+        next_continue.push(match position {
+            Position::Inside | Position::First => true,
+            Position::Last | Position::Only => false,
+        });
+
+        let mut txt = String::new();
+        let pad: String;
+        if does_continue.len() > 1 {
+            for &i in &does_continue[2..] {
+                txt.push_str(&format!(
+                    "{}{:indent$}",
+                    if i { config.symbols.continued } else { " " },
+                    "",
+                    indent = max(config.indent, 1) - 1
+                ));
+            }
+            pad = txt.clone();
+            let branch_size = max(config.indent, 2usize) - 2;
+            let branch = match config.symbols.branch.len() {
+                0 => "-".repeat(branch_size),
+                1 => config.symbols.branch.repeat(branch_size),
+                _n => config
+                    .symbols
+                    .branch
+                    .repeat(branch_size)
+                    .chars()
+                    .take(branch_size)
+                    .collect::<String>(),
+            };
+
+            let is_multiline = self
+                .text
+                .as_ref()
+                .map(|x| x.contains("\n"))
+                .unwrap_or(false);
+
+            let first_leaf = match (is_multiline, config.symbols.multiline_first) {
+                (true, Some(x)) => x,
+                _ => config.symbols.leaf,
+            };
+            txt.push_str(&format!(
+                "{}{}{}",
+                match position {
+                    Position::Only => config.symbols.join_only,
+                    Position::First => config.symbols.join_first,
+                    Position::Last => config.symbols.join_last,
+                    Position::Inside => config.symbols.join_inner,
+                },
+                branch,
+                first_leaf,
+            ));
+
+            let s = match &self.text {
+                Some(x) => match is_multiline {
+                    true => format!(
+                        "{}",
+                        x.replace(
+                            "\n",
+                            &format!(
+                                "\n{}{}{}{}",
+                                &pad,
+                                match position {
+                                    Position::Only | Position::Last =>
+                                        " ".repeat(config.symbols.continued.chars().count()),
+                                    _ => config.symbols.continued.to_string(),
+                                },
+                                " ".repeat(branch_size),
+                                match &config.symbols.multiline_continued {
+                                    Some(multi) => multi.to_string(),
+                                    _ => " ".repeat(first_leaf.chars().count()),
+                                }
+                            ),
+                        )
+                    ),
+                    false => x.clone(),
+                },
+                _ => String::new(),
+            };
+            txt.push_str(&s);
+        } else {
+            if let Some(x) = &self.text {
+                txt.push_str(&x);
+            }
+        }
+        let mut ret = vec![txt];
+        for (index, x) in self.children.iter().enumerate() {
+            for line in x.lines(&next_continue, index, self.children.len(), config) {
+                ret.push(line);
+            }
+        }
+        ret
+    }
+}
+
+/// Holds the current state of the tree, including the path to the branch.
+/// Multiple trees may point to the same data.
+#[derive(Debug, Clone)]
+pub(crate) struct TreeBuilderBase {
+    data: Arc<Mutex<Tree>>,
+    path: Vec<usize>,
+    dive_count: usize,
+    config: Option<TreeConfig>,
+    is_enabled: bool,
+}
+
+impl TreeBuilderBase {
+    /// Create a new state
+    pub fn new() -> TreeBuilderBase {
+        TreeBuilderBase {
+            data: Arc::new(Mutex::new(Tree::new(None))),
+            path: vec![],
+            dive_count: 1,
+            config: None,
+            is_enabled: true,
+        }
+    }
+
+    pub fn set_enabled(&mut self, enabled: bool) {
+        self.is_enabled = enabled;
+    }
+    pub fn is_enabled(&self) -> bool {
+        self.is_enabled
+    }
+
+    pub fn add_leaf(&mut self, text: &str) {
+        let &dive_count = &self.dive_count;
+        if dive_count > 0 {
+            for i in 0..dive_count {
+                let mut n = 0;
+                if let Some(x) = self.data.lock().unwrap().at_mut(&self.path) {
+                    x.children.push(Tree::new(if i == max(1, dive_count) - 1 {
+                        Some(&text)
+                    } else {
+                        None
+                    }));
+                    n = x.children.len() - 1;
+                }
+                self.path.push(n);
+            }
+            self.dive_count = 0;
+        } else {
+            if let Some(x) = self
+                .data
+                .lock()
+                .unwrap()
+                .at_mut(&self.path[..max(1, self.path.len()) - 1])
+            {
+                x.children.push(Tree::new(Some(&text)));
+                let n = match self.path.last() {
+                    Some(&x) => x + 1,
+                    _ => 0,
+                };
+                self.path.last_mut().map(|x| *x = n);
+            }
+        }
+    }
+
+    pub fn set_config_override(&mut self, config: Option<TreeConfig>) {
+        self.config = config;
+    }
+
+    pub fn config_override(&self) -> &Option<TreeConfig> {
+        &self.config
+    }
+    pub fn config_override_mut(&mut self) -> &mut Option<TreeConfig> {
+        &mut self.config
+    }
+
+    pub fn enter(&mut self) {
+        self.dive_count += 1;
+    }
+
+    /// Try stepping up to the parent tree branch.
+    /// Returns false if already at the top branch.
+    pub fn exit(&mut self) -> bool {
+        if self.dive_count > 0 {
+            self.dive_count -= 1;
+            true
+        } else {
+            if self.path.len() > 1 {
+                self.path.pop();
+                true
+            } else {
+                false
+            }
+        }
+    }
+
+    pub fn depth(&self) -> usize {
+        max(1, self.path.len() + self.dive_count) - 1
+    }
+
+    pub fn peek_print(&self) {
+        println!("{}", self.peek_string());
+    }
+
+    pub fn print(&mut self) {
+        self.peek_print();
+        self.clear();
+    }
+    pub fn clear(&mut self) {
+        *self = Self::new();
+    }
+
+    pub fn string(&mut self) -> String {
+        let s = self.peek_string();
+        self.clear();
+        s
+    }
+
+    pub fn peek_string(&self) -> String {
+        let config = self
+            .config_override()
+            .clone()
+            .unwrap_or_else(|| tree_config().clone());
+        (&self.data.lock().unwrap().lines(&vec![], 0, 1, &config)[1..]).join("\n")
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..3da09a2
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,805 @@
+use std::sync::{Arc, Mutex};
+
+#[macro_use]
+pub mod default;
+mod internal;
+pub mod scoped_branch;
+
+pub mod defer;
+mod test;
+pub mod tree_config;
+
+pub use default::default_tree;
+use once_cell::sync::Lazy;
+use scoped_branch::ScopedBranch;
+use std::collections::BTreeMap;
+use std::fs::File;
+use std::io::Write;
+
+pub use crate::tree_config::*;
+
+/// Reference wrapper for `TreeBuilderBase`
+#[derive(Debug, Clone)]
+pub struct TreeBuilder(Arc<Mutex<internal::TreeBuilderBase>>);
+
+impl TreeBuilder {
+    /// Returns a new `TreeBuilder` with an empty `Tree`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// ```
+    pub fn new() -> TreeBuilder {
+        TreeBuilder {
+            0: Arc::new(Mutex::new(internal::TreeBuilderBase::new())),
+        }
+    }
+
+    /// Set the configuration override for displaying trees
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to, TreeSymbols, TreeConfig};
+    /// let tree = TreeBuilder::new();
+    /// {
+    ///     add_branch_to!(tree, "1");
+    ///     {
+    ///         add_branch_to!(tree, "1.1");
+    ///         add_leaf_to!(tree, "1.1.1");
+    ///         add_leaf_to!(tree, "1.1.2");
+    ///     }
+    ///     add_leaf_to!(tree, "1.2");
+    /// }
+    /// add_leaf_to!(tree, "2");
+    /// tree.set_config_override(TreeConfig::new()
+    ///     .show_first_level()
+    ///     .symbols(TreeSymbols::with_rounded()));
+    /// tree.peek_print();
+    /// assert_eq!("\
+    /// ├╼ 1
+    /// │ ├╼ 1.1
+    /// │ │ ├╼ 1.1.1
+    /// │ │ ╰╼ 1.1.2
+    /// │ ╰╼ 1.2
+    /// ╰╼ 2" , &tree.string());
+    /// ```
+    pub fn set_config_override(&self, config: TreeConfig) {
+        let mut lock = self.0.lock().unwrap();
+        lock.set_config_override(Some(config))
+    }
+
+    /// Remove the configuration override
+    /// The default configuration will be used instead
+    pub fn remove_config_override(&self) {
+        self.0.lock().unwrap().set_config_override(None);
+    }
+
+    /// Update the configuration override for displaying trees
+    /// If an override doesn't yet exist, it is created.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to, TreeSymbols};
+    /// let tree = TreeBuilder::new();
+    /// {
+    ///     add_branch_to!(tree, "1");
+    ///     {
+    ///         add_branch_to!(tree, "1.1");
+    ///         add_leaf_to!(tree, "1.1.1");
+    ///         add_leaf_to!(tree, "1.1.2");
+    ///     }
+    ///     add_leaf_to!(tree, "1.2");
+    /// }
+    /// add_leaf_to!(tree, "2");
+    /// tree.update_config_override(|x|{
+    ///     x.indent = 3;
+    ///     x.symbols = TreeSymbols::with_rounded();
+    ///     x.show_first_level = true;
+    /// });
+    /// tree.peek_print();
+    /// assert_eq!("\
+    /// ├─╼ 1
+    /// │  ├─╼ 1.1
+    /// │  │  ├─╼ 1.1.1
+    /// │  │  ╰─╼ 1.1.2
+    /// │  ╰─╼ 1.2
+    /// ╰─╼ 2" , &tree.string());
+    /// ```
+    pub fn update_config_override<F: Fn(&mut TreeConfig)>(&self, update: F) {
+        let mut lock = self.0.lock().unwrap();
+        match lock.config_override_mut() {
+            Some(x) => update(x),
+            None => {
+                let mut x = TreeConfig::default();
+                update(&mut x);
+                lock.set_config_override(Some(x));
+            }
+        }
+    }
+
+    /// Returns the optional configuration override.
+    pub fn get_config_override(&self) -> Option<TreeConfig> {
+        let lock = self.0.lock().unwrap();
+        lock.config_override().clone()
+    }
+
+    /// Returns whether a configuration override is set.
+    pub fn has_config_override(&self) -> bool {
+        let lock = self.0.lock().unwrap();
+        lock.config_override().is_some()
+    }
+
+    /// Adds a new branch with text, `text` and returns a `ScopedBranch`.
+    /// When the returned `ScopedBranch` goes out of scope, (likely the end of the current block),
+    /// or if its `release()` method is called, the tree will step back out of the added branch.
+    ///
+    /// # Arguments
+    /// * `text` - A string slice to use as the newly added branch's text.
+    ///
+    /// # Examples
+    ///
+    /// Exiting branch when end of scope is reached.
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// {
+    ///     let _branch = tree.add_branch("Branch"); // _branch enters scope
+    ///     // tree is now pointed inside new branch.
+    ///     tree.add_leaf("Child of Branch");
+    ///     // _branch leaves scope, tree moves up to parent branch.
+    /// }
+    /// tree.add_leaf("Sibling of Branch");
+    /// assert_eq!("\
+    /// Branch
+    /// └╼ Child of Branch
+    /// Sibling of Branch" , &tree.string());
+    /// ```
+    ///
+    /// Using `release()` before out of scope.
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// {
+    ///     let mut branch = tree.add_branch("Branch"); // branch enters scope
+    ///     // tree is now pointed inside new branch.
+    ///     tree.add_leaf("Child of Branch");
+    ///     branch.release();
+    ///     tree.add_leaf("Sibling of Branch");
+    ///     // branch leaves scope, but no effect because its `release()` method has already been called
+    /// }
+    /// assert_eq!("\
+    /// Branch
+    /// └╼ Child of Branch
+    /// Sibling of Branch", &tree.string());
+    /// ```
+    pub fn add_branch(&self, text: &str) -> ScopedBranch {
+        self.add_leaf(text);
+        ScopedBranch::new(self.clone())
+    }
+
+    /// Adds a new branch with text, `text` and returns a `ScopedBranch`.
+    /// When the returned `ScopedBranch` goes out of scope, (likely the end of the current block),
+    /// or if its `release()` method is called, the tree tree will step back out of the added branch.
+    ///
+    /// # Arguments
+    /// * `text` - A string slice to use as the newly added branch's text.
+    ///
+    /// # Examples
+    ///
+    /// Stepping out of branch when end of scope is reached.
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// {
+    ///     tree.add_leaf("Branch");
+    ///     let _branch = tree.enter_scoped(); // _branch enters scope
+    ///     // tree is now pointed inside new branch.
+    ///     tree.add_leaf("Child of Branch");
+    ///     // _branch leaves scope, tree moves up to parent branch.
+    /// }
+    /// tree.add_leaf("Sibling of Branch");
+    /// assert_eq!("\
+    /// Branch
+    /// └╼ Child of Branch
+    /// Sibling of Branch", &tree.string());
+    /// ```
+    ///
+    /// Using `release()` before out of scope.
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// {
+    ///     tree.add_leaf("Branch");
+    ///     let mut branch = tree.enter_scoped(); // branch enters scope
+    ///     // tree is now pointed inside new branch.
+    ///     tree.add_leaf("Child of Branch");
+    ///     branch.release();
+    ///     tree.add_leaf("Sibling of Branch");
+    ///     // branch leaves scope, but no effect because its `release()` method has already been called
+    /// }
+    /// assert_eq!("\
+    /// Branch
+    /// └╼ Child of Branch
+    /// Sibling of Branch", &tree.string());
+    /// ```
+    pub fn enter_scoped(&self) -> ScopedBranch {
+        if self.is_enabled() {
+            ScopedBranch::new(self.clone())
+        } else {
+            ScopedBranch::none()
+        }
+    }
+
+    /// Adds a leaf to current branch with the given text, `text`.
+    ///
+    /// # Arguments
+    /// * `text` - A string slice to use as the newly added leaf's text.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("New leaf");
+    /// ```
+    pub fn add_leaf(&self, text: &str) {
+        let mut x = self.0.lock().unwrap();
+        if x.is_enabled() {
+            x.add_leaf(&text);
+        }
+    }
+
+    /// Steps into a new child branch.
+    /// Stepping out of the branch requires calling `exit()`.
+    ///
+    /// # Example
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Branch");
+    /// tree.enter();
+    /// tree.add_leaf("Child of Branch");
+    /// assert_eq!("\
+    /// Branch
+    /// └╼ Child of Branch", &tree.string());
+    /// ```
+    pub fn enter(&self) {
+        let mut x = self.0.lock().unwrap();
+        if x.is_enabled() {
+            x.enter();
+        }
+    }
+
+    /// Exits the current branch, to the parent branch.
+    /// If no parent branch exists, no action is taken
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Branch");
+    /// tree.enter();
+    /// tree.add_leaf("Child of Branch");
+    /// tree.exit();
+    /// tree.add_leaf("Sibling of Branch");
+    /// assert_eq!("\
+    /// Branch
+    /// └╼ Child of Branch
+    /// Sibling of Branch", &tree.string());
+    /// ```
+    pub fn exit(&self) -> bool {
+        let mut x = self.0.lock().unwrap();
+        if x.is_enabled() {
+            x.exit()
+        } else {
+            false
+        }
+    }
+
+    /// Returns the depth of the current branch
+    /// The initial depth when no branches have been adeed is 0.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// assert_eq!(0, tree.depth());
+    /// let _b = tree.add_branch("Branch");
+    /// assert_eq!(1, tree.depth());
+    /// let _b = tree.add_branch("Child branch");
+    /// assert_eq!(2, tree.depth());
+    /// ```
+    pub fn depth(&self) -> usize {
+        self.0.lock().unwrap().depth()
+    }
+
+    /// Prints the tree without clearing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Leaf");
+    /// tree.peek_print();
+    /// // Leaf
+    /// tree.peek_print();
+    /// // Leaf
+    /// // Leaf 2
+    /// ```
+    pub fn peek_print(&self) {
+        self.0.lock().unwrap().peek_print();
+    }
+
+    /// Prints the tree and then clears it.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Leaf");
+    /// tree.print();
+    /// // Leaf
+    /// tree.add_leaf("Leaf 2");
+    /// tree.print();
+    /// // Leaf 2
+    /// ```
+    pub fn print(&self) {
+        self.0.lock().unwrap().print();
+    }
+
+    /// Returns the tree as a string without clearing the tree.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Leaf");
+    /// assert_eq!("Leaf", tree.peek_string());
+    /// tree.add_leaf("Leaf 2");
+    /// assert_eq!("Leaf\nLeaf 2", tree.peek_string());
+    /// ```
+    pub fn peek_string(&self) -> String {
+        self.0.lock().unwrap().peek_string()
+    }
+
+    /// Returns the tree as a string and clears the tree.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Leaf");
+    /// assert_eq!("Leaf", tree.string());
+    /// tree.add_leaf("Leaf 2");
+    /// assert_eq!("Leaf 2", tree.string());
+    /// ```
+    pub fn string(&self) -> String {
+        self.0.lock().unwrap().string()
+    }
+
+    /// Writes the tree to file without clearing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// use std::fs::{read_to_string, create_dir};
+    /// use std::io::Read;
+    /// let tree = TreeBuilder::new();
+    /// create_dir("test_out").ok();
+    /// tree.add_leaf("Leaf");
+    /// assert_eq!(tree.peek_string(), "Leaf");
+    /// tree.peek_write("test_out/peek_write.txt");
+    /// assert_eq!(read_to_string("test_out/peek_write.txt").unwrap(), "Leaf");
+    /// assert_eq!(tree.peek_string(), "Leaf");
+    /// ```
+    pub fn peek_write(&self, path: &str) -> std::io::Result<()> {
+        let mut file = File::create(path)?;
+        file.write_all(self.peek_string().as_bytes())
+    }
+
+    /// Writes the tree to file without clearing.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// use std::io::Read;
+    /// use std::fs::{read_to_string, create_dir};
+    /// let tree = TreeBuilder::new();
+    /// create_dir("test_out").ok();
+    /// tree.add_leaf("Leaf");
+    /// assert_eq!(tree.peek_string(), "Leaf");
+    /// tree.write("test_out/write.txt");
+    /// assert_eq!(read_to_string("test_out/write.txt").unwrap(), "Leaf");
+    /// assert_eq!(tree.peek_string(), "");
+    /// ```
+    pub fn write(&self, path: &str) -> std::io::Result<()> {
+        let mut file = File::create(path)?;
+        file.write_all(self.string().as_bytes())
+    }
+
+    /// Clears the tree.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let tree = TreeBuilder::new();
+    /// tree.add_leaf("Leaf");
+    /// assert_eq!("Leaf", tree.peek_string());
+    /// tree.clear();
+    /// assert_eq!("", tree.peek_string());
+    /// ```
+    pub fn clear(&self) {
+        self.0.lock().unwrap().clear()
+    }
+
+    /// Sets the enabled state of the tree.
+    ///
+    /// If not enabled, the tree will not be modified by adding leaves or branches.
+    /// Additionally, if called using the `add_`... macros, arguments will not be processed.
+    /// This is particularly useful for suppressing output in production, with very little overhead.
+    ///
+    /// # Example
+    /// ```
+    /// #[macro_use]
+    /// use debug_tree::{TreeBuilder, add_leaf_to};
+    /// let mut tree = TreeBuilder::new();
+    /// tree.add_leaf("Leaf 1");
+    /// tree.set_enabled(false);
+    /// add_leaf_to!(tree, "Leaf 2");
+    /// tree.set_enabled(true);
+    /// add_leaf_to!(tree, "Leaf 3");
+    /// assert_eq!("Leaf 1\nLeaf 3", tree.peek_string());
+    /// ```
+    pub fn set_enabled(&self, enabled: bool) {
+        self.0.lock().unwrap().set_enabled(enabled);
+    }
+
+    /// Returns the enabled state of the tree.
+    ///
+    /// # Example
+    /// ```
+    /// use debug_tree::TreeBuilder;
+    /// let mut tree = TreeBuilder::new();
+    /// assert_eq!(true, tree.is_enabled());
+    /// tree.set_enabled(false);
+    /// assert_eq!(false, tree.is_enabled());
+    /// ```
+    pub fn is_enabled(&self) -> bool {
+        self.0.lock().unwrap().is_enabled()
+    }
+}
+
+pub trait AsTree {
+    fn as_tree(&self) -> TreeBuilder;
+    fn is_tree_enabled(&self) -> bool {
+        self.as_tree().is_enabled()
+    }
+}
+
+impl AsTree for TreeBuilder {
+    fn as_tree(&self) -> TreeBuilder {
+        self.clone()
+    }
+}
+
+pub(crate) fn get_or_add_tree<T: AsRef<str>>(name: T) -> TreeBuilder {
+    let mut map = TREE_MAP.lock().unwrap();
+    match map.get(name.as_ref()) {
+        Some(x) => x.clone(),
+        _ => {
+            let val = TreeBuilder::new();
+            map.insert(name.as_ref().to_string(), val.clone());
+            val
+        }
+    }
+}
+
+pub(crate) fn get_tree<T: AsRef<str>>(name: T) -> Option<TreeBuilder> {
+    TREE_MAP.lock().unwrap().get(name.as_ref()).cloned()
+}
+
+type TreeMap = BTreeMap<String, TreeBuilder>;
+
+static TREE_MAP: Lazy<Arc<Mutex<TreeMap>>> =
+    Lazy::new(|| -> Arc<Mutex<TreeMap>> { Arc::new(Mutex::new(TreeMap::new())) });
+
+/// Sets the enabled state of the tree.
+///
+/// # Arguments
+/// * `name` - The tree name
+/// * `enabled` - The enabled state
+///
+pub fn set_enabled<T: AsRef<str>>(name: T, enabled: bool) {
+    let mut map = TREE_MAP.lock().unwrap();
+    match map.get_mut(name.as_ref()) {
+        Some(x) => x.set_enabled(enabled),
+        _ => {
+            let tree = TreeBuilder::new();
+            tree.set_enabled(enabled);
+            map.insert(name.as_ref().to_string(), tree);
+        }
+    }
+}
+
+impl<T: AsRef<str>> AsTree for T {
+    fn as_tree(&self) -> TreeBuilder {
+        get_or_add_tree(self)
+    }
+    /// Check if the named tree is enabled and exists
+    /// This does not create a new tree if non-existent
+    ///
+    /// # Arguments
+    /// * `tree_name` - The tree name
+    ///
+    fn is_tree_enabled(&self) -> bool {
+        get_tree(self).map(|x| x.is_enabled()).unwrap_or(false)
+    }
+}
+
+/// Returns the tree
+/// If there is no tree then one is created and then returned.
+pub fn tree<T: AsTree>(tree: T) -> TreeBuilder {
+    tree.as_tree()
+}
+
+/// Returns the tree named `name`
+/// If there is no tree named `name` then one is created and then returned.
+pub fn is_tree_enabled<T: AsTree>(tree: &T) -> bool {
+    tree.is_tree_enabled()
+}
+
+/// Calls [clear](TreeBuilder::clear) for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn clear<T: AsRef<str>>(name: T) {
+    name.as_tree().clear();
+}
+
+/// Returns [string](TreeBuilder::string) for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn string<T: AsRef<str>>(name: T) -> String {
+    name.as_tree().string()
+}
+
+/// Returns [peek_string](TreeBuilder::peek_string) for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn peek_string<T: AsRef<str>>(name: T) -> String {
+    name.as_tree().peek_string()
+}
+
+/// Calls [print](TreeBuilder::print) for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn print<T: AsRef<str>>(name: T) {
+    name.as_tree().print();
+}
+
+/// Calls [peek_print](TreeBuilder::peek_print)  for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn peek_print<T: AsRef<str>>(name: T) {
+    name.as_tree().peek_print();
+}
+
+/// Calls [write](TreeBuilder::write) for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
+    name.as_tree().write(path.as_ref())
+}
+
+/// Calls [peek_print](TreeBuilder::peek_print)  for the tree named `name`
+/// If there is no tree named `name` then one is created
+pub fn peek_write<T: AsRef<str>, P: AsRef<str>>(name: T, path: P) -> std::io::Result<()> {
+    name.as_tree().peek_write(path.as_ref())
+}
+
+/// Adds a leaf to given tree with the given text and formatting arguments
+///
+/// # Arguments
+/// * `tree` - The tree that the leaf should be added to
+/// * `text...` - Formatted text arguments, as per `format!(...)`.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// use debug_tree::{TreeBuilder, add_leaf_to};
+/// fn main() {
+///     let tree = TreeBuilder::new();
+///     add_leaf_to!(tree, "A {} leaf", "new");
+///     assert_eq!("A new leaf", &tree.peek_string());
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_leaf_to {
+    ($tree:expr, $($arg:tt)*) => (if $crate::is_tree_enabled(&$tree) {
+        use $crate::AsTree;
+        $tree.as_tree().add_leaf(&format!($($arg)*))
+    });
+}
+
+/// Adds a leaf to given tree with the given `value` argument
+///
+/// # Arguments
+/// * `tree` - The tree that the leaf should be added to
+/// * `value` - An expression that implements the `Display` trait.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// use debug_tree::{TreeBuilder, add_leaf_value_to};
+/// fn main() {
+///     let tree = TreeBuilder::new();
+///     let value = add_leaf_value_to!(tree, 5 * 4 * 3 * 2);
+///     assert_eq!(120, value);
+///     assert_eq!("120", &tree.peek_string());
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_leaf_value_to {
+    ($tree:expr, $value:expr) => {{
+        let v = $value;
+        if $crate::is_tree_enabled(&$tree) {
+            use $crate::AsTree;
+            $tree.as_tree().add_leaf(&format!("{}", &v));
+        }
+        v
+    }};
+}
+
+/// Adds a scoped branch to given tree with the given text and formatting arguments
+/// The branch will be exited at the end of the current block.
+///
+/// # Arguments
+/// * `tree` - The tree that the leaf should be added to
+/// * `text...` - Formatted text arguments, as per `format!(...)`.
+///
+/// # Example
+///
+/// ```
+/// #[macro_use]
+/// use debug_tree::{TreeBuilder, add_branch_to, add_leaf_to};
+/// fn main() {
+///     let tree = TreeBuilder::new();
+///     {
+///         add_branch_to!(tree, "New {}", "Branch"); // _branch enters scope
+///         // tree is now pointed inside new branch.
+///         add_leaf_to!(tree, "Child of {}", "Branch");
+///         // Block ends, so tree exits the current branch.
+///     }
+///     add_leaf_to!(tree, "Sibling of {}", "Branch");
+///     assert_eq!("\
+/// New Branch
+/// └╼ Child of Branch
+/// Sibling of Branch" , &tree.string());
+/// }
+/// ```
+#[macro_export]
+macro_rules! add_branch_to {
+    ($tree:expr) => {
+        let _debug_tree_branch = if $crate::is_tree_enabled(&$tree) {
+            use $crate::AsTree;
+            $tree.as_tree().enter_scoped()
+        } else {
+            $crate::scoped_branch::ScopedBranch::none()
+        };
+    };
+    ($tree:expr, $($arg:tt)*) => {
+        let _debug_tree_branch = if $crate::is_tree_enabled(&$tree) {
+            use $crate::AsTree;
+            $tree.as_tree().add_branch(&format!($($arg)*))
+        } else {
+            $crate::scoped_branch::ScopedBranch::none()
+        };
+    };
+}
+
+/// Calls `function` with argument, `tree`, at the end of the current scope
+/// The function will only be executed if the tree is enabled when this macro is called
+#[macro_export]
+macro_rules! defer {
+    ($function:expr) => {
+        let _debug_tree_defer = {
+            use $crate::AsTree;
+            if $crate::default::default_tree().is_enabled() {
+                use $crate::AsTree;
+                $crate::defer::DeferredFn::new($crate::default::default_tree(), $function)
+            } else {
+                $crate::defer::DeferredFn::none()
+            }
+        };
+    };
+    ($tree:expr, $function:expr) => {
+        let _debug_tree_defer = {
+            use $crate::AsTree;
+            if $tree.as_tree().is_enabled() {
+                $crate::defer::DeferredFn::new($tree.as_tree(), $function)
+            } else {
+                $crate::defer::DeferredFn::none()
+            }
+        };
+    };
+}
+
+/// Calls [print](TreeBuilder::print) on `tree` at the end of the current scope.
+/// The function will only be executed if the tree is enabled when this macro is called
+#[macro_export]
+macro_rules! defer_print {
+    () => {
+        $crate::defer!(|x| {
+            x.print();
+        })
+    };
+    ($tree:expr) => {
+        $crate::defer!($tree, |x| {
+            x.print();
+        })
+    };
+}
+
+/// Calls [peek_print](TreeBuilder::peek_print) on `tree` at the end of the current scope.
+/// The function will only be executed if the tree is enabled when this macro is called
+#[macro_export]
+macro_rules! defer_peek_print {
+    () => {
+        $crate::defer!(|x| {
+            x.peek_print();
+        })
+    };
+    ($tree:expr) => {
+        $crate::defer!($tree, |x| {
+            x.peek_print();
+        })
+    };
+}
+
+/// Calls [write](TreeBuilder::write) on `tree` at the end of the current scope.
+/// The function will only be executed if the tree is enabled when this macro is called
+#[macro_export]
+macro_rules! defer_write {
+    ($tree:expr, $path:expr) => {
+        $crate::defer!($tree, |x| {
+            if let Err(err) = x.write($path) {
+                eprintln!("error during `defer_write`: {}", err);
+            }
+        })
+    };
+    ($path:expr) => {
+        $crate::defer!(|x| {
+            if let Err(err) = x.write($path) {
+                eprintln!("error during `defer_write`: {}", err);
+            }
+        })
+    };
+}
+
+/// Calls [peek_write](TreeBuilder::peek_write) on `tree` at the end of the current scope.
+/// The function will only be executed if the tree is enabled when this macro is called
+#[macro_export]
+macro_rules! defer_peek_write {
+    ($tree:expr, $path:expr) => {
+        $crate::defer!($tree, |x| {
+            if let Err(err) = x.peek_write($path) {
+                eprintln!("error during `defer_peek_write`: {}", err);
+            }
+        })
+    };
+    ($path:expr) => {
+        $crate::defer!(|x| {
+            if let Err(err) = x.peek_write($path) {
+                eprintln!("error during `defer_peek_write`: {}", err);
+            }
+        })
+    };
+}
diff --git a/src/scoped_branch.rs b/src/scoped_branch.rs
new file mode 100644
index 0000000..63aadb4
--- /dev/null
+++ b/src/scoped_branch.rs
@@ -0,0 +1,26 @@
+use crate::TreeBuilder;
+
+pub struct ScopedBranch {
+    state: Option<TreeBuilder>,
+}
+
+impl ScopedBranch {
+    pub fn new(state: TreeBuilder) -> ScopedBranch {
+        state.enter();
+        ScopedBranch { state: Some(state) }
+    }
+    pub fn none() -> ScopedBranch {
+        ScopedBranch { state: None }
+    }
+    pub fn release(&mut self) {
+        if let Some(x) = &self.state {
+            x.exit();
+        }
+        self.state = None;
+    }
+}
+impl Drop for ScopedBranch {
+    fn drop(&mut self) {
+        self.release();
+    }
+}
diff --git a/src/test.rs b/src/test.rs
new file mode 100644
index 0000000..40887ce
--- /dev/null
+++ b/src/test.rs
@@ -0,0 +1,596 @@
+#[cfg(test)]
+mod test {
+    use crate::*;
+    use futures::future::join5;
+    use std::cmp::{max, min};
+    use std::fs::{create_dir, read_to_string, remove_file};
+
+    #[test]
+    fn test_branch() {
+        let d: TreeBuilder = TreeBuilder::new();
+        d.add_leaf("1");
+        {
+            let _l = d.enter_scoped();
+            d.add_leaf("1.1");
+            d.add_leaf("1.2");
+        }
+        d.add_leaf("2");
+        d.add_leaf("3");
+        let _l = d.enter_scoped();
+        d.add_leaf("3.1");
+        d.add_leaf("3.2");
+        d.peek_print();
+        assert_eq!(
+            "\
+1
+├╼ 1.1
+└╼ 1.2
+2
+3
+├╼ 3.1
+└╼ 3.2",
+            d.string()
+        );
+    }
+
+    #[test]
+    fn test_branch2() {
+        let d = TreeBuilder::new();
+        d.add_leaf("1");
+        {
+            let _scope = d.enter_scoped();
+            d.add_leaf("1.1");
+            {
+                let _scope = d.enter_scoped();
+                d.add_leaf("1.1.1");
+            }
+        }
+
+        d.add_leaf("2");
+        d.enter();
+        d.add_leaf("2.1");
+        d.enter();
+        d.add_leaf("2.1.1");
+        d.peek_print();
+        assert_eq!(
+            "\
+1
+└╼ 1.1
+  └╼ 1.1.1
+2
+└╼ 2.1
+  └╼ 2.1.1",
+            d.string()
+        );
+    }
+
+    #[test]
+    fn simple() {
+        let d = TreeBuilder::new();
+        d.add_leaf("Hi");
+        assert_eq!("Hi", d.string());
+    }
+
+    #[test]
+    fn depth() {
+        let d = TreeBuilder::new();
+        assert_eq!(0, d.depth());
+        d.add_leaf("Hi");
+        assert_eq!(0, d.depth());
+        let _b = d.add_branch("Hi");
+        assert_eq!(1, d.depth());
+        d.add_leaf("Hi");
+        assert_eq!(1, d.depth());
+    }
+
+    #[test]
+    fn indent() {
+        let d = TreeBuilder::new();
+        d.add_leaf("1");
+        add_branch_to!(d);
+        d.add_leaf("1.1");
+        {
+            add_branch_to!(d);
+            d.add_leaf("1.1.1");
+        }
+        d.set_config_override(TreeConfig::new().indent(4));
+        d.peek_print();
+        assert_eq!(
+            "\
+1
+└──╼ 1.1
+    └──╼ 1.1.1",
+            d.string()
+        );
+    }
+
+    #[test]
+    fn macros() {
+        let d = TreeBuilder::new();
+        add_leaf_to!(d, "1");
+        {
+            add_branch_to!(d);
+            add_leaf_to!(d, "1.1")
+        }
+        d.peek_print();
+        assert_eq!(
+            "\
+1
+└╼ 1.1",
+            d.string()
+        );
+    }
+
+    #[test]
+    fn macros_with_fn() {
+        let d = TreeBuilder::new();
+        let tree = || d.clone();
+        add_leaf_to!(tree(), "1");
+        {
+            add_branch_to!(tree());
+            add_leaf_to!(tree(), "1.1")
+        }
+        tree().peek_print();
+        assert_eq!(
+            "\
+1
+└╼ 1.1",
+            d.string()
+        );
+    }
+
+    #[test]
+    fn leaf_with_value() {
+        let d = TreeBuilder::new();
+        let value = add_leaf_value_to!(d, 1);
+        d.peek_print();
+        assert_eq!("1", d.string());
+        assert_eq!(1, value);
+    }
+
+    #[test]
+    fn macros2() {
+        let d = TreeBuilder::new();
+        add_branch_to!(d, "1");
+        add_leaf_to!(d, "1.1");
+        d.peek_print();
+        assert_eq!(
+            "\
+1
+└╼ 1.1",
+            d.string()
+        );
+    }
+
+    #[test]
+    fn mid() {
+        let d = TreeBuilder::new();
+        d.add_leaf(&format!("{}{}", "1", "0"));
+        d.enter();
+        d.add_leaf("10.1");
+        d.add_leaf("10.2");
+        d.enter();
+        d.add_leaf("10.1.1");
+        d.add_leaf("10.1.2\nNext line");
+        d.exit();
+        d.add_leaf(&format!("10.3"));
+        d.peek_print();
+        assert_eq!(
+            "\
+10
+├╼ 10.1
+├╼ 10.2
+│ ├╼ 10.1.1
+│ └╼ 10.1.2
+│    Next line
+└╼ 10.3",
+            d.string()
+        );
+    }
+
+    fn factors(x: usize) {
+        add_branch!("{}", x);
+        for i in 1..x {
+            if x % i == 0 {
+                factors(i);
+            }
+        }
+    }
+
+    #[test]
+    fn recursive() {
+        factors(6);
+        default_tree().peek_print();
+        assert_eq!(
+            "\
+6
+├╼ 1
+├╼ 2
+│ └╼ 1
+└╼ 3
+  └╼ 1",
+            default_tree().string()
+        );
+    }
+
+    fn a() {
+        add_branch!("a");
+        b();
+        c();
+    }
+
+    fn b() {
+        add_branch!("b");
+        c();
+    }
+
+    fn c() {
+        add_branch!("c");
+        add_leaf!("Nothing to see here");
+    }
+
+    #[test]
+    fn nested() {
+        a();
+        default_tree().peek_print();
+        assert_eq!(
+            "\
+a
+├╼ b
+│ └╼ c
+│   └╼ Nothing to see here
+└╼ c
+  └╼ Nothing to see here",
+            default_tree().string()
+        );
+    }
+
+    #[test]
+    fn disabled_output() {
+        let tree = TreeBuilder::new();
+        tree.set_enabled(false);
+        add_leaf_to!(tree, "Leaf");
+        tree.add_leaf("Leaf");
+
+        add_branch_to!(tree, "Branch");
+        tree.add_branch("Branch");
+        assert_eq!("", tree.string());
+    }
+
+    #[test]
+    fn enabled_output() {
+        let tree = TreeBuilder::new();
+        tree.set_enabled(false);
+        add_branch_to!(tree, "Ignored branch");
+        add_leaf_to!(tree, "Ignored leaf");
+        tree.set_enabled(true);
+        add_leaf_to!(tree, "Leaf");
+        tree.add_leaf("Leaf");
+
+        add_branch_to!(tree, "Branch");
+        tree.add_branch("Branch");
+        assert_eq!(
+            "Leaf
+Leaf
+Branch
+└╼ Branch",
+            tree.string()
+        );
+    }
+
+    #[test]
+    fn tree_by_name() {
+        clear("A");
+        let b = tree("B");
+        b.clear();
+        {
+            add_branch_to!("A", "1");
+            add_branch_to!(b, "3");
+            add_leaf_to!("A", "1.1");
+            add_leaf_to!("B", "3.1");
+        }
+        add_leaf_to!("A", "2");
+        peek_print("A");
+        b.peek_print();
+        assert_eq!(
+            "1
+└╼ 1.1
+2",
+            string("A")
+        );
+        assert_eq!(
+            "3
+└╼ 3.1",
+            b.string()
+        );
+    }
+
+    #[test]
+    fn tree_by_name_disabled() {
+        let d = tree("D");
+        d.clear();
+        d.set_enabled(true);
+        clear("C");
+        set_enabled("C", false);
+        {
+            add_branch_to!("C", "1");
+            set_enabled("C", true);
+            add_branch_to!(d, "3");
+            add_leaf_to!("C", "1.1");
+            d.set_enabled(false);
+            add_leaf_to!("D", "3.1");
+        }
+        add_leaf_to!("C", "2");
+        peek_print("C");
+        d.peek_print();
+        assert_eq!(
+            "1.1
+2",
+            string("C")
+        );
+        assert_eq!("3", d.string());
+    }
+
+    #[test]
+    fn defer_write() {
+        let tree = TreeBuilder::new();
+        {
+            create_dir("test_out").ok();
+            remove_file("test_out/defer_write.txt").ok();
+            File::create("test_out/defer_write.txt").unwrap();
+            defer_write!(tree, "test_out/defer_write.txt");
+            tree.add_leaf("Branch");
+            assert_eq!(read_to_string("test_out/defer_write.txt").unwrap(), "");
+            assert_eq!(tree.peek_string(), "Branch");
+        }
+        assert_eq!(tree.peek_string(), "");
+        assert_eq!(
+            read_to_string("test_out/defer_write.txt").unwrap(),
+            "Branch"
+        );
+    }
+
+    #[test]
+    fn defer_peek_write() {
+        let tree = TreeBuilder::new();
+        {
+            create_dir("test_out").ok();
+            remove_file("test_out/defer_peek_write.txt").ok();
+            File::create("test_out/defer_peek_write.txt").unwrap();
+            defer_peek_write!(tree, "test_out/defer_peek_write.txt");
+            tree.add_leaf("Branch");
+            assert_eq!(read_to_string("test_out/defer_peek_write.txt").unwrap(), "");
+            assert_eq!(tree.peek_string(), "Branch");
+        }
+        assert_eq!(tree.peek_string(), "Branch");
+        assert_eq!(
+            read_to_string("test_out/defer_peek_write.txt").unwrap(),
+            "Branch"
+        );
+    }
+
+    #[test]
+    #[should_panic]
+    #[allow(unreachable_code)]
+    fn defer_peek_write_panic() {
+        let tree = TreeBuilder::new();
+        {
+            create_dir("test_out").ok();
+            remove_file("test_out/defer_peek_write_panic.txt").ok();
+            File::create("test_out/defer_peek_write_panic.txt").unwrap();
+            defer_peek_write!(tree, "test_out/defer_peek_write_panic.txt");
+            tree.add_leaf("This should be the only line in this file");
+            assert_eq!(read_to_string("test_out/defer_peek_write.txt").unwrap(), "");
+            assert_eq!(
+                tree.peek_string(),
+                "This should be the only line in this file"
+            );
+            panic!();
+            tree.add_leaf("This line should not exist");
+        }
+    }
+
+    fn example_tree() -> TreeBuilder {
+        let tree = TreeBuilder::new();
+        {
+            add_branch_to!(tree, "1");
+            {
+                add_branch_to!(tree, "1.1");
+                add_leaf_to!(tree, "1.1.1");
+                add_leaf_to!(tree, "1.1.2\nWith two\nextra lines");
+                add_leaf_to!(tree, "1.1.3");
+            }
+            add_branch_to!(tree, "1.2");
+            add_leaf_to!(tree, "1.2.1");
+        }
+        {
+            add_branch_to!(tree, "2");
+            add_leaf_to!(tree, "2.1");
+            add_leaf_to!(tree, "2.2");
+        }
+        add_leaf_to!(tree, "3");
+        tree
+    }
+
+    #[test]
+    fn format_output() {
+        let tree = example_tree();
+        tree.set_config_override(
+            TreeConfig::new()
+                .indent(8)
+                .symbols(TreeSymbols {
+                    continued: "| |",
+                    join_first: "|A|",
+                    join_last: "|Z|",
+                    join_inner: "|N|",
+                    join_only: "|O|",
+                    branch: "123456[NOT SHOWN]",
+                    leaf: ")}>",
+                    multiline_first: Some(")}MULTI>"),
+                    multiline_continued: Some(".. CONTINUED: "),
+                })
+                .show_first_level(),
+        );
+        tree.peek_print();
+        assert_eq!(
+            tree.string(),
+            "\
+|A|123456)}>1
+| |       |A|123456)}>1.1
+| |       | |       |A|123456)}>1.1.1
+| |       | |       |N|123456)}MULTI>1.1.2
+| |       | |       | |      .. CONTINUED: With two
+| |       | |       | |      .. CONTINUED: extra lines
+| |       | |       |Z|123456)}>1.1.3
+| |       |Z|123456)}>1.2
+| |               |O|123456)}>1.2.1
+|N|123456)}>2
+| |       |A|123456)}>2.1
+| |       |Z|123456)}>2.2
+|Z|123456)}>3"
+        );
+    }
+
+    #[test]
+    fn format_output_thick() {
+        let tree = example_tree();
+        tree.set_config_override(
+            TreeConfig::new()
+                .symbols(TreeSymbols::with_thick())
+                .indent(4)
+                .show_first_level(),
+        );
+        tree.peek_print();
+        assert_eq!(
+            tree.string(),
+            "\
+┣━━╼ 1
+┃   ┣━━╼ 1.1
+┃   ┃   ┣━━╼ 1.1.1
+┃   ┃   ┣━━╼ 1.1.2
+┃   ┃   ┃    With two
+┃   ┃   ┃    extra lines
+┃   ┃   ┗━━╼ 1.1.3
+┃   ┗━━╼ 1.2
+┃       ┗━━╼ 1.2.1
+┣━━╼ 2
+┃   ┣━━╼ 2.1
+┃   ┗━━╼ 2.2
+┗━━╼ 3"
+        );
+    }
+
+    #[test]
+    fn format_output_pipes() {
+        let tree = example_tree();
+        tree.set_config_override(
+            TreeConfig::new()
+                .symbols(TreeSymbols::with_pipes())
+                .indent(3)
+                .show_first_level(),
+        );
+        tree.peek_print();
+        assert_eq!(
+            tree.string(),
+            "\
+╠═╼ 1
+║  ╠═╼ 1.1
+║  ║  ╠═╼ 1.1.1
+║  ║  ╠═╼ 1.1.2
+║  ║  ║   With two
+║  ║  ║   extra lines
+║  ║  ╚═╼ 1.1.3
+║  ╚═╼ 1.2
+║     ╚═╼ 1.2.1
+╠═╼ 2
+║  ╠═╼ 2.1
+║  ╚═╼ 2.2
+╚═╼ 3"
+        );
+    }
+
+    #[test]
+    fn format_output_dashed() {
+        let tree = example_tree();
+        tree.set_config_override(
+            TreeConfig::new()
+                .symbols(TreeSymbols::with_dashed().multiline_continued("  > "))
+                .indent(4)
+                .show_first_level(),
+        );
+        tree.peek_print();
+        assert_eq!(
+            tree.string(),
+            "\
+┊╌╌- 1
+┊   ┊╌╌- 1.1
+┊   ┊   ┊╌╌- 1.1.1
+┊   ┊   ┊╌╌- 1.1.2
+┊   ┊   ┊    > With two
+┊   ┊   ┊    > extra lines
+┊   ┊   '╌╌- 1.1.3
+┊   '╌╌- 1.2
+┊       '╌╌- 1.2.1
+┊╌╌- 2
+┊   ┊╌╌- 2.1
+┊   '╌╌- 2.2
+'╌╌- 3"
+        );
+    }
+
+    #[test]
+    fn format_output_rounded() {
+        let tree = example_tree();
+        tree.set_config_override(
+            TreeConfig::new()
+                .symbols(TreeSymbols::with_rounded())
+                .indent(4),
+        );
+        tree.peek_print();
+        assert_eq!(
+            tree.string(),
+            "\
+1
+├──╼ 1.1
+│   ├──╼ 1.1.1
+│   ├──╼ 1.1.2
+│   │    With two
+│   │    extra lines
+│   ╰──╼ 1.1.3
+╰──╼ 1.2
+    ╰──╼ 1.2.1
+2
+├──╼ 2.1
+╰──╼ 2.2
+3"
+        );
+    }
+
+    async fn wait_a_bit(tree: TreeBuilder, index: usize) {
+        tree.print();
+        add_branch_to!(tree, "inside async branch {}", index);
+        tree.print();
+        add_leaf_to!(tree, "inside async leaf {}", index);
+        tree.print();
+    }
+
+    #[tokio::test]
+    async fn async_barrier() {
+        let tree = TreeBuilder::new();
+        defer_peek_print!(tree);
+        add_branch_to!(tree, "root");
+        add_leaf_to!(tree, "before async");
+
+        let x2 = wait_a_bit(tree.clone(), 4);
+        let x1 = wait_a_bit(tree.clone(), 5);
+        let x3 = wait_a_bit(tree.clone(), 3);
+        let x4 = wait_a_bit(tree.clone(), 2);
+        let x5 = wait_a_bit(tree.clone(), 1);
+
+        add_leaf_to!(tree, "before join async");
+
+        join5(x1, x2, x3, x4, x5).await;
+        add_leaf_to!(tree, "after join async");
+        assert_eq!(tree.peek_string(), "after join async");
+    }
+}
diff --git a/src/tree_config.rs b/src/tree_config.rs
new file mode 100644
index 0000000..ec534a3
--- /dev/null
+++ b/src/tree_config.rs
@@ -0,0 +1,224 @@
+use once_cell::sync::Lazy;
+use std::sync::{Arc, Mutex};
+
+#[derive(Debug, Clone)]
+pub struct TreeSymbols {
+    /// A vertical base of the tree (│)
+    pub continued: &'static str,
+
+    /// Symbol for joining the first branch in a group (├)
+    pub join_first: &'static str,
+
+    /// Symbol for joining the last branch in a group (└)
+    pub join_last: &'static str,
+
+    /// Symbol for joining a branch that is not first or last in its group (├)
+    pub join_inner: &'static str,
+
+    /// Symbol for joining a branch if it is the only one in its group (├)
+    pub join_only: &'static str,
+
+    /// A repeated branch token (─)
+    pub branch: &'static str,
+
+    /// End of a leaf (╼)
+    pub leaf: &'static str,
+
+    pub multiline_first: Option<&'static str>,
+    pub multiline_continued: Option<&'static str>,
+}
+
+#[derive(Debug, Clone)]
+pub struct TreeConfig {
+    pub symbols: TreeSymbols,
+
+    /// Aside from the first branch, `indent` is equal to the number of spaces a child branch is
+    /// shifted from its parent.
+    pub indent: usize,
+
+    pub show_first_level: bool,
+}
+impl TreeSymbols {
+    pub fn new() -> Self {
+        Self {
+            continued: "│",
+            join_first: "├",
+            join_inner: "├",
+            join_last: "└",
+            join_only: "└",
+            branch: "─",
+            leaf: "╼ ",
+            multiline_first: None,
+            multiline_continued: None,
+        }
+    }
+    pub fn with_pipes() -> Self {
+        Self {
+            continued: "║",
+            join_first: "╠",
+            join_inner: "╠",
+            join_last: "╚",
+            join_only: "╚",
+            branch: "═",
+            leaf: "╼ ",
+            multiline_first: None,
+            multiline_continued: None,
+        }
+    }
+    pub fn with_thick() -> Self {
+        Self {
+            continued: "┃",
+            join_first: "┣",
+            join_inner: "┣",
+            join_last: "┗",
+            join_only: "┗",
+            branch: "━",
+            leaf: "╼ ",
+            multiline_first: None,
+            multiline_continued: None,
+        }
+    }
+    pub fn with_rounded() -> Self {
+        Self {
+            continued: "│",
+            join_first: "├",
+            join_inner: "├",
+            join_last: "╰",
+            join_only: "╰",
+            branch: "─",
+            leaf: "╼ ",
+            multiline_first: None,
+            multiline_continued: None,
+        }
+    }
+    pub fn with_dashed() -> Self {
+        Self {
+            continued: "┊",
+            join_first: "┊",
+            join_inner: "┊",
+            join_last: "'",
+            join_only: "'",
+            branch: "╌",
+            leaf: "- ",
+            multiline_first: None,
+            multiline_continued: None,
+        }
+    }
+
+    pub fn continued(mut self, sym: &'static str) -> Self {
+        self.continued = sym;
+        self
+    }
+    pub fn join_first(mut self, sym: &'static str) -> Self {
+        self.join_first = sym;
+        self
+    }
+    pub fn join_inner(mut self, sym: &'static str) -> Self {
+        self.join_inner = sym;
+        self
+    }
+    pub fn join_last(mut self, sym: &'static str) -> Self {
+        self.join_last = sym;
+        self
+    }
+    pub fn join_only(mut self, sym: &'static str) -> Self {
+        self.join_only = sym;
+        self
+    }
+
+    pub fn branch(mut self, sym: &'static str) -> Self {
+        self.branch = sym;
+        self
+    }
+    pub fn leaf(mut self, sym: &'static str) -> Self {
+        self.leaf = sym;
+        self
+    }
+    pub fn multiline_first(mut self, sym: &'static str) -> Self {
+        self.multiline_first = Some(sym);
+        self
+    }
+    pub fn multiline_continued(mut self, sym: &'static str) -> Self {
+        self.multiline_continued = Some(sym);
+        self
+    }
+}
+
+impl TreeConfig {
+    pub fn new() -> Self {
+        Self {
+            symbols: TreeSymbols::new(),
+            indent: 2,
+            show_first_level: false,
+        }
+    }
+    pub fn with_symbols(symbols: TreeSymbols) -> Self {
+        Self {
+            symbols,
+            indent: 2,
+            show_first_level: false,
+        }
+    }
+    pub fn indent(mut self, x: usize) -> Self {
+        self.indent = x;
+        self
+    }
+    pub fn show_first_level(mut self) -> Self {
+        self.show_first_level = true;
+        self
+    }
+    pub fn hide_first_level(mut self) -> Self {
+        self.show_first_level = false;
+        self
+    }
+    pub fn symbols(mut self, x: TreeSymbols) -> Self {
+        self.symbols = x;
+        self
+    }
+}
+
+impl Default for TreeSymbols {
+    fn default() -> Self {
+        tree_config_symbols()
+    }
+}
+impl Default for TreeConfig {
+    fn default() -> Self {
+        tree_config()
+    }
+}
+
+static DEFAULT_CONFIG: Lazy<Arc<Mutex<TreeConfig>>> =
+    Lazy::new(|| -> Arc<Mutex<TreeConfig>> { Arc::new(Mutex::new(TreeConfig::new())) });
+
+/// Set the default tree config
+pub fn set_tree_config(x: TreeConfig) {
+    *DEFAULT_CONFIG.lock().unwrap() = x;
+}
+
+/// The default tree config
+pub fn tree_config() -> TreeConfig {
+    DEFAULT_CONFIG.lock().unwrap().clone()
+}
+
+/// Set the default tree symbols config
+pub fn set_tree_config_symbols(x: TreeSymbols) {
+    DEFAULT_CONFIG.lock().unwrap().symbols = x;
+}
+
+/// The default tree symbols config
+pub fn tree_config_symbols() -> TreeSymbols {
+    DEFAULT_CONFIG.lock().unwrap().symbols.clone()
+}
+
+/// The default tree symbols config
+pub fn update_tree_config<F: FnMut(&mut TreeConfig)>(mut update: F) {
+    let mut x = DEFAULT_CONFIG.lock().unwrap();
+    update(&mut x);
+}
+
+/// The default tree symbols config
+pub fn update_tree_config_symbols<F: FnMut(&mut TreeSymbols)>(mut update: F) {
+    let mut x = DEFAULT_CONFIG.lock().unwrap();
+    update(&mut x.symbols);
+}