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
40/// Prywatna funkcja pomocnicza, która odwala całą powtarzalną robotę.
41fn plot(nodes: &[FileNode], indent: &str, s: &TreeStyle, use_color: bool) -> String {
42    let mut result = String::new();
43
44    for (i, node) in nodes.iter().enumerate() {
45        let is_last = i == nodes.len() - 1;
46        let has_children = !node.children.is_empty();
47
48        // 1. Wybór odpowiedniego znaku gałęzi
49        let branch = if node.is_dir {
50            match (is_last, has_children) {
51                (true, true)   => &s.dir_last_with_children,
52                (false, true)  => &s.dir_mid_with_children,
53                (true, false)  => &s.dir_last_no_children,
54                (false, false) => &s.dir_mid_no_children,
55            }
56        } else if is_last {
57            &s.file_last
58        } else {
59            &s.file_mid
60        };
61
62        // 2. Formatowanie konkretnej linii (z kolorami lub bez)
63        let line = if use_color {
64            if node.is_dir {
65                format!("{}{} {}{}/\n", indent.green(), branch.green(), node.icon, node.name.truecolor(200, 200, 50))
66            } else {
67                format!("{}{} {}{}\n", indent.green(), branch.green(), node.icon, node.name.white())
68            }
69        } else {
70            format!("{}{} {} {}\n", indent, branch, node.icon, node.name)
71        };
72        
73        result.push_str(&line);
74        
75        // 3. Rekurencja dla dzieci z wyliczonym nowym wcięciem
76        if has_children {
77            let new_indent = if is_last {
78                format!("{}{}", indent, s.indent_last)
79            } else {
80                format!("{}{}", indent, s.indent_mid)
81            };
82            result.push_str(&plot(&node.children, &new_indent, s, use_color));
83        }
84    }
85
86    result
87}
88
89/// GENEROWANIE PLAIN TEXT / MARKDOWN
90pub fn plotfiles_txt(nodes: &[FileNode], indent: &str, style: Option<&TreeStyle>) -> String {
91    let default_style = TreeStyle::default();
92    let s = style.unwrap_or(&default_style);
93    
94    plot(nodes, indent, s, false)
95}
96
97/// GENEROWANIE KOLOROWANEGO ASCII DO CLI
98pub fn plotfiles_cli(nodes: &[FileNode], indent: &str, style: Option<&TreeStyle>) -> String {
99    let default_style = TreeStyle::default();
100    let s = style.unwrap_or(&default_style);
101    
102    plot(nodes, indent, s, true)
103}