1use crate::fn_pathtype::{DIR_ICON, get_file_type};
2use std::cmp::Ordering;
3use std::collections::BTreeMap;
4use std::path::PathBuf;
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
46 .parent()
47 .map(|p| p.to_path_buf())
48 .unwrap_or_else(|| PathBuf::from("/"));
49 tree_map.entry(parent).or_default().push(p.clone());
50 }
51
52 fn build_node(
54 path: &PathBuf,
55 paths: &BTreeMap<PathBuf, Vec<PathBuf>>,
56 sort_method: &str,
57 ) -> FileNode {
58 let name = path
59 .file_name()
60 .map(|n| n.to_string_lossy().to_string())
61 .unwrap_or_else(|| "/".to_string());
62
63 let is_dir = path.is_dir();
64
65 let icon = if is_dir {
67 DIR_ICON.to_string()
68 } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
69 get_file_type(ext).icon.to_string()
70 } else {
71 "📄".to_string()
72 };
73
74 let mut children = vec![];
75 if let Some(child_paths) = paths.get(path) {
76 let mut child_nodes: Vec<FileNode> = child_paths
77 .iter()
78 .map(|c| build_node(c, paths, sort_method)) .collect();
80
81 crate::fn_filestree::sort_nodes(&mut child_nodes, sort_method);
82 children = child_nodes;
83 }
84
85 FileNode {
86 name,
87 path: path.clone(),
88 is_dir,
89 icon,
90 children,
91 }
92 }
93
94 let roots: Vec<PathBuf> = paths
95 .iter()
96 .filter(|p| p.parent().is_none() || !paths.contains(&p.parent().unwrap().to_path_buf()))
97 .cloned()
98 .collect();
99
100 let mut top_nodes: Vec<FileNode> = roots
101 .into_iter()
102 .map(|r| build_node(&r, &tree_map, sort_method)) .collect();
104
105 crate::fn_filestree::sort_nodes(&mut top_nodes, sort_method);
106
107 top_nodes
108}