use colored::Colorize;
use comfy_table::{Cell, Table};
use humansize::{DECIMAL, format_size};
use rayon::prelude::*;
use std::fs;
use std::path::Path;
const MAX_FILENAME_LENGTH: usize = 25;
#[derive(Clone, Debug, PartialEq)]
pub struct Sizes {
pub name: String,
pub size: u64,
pub is_dir: bool,
}
pub fn calculate_dir_size(dir_path: &Path) -> u64 {
fs::read_dir(dir_path)
.map(|entries| {
entries
.filter_map(Result::ok)
.par_bridge()
.map(|entry| {
let file_type = match entry.file_type() {
Ok(ft) => ft,
Err(_) => return 0,
};
if file_type.is_symlink() {
return 0;
}
if file_type.is_dir() {
calculate_dir_size(&entry.path())
} else {
entry.metadata().map(|m| m.len()).unwrap_or(0)
}
})
.sum()
})
.unwrap_or(0)
}
pub fn sort_by_size(sizes: &mut [Sizes]) {
sizes.sort_by(|a, b| b.size.cmp(&a.size));
}
pub fn sort_by_name(sizes: &mut [Sizes]) {
sizes.sort_by(|a, b| a.name.cmp(&b.name));
}
pub fn truncate_filename(path: &Path) -> String {
let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("");
let extension = path.extension().and_then(|e| e.to_str()).unwrap_or("");
let truncated_stem = if stem.len() > MAX_FILENAME_LENGTH {
format!("{}...", &stem[..MAX_FILENAME_LENGTH])
} else {
stem.to_string()
};
if !extension.is_empty() {
format!("{}.{}", truncated_stem, extension)
} else {
truncated_stem
}
}
pub fn add_row(table: &mut Table, values: &[Sizes]) {
for s in values {
let sz = format_size(s.size, DECIMAL);
let (name_cell, size_cell) = if s.is_dir {
(
Cell::new(format!("{}/", s.name.blue())),
Cell::new(sz.blue().to_string()),
)
} else {
(
Cell::new(format!("{}*", s.name.green())),
Cell::new(sz.green().to_string()),
)
};
table.add_row(vec![name_cell, size_cell]);
}
}