1use std::fmt;
2use super::{Resources, Directory, Entry};
3
4#[derive(Debug)]
6struct Art {
7 margin_draw: &'static str,
8 margin_open: &'static str,
9 dir_entry: &'static str,
10 dir_tail: &'static str,
11 file_entry: &'static str,
12 file_tail: &'static str,
13}
14static U: Art = Art {
16 margin_draw: "│ ",
17 margin_open: " ",
18 dir_entry: "├── ",
19 dir_tail: "└── ",
20 file_entry: "├── ",
21 file_tail: "└── ",
22};
23static A: Art = Art {
25 margin_draw: "| ",
26 margin_open: " ",
27 dir_entry: "+-- ",
28 dir_tail: "`-- ",
29 file_entry: "+-- ",
30 file_tail: "`-- ",
31};
32
33#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34#[allow(dead_code)]
35enum TreeArt {
36 Ascii,
37 Unicode,
38}
39
40#[derive(Clone, Debug)]
41struct TreeFmt<'a: 'd, 'd> {
42 dir: &'d Directory<'a>,
43 art: &'static Art,
44 depth: u32,
45 margin: u32,
46}
47impl<'a, 'd> TreeFmt<'a, 'd> {
48 fn root(root: &'d Directory<'a>, art: TreeArt) -> TreeFmt<'a, 'd> {
49 let art = match art {
50 TreeArt::Ascii => &A,
51 TreeArt::Unicode => &U,
52 };
53 TreeFmt { dir: root, art, depth: !0, margin: 0 }
54 }
55 fn dir(dir: &'d Directory<'a>, art: TreeArt) -> TreeFmt<'a, 'd> {
56 let art = match art {
57 TreeArt::Ascii => &A,
58 TreeArt::Unicode => &U,
59 };
60 TreeFmt { dir, art, depth: 0, margin: 0 }
61 }
62
63 fn draw<F: fmt::Write>(&self, f: &mut F) -> fmt::Result {
64 let (root, depth) = if self.depth == !0 { (true, 0) } else { (false, self.depth) };
66
67 if depth >= 32 {
69 return Ok(());
70 }
71
72 let mut entries = self.dir.entries();
73 while let Some(e) = entries.next() {
74 for open in (0..depth).map(|i| self.margin & (1 << i) != 0) {
76 f.write_str(if open { self.art.margin_open } else { self.art.margin_draw })?;
77 }
78 let tail = entries.len() == 0;
80 let prefix = match (tail, e.is_dir()) {
81 (false, false) => self.art.file_entry,
82 (true, false) => self.art.file_tail,
83 (false, true) => self.art.dir_entry,
84 (true, true) => self.art.dir_tail,
85 };
86 f.write_str(prefix)?;
87 match e.name() {
89 Ok(name) => write!(f, "{}", name.rename_id(if root { &super::RSRC_TYPES } else { &[] })),
90 Err(err) => write!(f, "{}", err),
91 }.and_then(|_| {
92 f.write_str(if e.is_dir() { "/\n" } else { "\n" })
93 })?;
94 if let Ok(Entry::Directory(dir)) = e.entry() {
96 TreeFmt {
97 dir: &dir,
98 art: self.art,
99 depth: depth + 1,
100 margin: self.margin | (tail as u32) << depth,
101 }.draw(f)?;
102 }
103 }
104 Ok(())
105 }
106}
107
108impl<'a> fmt::Display for Resources<'a> {
109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 f.write_str("Resources/\n")?;
111 match self.root() {
112 Ok(root) => TreeFmt::root(&root, TreeArt::Ascii).draw(f),
113 Err(err) => err.fmt(f),
114 }
115 }
116}
117
118impl<'a> fmt::Display for Directory<'a> {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 f.write_str("Directory/\n")?;
121 TreeFmt::dir(self, TreeArt::Ascii).draw(f)
122 }
123}