/
tree.rs
77 lines (63 loc) · 1.89 KB
/
tree.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use std::env;
use std::path::Path;
use std::fs::{self, DirEntry};
struct Entry {
name: String,
children: Vec<Entry>
}
fn main() {
let args: Vec<String> = env::args().collect();
println!("{}", render_tree(&tree(Path::new(&args[1]))).join("\n"));
}
fn children(dir: &Path) -> Vec<Entry> {
fs::read_dir(dir)
.expect("unable to read dir")
.into_iter()
.map(|e| e.expect("unable to get entry"))
.filter(|e| is_not_hidden(e))
.map(|e| e.path())
.map(|e| tree(&e))
.collect()
}
fn is_not_hidden(entry: &DirEntry) -> bool {
entry
.file_name()
.to_str()
.map(|s| !s.starts_with("."))
.unwrap_or(false)
}
fn tree(path: &Path) -> Entry {
Entry{
name: path.file_name()
.and_then(|name| name.to_str())
.map_or(String::from("."),|str| String::from(str)),
children: if path.is_dir() {
children(path)
} else {
Vec::new()
}
}
}
fn render_tree(tree: &Entry) -> Vec<String> {
let mut names = vec![tree.name.to_owned()];
let children = &tree.children;
let children: Vec<_> = children
.iter()
.enumerate()
.map(|(i, child)| decorate(children.len() - 1 == i, render_tree(child)))
.flatten()
.collect();
names.extend(children);
names
}
fn decorate(is_last: bool, children: Vec<String>) -> Vec<String> {
const I_BRANCH: &str = "│ ";
const T_BRANCH: &str = "├── ";
const L_BRANCH: &str = "└── ";
const SPACER: &str = " ";
let prefix_first = if is_last { L_BRANCH } else { T_BRANCH };
let prefix_rest = if is_last { SPACER } else { I_BRANCH };
let mut first = vec![format!("{}{}", prefix_first, children[0])];
first.extend(children[1..].iter().map(|child| format!("{}{}", prefix_rest, child)).collect::<Vec<_>>());
first
}