Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 47 additions & 31 deletions src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use std::iter::repeat_n;
use std::path::Path;
use thousands::Separable;

pub static UNITS: [char; 5] = ['P', 'T', 'G', 'M', 'K'];
pub static SI_UNITS: [&str; 5] = ["P", "T", "G", "M", "K"];
pub static IEC_UNITS: [&str; 5] = ["Pi", "Ti", "Gi", "Mi", "Ki"];
static BLOCKS: [char; 5] = ['█', '▓', '▒', '░', ' '];
const FILETIME_SHOW_LENGTH: usize = 19;

Expand Down Expand Up @@ -412,6 +413,14 @@ fn get_pretty_name(
}
}

pub fn get_units(output_str: &str) -> &'static [&'static str; 5] {
if get_type_of_thousand(output_str) == 1024 {
&IEC_UNITS
} else {
&SI_UNITS
}
}

// If we are working with SI units or not
pub fn get_type_of_thousand(output_str: &str) -> u64 {
if output_str.is_empty() {
Expand All @@ -425,14 +434,16 @@ pub fn get_type_of_thousand(output_str: &str) -> u64 {
}
}

pub fn get_number_format(output_str: &str) -> Option<(u64, char)> {
pub fn get_number_format(output_str: &str) -> Option<(u64, &'static str)> {
if output_str.starts_with('b') {
return Some((1, 'B'));
}
for (i, u) in UNITS.iter().enumerate() {
if output_str.starts_with((*u).to_ascii_lowercase()) {
let marker = get_type_of_thousand(output_str).pow((UNITS.len() - i) as u32);
return Some((marker, *u));
return Some((1, "B"));
}
let units = get_units(output_str);
for (i, u) in units.iter().enumerate() {
if output_str.starts_with(u.chars().next().unwrap().to_ascii_lowercase()) {
let thousand = get_type_of_thousand(output_str);
let marker = thousand.pow((units.len() - i) as u32);
return Some((marker, u));
}
}
None
Expand All @@ -447,8 +458,10 @@ pub fn human_readable_number(size: u64, output_str: &str) -> String {
format!("{}{}", (size / x), u)
}
None => {
for (i, u) in UNITS.iter().enumerate() {
let marker = get_type_of_thousand(output_str).pow((UNITS.len() - i) as u32);
let units = get_units(output_str);
let thousand = get_type_of_thousand(output_str);
for (i, u) in units.iter().enumerate() {
let marker = thousand.pow((units.len() - i) as u32);
if size >= marker {
if size / marker < 10 {
return format!("{:.1}{}", (size as f32 / marker as f32), u);
Expand Down Expand Up @@ -502,7 +515,7 @@ mod tests {
let data = get_fake_display_data(20);

let s = format_string(&n, indent, percent_bar, is_biggest, &data);
assert_eq!(s, " 4.0K ┌─┴ short");
assert_eq!(s, "4.0Ki ┌─┴ short");
}

#[test]
Expand All @@ -521,7 +534,7 @@ mod tests {
let s = format_string(&n, indent, percent_bar, is_biggest, &data);
assert_eq!(
s,
" 4.0K ┌─┴ very_long_name_longer_than_the_eighty_character_limit_very_.."
"4.0Ki ┌─┴ very_long_name_longer_than_the_eighty_character_limit_very_.."
);
}

Expand All @@ -539,7 +552,7 @@ mod tests {
data.initial.is_screen_reader = true;

let s = format_string(&n, indent, percent_bar, is_biggest, &data);
assert_eq!(s, "short 3 4.0K 100%");
assert_eq!(s, "short 3 4.0Ki 100%");
}

#[test]
Expand All @@ -554,26 +567,29 @@ mod tests {
assert_eq!(human_readable_number(1, ""), "1B");
assert_eq!(human_readable_number(956, ""), "956B");
assert_eq!(human_readable_number(1004, ""), "1004B");
assert_eq!(human_readable_number(1024, ""), "1.0K");
assert_eq!(human_readable_number(1536, ""), "1.5K");
assert_eq!(human_readable_number(1024 * 512, ""), "512K");
assert_eq!(human_readable_number(1024 * 1024, ""), "1.0M");
assert_eq!(human_readable_number(1024 * 1024 * 1024 - 1, ""), "1023M");
assert_eq!(human_readable_number(1024 * 1024 * 1024 * 20, ""), "20G");
assert_eq!(human_readable_number(1024 * 1024 * 1024 * 1024, ""), "1.0T");
assert_eq!(human_readable_number(1024, ""), "1.0Ki");
assert_eq!(human_readable_number(1536, ""), "1.5Ki");
assert_eq!(human_readable_number(1024 * 512, ""), "512Ki");
assert_eq!(human_readable_number(1024 * 1024, ""), "1.0Mi");
assert_eq!(human_readable_number(1024 * 1024 * 1024 - 1, ""), "1023Mi");
assert_eq!(human_readable_number(1024 * 1024 * 1024 * 20, ""), "20Gi");
assert_eq!(
human_readable_number(1024 * 1024 * 1024 * 1024, ""),
"1.0Ti"
);
assert_eq!(
human_readable_number(1024 * 1024 * 1024 * 1024 * 234, ""),
"234T"
"234Ti"
);
assert_eq!(
human_readable_number(1024 * 1024 * 1024 * 1024 * 1024, ""),
"1.0P"
"1.0Pi"
);
}

#[test]
fn test_human_readable_number_si() {
assert_eq!(human_readable_number(1024 * 100, ""), "100K");
assert_eq!(human_readable_number(1024 * 100, ""), "100Ki");
assert_eq!(human_readable_number(1024 * 100, "si"), "102K");
}

Expand All @@ -584,14 +600,14 @@ mod tests {
assert_eq!(hrn(1023, "b"), "1023B");
assert_eq!(hrn(1000 * 1000, "bytes"), "1000000B");
assert_eq!(hrn(1023, "kb"), "1K");
assert_eq!(hrn(1023, "k"), "0K");
assert_eq!(hrn(1023, "kib"), "0K");
assert_eq!(hrn(1024, "kib"), "1K");
assert_eq!(hrn(1024 * 512, "kib"), "512K");
assert_eq!(hrn(1024 * 1024, "kib"), "1024K");
assert_eq!(hrn(1024 * 1000 * 1000 * 20, "kib"), "20000000K");
assert_eq!(hrn(1024 * 1024 * 1000 * 20, "mib"), "20000M");
assert_eq!(hrn(1024 * 1024 * 1024 * 20, "gib"), "20G");
assert_eq!(hrn(1023, "k"), "0Ki");
assert_eq!(hrn(1023, "kib"), "0Ki");
assert_eq!(hrn(1024, "kib"), "1Ki");
assert_eq!(hrn(1024 * 512, "kib"), "512Ki");
assert_eq!(hrn(1024 * 1024, "kib"), "1024Ki");
assert_eq!(hrn(1024 * 1000 * 1000 * 20, "kib"), "20000000Ki");
assert_eq!(hrn(1024 * 1024 * 1000 * 20, "mib"), "20000Mi");
assert_eq!(hrn(1024 * 1024 * 1024 * 20, "gib"), "20Gi");
}

#[cfg(test)]
Expand Down
80 changes: 40 additions & 40 deletions tests/test_exact_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,19 @@ fn main_output() -> Vec<String> {
// Some linux currently thought to be Manjaro, Arch
// Although probably depends on how drive is formatted
let mac_and_some_linux = r#"
0B ┌── a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0K ├── hello_file│████████████████████████████████████████████████ │ 100%
4.0K ┌─┴ many │████████████████████████████████████████████████ │ 100%
4.0K ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
0B ┌── a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0Ki ├── hello_file│████████████████████████████████████████████████ │ 100%
4.0Ki ┌─┴ many │████████████████████████████████████████████████ │ 100%
4.0Ki ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
"#
.trim()
.to_string();

let ubuntu = r#"
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0K ├── hello_file│ ░░░░░░░░░░░░░░░░█████████████████ │ 33%
8.0K ┌─┴ many │ █████████████████████████████████ │ 67%
12K ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0Ki ├── hello_file│ ░░░░░░░░░░░░░░░░█████████████████ │ 33%
8.0Ki ┌─┴ many │ █████████████████████████████████ │ 67%
12Ki ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
"#
.trim()
.to_string();
Expand All @@ -146,18 +146,18 @@ pub fn test_main_long_paths() {

fn main_output_long_paths() -> Vec<String> {
let mac_and_some_linux = r#"
0B ┌── /tmp/test_dir/many/a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0K ├── /tmp/test_dir/many/hello_file│██████████████████████████████ │ 100%
4.0K ┌─┴ /tmp/test_dir/many │██████████████████████████████ │ 100%
4.0K ┌─┴ /tmp/test_dir │██████████████████████████████ │ 100%
0B ┌── /tmp/test_dir/many/a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0Ki ├── /tmp/test_dir/many/hello_file│████████████████████████████ │ 100%
4.0Ki ┌─┴ /tmp/test_dir/many │████████████████████████████ │ 100%
4.0Ki ┌─┴ /tmp/test_dir │████████████████████████████ │ 100%
"#
.trim()
.to_string();
let ubuntu = r#"
0B ┌── /tmp/test_dir/many/a_file │ ░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0K ├── /tmp/test_dir/many/hello_file│ ░░░░░░░░░░██████████ │ 33%
8.0K ┌─┴ /tmp/test_dir/many │ ████████████████████ │ 67%
12K ┌─┴ /tmp/test_dir │█████████████████████████████ │ 100%
0B ┌── /tmp/test_dir/many/a_file │ ░░░░░░░░░░░░░░░░░░░█ │ 0%
4.0Ki ├── /tmp/test_dir/many/hello_file│ ░░░░░░░░░░██████████ │ 33%
8.0Ki ┌─┴ /tmp/test_dir/many │ ████████████████████ │ 67%
12Ki ┌─┴ /tmp/test_dir │█████████████████████████████ │ 100%
"#
.trim()
.to_string();
Expand All @@ -174,25 +174,25 @@ pub fn test_substring_of_names_and_long_names() {

fn no_substring_of_names_output() -> Vec<String> {
let ubuntu = "
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_goes..
4.0K ├── dir_name_clash
4.0K │ ┌── hello
8.0K ├─┴ dir
4.0K │ ┌── hello
8.0K ├─┴ dir_substring
24K ┌─┴ test_dir2
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_goe..
4.0Ki ├── dir_name_clash
4.0Ki │ ┌── hello
8.0Ki ├─┴ dir
4.0Ki │ ┌── hello
8.0Ki ├─┴ dir_substring
24Ki ┌─┴ test_dir2
"
.trim()
.into();

let mac_and_some_linux = "
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_goes..
4.0K │ ┌── hello
4.0K ├─┴ dir
4.0K ├── dir_name_clash
4.0K │ ┌── hello
4.0K ├─┴ dir_substring
12K ┌─┴ test_dir2
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_goe..
4.0Ki │ ┌── hello
4.0Ki ├─┴ dir
4.0Ki ├── dir_name_clash
4.0Ki │ ┌── hello
4.0Ki ├─┴ dir_substring
12Ki ┌─┴ test_dir2
"
.trim()
.into();
Expand All @@ -209,9 +209,9 @@ pub fn test_unicode_directories() {
fn unicode_dir() -> Vec<String> {
// The way unicode & asian characters are rendered on the terminal should make this line up
let ubuntu = "
0B ┌── ラウトは難しいです!.japan│ █ │ 0%
0B ├── 👩.unicode │ █ │ 0%
4.0K ┌─┴ test_dir_unicode │██████████████████████████████████ │ 100%
0B ┌── ラウトは難しいです!.japan│ █ │ 0%
0B ├── 👩.unicode │ █ │ 0%
4.0Ki ┌─┴ test_dir_unicode │██████████████████████████████████ │ 100%
"
.trim()
.into();
Expand All @@ -235,21 +235,21 @@ pub fn test_apparent_size() {

fn apparent_size_output() -> Vec<String> {
// The apparent directory sizes are too unpredictable and system dependent to try and match
let one_space_before = r#"
0B ┌── a_file
6B ├── hello_file
let two_space_before = r#"
0B ┌── a_file
6B ├── hello_file
"#
.trim()
.to_string();

let two_space_before = r#"
0B ┌── a_file
6B ├── hello_file
let three_space_before = r#"
0B ┌── a_file
6B ├── hello_file
"#
.trim()
.to_string();

vec![one_space_before, two_space_before]
vec![two_space_before, three_space_before]
}

#[cfg_attr(target_os = "windows", ignore)]
Expand Down