egui_file_dialog/
file_system.rs1use std::io::{self, Read};
2use std::path::{Path, PathBuf};
3
4use crate::data::{Disks, Metadata, UserDirectories};
5
6pub trait FileSystem {
34 fn metadata(&self, path: &Path) -> io::Result<Metadata>;
36
37 fn is_dir(&self, path: &Path) -> bool;
39
40 fn is_file(&self, path: &Path) -> bool;
42
43 fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
45
46 fn get_disks(&self, canonicalize_paths: bool) -> Disks;
48
49 fn is_path_hidden(&self, path: &Path) -> bool;
51
52 fn create_dir(&self, path: &Path) -> io::Result<()>;
54
55 fn user_dirs(&self, canonicalize_paths: bool) -> Option<UserDirectories>;
57
58 fn current_dir(&self) -> io::Result<PathBuf>;
60
61 fn load_text_file_preview(&self, _path: &Path, _max_chars: usize) -> io::Result<String> {
63 Err(std::io::Error::new(
64 std::io::ErrorKind::Unsupported,
65 "load_text_file_preview not implemented.".to_string(),
66 ))
67 }
68}
69
70impl std::fmt::Debug for dyn FileSystem + Send + Sync {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "<FileSystem>")
73 }
74}
75
76pub struct NativeFileSystem;
78
79impl FileSystem for NativeFileSystem {
80 fn metadata(&self, path: &Path) -> io::Result<Metadata> {
81 let mut metadata = Metadata::default();
82
83 let md = std::fs::metadata(path)?;
84 metadata.size = Some(md.len());
85 metadata.last_modified = md.modified().ok();
86 metadata.created = md.created().ok();
87 metadata.file_type = Some(format!("{:?}", md.file_type()));
88
89 Ok(metadata)
90 }
91
92 fn is_dir(&self, path: &Path) -> bool {
93 path.is_dir()
94 }
95
96 fn is_file(&self, path: &Path) -> bool {
97 path.is_file()
98 }
99
100 fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
101 Ok(std::fs::read_dir(path)?
102 .filter_map(Result::ok)
103 .map(|entry| entry.path())
104 .collect())
105 }
106
107 fn load_text_file_preview(&self, path: &Path, max_chars: usize) -> io::Result<String> {
108 let mut file = std::fs::File::open(path)?;
109 let mut chunk = [0; 96]; let mut buffer = String::new();
111
112 let mut total_read = 0;
114
115 while total_read < max_chars {
117 let bytes_read = file.read(&mut chunk)?;
118 if bytes_read == 0 {
119 break; }
121 let chars_read: String = String::from_utf8(chunk[..bytes_read].to_vec())
122 .map_err(|_| io::Error::from(io::ErrorKind::InvalidData))?;
123 total_read += chars_read.len();
124 buffer.push_str(&chars_read);
125 }
126
127 Ok(buffer.to_string())
128 }
129
130 fn get_disks(&self, canonicalize_paths: bool) -> Disks {
131 Disks::new_native_disks(canonicalize_paths)
132 }
133
134 fn is_path_hidden(&self, path: &Path) -> bool {
135 is_path_hidden(path)
136 }
137
138 fn create_dir(&self, path: &Path) -> io::Result<()> {
139 std::fs::create_dir(path)
140 }
141
142 fn user_dirs(&self, canonicalize_paths: bool) -> Option<UserDirectories> {
143 if let Some(dirs) = directories::UserDirs::new() {
144 return Some(UserDirectories::new(
145 UserDirectories::canonicalize(Some(dirs.home_dir()), canonicalize_paths),
146 UserDirectories::canonicalize(dirs.audio_dir(), canonicalize_paths),
147 UserDirectories::canonicalize(dirs.desktop_dir(), canonicalize_paths),
148 UserDirectories::canonicalize(dirs.document_dir(), canonicalize_paths),
149 UserDirectories::canonicalize(dirs.download_dir(), canonicalize_paths),
150 UserDirectories::canonicalize(dirs.picture_dir(), canonicalize_paths),
151 UserDirectories::canonicalize(dirs.video_dir(), canonicalize_paths),
152 ));
153 }
154
155 None
156 }
157
158 fn current_dir(&self) -> io::Result<PathBuf> {
159 std::env::current_dir()
160 }
161}
162
163#[cfg(windows)]
164fn is_path_hidden(path: &Path) -> bool {
165 use std::os::windows::fs::MetadataExt;
166
167 std::fs::metadata(path).is_ok_and(|metadata| metadata.file_attributes() & 0x2 > 0)
168}
169
170#[cfg(not(windows))]
171fn is_path_hidden(path: &Path) -> bool {
172 let Some(file_name) = path.file_name() else {
173 return false;
174 };
175 let Some(s) = file_name.to_str() else {
176 return false;
177 };
178
179 if s.starts_with('.') {
180 return true;
181 }
182
183 false
184}