mirror of
https://github.com/bootandy/dust.git
synced 2026-06-08 11:29:05 +03:00
Add reverse flag
Pull several variables related to how output is printed into DisplayData struct
This commit is contained in:
+115
-125
@@ -2,65 +2,129 @@ extern crate ansi_term;
|
|||||||
|
|
||||||
use self::ansi_term::Colour::Fixed;
|
use self::ansi_term::Colour::Fixed;
|
||||||
use self::ansi_term::Style;
|
use self::ansi_term::Style;
|
||||||
|
use std::cmp::max;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use utils::{ensure_end_slash, strip_end_slash_including_root};
|
use utils::{ensure_end_slash, strip_end_slash_including_root};
|
||||||
|
|
||||||
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
||||||
|
|
||||||
pub fn draw_it(
|
pub struct DisplayData {
|
||||||
permissions: bool,
|
pub short_paths: bool,
|
||||||
short_paths: bool,
|
pub is_reversed: bool,
|
||||||
depth: Option<u64>,
|
pub to_display: Vec<(String, u64)>,
|
||||||
base_dirs: HashSet<String>,
|
}
|
||||||
to_display: Vec<(String, u64)>,
|
|
||||||
is_reversed: bool,
|
impl DisplayData {
|
||||||
) {
|
fn get_first_chars(&self) -> &str {
|
||||||
if !permissions {
|
if self.is_reversed {
|
||||||
eprintln!("Did not have permissions for all directories");
|
|
||||||
}
|
|
||||||
let mut found = HashSet::new();
|
|
||||||
let first_tree_chars = {
|
|
||||||
if is_reversed {
|
|
||||||
"─┴"
|
"─┴"
|
||||||
} else {
|
} else {
|
||||||
"─┬"
|
"─┬"
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
for &(ref k, _) in to_display.iter() {
|
fn get_tree_chars(
|
||||||
if base_dirs.contains(k) {
|
&self,
|
||||||
display_node(
|
num_siblings: u64,
|
||||||
&k,
|
max_siblings: u64,
|
||||||
&mut found,
|
has_children: bool,
|
||||||
&to_display,
|
) -> &'static str {
|
||||||
true,
|
if self.is_reversed {
|
||||||
short_paths,
|
if num_siblings == max_siblings - 1 {
|
||||||
depth,
|
if has_children {
|
||||||
first_tree_chars,
|
"┌─┴"
|
||||||
is_reversed,
|
} else {
|
||||||
);
|
"┌──"
|
||||||
|
}
|
||||||
|
} else if has_children {
|
||||||
|
"├─┴"
|
||||||
|
} else {
|
||||||
|
"├──"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if num_siblings == 0 {
|
||||||
|
if has_children {
|
||||||
|
"└─┬"
|
||||||
|
} else {
|
||||||
|
"└──"
|
||||||
|
}
|
||||||
|
} else if has_children {
|
||||||
|
"├─┬"
|
||||||
|
} else {
|
||||||
|
"├──"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn biggest(&self, num_siblings: u64, max_siblings: u64) -> bool {
|
||||||
|
if self.is_reversed {
|
||||||
|
num_siblings == 0
|
||||||
|
} else {
|
||||||
|
num_siblings == max_siblings - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_size(&self, node_to_print: &str) -> Option<u64> {
|
||||||
|
for &(ref k, ref v) in self.to_display.iter() {
|
||||||
|
if *k == *node_to_print {
|
||||||
|
return Some(*v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_siblings(&self, num_slashes: usize, ntp: &str) -> u64 {
|
||||||
|
self.to_display.iter().fold(0, |a, b| {
|
||||||
|
if b.0.starts_with(ntp) && b.0.as_str().matches('/').count() == num_slashes + 1 {
|
||||||
|
a + 1
|
||||||
|
} else {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_children(&self, new_depth: Option<u64>, ntp: &str, num_slashes: usize) -> bool {
|
||||||
|
// this shouldn't be needed we should have already stripped
|
||||||
|
if new_depth.is_none() || new_depth.unwrap() != 1 {
|
||||||
|
for &(ref k2, _) in self.to_display.iter() {
|
||||||
|
let ntp_with_slash = String::from(ntp.to_owned() + "/");
|
||||||
|
if k2.starts_with(ntp_with_slash.as_str())
|
||||||
|
&& k2.matches('/').count() == num_slashes + 1
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(nodes: &[(String, u64)], node_to_print: &str) -> Option<u64> {
|
pub fn draw_it(
|
||||||
for &(ref k, ref v) in nodes.iter() {
|
permissions: bool,
|
||||||
if *k == *node_to_print {
|
depth: Option<u64>,
|
||||||
return Some(*v);
|
base_dirs: HashSet<String>,
|
||||||
|
display_data: &DisplayData,
|
||||||
|
) {
|
||||||
|
if !permissions {
|
||||||
|
eprintln!("Did not have permissions for all directories");
|
||||||
|
}
|
||||||
|
let first_tree_chars = display_data.get_first_chars();
|
||||||
|
let mut found = HashSet::new();
|
||||||
|
|
||||||
|
for &(ref k, _) in display_data.to_display.iter() {
|
||||||
|
if base_dirs.contains(k) {
|
||||||
|
display_node(&k, &mut found, true, depth, first_tree_chars, display_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_node(
|
fn display_node(
|
||||||
node: &str,
|
node: &str,
|
||||||
nodes_already_found: &mut HashSet<String>,
|
nodes_already_found: &mut HashSet<String>,
|
||||||
to_display: &[(String, u64)],
|
|
||||||
is_biggest: bool,
|
is_biggest: bool,
|
||||||
short_paths: bool,
|
|
||||||
depth: Option<u64>,
|
depth: Option<u64>,
|
||||||
indent: &str,
|
indent: &str,
|
||||||
is_reversed: bool,
|
display_data: &DisplayData,
|
||||||
) {
|
) {
|
||||||
if nodes_already_found.contains(node) {
|
if nodes_already_found.contains(node) {
|
||||||
return;
|
return;
|
||||||
@@ -73,23 +137,17 @@ fn display_node(
|
|||||||
Some(d) => Some(d - 1),
|
Some(d) => Some(d - 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
match get_size(to_display, node) {
|
match display_data.get_size(node) {
|
||||||
None => println!("Can not find path: {}", node),
|
None => println!("Can not find path: {}", node),
|
||||||
Some(size) => {
|
Some(size) => {
|
||||||
if !is_reversed {
|
let short_path = display_data.short_paths;
|
||||||
print_this_node(node, size, is_biggest, short_paths, indent);
|
// move this inside display_data?
|
||||||
|
if !display_data.is_reversed {
|
||||||
|
print_this_node(node, size, is_biggest, short_path, indent);
|
||||||
}
|
}
|
||||||
fan_out(
|
fan_out(node, nodes_already_found, new_depth, indent, display_data);
|
||||||
node,
|
if display_data.is_reversed {
|
||||||
nodes_already_found,
|
print_this_node(node, size, is_biggest, short_path, indent);
|
||||||
to_display,
|
|
||||||
short_paths,
|
|
||||||
new_depth,
|
|
||||||
indent,
|
|
||||||
is_reversed,
|
|
||||||
);
|
|
||||||
if is_reversed {
|
|
||||||
print_this_node(node, size, is_biggest, short_paths, indent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,45 +156,33 @@ fn display_node(
|
|||||||
fn fan_out(
|
fn fan_out(
|
||||||
node_to_print: &str,
|
node_to_print: &str,
|
||||||
nodes_already_found: &mut HashSet<String>,
|
nodes_already_found: &mut HashSet<String>,
|
||||||
to_display: &[(String, u64)],
|
|
||||||
short_paths: bool,
|
|
||||||
new_depth: Option<u64>,
|
new_depth: Option<u64>,
|
||||||
indentation_str: &str,
|
indentation_str: &str,
|
||||||
is_reversed: bool,
|
display_data: &DisplayData,
|
||||||
) {
|
) {
|
||||||
let new_indent = clean_indentation_string(indentation_str);
|
let new_indent = clean_indentation_string(indentation_str);
|
||||||
let num_slashes = strip_end_slash_including_root(node_to_print)
|
let num_slashes = strip_end_slash_including_root(node_to_print)
|
||||||
.matches('/')
|
.matches('/')
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
let mut num_siblings = count_siblings(to_display, num_slashes, node_to_print);
|
let mut num_siblings = display_data.count_siblings(num_slashes, node_to_print);
|
||||||
let max_siblings = num_siblings;
|
let max_siblings = num_siblings;
|
||||||
|
|
||||||
for &(ref k, _) in to_display.iter() {
|
for &(ref k, _) in display_data.to_display.iter() {
|
||||||
let temp = String::from(ensure_end_slash(node_to_print));
|
let temp = String::from(ensure_end_slash(node_to_print));
|
||||||
if k.starts_with(temp.as_str()) && k.matches('/').count() == num_slashes + 1 {
|
if k.starts_with(temp.as_str()) && k.matches('/').count() == num_slashes + 1 {
|
||||||
num_siblings -= 1;
|
num_siblings -= 1;
|
||||||
let has_children = has_children(to_display, new_depth, k, num_slashes + 1);
|
let has_children = display_data.has_children(new_depth, k, num_slashes + 1);
|
||||||
let (new_tree_chars, biggest) = if is_reversed {
|
let new_tree_chars =
|
||||||
(
|
display_data.get_tree_chars(num_siblings, max_siblings, has_children);
|
||||||
get_tree_chars_reversed(num_siblings != max_siblings - 1, has_children),
|
let biggest = display_data.biggest(num_siblings, max_siblings);
|
||||||
num_siblings == 0,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
get_tree_chars(num_siblings != 0, has_children),
|
|
||||||
num_siblings == max_siblings - 1,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
display_node(
|
display_node(
|
||||||
k,
|
k,
|
||||||
nodes_already_found,
|
nodes_already_found,
|
||||||
to_display,
|
|
||||||
biggest,
|
biggest,
|
||||||
short_paths,
|
|
||||||
new_depth,
|
new_depth,
|
||||||
&*(new_indent.to_string() + new_tree_chars),
|
&*(new_indent.to_string() + new_tree_chars),
|
||||||
is_reversed,
|
display_data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,62 +205,6 @@ fn clean_indentation_string(s: &str) -> String {
|
|||||||
is
|
is
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_siblings(to_display: &[(String, u64)], num_slashes: usize, ntp: &str) -> u64 {
|
|
||||||
to_display.iter().fold(0, |a, b| {
|
|
||||||
if b.0.starts_with(ntp) && b.0.as_str().matches('/').count() == num_slashes + 1 {
|
|
||||||
a + 1
|
|
||||||
} else {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_children(
|
|
||||||
to_display: &[(String, u64)],
|
|
||||||
new_depth: Option<u64>,
|
|
||||||
ntp: &str,
|
|
||||||
num_slashes: usize,
|
|
||||||
) -> bool {
|
|
||||||
if new_depth.is_none() || new_depth.unwrap() != 1 {
|
|
||||||
for &(ref k2, _) in to_display.iter() {
|
|
||||||
let ntp_with_slash = String::from(ntp.to_owned() + "/");
|
|
||||||
if k2.starts_with(ntp_with_slash.as_str()) && k2.matches('/').count() == num_slashes + 1
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_tree_chars(has_smaller_siblings: bool, has_children: bool) -> &'static str {
|
|
||||||
if !has_smaller_siblings {
|
|
||||||
if has_children {
|
|
||||||
"└─┬"
|
|
||||||
} else {
|
|
||||||
"└──"
|
|
||||||
}
|
|
||||||
} else if has_children {
|
|
||||||
"├─┬"
|
|
||||||
} else {
|
|
||||||
"├──"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
fn print_this_node(
|
||||||
node_name: &str,
|
node_name: &str,
|
||||||
size: u64,
|
size: u64,
|
||||||
|
|||||||
+7
-8
@@ -4,6 +4,7 @@ extern crate assert_cli;
|
|||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
|
|
||||||
use self::display::draw_it;
|
use self::display::draw_it;
|
||||||
|
use self::display::DisplayData;
|
||||||
use clap::{App, AppSettings, Arg};
|
use clap::{App, AppSettings, Arg};
|
||||||
use utils::{
|
use utils::{
|
||||||
compare_tuple_smallest_first, find_big_ones, get_dir_tree, simplify_dir_names, sort,
|
compare_tuple_smallest_first, find_big_ones, get_dir_tree, simplify_dir_names, sort,
|
||||||
@@ -103,15 +104,13 @@ fn main() {
|
|||||||
if options.is_present("reverse") {
|
if options.is_present("reverse") {
|
||||||
biggest_ones.sort_by(compare_tuple_smallest_first);
|
biggest_ones.sort_by(compare_tuple_smallest_first);
|
||||||
}
|
}
|
||||||
|
let dd = DisplayData {
|
||||||
|
short_paths: !use_full_path,
|
||||||
|
is_reversed: options.is_present("reverse"),
|
||||||
|
to_display: biggest_ones,
|
||||||
|
};
|
||||||
|
|
||||||
draw_it(
|
draw_it(permissions, depth, simplified_dirs, &dd);
|
||||||
permissions,
|
|
||||||
!use_full_path,
|
|
||||||
depth,
|
|
||||||
simplified_dirs,
|
|
||||||
biggest_ones,
|
|
||||||
options.is_present("reverse"),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user