Skip to main content

lib/
fn_plotfiles.rs

1use crate::fn_filestree::FileNode;
2use colored::*;
3
4/// Zestaw znaków używanych do rysowania gałęzi drzewa.
5#[derive(Debug, Clone)]
6pub struct TreeStyle {
7    // Foldery (d)
8    pub dir_last_with_children: String, // └──┬
9    pub dir_last_no_children: String,   // └───
10    pub dir_mid_with_children: String,  // ├──┬
11    pub dir_mid_no_children: String,    // ├───
12
13    // Pliki (f)
14    pub file_last: String, // └──
15    pub file_mid: String,  // ├──
16
17    // Wcięcia dla kolejnych poziomów (i)
18    pub indent_last: String, // "   " (3 spacje)
19    pub indent_mid: String,  // "│  " (kreska + 2 spacje)
20}
21
22impl Default for TreeStyle {
23    fn default() -> Self {
24        Self {
25            dir_last_with_children: "└──┬".to_string(),
26            dir_last_no_children: "└───".to_string(),
27            dir_mid_with_children: "├──┬".to_string(),
28            dir_mid_no_children: "├───".to_string(),
29
30            file_last: "└──•".to_string(),
31            file_mid: "├──•".to_string(),
32
33            indent_last: "   ".to_string(),
34            indent_mid: "│  ".to_string(),
35        }
36    }
37}
38
39/// Prywatna funkcja pomocnicza, która odwala całą powtarzalną robotę.
40fn plot(nodes: &[FileNode], indent: &str, s: &TreeStyle, use_color: bool) -> String {
41    let mut result = String::new();
42
43    for (i, node) in nodes.iter().enumerate() {
44        let is_last = i == nodes.len() - 1;
45        let has_children = !node.children.is_empty();
46
47        // 1. Wybór odpowiedniego znaku gałęzi
48        let branch = if node.is_dir {
49            match (is_last, has_children) {
50                (true, true) => &s.dir_last_with_children,
51                (false, true) => &s.dir_mid_with_children,
52                (true, false) => &s.dir_last_no_children,
53                (false, false) => &s.dir_mid_no_children,
54            }
55        } else if is_last {
56            &s.file_last
57        } else {
58            &s.file_mid
59        };
60
61        // 2. Formatowanie konkretnej linii (z kolorami lub bez)
62        let line = if use_color {
63            if node.is_dir {
64                format!(
65                    "{}{} {}{}/\n",
66                    indent.green(),
67                    branch.green(),
68                    node.icon,
69                    node.name.truecolor(200, 200, 50)
70                )
71            } else {
72                format!(
73                    "{}{} {}{}\n",
74                    indent.green(),
75                    branch.green(),
76                    node.icon,
77                    node.name.white()
78                )
79            }
80        } else {
81            format!("{}{} {} {}\n", indent, branch, node.icon, node.name)
82        };
83
84        result.push_str(&line);
85
86        // 3. Rekurencja dla dzieci z wyliczonym nowym wcięciem
87        if has_children {
88            let new_indent = if is_last {
89                format!("{}{}", indent, s.indent_last)
90            } else {
91                format!("{}{}", indent, s.indent_mid)
92            };
93            result.push_str(&plot(&node.children, &new_indent, s, use_color));
94        }
95    }
96
97    result
98}
99
100/// GENEROWANIE PLAIN TEXT / MARKDOWN
101pub fn plotfiles_txt(nodes: &[FileNode], indent: &str, style: Option<&TreeStyle>) -> String {
102    let default_style = TreeStyle::default();
103    let s = style.unwrap_or(&default_style);
104
105    plot(nodes, indent, s, false)
106}
107
108/// GENEROWANIE KOLOROWANEGO ASCII DO CLI
109pub fn plotfiles_cli(nodes: &[FileNode], indent: &str, style: Option<&TreeStyle>) -> String {
110    let default_style = TreeStyle::default();
111    let s = style.unwrap_or(&default_style);
112
113    plot(nodes, indent, s, true)
114}