Skip to main content

lib/
fn_filestree.rs

1// Zaktualizowany Plik-004: src/lib/fn_filestree.rs
2use crate::fn_pathtype::{DIR_ICON, get_file_type};
3use crate::fn_weight::{WeightConfig, format_weight, get_path_weight};
4use std::cmp::Ordering;
5use std::collections::BTreeMap;
6use std::path::PathBuf;
7
8/// Struktura węzła drzewa
9#[derive(Debug, Clone)]
10pub struct FileNode {
11    pub name: String,
12    pub path: PathBuf,
13    pub is_dir: bool,
14    pub icon: String,
15    pub weight_str: String, // Nowe pole na sformatowaną wagę [qq xxxxx]
16    pub weight_bytes: u64,  // Surowa waga do obliczeń sumarycznych
17    pub children: Vec<FileNode>,
18}
19
20/// Helper do sortowania węzłów zgodnie z wybraną metodą
21fn sort_nodes(nodes: &mut [FileNode], sort_method: &str) {
22    match sort_method {
23        "files-first" => nodes.sort_by(|a, b| {
24            if a.is_dir == b.is_dir {
25                a.name.cmp(&b.name)
26            } else if !a.is_dir {
27                Ordering::Less
28            } else {
29                Ordering::Greater
30            }
31        }),
32        "dirs-first" => nodes.sort_by(|a, b| {
33            if a.is_dir == b.is_dir {
34                a.name.cmp(&b.name)
35            } else if a.is_dir {
36                Ordering::Less
37            } else {
38                Ordering::Greater
39            }
40        }),
41        _ => nodes.sort_by(|a, b| a.name.cmp(&b.name)),
42    }
43}
44
45/// Funkcja formatująca - buduje drzewo i przypisuje ikony oraz wagi
46pub fn filestree(
47    paths: Vec<PathBuf>,
48    sort_method: &str,
49    weight_cfg: &WeightConfig, // NOWY ARGUMENT
50) -> Vec<FileNode> {
51    let mut tree_map: BTreeMap<PathBuf, Vec<PathBuf>> = BTreeMap::new();
52    for p in &paths {
53        let parent = p
54            .parent()
55            .map(|p| p.to_path_buf())
56            .unwrap_or_else(|| PathBuf::from("/"));
57        tree_map.entry(parent).or_default().push(p.clone());
58    }
59
60    fn build_node(
61        path: &PathBuf,
62        paths: &BTreeMap<PathBuf, Vec<PathBuf>>,
63        sort_method: &str,
64        weight_cfg: &WeightConfig, // NOWY ARGUMENT
65    ) -> FileNode {
66        let name = path
67            .file_name()
68            .map(|n| n.to_string_lossy().to_string())
69            .unwrap_or_else(|| "/".to_string());
70
71        let is_dir = path.is_dir();
72
73        let icon = if is_dir {
74            DIR_ICON.to_string()
75        } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
76            get_file_type(ext).icon.to_string()
77        } else {
78            "📄".to_string()
79        };
80
81        // KROK A: Pobieramy bazową wagę (0 dla folderów w trybie sumy uwzględnionych)
82        let mut weight_bytes = get_path_weight(path, weight_cfg.dir_sum_included);
83
84        let mut children = vec![];
85        if let Some(child_paths) = paths.get(path) {
86            let mut child_nodes: Vec<FileNode> = child_paths
87                .iter()
88                .map(|c| build_node(c, paths, sort_method, weight_cfg))
89                .collect();
90
91            crate::fn_filestree::sort_nodes(&mut child_nodes, sort_method);
92
93            // KROK B: Jeśli to folder i sumujemy tylko ujęte pliki, zsumuj wagi dzieci
94            if is_dir && weight_cfg.dir_sum_included {
95                weight_bytes = child_nodes.iter().map(|n| n.weight_bytes).sum();
96            }
97
98            children = child_nodes;
99        }
100
101        // KROK C: Formatowanie wagi do ciągu "[qq xxxxx]"
102        let mut weight_str = String::new();
103
104        // Sprawdzamy czy system wag jest w ogóle włączony
105        if weight_cfg.system != crate::fn_weight::UnitSystem::None {
106            let should_show =
107                (is_dir && weight_cfg.show_for_dirs) || (!is_dir && weight_cfg.show_for_files);
108
109            if should_show {
110                weight_str = format_weight(weight_bytes, weight_cfg);
111            } else {
112                // Jeśli ukrywamy wagę dla tego węzła, wstawiamy puste spacje
113                // szerokość = 7 (nawiasy, jednostka, spacje) + precyzja
114                let empty_width = 7 + weight_cfg.precision;
115                weight_str = format!("{:width$}", "", width = empty_width);
116            }
117        }
118
119        FileNode {
120            name,
121            path: path.clone(),
122            is_dir,
123            icon,
124            weight_str,
125            weight_bytes,
126            children,
127        }
128    }
129
130    let roots: Vec<PathBuf> = paths
131        .iter()
132        .filter(|p| p.parent().is_none() || !paths.contains(&p.parent().unwrap().to_path_buf()))
133        .cloned()
134        .collect();
135
136    let mut top_nodes: Vec<FileNode> = roots
137        .into_iter()
138        .map(|r| build_node(&r, &tree_map, sort_method, weight_cfg))
139        .collect();
140
141    crate::fn_filestree::sort_nodes(&mut top_nodes, sort_method);
142
143    top_nodes
144}