1use std::collections::BTreeMap;
2use std::path::PathBuf;
3use std::cmp::Ordering;
4use crate::fn_pathtype::{get_file_type, DIR_ICON};
5
6#[derive(Debug, Clone)]
8pub struct FileNode {
9 pub name: String,
10 pub path: PathBuf,
11 pub is_dir: bool,
12 pub icon: String,
13 pub children: Vec<FileNode>,
14}
15
16fn sort_nodes(nodes: &mut [FileNode], sort_method: &str) {
18 match sort_method {
19 "files-first" => nodes.sort_by(|a, b| {
20 if a.is_dir == b.is_dir {
21 a.name.cmp(&b.name)
22 } else if !a.is_dir {
23 Ordering::Less } else {
25 Ordering::Greater }
27 }),
28 "dirs-first" => nodes.sort_by(|a, b| {
29 if a.is_dir == b.is_dir {
30 a.name.cmp(&b.name)
31 } else if a.is_dir {
32 Ordering::Less } else {
34 Ordering::Greater
35 }
36 }),
37 _ => nodes.sort_by(|a, b| a.name.cmp(&b.name)),
38 }
39}
40
41pub fn filestree(paths: Vec<PathBuf>, sort_method: &str) -> Vec<FileNode> {
43 let mut tree_map: BTreeMap<PathBuf, Vec<PathBuf>> = BTreeMap::new();
44 for p in &paths {
45 let parent = p.parent().map(|p| p.to_path_buf()).unwrap_or_else(|| PathBuf::from("/"));
46 tree_map.entry(parent).or_default().push(p.clone());
47 }
48
49 fn build_node(
51 path: &PathBuf,
52 paths: &BTreeMap<PathBuf, Vec<PathBuf>>,
53 sort_method: &str,
54 ) -> FileNode {
55 let name = path.file_name()
56 .map(|n| n.to_string_lossy().to_string())
57 .unwrap_or_else(|| "/".to_string());
58
59 let is_dir = path.is_dir();
60
61 let icon = if is_dir {
63 DIR_ICON.to_string()
64 } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
65 get_file_type(ext).icon.to_string()
66 } else {
67 "📄".to_string()
68 };
69
70 let mut children = vec![];
71 if let Some(child_paths) = paths.get(path) {
72 let mut child_nodes: Vec<FileNode> = child_paths
73 .iter()
74 .map(|c| build_node(c, paths, sort_method)) .collect();
76
77 crate::fn_filestree::sort_nodes(&mut child_nodes, sort_method);
78 children = child_nodes;
79 }
80
81 FileNode { name, path: path.clone(), is_dir, icon, children }
82 }
83
84 let roots: Vec<PathBuf> = paths.iter()
85 .filter(|p| p.parent().is_none() || !paths.contains(&p.parent().unwrap().to_path_buf()))
86 .cloned()
87 .collect();
88
89 let mut top_nodes: Vec<FileNode> = roots
90 .into_iter()
91 .map(|r| build_node(&r, &tree_map, sort_method)) .collect();
93
94 crate::fn_filestree::sort_nodes(&mut top_nodes, sort_method);
95
96 top_nodes
97}