use std::path::{Path, PathBuf};
use crate::cache::TreeCache;
use crate::config::{DisplayFilter, TreeConfig};
use crate::node::TreeNode;
use crate::scan::{self, LoadedOutcome};
use crate::selection;
pub(crate) mod transitions;
#[derive(Debug, Clone, PartialEq)]
pub struct DirectoryTree {
pub(crate) root: TreeNode,
pub(crate) config: TreeConfig,
pub(crate) cache: TreeCache,
pub(crate) generation: u32,
pub(crate) selected_paths: Vec<PathBuf>,
pub(crate) active_path: Option<PathBuf>,
pub(crate) anchor_path: Option<PathBuf>,
}
impl DirectoryTree {
pub fn new(root_path: impl Into<PathBuf>) -> Self {
let config = TreeConfig::new(root_path);
let root = TreeNode::new_root(config.root_path.clone());
Self {
root,
config,
cache: TreeCache::default(),
generation: 0,
selected_paths: Vec::new(),
active_path: None,
anchor_path: None,
}
}
pub fn with_filter(mut self, filter: DisplayFilter) -> Self {
self.config.filter = filter;
self
}
pub fn with_max_depth(mut self, max_depth: u32) -> Self {
self.config.max_depth = Some(max_depth);
self
}
pub fn root(&self) -> &TreeNode {
&self.root
}
pub fn config(&self) -> &TreeConfig {
&self.config
}
pub fn filter(&self) -> DisplayFilter {
self.config.filter
}
pub fn generation(&self) -> u32 {
self.generation
}
pub fn cache(&self) -> &TreeCache {
&self.cache
}
pub fn find(&self, path: &Path) -> Option<&TreeNode> {
self.root.find(path)
}
pub fn depth_of(&self, path: &Path) -> Option<u32> {
let rel = path.strip_prefix(&self.config.root_path).ok()?;
Some(rel.components().count() as u32)
}
pub fn set_filter(&mut self, filter: DisplayFilter) {
if filter == self.config.filter {
return;
}
self.config.filter = filter;
transitions::refresh_from_cache(&mut self.root, &self.cache, filter);
selection::sync_flags(&mut self.root, &self.selected_paths);
}
pub fn visible_rows(&self) -> Vec<(&TreeNode, u32)> {
let mut rows = Vec::new();
collect_rows(&self.root, 0, &mut rows);
rows
}
pub fn expand_blocking(&mut self, path: &Path) -> Option<LoadedOutcome> {
let request = self.on_toggled(path)?;
let payload = scan::run(&request);
Some(self.on_loaded(payload))
}
pub fn selected_paths(&self) -> &[PathBuf] {
&self.selected_paths
}
pub fn selected_path(&self) -> Option<&Path> {
self.active_path.as_deref()
}
pub fn is_selected(&self, path: &Path) -> bool {
self.selected_paths.iter().any(|p| p == path)
}
}
fn collect_rows<'a>(node: &'a TreeNode, depth: u32, rows: &mut Vec<(&'a TreeNode, u32)>) {
rows.push((node, depth));
if node.is_dir && node.is_expanded && node.is_loaded {
for child in &node.children {
collect_rows(child, depth + 1, rows);
}
}
}