purple_ssh/app/
file_browser_state.rs1use std::collections::{HashMap, HashSet};
2use std::path::PathBuf;
3
4#[derive(Debug, Default, Clone)]
6pub struct FileBrowserState {
7 pub(in crate::app) host_paths: HashMap<String, (PathBuf, String)>,
8}
9
10impl FileBrowserState {
11 pub fn host_path(&self, alias: &str) -> Option<&(PathBuf, String)> {
12 self.host_paths.get(alias)
13 }
14
15 pub fn contains_host(&self, alias: &str) -> bool {
16 self.host_paths.contains_key(alias)
17 }
18
19 pub fn set_host_path(&mut self, alias: String, local: PathBuf, remote: String) {
20 self.host_paths.insert(alias, (local, remote));
21 }
22
23 pub fn prune_orphans(&mut self, valid_aliases: &HashSet<&str>) {
27 let pre = self.host_paths.len();
28 self.host_paths
29 .retain(|alias, _| valid_aliases.contains(alias.as_str()));
30 let dropped = pre.saturating_sub(self.host_paths.len());
31 if dropped > 0 {
32 log::debug!(
33 "[purple] reload_hosts: dropped {dropped} orphan file_browser host_paths entrie(s)"
34 );
35 }
36 }
37
38 pub fn migrate_alias(&mut self, old: &str, new: &str) {
43 if old == new {
44 return;
45 }
46 if let Some(v) = self.host_paths.remove(old) {
47 self.host_paths.insert(new.to_string(), v);
48 }
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn prune_orphans_drops_unknown_aliases() {
58 let mut s = FileBrowserState::default();
59 s.set_host_path(
60 "keep".to_string(),
61 PathBuf::from("/a/b"),
62 "remote".to_string(),
63 );
64 s.set_host_path(
65 "drop".to_string(),
66 PathBuf::from("/x/y"),
67 "remote".to_string(),
68 );
69
70 let valid: HashSet<&str> = ["keep"].into_iter().collect();
71 s.prune_orphans(&valid);
72
73 assert!(s.contains_host("keep"));
74 assert!(!s.contains_host("drop"));
75 }
76
77 #[test]
78 fn migrate_alias_moves_host_path() {
79 let mut s = FileBrowserState::default();
80 s.set_host_path(
81 "old".to_string(),
82 PathBuf::from("/local"),
83 "/remote".to_string(),
84 );
85
86 s.migrate_alias("old", "new");
87
88 assert!(!s.contains_host("old"));
89 assert!(s.contains_host("new"));
90 let (local, remote) = s.host_path("new").expect("new alias must hold path");
91 assert_eq!(local, &PathBuf::from("/local"));
92 assert_eq!(remote, "/remote");
93 }
94}