1use std::{
2 cmp::{self, Ordering},
3 collections::HashMap,
4 path::{Path, PathBuf},
5};
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
10pub struct FileNodeItem {
11 pub path_buf: PathBuf,
12 pub is_dir: bool,
13 pub read: bool,
14 pub open: bool,
15 pub children: HashMap<PathBuf, FileNodeItem>,
16 pub children_open_count: usize,
17}
18
19impl std::cmp::PartialOrd for FileNodeItem {
20 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
21 let self_dir = self.is_dir;
22 let other_dir = other.is_dir;
23 if self_dir && !other_dir {
24 return Some(cmp::Ordering::Less);
25 }
26 if !self_dir && other_dir {
27 return Some(cmp::Ordering::Greater);
28 }
29
30 let self_file_name = self.path_buf.file_name()?.to_str()?.to_lowercase();
31 let other_file_name = other.path_buf.file_name()?.to_str()?.to_lowercase();
32 if self_file_name.starts_with('.') && !other_file_name.starts_with('.') {
33 return Some(cmp::Ordering::Less);
34 }
35 if !self_file_name.starts_with('.') && other_file_name.starts_with('.') {
36 return Some(cmp::Ordering::Greater);
37 }
38 self_file_name.partial_cmp(&other_file_name)
39 }
40}
41
42impl FileNodeItem {
43 pub fn sorted_children(&self) -> Vec<&FileNodeItem> {
44 let mut children = self
45 .children
46 .iter()
47 .map(|(_, item)| item)
48 .collect::<Vec<&FileNodeItem>>();
49 children.sort_by(|a, b| match (a.is_dir, b.is_dir) {
50 (true, true) => a
51 .path_buf
52 .to_str()
53 .unwrap()
54 .cmp(b.path_buf.to_str().unwrap()),
55 (true, false) => Ordering::Less,
56 (false, true) => Ordering::Greater,
57 (false, false) => a
58 .path_buf
59 .to_str()
60 .unwrap()
61 .cmp(b.path_buf.to_str().unwrap()),
62 });
63 children
64 }
65
66 pub fn sorted_children_mut(&mut self) -> Vec<&mut FileNodeItem> {
67 let mut children = self
68 .children
69 .iter_mut()
70 .map(|(_, item)| item)
71 .collect::<Vec<&mut FileNodeItem>>();
72 children.sort_by(|a, b| match (a.is_dir, b.is_dir) {
73 (true, true) => a
74 .path_buf
75 .to_str()
76 .unwrap()
77 .cmp(b.path_buf.to_str().unwrap()),
78 (true, false) => Ordering::Less,
79 (false, true) => Ordering::Greater,
80 (false, false) => a
81 .path_buf
82 .to_str()
83 .unwrap()
84 .cmp(b.path_buf.to_str().unwrap()),
85 });
86 children
87 }
88
89 pub fn get_file_node(&self, path: &Path) -> Option<&FileNodeItem> {
90 let path_buf = self.path_buf.clone();
91 let path = path.strip_prefix(&self.path_buf).ok()?;
92 let ancestors = path.ancestors().collect::<Vec<&Path>>();
93
94 let mut node = Some(self);
95 for p in ancestors[..ancestors.len() - 1].iter().rev() {
96 node = Some(node?.children.get(&path_buf.join(p))?);
97 }
98 node
99 }
100
101 pub fn get_file_node_mut(&mut self, path: &Path) -> Option<&mut FileNodeItem> {
102 let path_buf = self.path_buf.clone();
103 let path = path.strip_prefix(&self.path_buf).ok()?;
104 let ancestors = path.ancestors().collect::<Vec<&Path>>();
105
106 let mut node = Some(self);
107 for p in ancestors[..ancestors.len() - 1].iter().rev() {
108 node = Some(node?.children.get_mut(&path_buf.join(p))?);
109 }
110 node
111 }
112
113 pub fn remove_child(&mut self, path: &Path) -> Option<FileNodeItem> {
114 let parent = path.parent()?;
115 let node = self.get_file_node_mut(parent)?;
116 let node = node.children.remove(path)?;
117 for p in path.ancestors() {
118 self.update_node_count(p);
119 }
120
121 Some(node)
122 }
123
124 pub fn add_child(&mut self, path: &Path, is_dir: bool) -> Option<()> {
125 let parent = path.parent()?;
126 let node = self.get_file_node_mut(parent)?;
127 node.children.insert(
128 PathBuf::from(path),
129 FileNodeItem {
130 path_buf: PathBuf::from(path),
131 is_dir,
132 read: false,
133 open: false,
134 children: HashMap::new(),
135 children_open_count: 0,
136 },
137 );
138 for p in path.ancestors() {
139 self.update_node_count(p);
140 }
141
142 Some(())
143 }
144
145 pub fn set_item_children(
146 &mut self,
147 path: &Path,
148 children: HashMap<PathBuf, FileNodeItem>,
149 ) {
150 if let Some(node) = self.get_file_node_mut(path) {
151 node.open = true;
152 node.read = true;
153 node.children = children;
154 }
155
156 for p in path.ancestors() {
157 self.update_node_count(p);
158 }
159 }
160
161 pub fn update_node_count(&mut self, path: &Path) -> Option<()> {
162 let node = self.get_file_node_mut(path)?;
163 if node.is_dir {
164 if node.open {
165 node.children_open_count = node
166 .children
167 .iter()
168 .map(|(_, item)| item.children_open_count + 1)
169 .sum::<usize>();
170 } else {
171 node.children_open_count = 0;
172 }
173 }
174 None
175 }
176}