mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-31 21:48:53 -06:00
Local: on Windows the folder trees leave out hidden folders such as AppData
The Local trees left out folders whose names start with a dot, but on Windows a folder is hidden by its attribute. Home's tree listed AppData, and browsing a folder inside the temp folder opened Home's tree down through AppData\Local\Temp, drawing one row for every folder there on each frame. On a machine with 148,400 folders in Temp each frame took about 4 s, and tests_panels::local_photos_cannot_be_added_to_albums_until_they_join_my_photos timed out on its ui.drag. list_subfolders now also skips folders with FILE_ATTRIBUTE_HIDDEN set. Test: panels::left::tests::subfolders_leave_out_hidden_folders.
This commit is contained in:
@@ -1040,7 +1040,7 @@ fn list_subfolders(path: &str) -> Vec<(String, String)> {
|
||||
let mut v: Vec<(String, String)> = std::fs::read_dir(path)
|
||||
.map(|rd| {
|
||||
rd.flatten()
|
||||
.filter(|e| e.file_type().is_ok_and(|t| t.is_dir()))
|
||||
.filter(|e| e.file_type().is_ok_and(|t| t.is_dir()) && !hidden_attribute(e))
|
||||
.filter_map(|e| {
|
||||
let name = e.file_name().to_string_lossy().to_string();
|
||||
(!name.starts_with('.')).then(|| (name, e.path().to_string_lossy().to_string()))
|
||||
@@ -1052,6 +1052,20 @@ fn list_subfolders(path: &str) -> Vec<(String, String)> {
|
||||
v
|
||||
}
|
||||
|
||||
/// On Windows a folder is hidden by an attribute (AppData in the home folder is), not by a
|
||||
/// leading dot.
|
||||
#[cfg(windows)]
|
||||
fn hidden_attribute(e: &std::fs::DirEntry) -> bool {
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2;
|
||||
e.metadata().is_ok_and(|m| m.file_attributes() & FILE_ATTRIBUTE_HIDDEN != 0)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn hidden_attribute(_: &std::fs::DirEntry) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// How many [`fs_cached`] answers for `ctx` are being worked out right now. Rows appear (and
|
||||
/// the sidebar below them moves) when they land, so the headless driver counts them as pending
|
||||
/// work and waits for them before acting on widget positions.
|
||||
@@ -2370,6 +2384,27 @@ mod tests {
|
||||
assert_eq!((names(&l.places), l.owner), (vec!["Pictures"], Some(0)));
|
||||
}
|
||||
|
||||
/// A folder tree leaves out hidden subfolders: a leading dot everywhere, and on Windows the
|
||||
/// hidden attribute, so Home's tree does not list AppData and open down into its temp folder.
|
||||
#[test]
|
||||
fn subfolders_leave_out_hidden_folders() {
|
||||
let dir = std::env::temp_dir().join(format!("lc-ui-hidden-subfolders-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
for name in ["Shown", ".dot", "Hidden"] {
|
||||
std::fs::create_dir_all(dir.join(name)).unwrap();
|
||||
}
|
||||
let expected = if cfg!(windows) {
|
||||
let status = std::process::Command::new("attrib").arg("+h").arg(dir.join("Hidden")).status().unwrap();
|
||||
assert!(status.success(), "attrib +h: {status}");
|
||||
vec!["Shown"]
|
||||
} else {
|
||||
vec!["Hidden", "Shown"]
|
||||
};
|
||||
let listed = super::list_subfolders(&dir.to_string_lossy());
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
assert_eq!(listed.iter().map(|(n, _)| n.as_str()).collect::<Vec<_>>(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_local_folder_lines_up_with_the_rows_above_and_its_triangle_stays_left_of_the_icon() {
|
||||
use crate::Services;
|
||||
|
||||
Reference in New Issue
Block a user