diff options
author | Benjamin Nguyen <benjamin.van.nguyen@gmail.com> | 2023-11-26 17:37:26 -0800 |
---|---|---|
committer | Benjamin Nguyen <benjamin.van.nguyen@gmail.com> | 2023-11-26 17:37:26 -0800 |
commit | b2efcf666b6b7ce3fbedbe45ab93c9201877de34 (patch) | |
tree | d85be1e34f4e8fb017bd4eee3bf001c8a3f03157 | |
parent | 8fa8f72ca6289695515f497c08ba1b6125cb5bce (diff) |
inverted tree
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/render/mod.rs | 105 | ||||
-rw-r--r-- | src/render/row/mod.rs | 13 |
3 files changed, 110 insertions, 10 deletions
diff --git a/src/main.rs b/src/main.rs index 6691d3a..1dc860a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ fn run() -> Result<()> { Ok(tree) })?; - let output = render::tree(&file_tree, &ctx)?; + let output = render::output(&file_tree, &ctx)?; let mut stdout = stdout().lock(); writeln!(stdout, "{output}").into_report(ErrorCategory::Warning)?; diff --git a/src/render/mod.rs b/src/render/mod.rs index f816da4..0a5863c 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,4 +1,4 @@ -use crate::{error::prelude::*, file, user::Context}; +use crate::{error::prelude::*, file, user::{args::Layout, Context}}; use indextree::{NodeEdge, NodeId}; /// Used for padding between tree branches. @@ -20,7 +20,22 @@ pub const ROTATED_T: &str = "\u{251C}\u{2500} "; /// row in the program output. mod row; -pub fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> { +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Root node could not be computed")] + MissingRoot +} + +pub fn output(file_tree: &file::Tree, ctx: &Context) -> Result<String> { + match ctx.layout { + Layout::Regular => tree(file_tree, ctx), + Layout::Inverted => inverted_tree(file_tree, ctx), + Layout::Flat => todo!(), + Layout::Iflat => todo!(), + } +} + +fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> { let arena = file_tree.arena(); let root = file_tree.root_id(); let max_depth = ctx.level(); @@ -94,6 +109,92 @@ pub fn tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> { Ok(buf) } +pub fn inverted_tree(file_tree: &file::Tree, ctx: &Context) -> Result<String> { + let arena = file_tree.arena(); + let root = file_tree.root_id(); + let max_depth = ctx.level(); + + let mut buf = String::new(); + + let is_last_sibling = |node_id: NodeId, depth: usize| { + (depth > 0) + .then(|| node_id.following_siblings(arena).skip(1).next().is_none()) + .unwrap_or(false) + }; + + let mut inherited_prefix_components = vec![""]; + + let mut formatter = row::formatter(&mut buf, ctx); + + let mut traverse = root.traverse(arena); + + match traverse + .next() + .ok_or(Error::MissingRoot) + .into_report(ErrorCategory::Internal) + .context(error_source!())? + { + NodeEdge::Start(root_id) => { + formatter(arena[root_id].get(), "".to_string()) + .into_report(ErrorCategory::Internal) + .context(error_source!())?; + } + _ => unreachable!() + } + + for node_edge in traverse { + let (node, node_id, depth) = match node_edge { + NodeEdge::Start(node_id) => { + let node = arena[node_id].get(); + let depth = node.depth(); + + if depth > max_depth { + continue; + } + + (node, node_id, depth) + } + NodeEdge::End(node_id) => { + let node = arena[node_id].get(); + let depth = node.depth(); + + if utils::node_is_dir(&node) && depth < max_depth { + inherited_prefix_components.pop(); + } + continue; + } + }; + + let prefix = format!( + "{}{}", + inherited_prefix_components.join(""), + (depth > 0) + .then(|| { + is_last_sibling(node_id, depth) + .then_some(BL_CORNER) + .unwrap_or(ROTATED_T) + }) + .unwrap_or("") + ); + + if let Err(e) = formatter(&node, prefix) { + log::warn!("{e}"); + } + + if utils::node_is_dir(&node) && depth < max_depth { + if is_last_sibling(node_id, depth) { + inherited_prefix_components.push(SEP); + } else { + inherited_prefix_components.push(VLINE); + } + } + } + + drop(formatter); + + Ok(buf) +} + mod utils { use crate::file::File; diff --git a/src/render/row/mod.rs b/src/render/row/mod.rs index b035906..ddeac87 100644 --- a/src/render/row/mod.rs +++ b/src/render/row/mod.rs @@ -1,5 +1,5 @@ -use crate::{error::prelude::*, file::File, user::{Context, column}}; -use std::fmt::Write; +use crate::{file::File, user::{Context, column}}; +use std::fmt::{self, Write}; /// Concerned with how to present long-format for a particular file. #[cfg(unix)] @@ -9,14 +9,14 @@ mod long; pub fn formatter<'a>( buf: &'a mut String, ctx: &'a Context, -) -> Box<dyn FnMut(&File, String) -> Result<()> + 'a> { +) -> Box<dyn FnMut(&File, String) -> fmt::Result + 'a> { Box::new(|file, prefix| { let size = format!("{}", file.size()); let name = file.file_name().to_string_lossy(); let column::Widths { size: size_width, .. } = ctx.col_widths(); - writeln!(buf, "{size:>size_width$} {prefix}{name}").into_report(ErrorCategory::Warning) + writeln!(buf, "{size:>size_width$} {prefix}{name}") }) } @@ -24,7 +24,7 @@ pub fn formatter<'a>( pub fn formatter<'a>( buf: &'a mut String, ctx: &'a Context, -) -> Box<dyn FnMut(&File, String) -> Result<()> + 'a> { +) -> Box<dyn FnMut(&File, String) -> fmt::Result + 'a> { if !ctx.long { return Box::new(|file, prefix| { let size = format!("{}", file.size()); @@ -32,7 +32,7 @@ pub fn formatter<'a>( let column::Metadata { max_size_width, .. } = ctx.column_metadata; - writeln!(buf, "{size:>max_size_width$} {prefix}{name}").into_report(ErrorCategory::Warning) + writeln!(buf, "{size:>max_size_width$} {prefix}{name}") }); } @@ -44,6 +44,5 @@ pub fn formatter<'a>( let long_format = long::Format::new(file, ctx); writeln!(buf, "{long_format} {size:>max_size_width$} {prefix}{name}") - .into_report(ErrorCategory::Warning) }) } |