use std::collections::HashMap;
use std::path::{Path, PathBuf};
use crate::cache::TreeCache;
use crate::config::DisplayFilter;
use crate::entry::LoadedEntry;
use crate::node::TreeNode;
use crate::scan::{LoadPayload, LoadedOutcome, ScanRequest};
use crate::tree::DirectoryTree;
impl DirectoryTree {
pub fn on_toggled(&mut self, path: &Path) -> Option<ScanRequest> {
let depth = self.depth_of(path)?;
let max_depth = self.config.max_depth;
let node = self.root.find_mut(path)?;
if !node.is_dir {
return None;
}
if node.is_expanded {
node.is_expanded = false;
return None;
}
if node.is_loaded {
node.is_expanded = true;
return None;
}
if let Some(max) = max_depth
&& depth > max
{
node.is_loaded = true;
node.is_expanded = true;
node.children.clear();
return None;
}
node.is_expanded = true;
self.generation = self.generation.wrapping_add(1);
Some(ScanRequest {
path: path.to_path_buf(),
generation: self.generation,
depth,
})
}
pub fn on_loaded(&mut self, payload: LoadPayload) -> LoadedOutcome {
if payload.generation != self.generation {
return LoadedOutcome::discarded();
}
let filter = self.config.filter;
let Some(node) = self.root.find_mut(&payload.path) else {
return LoadedOutcome::discarded();
};
match payload.result {
Ok(entries) => {
rebuild_children(node, &entries, filter);
node.error = None;
node.is_loaded = true;
self.cache.insert(payload.path, payload.generation, entries);
}
Err(issue) => {
node.children.clear();
node.error = Some(issue);
node.is_loaded = true;
}
}
LoadedOutcome::accepted()
}
}
pub(crate) fn rebuild_children(
node: &mut TreeNode,
entries: &[LoadedEntry],
filter: DisplayFilter,
) {
let mut previous: HashMap<PathBuf, TreeNode> = std::mem::take(&mut node.children)
.into_iter()
.map(|child| (child.path.clone(), child))
.collect();
node.children = entries
.iter()
.filter(|entry| filter.admits(entry))
.map(|entry| {
previous
.remove(&entry.path)
.unwrap_or_else(|| TreeNode::from_entry(entry))
})
.collect();
}
pub(crate) fn refresh_from_cache(node: &mut TreeNode, cache: &TreeCache, filter: DisplayFilter) {
if node.is_dir
&& node.is_loaded
&& node.error.is_none()
&& let Some(cached) = cache.get(&node.path)
{
rebuild_children(node, &cached.entries, filter);
}
for child in &mut node.children {
refresh_from_cache(child, cache, filter);
}
}