ascii_tree/lib.rs
1//! Crate to write an ascii tree.
2//!
3//! ```rust
4//! let l1 = Leaf(vec![String::from("line1"), String::from("line2"), String::from("line3"), String::from("line4")]);
5//! let l2 = Leaf(vec![String::from("only one line")]);
6//! let n1 = Node(String::from("node 1"), vec![l1.clone(), l2.clone()]);
7//! let n2 = Node(String::from("node 2"), vec![l2.clone(), l1.clone(), l2.clone()]);
8//! let n3 = Node(String::from("node 3"), vec![n1.clone(), l1.clone(), l2.clone()]);
9//! let n4 = Node(String::from("node 4"), vec![n1, n2, n3]);
10//!
11//! let mut output = String::new();
12//! let _ = write_tree(&mut output, &n4);
13//! ```
14//!
15//! The result would be:
16//! <pre>
17//! node 4
18//! ├─ node 1
19//! │ ├─ line1
20//! │ │ line2
21//! │ │ line3
22//! │ │ line4
23//! │ └─ only one line
24//! ├─ node 2
25//! │ ├─ only one line
26//! │ ├─ line1
27//! │ │ line2
28//! │ │ line3
29//! │ │ line4
30//! │ └─ only one line
31//! └─ node 3
32//! ├─ node 1
33//! │ ├─ line1
34//! │ │ line2
35//! │ │ line3
36//! │ │ line4
37//! │ └─ only one line
38//! ├─ line1
39//! │ line2
40//! │ line3
41//! │ line4
42//! └─ only one line
43//! </pre>
44
45use std::fmt;
46use std::fmt::Write;
47
48#[derive(Clone)]
49pub enum Tree {
50 Node(String, Vec<Tree>),
51 Leaf(Vec<String>)
52}
53
54#[inline]
55/// writes a tree in an ascii tree to the writer
56///
57/// ```
58/// let mut output = String::new();
59/// write_tree(&mut output, &tree);
60///
61/// ```
62pub fn write_tree(f: &mut Write, tree: &Tree) -> fmt::Result { write_tree_element(f, tree, &vec![]) }
63
64fn write_tree_element(f: &mut Write, tree: &Tree, level: &Vec<usize>) -> fmt::Result {
65 use Tree::*;
66 const EMPTY: &str = " ";
67 const EDGE: &str = " └─";
68 const PIPE: &str = " │ ";
69 const BRANCH: &str = " ├─";
70
71 let maxpos = level.len();
72 let mut second_line = String::new();
73 for (pos, l) in level.iter().enumerate() {
74 let last_row = pos == maxpos - 1;
75 if *l == 1 {
76 if !last_row { write!(f, "{}", EMPTY)? } else { write!(f, "{}", EDGE)? }
77 second_line.push_str(EMPTY);
78 } else {
79 if !last_row { write!(f, "{}", PIPE)? } else { write!(f, "{}", BRANCH)? }
80 second_line.push_str(PIPE);
81 }
82 }
83 match tree {
84 Node(title, children) => {
85 let mut d = children.len();
86 write!(f, " {}\n", title)?;
87 for s in children {
88 let mut lnext = level.clone();
89 lnext.push(d);
90 d -= 1;
91 write_tree_element(f, s, &lnext)?;
92 }
93 }
94 Leaf(lines) => {
95 for (i, s) in lines.iter().enumerate() {
96 match i {
97 0 => writeln!(f, " {}", s)?,
98 _ => writeln!(f, "{} {}", second_line, s)?
99 }
100 }
101 }
102 }
103 Ok(())
104}