From 1d9a56e025a3268783fa2fd82005d7d9d3edb22e Mon Sep 17 00:00:00 2001 From: "andy.boot" Date: Wed, 2 Oct 2019 22:31:49 +0100 Subject: [PATCH] A way of supporting reverse --- src/display.rs | 98 ++++++++++++++++++++++++++++++++++++------------ src/main.rs | 18 ++++++++- src/utils/mod.rs | 9 +++++ 3 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/display.rs b/src/display.rs index d12b02a..cf2a81b 100644 --- a/src/display.rs +++ b/src/display.rs @@ -13,15 +13,32 @@ pub fn draw_it( depth: Option, base_dirs: HashSet, to_display: Vec<(String, u64)>, + is_reversed: bool, ) { if !permissions { eprintln!("Did not have permissions for all directories"); } let mut found = HashSet::new(); + let first_tree_chars = { + if is_reversed { + "─┴" + } else { + "─┬" + } + }; for &(ref k, _) in to_display.iter() { if base_dirs.contains(k) { - display_node(&k, &mut found, &to_display, true, short_paths, depth, "─┬"); + display_node( + &k, + &mut found, + &to_display, + true, + short_paths, + depth, + first_tree_chars, + is_reversed, + ); } } } @@ -36,18 +53,19 @@ fn get_size(nodes: &[(String, u64)], node_to_print: &str) -> Option { } fn display_node( - node_to_print: &str, - found: &mut HashSet, + node: &str, + nodes_already_found: &mut HashSet, to_display: &[(String, u64)], is_biggest: bool, short_paths: bool, depth: Option, - indentation_str: &str, + indent: &str, + is_reversed: bool, ) { - if found.contains(node_to_print) { + if nodes_already_found.contains(node) { return; } - found.insert(node_to_print.to_string()); + nodes_already_found.insert(node.to_string()); let new_depth = match depth { None => None, @@ -55,35 +73,36 @@ fn display_node( Some(d) => Some(d - 1), }; - match get_size(to_display, node_to_print) { - None => println!("Can not find path: {}", node_to_print), + match get_size(to_display, node) { + None => println!("Can not find path: {}", node), Some(size) => { - print_this_node( - node_to_print, - size, - is_biggest, - short_paths, - indentation_str, - ); + if !is_reversed { + print_this_node(node, size, is_biggest, short_paths, indent); + } fan_out( - node_to_print, - found, + node, + nodes_already_found, to_display, short_paths, new_depth, - indentation_str, + indent, + is_reversed, ); + if is_reversed { + print_this_node(node, size, is_biggest, short_paths, indent); + } } } } fn fan_out( node_to_print: &str, - found: &mut HashSet, + nodes_already_found: &mut HashSet, to_display: &[(String, u64)], short_paths: bool, new_depth: Option, indentation_str: &str, + is_reversed: bool, ) { let new_indent = clean_indentation_string(indentation_str); let num_slashes = strip_end_slash_including_root(node_to_print) @@ -98,14 +117,26 @@ fn fan_out( if k.starts_with(temp.as_str()) && k.matches('/').count() == num_slashes + 1 { num_siblings -= 1; let has_children = has_children(to_display, new_depth, k, num_slashes + 1); + let (new_tree_chars, biggest) = if is_reversed { + ( + get_tree_chars_reversed(num_siblings != max_siblings - 1, has_children), + num_siblings == 0, + ) + } else { + ( + get_tree_chars(num_siblings != 0, has_children), + num_siblings == max_siblings - 1, + ) + }; display_node( k, - found, + nodes_already_found, to_display, - num_siblings == max_siblings - 1, + biggest, short_paths, new_depth, - &*(new_indent.to_string() + get_tree_chars(num_siblings != 0, has_children)), + &*(new_indent.to_string() + new_tree_chars), + is_reversed, ); } } @@ -113,11 +144,18 @@ fn fan_out( fn clean_indentation_string(s: &str) -> String { let mut is: String = s.into(); + // For reversed: + is = is.replace("┌─┴", " "); + is = is.replace("┌──", " "); + is = is.replace("├─┴", "│ "); + is = is.replace("─┴", " "); + // For normal is = is.replace("└─┬", " "); is = is.replace("└──", " "); - is = is.replace("├──", "│ "); is = is.replace("├─┬", "│ "); is = is.replace("─┬", " "); + // For both + is = is.replace("├──", "│ "); is } @@ -163,6 +201,20 @@ fn get_tree_chars(has_smaller_siblings: bool, has_children: bool) -> &'static st } } +fn get_tree_chars_reversed(has_smaller_siblings: bool, has_children: bool) -> &'static str { + if !has_smaller_siblings { + if has_children { + "┌─┴" + } else { + "┬──" + } + } else if has_children { + "├─┴" + } else { + "├──" + } +} + fn print_this_node( node_name: &str, size: u64, diff --git a/src/main.rs b/src/main.rs index 5e4888a..e6bfa79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,10 @@ extern crate walkdir; use self::display::draw_it; use clap::{App, AppSettings, Arg}; -use utils::{find_big_ones, get_dir_tree, simplify_dir_names, sort, trim_deep_ones}; +use utils::{ + compare_tuple_smallest_first, find_big_ones, get_dir_tree, simplify_dir_names, sort, + trim_deep_ones, +}; mod display; mod utils; @@ -43,6 +46,12 @@ fn main() { .long("apparent-size") .help("If set will use file length. Otherwise we use blocks"), ) + .arg( + Arg::with_name("reverse") + .short("r") + .long("reverse") + .help("If applied tree will be printed upside down (biggest lowest)"), + ) .arg(Arg::with_name("inputs").multiple(true)) .get_matches(); @@ -85,18 +94,23 @@ fn main() { let simplified_dirs = simplify_dir_names(target_dirs); let (permissions, nodes) = get_dir_tree(&simplified_dirs, use_apparent_size); let sorted_data = sort(nodes); - let biggest_ones = { + let mut biggest_ones = { match depth { None => find_big_ones(sorted_data, number_of_lines + simplified_dirs.len()), Some(d) => trim_deep_ones(sorted_data, d, &simplified_dirs), } }; + if options.is_present("reverse") { + biggest_ones.sort_by(compare_tuple_smallest_first); + } + draw_it( permissions, !use_full_path, depth, simplified_dirs, biggest_ones, + options.is_present("reverse"), ); } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index c6c813c..6263686 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -121,6 +121,15 @@ pub fn compare_tuple(a: &(String, u64), b: &(String, u64)) -> Ordering { } } +pub fn compare_tuple_smallest_first(a: &(String, u64), b: &(String, u64)) -> Ordering { + let result = a.1.cmp(&b.1); + if result == Ordering::Equal { + b.0.cmp(&a.0) + } else { + result + } +} + pub fn sort(data: HashMap) -> Vec<(String, u64)> { let mut new_l: Vec<(String, u64)> = data.iter().map(|(a, b)| (a.clone(), *b)).collect(); new_l.sort_by(|a, b| compare_tuple(&a, &b));