From c59304490fd22c185765b77bb15f6810356877a3 Mon Sep 17 00:00:00 2001 From: Benjamin Nguyen Date: Mon, 1 May 2023 20:32:50 -0700 Subject: [PATCH] restore clap descriptions --- src/render/context/mod.rs | 9 ++- src/render/display/flat.rs | 37 ++++++++++++ src/render/display/inverted.rs | 92 +++++++++++++++++++++++++++++ src/render/display/mod.rs | 5 ++ src/render/display/regular.rs | 104 +++++++++++++++++++++++++++++++++ src/render/theme.rs | 37 ++++++++++++ 6 files changed, 279 insertions(+), 5 deletions(-) create mode 100644 src/render/display/flat.rs create mode 100644 src/render/display/inverted.rs create mode 100644 src/render/display/mod.rs create mode 100644 src/render/display/regular.rs create mode 100644 src/render/theme.rs diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs index e6394e79..2770b189 100644 --- a/src/render/context/mod.rs +++ b/src/render/context/mod.rs @@ -47,11 +47,10 @@ mod test; /// Defines the CLI. #[derive(Parser, Debug)] -#[command(name = env!("CARGO_PKG_NAME", "The Package Name is missing!"))] -#[command(author = env!("CARGO_PKG_AUTHORS", "The Author of the Package is missing!"))] -#[command(version = env!("CARGO_PKG_VERSION_MAJOR", "The Package version is missing!"))] -#[command(about = "erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage analysis tool.", - long_about = env!("CARGO_PKG_DESCRIPTION", "The Long Package Description is missing!"))] +#[command(name = "erdtree")] +#[command(author = "Benjamin Nguyen. ")] +#[command(version = "2.0.0")] +#[command(about = "erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage analysis tool.", long_about = None)] pub struct Context { /// Directory to traverse; defaults to current working directory dir: Option, diff --git a/src/render/display/flat.rs b/src/render/display/flat.rs new file mode 100644 index 00000000..925440dd --- /dev/null +++ b/src/render/display/flat.rs @@ -0,0 +1,37 @@ +use crate::{ + render::Engine, + tree::{count::FileCount, Tree}, +}; +use std::fmt::{self, Display}; + +pub struct Flat; + +impl Display for Engine { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ctx = self.context(); + let tree = self.tree(); + let arena = tree.arena(); + let root_id = tree.root_id(); + let max_depth = ctx.level(); + let mut file_count_data = vec![]; + + let descendants = root_id.descendants(arena); + + for node_id in descendants { + let node = arena[node_id].get(); + + if node.depth() > max_depth { + continue; + } + + node.flat_display(f, ctx)?; + file_count_data.push(Tree::compute_file_count(node_id, arena)); + } + + if !file_count_data.is_empty() { + write!(f, "\n{}", FileCount::from(file_count_data))?; + } + + Ok(()) + } +} diff --git a/src/render/display/inverted.rs b/src/render/display/inverted.rs new file mode 100644 index 00000000..bb08dee6 --- /dev/null +++ b/src/render/display/inverted.rs @@ -0,0 +1,92 @@ +use crate::{ + render::{Engine, theme}, + styles, + tree::{count::FileCount, node::Node, Tree}, +}; +use indextree::NodeId; +use std::fmt::{self, Display}; + +pub struct Inverted; + +impl Display for Engine { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ctx = self.context(); + let tree = self.tree(); + + let root_id = tree.root_id(); + let arena = tree.arena(); + let level = ctx.level(); + let mut file_count_data = vec![]; + + let mut descendants = root_id.descendants(arena).skip(1).peekable(); + + let mut display_node = |node_id: NodeId, node: &Node, prefix: &str| -> fmt::Result { + node.tree_display(f, prefix, ctx)?; + file_count_data.push(Tree::compute_file_count(node_id, arena)); + writeln!(f) + }; + + display_node(root_id, arena[root_id].get(), "")?; + + let mut get_theme = if ctx.follow { + theme::link_theme_getter() + } else { + theme::regular_theme_getter() + }; + + let mut base_prefix_components = vec![""]; + + while let Some(current_node_id) = descendants.next() { + let current_node = arena[current_node_id].get(); + + let current_depth = current_node.depth(); + + let mut siblings = current_node_id.following_siblings(arena).skip(1).peekable(); + + let last_sibling = siblings.peek().is_none(); + + let theme = get_theme(current_node); + + if current_depth <= level { + let prefix_part = if last_sibling { + theme.get("uprt").unwrap() + } else { + theme.get("vtrt").unwrap() + }; + + let mut current_prefix_components = base_prefix_components.clone(); + + current_prefix_components.push(prefix_part); + + let prefix = current_prefix_components.join(""); + + display_node(current_node_id, current_node, &prefix)?; + } + + if let Some(next_id) = descendants.peek() { + let next_node = arena[*next_id].get(); + + let next_depth = next_node.depth(); + + if next_depth == current_depth + 1 { + if last_sibling { + base_prefix_components.push(styles::SEP); + } else { + let prefix = theme.get("vt").unwrap(); + base_prefix_components.push(prefix); + } + } else if next_depth < current_depth { + let depth_delta = current_depth - next_depth; + + base_prefix_components.truncate(base_prefix_components.len() - depth_delta); + } + } + } + + if !file_count_data.is_empty() { + write!(f, "\n{}", FileCount::from(file_count_data))?; + } + + Ok(()) + } +} diff --git a/src/render/display/mod.rs b/src/render/display/mod.rs new file mode 100644 index 00000000..e54455d5 --- /dev/null +++ b/src/render/display/mod.rs @@ -0,0 +1,5 @@ +pub mod regular; + +pub mod flat; + +pub mod inverted; diff --git a/src/render/display/regular.rs b/src/render/display/regular.rs new file mode 100644 index 00000000..7e0af7a3 --- /dev/null +++ b/src/render/display/regular.rs @@ -0,0 +1,104 @@ +use crate::{ + render::{Engine, theme}, + styles, + tree::{count::FileCount, node::Node, Tree}, +}; +use indextree::{NodeEdge, NodeId}; +use std::fmt::{self, Display}; + +pub struct Regular; + +impl Display for Engine { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ctx = self.context(); + let tree = self.tree(); + let root_id = tree.root_id(); + let arena = tree.arena(); + let max_depth = ctx.level(); + let mut file_count_data = vec![]; + + let mut display_node = |node_id: NodeId, node: &Node, prefix: &str| -> fmt::Result { + node.tree_display(f, prefix, ctx)?; + file_count_data.push(Tree::compute_file_count(node_id, arena)); + writeln!(f) + }; + + let mut get_theme = if ctx.follow { + theme::link_theme_getter() + } else { + theme::regular_theme_getter() + }; + + let mut base_prefix_components = vec![""]; + + let mut tree_edges = root_id.reverse_traverse(arena).skip(1).peekable(); + + while let Some(node_edge) = tree_edges.next() { + let current_node_id = match node_edge { + NodeEdge::Start(id) => id, + + NodeEdge::End(id) => { + let current_node = arena[id].get(); + + if !current_node.is_dir() || id.children(arena).count() == 0 { + continue; + } + + let theme = get_theme(current_node); + + let topmost_sibling = id.following_siblings(arena).nth(1).is_none(); + + if topmost_sibling { + base_prefix_components.push(styles::SEP); + } else { + base_prefix_components.push(theme.get("vt").unwrap()); + } + + continue; + } + }; + + let current_node = arena[current_node_id].get(); + + let node_depth = current_node.depth(); + + let topmost_sibling = current_node_id.following_siblings(arena).nth(1).is_none(); + + let theme = get_theme(current_node); + + if node_depth <= max_depth { + if node_depth == 0 { + display_node(current_node_id, current_node, "")?; + } else { + let prefix_part = if topmost_sibling { + theme.get("drt").unwrap() + } else { + theme.get("vtrt").unwrap() + }; + + let mut current_prefix_components = base_prefix_components.clone(); + + current_prefix_components.push(prefix_part); + + let prefix = current_prefix_components.join(""); + + display_node(current_node_id, current_node, &prefix)?; + } + } + + if let Some(NodeEdge::Start(next_id)) = tree_edges.peek() { + let next_node = arena[*next_id].get(); + + if next_node.depth() < node_depth { + base_prefix_components.pop(); + } + } + } + + if !file_count_data.is_empty() { + write!(f, "\n{}", FileCount::from(file_count_data))?; + } + + Ok(()) + } +} diff --git a/src/render/theme.rs b/src/render/theme.rs new file mode 100644 index 00000000..d33d1901 --- /dev/null +++ b/src/render/theme.rs @@ -0,0 +1,37 @@ +use crate::{ + styles::{self, ThemesMap}, + tree::node::Node, +}; + +type Theme = Box &'static ThemesMap>; + +/// Returns a closure that retrieves the regular theme. +pub fn regular_theme_getter() -> Theme { + Box::new(|_node: &Node| styles::get_tree_theme().unwrap()) +} + +/// Returns a closure that can smartly determine when a symlink is being followed and when it is +/// not being followed. When a symlink is being followed, all of its descendents should have tree +/// branches that are colored differently. +pub fn link_theme_getter() -> Theme { + let mut link_depth = None; + + Box::new(move |node: &Node| { + let current_depth = node.depth(); + + if let Some(ldepth) = link_depth { + if current_depth == ldepth { + link_depth = None; + } + } + + if link_depth.is_some() || node.is_symlink() { + if node.is_dir() && link_depth.is_none() { + link_depth = Some(current_depth); + } + styles::get_link_theme().unwrap() + } else { + styles::get_tree_theme().unwrap() + } + }) +}