1use std::fs;
14use std::io;
15use std::path::{Path, PathBuf};
16
17pub fn write_cwd_file(cwd: &Path, cwd_file_path: &Path) -> io::Result<()> {
33 if cwd.to_str().is_none() {
37 return Err(io::Error::new(
38 io::ErrorKind::InvalidData,
39 "cwd is not valid UTF-8",
40 ));
41 }
42
43 fs::write(cwd_file_path, crate::pathfmt::display(cwd))
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use std::path::PathBuf;
53
54 #[test]
55 fn write_cwd_file_round_trips() {
56 let dir = tempfile::tempdir().expect("tempdir");
57 let out = dir.path().join("cwd.txt");
58 let cwd = PathBuf::from("/some/test/path");
59 write_cwd_file(&cwd, &out).expect("write_cwd_file");
60 let contents = std::fs::read_to_string(&out).expect("read");
61 assert_eq!(contents, "/some/test/path");
62 }
63
64 #[test]
65 fn write_cwd_file_creates_file() {
66 let dir = tempfile::tempdir().expect("tempdir");
67 let out = dir.path().join("new_file.txt");
68 assert!(!out.exists());
69 let cwd = PathBuf::from("/tmp");
70 write_cwd_file(&cwd, &out).expect("write");
71 assert!(out.exists());
72 }
73
74 #[test]
75 #[cfg(windows)]
76 fn write_cwd_file_strips_windows_verbatim_prefix() {
77 let dir = tempfile::tempdir().expect("tempdir");
78 let out = dir.path().join("cwd.txt");
79 let cwd = PathBuf::from(r"\\?\C:\Windows\System32");
80 write_cwd_file(&cwd, &out).expect("write_cwd_file");
81 let contents = std::fs::read_to_string(&out).expect("read");
82 assert_eq!(contents, r"C:\Windows\System32");
83 }
84
85 #[test]
86 #[cfg(windows)]
87 fn write_cwd_file_strips_windows_verbatim_unc_prefix() {
88 let dir = tempfile::tempdir().expect("tempdir");
89 let out = dir.path().join("cwd.txt");
90 let cwd = PathBuf::from(r"\\?\UNC\server\share");
91 write_cwd_file(&cwd, &out).expect("write_cwd_file");
92 let contents = std::fs::read_to_string(&out).expect("read");
93 assert_eq!(contents, r"\\server\share");
94 }
95}
96
97use serde::{Deserialize, Serialize};
98
99const MAX_RECENT_DIRS: usize = 50;
101
102#[derive(Debug, Default, Serialize, Deserialize)]
104pub struct RecentDirs {
105 pub paths: Vec<PathBuf>,
107}
108
109impl RecentDirs {
110 pub fn load(file_path: &Path) -> Self {
112 if let Ok(content) = fs::read_to_string(file_path) {
113 if let Ok(recent) = toml::from_str(&content) {
114 return recent;
115 }
116 }
117 Self::default()
118 }
119
120 pub fn save(&self, file_path: &Path) {
122 if let Ok(content) = toml::to_string_pretty(self) {
123 let _ = fs::write(file_path, content);
124 }
125 }
126
127 pub fn visit(&mut self, path: PathBuf) {
129 self.paths.retain(|p| p != &path);
130 self.paths.insert(0, path);
131 self.paths.truncate(MAX_RECENT_DIRS);
132 }
133}