use std::path::PathBuf;
use crate::directory_tree::DirectoryTree;
use crate::directory_tree::message::LoadPayload;
use crate::directory_tree::node::{LoadedEntry, TreeNode};
impl DirectoryTree {
pub(super) fn on_loaded(&mut self, payload: LoadPayload) -> Vec<PathBuf> {
let LoadPayload {
path,
generation,
depth: _,
result,
} = payload;
if generation != self.generation {
return Vec::new();
}
let Some(node) = self.root.find_mut(&path) else {
return Vec::new();
};
if !node.is_dir {
return Vec::new();
}
match result.as_ref() {
Ok(entries) => {
node.children = build_children(entries, self.config.filter);
node.error = None;
}
Err(err) => {
node.children.clear();
node.error = Some(err.clone());
}
}
node.is_loaded = true;
if let Ok(entries) = result.as_ref() {
self.cache.put(path.clone(), generation, entries.clone());
}
self.sync_selection_flags();
self.recompute_search_visibility();
if self.prefetching_paths.remove(&path) {
return Vec::new();
}
self.select_prefetch_targets(&path)
}
pub(super) fn select_prefetch_targets(&self, parent: &std::path::Path) -> Vec<PathBuf> {
let limit = self.config.prefetch_per_parent;
if limit == 0 {
return Vec::new();
}
let Some(node) = find_ref(&self.root, parent) else {
return Vec::new();
};
let max_depth = self.config.max_depth;
let root = &self.config.root_path;
let skip = &self.config.prefetch_skip;
node.children
.iter()
.filter(|c| c.is_dir && !c.is_loaded && c.error.is_none())
.filter(|c| match max_depth {
None => true,
Some(cap) => super::depth_of(root, &c.path) <= cap,
})
.filter(|c| !basename_in_skip_list(&c.path, skip))
.take(limit)
.map(|c| c.path.clone())
.collect()
}
}
fn find_ref<'a>(node: &'a TreeNode, target: &std::path::Path) -> Option<&'a TreeNode> {
if node.path == target {
return Some(node);
}
if !target.starts_with(&node.path) {
return None;
}
node.children.iter().find_map(|c| find_ref(c, target))
}
fn basename_in_skip_list(path: &std::path::Path, skip: &[String]) -> bool {
let Some(basename) = path.file_name().and_then(|s| s.to_str()) else {
return false;
};
skip.iter().any(|s| s.eq_ignore_ascii_case(basename))
}
fn build_children(entries: &[LoadedEntry], filter: crate::DirectoryFilter) -> Vec<TreeNode> {
entries
.iter()
.filter(|e| e.passes(filter))
.map(TreeNode::from_entry)
.collect()
}