pub(crate) mod config;
pub(crate) mod error;
pub(crate) mod executor;
pub(crate) mod icon;
pub(crate) mod keyboard;
pub(crate) mod message;
pub(crate) mod node;
pub(crate) mod update;
pub(crate) mod view;
pub(crate) mod walker;
use std::path::PathBuf;
use std::sync::Arc;
use self::{
config::{DirectoryFilter, TreeConfig},
executor::{ScanExecutor, ThreadExecutor},
node::{TreeCache, TreeNode},
};
pub struct DirectoryTree {
pub(crate) root: TreeNode,
pub(crate) config: TreeConfig,
pub(crate) cache: TreeCache,
pub(crate) generation: u64,
pub(crate) selected_path: Option<std::path::PathBuf>,
pub(crate) executor: Arc<dyn ScanExecutor>,
}
impl DirectoryTree {
pub fn new(root: PathBuf) -> Self {
let root_node = TreeNode::new_root(root.clone());
Self {
root: root_node,
config: TreeConfig {
root_path: root,
filter: DirectoryFilter::default(),
max_depth: None,
},
cache: TreeCache::default(),
generation: 0,
selected_path: None,
executor: Arc::new(ThreadExecutor),
}
}
pub fn with_filter(mut self, filter: DirectoryFilter) -> Self {
self.set_filter(filter);
self
}
pub fn with_max_depth(mut self, depth: u32) -> Self {
self.config.max_depth = Some(depth);
self
}
pub fn with_executor(mut self, executor: Arc<dyn ScanExecutor>) -> Self {
self.executor = executor;
self
}
pub fn set_filter(&mut self, filter: DirectoryFilter) {
if self.config.filter == filter {
return;
}
self.config.filter = filter;
rebuild_from_cache(&mut self.root, &self.cache, filter);
if let Some(p) = self.selected_path.clone() {
self.sync_selection_flag(&p);
}
}
pub fn root_path(&self) -> &std::path::Path {
&self.config.root_path
}
pub fn filter(&self) -> DirectoryFilter {
self.config.filter
}
pub fn max_depth(&self) -> Option<u32> {
self.config.max_depth
}
pub fn selected_path(&self) -> Option<&std::path::Path> {
self.selected_path.as_deref()
}
pub(crate) fn sync_selection_flag(&mut self, target: &std::path::Path) {
self.root.clear_selection();
if let Some(node) = self.root.find_mut(target) {
node.is_selected = true;
}
}
}
fn rebuild_from_cache(node: &mut TreeNode, cache: &node::TreeCache, filter: DirectoryFilter) {
if node.is_dir && node.is_loaded {
if let Some(cached) = cache.get(&node.path) {
let mut previous: std::collections::HashMap<PathBuf, TreeNode> = node
.children
.drain(..)
.map(|c| (c.path.clone(), c))
.collect();
node.children = cached
.raw
.iter()
.filter(|e| e.passes(filter))
.map(|e| {
previous
.remove(&e.path)
.unwrap_or_else(|| TreeNode::from_entry(e))
})
.collect();
} else {
}
}
for child in &mut node.children {
rebuild_from_cache(child, cache, filter);
}
}