Skip to content

Commit

Permalink
add total when there is more than one dirs
Browse files Browse the repository at this point in the history
  • Loading branch information
seamile committed Jan 18, 2023
1 parent d2e3bf1 commit c192da0
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 52 deletions.
52 changes: 31 additions & 21 deletions src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,36 @@ pub fn color_me(arg: &dyn Display, color: Color, effect: Effect) -> String {

#[allow(unused)]
pub fn title(arg: &dyn Display) -> String {
color_me(arg, Color::BrightGreen, Effect::Underline)
return color_me(arg, Color::BrightGreen, Effect::Underline);
}

#[allow(unused)]
pub fn info(arg: &dyn Display) -> String {
color_me(arg, Color::BrightBlue, Effect::Default)
return color_me(arg, Color::BrightBlue, Effect::Default);
}

#[allow(unused)]
pub fn warn(arg: &dyn Display) -> String {
color_me(arg, Color::Yellow, Effect::Default)
return color_me(arg, Color::Yellow, Effect::Default);
}

#[allow(unused)]
pub fn err(arg: &dyn Display) -> String {
color_me(arg, Color::Red, Effect::Default)
return color_me(arg, Color::Red, Effect::Default);
}

fn spaces(width: usize) -> String {
return String::from_utf8(vec![32_u8; width]).unwrap();
#[allow(unused)]
pub fn strong(arg: &dyn Display) -> String {
return color_me(arg, Color::Default, Effect::Bold);
}

pub fn fill_char(chr: char, width: usize) -> String {
let s = vec![chr as u16; width];
return String::from_utf16(&s).unwrap();
}

pub fn spaces(width: usize) -> String {
return fill_char(' ', width);
}

pub fn display_width(s: &String) -> usize {
Expand All @@ -69,7 +79,7 @@ pub fn display_width(s: &String) -> usize {
}

#[allow(unused)]
pub fn align_center(s: &dyn ToString, width: usize) -> String {
pub fn center_justify(s: &dyn ToString, width: usize) -> String {
let mut string = s.to_string();
let d_width = display_width(&string);
if d_width < width {
Expand All @@ -87,7 +97,7 @@ pub fn align_center(s: &dyn ToString, width: usize) -> String {
}

#[allow(unused)]
pub fn align_left(s: &dyn ToString, width: usize) -> String {
pub fn left_justify(s: &dyn ToString, width: usize) -> String {
let mut string = s.to_string();
let d_width = display_width(&string);
if d_width < width {
Expand All @@ -98,7 +108,7 @@ pub fn align_left(s: &dyn ToString, width: usize) -> String {
}

#[allow(unused)]
pub fn align_right(s: &dyn ToString, width: usize) -> String {
pub fn right_justify(s: &dyn ToString, width: usize) -> String {
let mut string = s.to_string();
let d_width = display_width(&string);
if d_width < width {
Expand All @@ -124,17 +134,17 @@ fn test_color() {
#[test]
fn test_align() {
let s = "HelloWorld";
assert_eq!(align_center(&s, 14), String::from(" HelloWorld "));
assert_eq!(align_center(&s, 15), String::from(" HelloWorld "));
assert_eq!(align_left(&s, 15), String::from("HelloWorld "));
assert_eq!(align_right(&s, 15), String::from(" HelloWorld"));
assert_eq!(center_justify(&s, 14), String::from(" HelloWorld "));
assert_eq!(center_justify(&s, 15), String::from(" HelloWorld "));
assert_eq!(left_justify(&s, 15), String::from("HelloWorld "));
assert_eq!(right_justify(&s, 15), String::from(" HelloWorld"));

let t = title(
&vec![
align_left(&"Name", 8),
align_right(&"Files", 5),
align_right(&"Dirs", 5),
align_right(&"Size", 9),
left_justify(&"Name", 8),
right_justify(&"Files", 5),
right_justify(&"Dirs", 5),
right_justify(&"Size", 9),
]
.join(" "),
);
Expand All @@ -153,10 +163,10 @@ fn test_non_ascii() {
let s3 = "Séamile: 🌊😀";
let s4 = "EVA,人の作り出した物";

let aligned_s1 = align_right(&s1, 25);
let aligned_s2 = align_center(&s2, 25);
let aligned_s3 = align_left(&s3, 25);
let aligned_s4 = align_left(&s4, 25);
let aligned_s1 = right_justify(&s1, 25);
let aligned_s2 = center_justify(&s2, 25);
let aligned_s3 = left_justify(&s3, 25);
let aligned_s4 = left_justify(&s4, 25);

println!("s1 => |{}|", aligned_s1);
println!("s2 => |{}|", aligned_s2);
Expand Down
123 changes: 92 additions & 31 deletions src/walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct Counter {
impl Counter {
const SZ_UNIT: [&str; 7] = ["B", "K", "M", "G", "T", "P", "E"];

/// Create a new Counter
pub fn new(dirpath: &PathBuf, with_size: bool) -> Self {
return Self {
dirpath: dirpath.clone(),
Expand All @@ -49,26 +50,28 @@ impl Counter {
};
}

fn name(&self) -> &str {
// the dirpath with `&str` type
fn path(&self) -> &str {
return self.dirpath.to_str().expect("dir path err");
}

// get the file size from Metadata
fn file_size(metadata: &fs::Metadata) -> u64 {
let sz = metadata.st_size() as f64;
let blksz = metadata.st_blksize() as f64;
return (blksz * (sz / blksz).ceil()) as u64;
}

// calculate the total size of files in dirpath
pub fn size(&self) -> u64 {
match self.sz_map.as_ref() {
Some(mp) => mp.values().sum(),
None => 0,
}
}

// Make "size" more readable
fn readable_size(&self) -> String {
let mut sz = self.size() as f64;
fn add_unit_to_size(size: u64) -> String {
let mut sz = size as f64;
let mut str_sz = String::new();

for unit in Self::SZ_UNIT {
Expand All @@ -86,6 +89,11 @@ impl Counter {
return str_sz;
}

// make "size" more readable
fn readable_size(&self) -> String {
return Self::add_unit_to_size(self.size());
}

// merge from anther Counter
fn merge(&mut self, other: &Self) {
if other.dirpath.starts_with(&self.dirpath) {
Expand All @@ -97,52 +105,105 @@ impl Counter {
}
}

// get the length of each field for display
fn lengths(&self) -> Lengths {
return (
op::display_width(&self.name().to_string()),
op::display_width(&self.path().to_string()),
self.n_files.to_string().len(),
self.n_dirs.to_string().len(),
self.readable_size().len(),
);
}

fn make_title(with_size: bool, lens: Lengths) -> String {
let f0 = op::align_left(&"Name", lens.0);
let f1 = op::align_right(&"Files", lens.1);
let f2 = op::align_right(&"Dirs", lens.2);
fn join_fields(fields: Vec<&dyn ToString>, with_size: bool, lens: Lengths) -> String {
let f0 = op::left_justify(fields[0], lens.0);
let f1 = op::right_justify(fields[1], lens.1);
let f2 = op::right_justify(fields[2], lens.2);
if with_size {
let f3 = op::align_right(&"Size", lens.3);
return op::title(&vec![f0, f1, f2, f3].join(" "));
let f3 = op::right_justify(fields[3], lens.3);
return vec![f0, f1, f2, f3].join(" ");
} else {
return op::title(&vec![f0, f1, f2].join(" "));
return vec![f0, f1, f2].join(" ");
}
}

fn join_fields(&self, lens: Lengths) -> String {
let f0 = op::align_left(&self.name(), lens.0);
let f1 = op::align_right(&self.n_files, lens.1);
let f2 = op::align_right(&self.n_dirs, lens.2);
if self.sz_map == None {
return vec![f0, f1, f2].join(" ");
} else {
let f3 = op::align_right(&self.readable_size(), lens.3);
return vec![f0, f1, f2, f3].join(" ");
fn to_string(&self, lens: Lengths) -> String {
let path = self.path();
let size = self.readable_size();
let fields: Vec<&dyn ToString> = vec![&path, &self.n_files, &self.n_dirs, &size];
let with_size = self.sz_map != None;
return Self::join_fields(fields, with_size, lens);
}

fn make_head_line(with_size: bool, lens: Lengths) -> String {
let fields: Vec<&dyn ToString> = vec![&"Path", &"Files", &"Dirs", &"Size"];
return op::title(&Self::join_fields(fields, with_size, lens));
}

fn make_total_line(
total: (String, String, String, String),
with_size: bool,
lens: Lengths,
) -> String {
let fields: Vec<&dyn ToString> = vec![&total.0, &total.1, &total.2, &total.3];
let total_line = Self::join_fields(fields, with_size, lens);
let hor_line = op::fill_char('─', total_line.len());

return format!("{}\n{}", hor_line, op::strong(&total_line));
}

fn summarize(counters: &Vec<Self>) -> (String, String, String, String) {
let mut sum = (0_u64, 0_u64, 0_u64);
for c in counters {
sum.0 += c.n_files;
sum.1 += c.n_dirs;
sum.2 += c.size();
}

return (
String::from("Total"),
sum.0.to_string(),
sum.1.to_string(),
Self::add_unit_to_size(sum.2),
);
}

fn max_lengths(lens: Vec<Lengths>) -> Lengths {
let mut max_lens: Lengths = (0, 0, 0, 0);
for (l0, l1, l2, l3) in lens {
max_lens.0 = max_lens.0.max(l0);
max_lens.1 = max_lens.1.max(l1);
max_lens.2 = max_lens.2.max(l2);
max_lens.3 = max_lens.3.max(l3);
}
return max_lens;
}

pub fn output(counters: &Vec<Self>, with_size: bool) {
let total = if counters.len() > 1 {
Self::summarize(counters)
} else {
(String::new(), String::new(), String::new(), String::new())
};

// calculate the max value from `title`, `total` and `contents` lengths
let title_lens = (4_usize, 5_usize, 4_usize, 4_usize);
let total_lens = (total.0.len(), total.1.len(), total.2.len(), total.3.len());
let mut lens = Vec::from_iter(counters.iter().map(|c| c.lengths()));
lens.append(&mut vec![total_lens, title_lens]);
let max_lens = Self::max_lengths(lens);

// create the output lines from title, content and total
let mut lines: Vec<String> = vec![];
let lens = counters
.iter()
.map(|c| c.lengths())
.map(|w| (w.0.max(4), w.1.max(5), w.2.max(4), w.3.max(4)))
.reduce(|m, n| (n.0.max(m.0), n.1.max(m.1), n.2.max(m.2), n.3.max(m.3)))
.unwrap();

// make title and content lines
lines.push(op::title(&Self::make_title(with_size, lens)));
lines.push(Self::make_head_line(with_size, max_lens));
for cnt in counters {
lines.push(cnt.join_fields(lens));
lines.push(cnt.to_string(max_lens));
}

// output the total only when there is more than one counters
if counters.len() > 1 {
let total_line = Self::make_total_line(total, with_size, max_lens);
lines.push(total_line);
}

// output
Expand Down

0 comments on commit c192da0

Please sign in to comment.