print_flat_tree/
lib.rs

1//! Converts a [`flat tree`](http://docs.rs/flat-tree) to a string.
2//!
3//! ## Usage
4//! ```rust,ignore
5//! extern crate print_flat_tree;
6//!
7//! use print_flat_tree::fmt;
8//!
9//! let tree = vec!(0, 1, 2, 3, 7, 8, 9, 10);
10//! print!("{}", fmt(tree));
11//! ```
12//!
13//! Which outputs:
14//!
15//! ```text
16//!  0──┐
17//!     1──┐
18//!  2──┘  │
19//!        3──┐
20//!           │
21//!           │
22//!           │
23//!           7
24//!  8──┐
25//!     9
26//! 10──┘
27//! ```
28//!
29//! ## Command Line
30//! ```txt
31//! print-flat-tree
32//! Converts a flat-tree to a string
33//!
34//! USAGE:
35//!     print-flat-tree [tree]...
36//!
37//! FLAGS:
38//!     -h, --help       Prints help information
39//!     -V, --version    Prints version information
40//!
41//! ARGS:
42//!     <tree>...    For example '0 1 2 3 7 8 9 10'
43//! ```
44//!
45//! As can be seen from the above diagram `7` is the parent of `3`, and `3` is
46//! the parent of `1` etc.
47//!
48//! ## See Also
49//! - [mafintosh/print-flat-tree (JavaScript)](https://github.com/mafintosh/print-flat-tree)
50//! - [flat-tree](https://docs.rs/flat-tree)
51
52#![deny(warnings)]
53
54extern crate flat_tree;
55
56use std::cmp;
57
58const DOWN: char = '│';
59const LEFT: char = '─';
60const TURN_DOWN: char = '┐';
61const TURN_UP: char = '┘';
62
63/// Converts a `flat_tree` to a string.
64pub fn fmt(tree: &[usize]) -> String {
65  // Fill a vec with bools, indicating if a value exists or not.
66  let max = tree.iter().fold(0, |prev, curr| cmp::max(prev, *curr));
67  let mut list = vec![false; max + 1];
68  println!("{:?}", list);
69  for &i in tree {
70    list[i] = true;
71  }
72
73  let width = (list.len().to_string()).len() + 1;
74  let last_block = list.len() - list.len() % 2;
75  let mut _roots = Vec::with_capacity(16);
76  flat_tree::full_roots(last_block, &mut _roots);
77
78  let blank = format!("{:width$}", ' ', width = width);
79  let mut matrix = vec![vec![blank.to_string(); max + 1]; list.len()];
80
81  for i in 0..list.len() {
82    if !list[i] {
83      continue;
84    }
85    let depth = flat_tree::depth(i);
86    let val = format!("{:width$}", i, width = width);
87    matrix[i][depth] = val;
88
89    if let Some(children) = flat_tree::children(i) {
90      add_path(&list, &mut matrix, children.0, i, depth, 1);
91      if children.1 < list.len() {
92        add_path(&list, &mut matrix, children.1, i, depth, -1);
93      }
94    }
95  }
96
97  let mut flat_tree_str = String::from("");
98  for arr in matrix {
99    let partial = arr.join("").trim_right().to_string() + "\n";
100    flat_tree_str.push_str(partial.as_str());
101  }
102
103  flat_tree_str
104}
105
106
107#[test]
108fn fmt_works_0() {
109  let tree = vec!(0);
110  let result = fmt(&tree);
111  assert_eq!(result, " 0\n");
112}
113
114#[test]
115fn fmt_works_1() {
116  let tree = vec!(1);
117  let result = fmt(&tree);
118  assert_eq!(result, "\n   1\n");
119}
120
121#[test]
122fn fmt_works_0_1_2() {
123  let tree = vec!(0, 1, 2);
124  let result = fmt(&tree);
125  assert_eq!(result, " 0─┐\n   1\n 2─┘\n");
126}
127
128fn add_path(
129  list: &[bool],
130  matrix: &mut Vec<Vec<String>>,
131  child: usize,
132  parent: usize,
133  parent_depth: usize,
134  dir: i32,
135) -> () {
136  if !list[child] {
137    return;
138  }
139
140  let depth = flat_tree::depth(child);
141  let width = (list.len().to_string()).len() + 1;
142  let ptr = depth + 1;
143
144  for i in ptr..parent_depth {
145    matrix[child][i] = pad(LEFT, LEFT, width);
146  }
147
148  let turn_char = if dir < 0 { TURN_UP } else { TURN_DOWN };
149  matrix[child][ptr] = pad(turn_char, LEFT, width);
150
151  let mut _child: i32 = child as i32;
152  loop {
153    _child += dir;
154    if _child == parent as i32 {
155      break;
156    };
157    matrix[_child as usize][ptr] = pad(DOWN, ' ', width);
158  }
159}
160
161fn pad(str: char, pad_char: char, width: usize) -> String {
162  let mut symbol = String::from("");
163  for i in 0..width {
164    if i == width - 1 {
165      symbol.push(str);
166    } else {
167      symbol.push(pad_char);
168    }
169  }
170  symbol
171}