lapce_rpc/
file.rs

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}