runa_tui/
file_manager.rs

1use std::ffi::OsString;
2use std::fs;
3
4#[derive(Debug, Clone)]
5pub struct FileEntry {
6    name: OsString,
7    name_str: String,
8    lowercase_name: String,
9    display_name: String,
10    is_dir: bool,
11    is_hidden: bool,
12    is_system: bool,
13}
14
15impl FileEntry {
16    // Getters / accessors
17    pub fn name(&self) -> &OsString {
18        &self.name
19    }
20
21    pub fn name_str(&self) -> &str {
22        &self.name_str
23    }
24
25    pub fn lowercase_name(&self) -> &str {
26        &self.lowercase_name
27    }
28
29    pub fn display_name(&self) -> &str {
30        &self.display_name
31    }
32
33    pub fn is_dir(&self) -> bool {
34        self.is_dir
35    }
36
37    pub fn is_hidden(&self) -> bool {
38        self.is_hidden
39    }
40
41    pub fn is_system(&self) -> bool {
42        self.is_system
43    }
44
45    // Setters
46    pub fn set_display_name(&mut self, new_name: String) {
47        self.display_name = new_name;
48    }
49}
50
51pub fn browse_dir(path: &std::path::Path) -> std::io::Result<Vec<FileEntry>> {
52    let mut entries = Vec::with_capacity(256);
53    for entry in fs::read_dir(path)? {
54        let entry = match entry {
55            Ok(e) => e,
56            Err(_) => continue,
57        };
58
59        let name = entry.file_name();
60        let name_lossy = name.to_string_lossy();
61        let name_str = name_lossy.to_string();
62        let lowercase_name = name_lossy.to_lowercase();
63
64        let is_dir = entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false);
65
66        let display_name = if is_dir {
67            format!("{}/", name_lossy)
68        } else {
69            name_lossy.into_owned()
70        };
71
72        #[cfg(unix)]
73        let (is_hidden, is_system) = {
74            use std::os::unix::ffi::OsStrExt;
75            // Native byte check: no string conversion needed
76            let is_hidden = name.as_bytes().first() == Some(&b'.');
77            (is_hidden, false)
78        };
79
80        #[cfg(windows)]
81        let (is_dir, is_hidden, is_system) = {
82            use std::os::windows::fs::MetadataExt;
83            let starts_with_dot = lowercase_name.starts_with('.');
84
85            if let Ok(md) = entry.metadata() {
86                let attrs = md.file_attributes();
87                (
88                    md.is_dir(),
89                    (attrs & 0x2 != 0) || starts_with_dot,
90                    (attrs & 0x4 != 0),
91                )
92            } else {
93                (is_dir, starts_with_dot, false)
94            }
95        };
96
97        entries.push(FileEntry {
98            name,
99            name_str,
100            lowercase_name,
101            display_name,
102            is_dir,
103            is_hidden,
104            is_system,
105        });
106    }
107    Ok(entries)
108}