diff --git a/README.md b/README.md index 7a4b0ae8..987afbac 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Usage: dust -d 3 (Shows 3 levels of subdirectories) Usage: dust -D (Show only directories (eg dust -D)) Usage: dust -F (Show only files - finds your largest files) Usage: dust -r (reverse order of output) -Usage: dust -H (si print sizes in powers of 1000 instead of 1024) +Usage: dust -o si/b/kb/kib/mb/mib/gb/gib (si - prints sizes in powers of 1000. Others print size in that format). Usage: dust -X ignore (ignore all files and directories with the name 'ignore') Usage: dust -x (Only show directories on the same filesystem) Usage: dust -b (Do not show percentages or draw ASCII bars) @@ -85,7 +85,7 @@ Usage: dust -P (Disable the progress indicator) Usage: dust -R (For screen readers. Removes bars/symbols. Adds new column: depth level. (May want to use -p for full path too)) Usage: dust -S (Custom Stack size - Use if you see: 'fatal runtime error: stack overflow' (default allocation: low memory=1048576, high memory=1073741824)"), Usage: dust --skip-total (No total row will be displayed) -Usage: dust -z 4000000 (Exclude output files/directories below size 4MB) +Usage: dust -z 40000/30MB/20kib (Exclude output files/directories below size 40000 bytes / 30MB / 20KiB) ``` ## Config file diff --git a/completions/_dust b/completions/_dust index ec51dd1e..4b850d74 100644 --- a/completions/_dust +++ b/completions/_dust @@ -31,6 +31,8 @@ _dust() { '(-t --file_types)*--filter=[Only include filepaths matching this regex. For png files type\: -e "\\.png\$" ]: : ' \ '-w+[Specify width of output overriding the auto detection of terminal width]: : ' \ '--terminal_width=[Specify width of output overriding the auto detection of terminal width]: : ' \ +'-o+[Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size]: : ' \ +'--output-format=[Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size]: : ' \ '-S+[Specify memory to use as stack size - use if you see\: '\''fatal runtime error\: stack overflow'\'' (default low memory=1048576, high memory=1073741824)]: : ' \ '--stack-size=[Specify memory to use as stack size - use if you see\: '\''fatal runtime error\: stack overflow'\'' (default low memory=1048576, high memory=1073741824)]: : ' \ '-p[Subdirectories will not have their path shortened]' \ @@ -58,8 +60,6 @@ _dust() { '--ignore_hidden[Do not display hidden files]' \ '(-d --depth -D --only-dir)-t[show only these file types]' \ '(-d --depth -D --only-dir)--file_types[show only these file types]' \ -'-H[print sizes in powers of 1000 (e.g., 1.1G)]' \ -'--si[print sizes in powers of 1000 (e.g., 1.1G)]' \ '-P[Disable the progress indication.]' \ '--no-progress[Disable the progress indication.]' \ '(-F --only-file -t --file_types)-D[Only directories will be displayed.]' \ diff --git a/completions/_dust.ps1 b/completions/_dust.ps1 index f59c04e9..ddfb26f6 100644 --- a/completions/_dust.ps1 +++ b/completions/_dust.ps1 @@ -37,6 +37,8 @@ Register-ArgumentCompleter -Native -CommandName 'dust' -ScriptBlock { [CompletionResult]::new('--filter', 'filter', [CompletionResultType]::ParameterName, 'Only include filepaths matching this regex. For png files type: -e "\.png$" ') [CompletionResult]::new('-w', 'w', [CompletionResultType]::ParameterName, 'Specify width of output overriding the auto detection of terminal width') [CompletionResult]::new('--terminal_width', 'terminal_width', [CompletionResultType]::ParameterName, 'Specify width of output overriding the auto detection of terminal width') + [CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size') + [CompletionResult]::new('--output-format', 'output-format', [CompletionResultType]::ParameterName, 'Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size') [CompletionResult]::new('-S', 'S ', [CompletionResultType]::ParameterName, 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)') [CompletionResult]::new('--stack-size', 'stack-size', [CompletionResultType]::ParameterName, 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)') [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Subdirectories will not have their path shortened') @@ -64,8 +66,6 @@ Register-ArgumentCompleter -Native -CommandName 'dust' -ScriptBlock { [CompletionResult]::new('--ignore_hidden', 'ignore_hidden', [CompletionResultType]::ParameterName, 'Do not display hidden files') [CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'show only these file types') [CompletionResult]::new('--file_types', 'file_types', [CompletionResultType]::ParameterName, 'show only these file types') - [CompletionResult]::new('-H', 'H ', [CompletionResultType]::ParameterName, 'print sizes in powers of 1000 (e.g., 1.1G)') - [CompletionResult]::new('--si', 'si', [CompletionResultType]::ParameterName, 'print sizes in powers of 1000 (e.g., 1.1G)') [CompletionResult]::new('-P', 'P ', [CompletionResultType]::ParameterName, 'Disable the progress indication.') [CompletionResult]::new('--no-progress', 'no-progress', [CompletionResultType]::ParameterName, 'Disable the progress indication.') [CompletionResult]::new('-D', 'D ', [CompletionResultType]::ParameterName, 'Only directories will be displayed.') diff --git a/completions/dust.bash b/completions/dust.bash index eddf14f7..24c37e0c 100644 --- a/completions/dust.bash +++ b/completions/dust.bash @@ -19,7 +19,7 @@ _dust() { case "${cmd}" in dust) - opts="-d -n -p -X -I -L -x -s -r -c -b -B -z -R -f -i -v -e -t -w -H -P -D -F -S -h -V --depth --number-of-lines --full-paths --ignore-directory --ignore-all-in-file --dereference-links --limit-filesystem --apparent-size --reverse --no-colors --no-percent-bars --bars-on-right --min-size --screen-reader --skip-total --filecount --ignore_hidden --invert-filter --filter --file_types --terminal_width --si --no-progress --only-dir --only-file --stack-size --help --version [params]..." + opts="-d -n -p -X -I -L -x -s -r -c -b -B -z -R -f -i -v -e -t -w -P -D -F -o -S -h -V --depth --number-of-lines --full-paths --ignore-directory --ignore-all-in-file --dereference-links --limit-filesystem --apparent-size --reverse --no-colors --no-percent-bars --bars-on-right --min-size --screen-reader --skip-total --filecount --ignore_hidden --invert-filter --filter --file_types --terminal_width --no-progress --only-dir --only-file --output-format --stack-size --help --version [params]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -89,6 +89,14 @@ _dust() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --output-format) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --stack-size) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/completions/dust.elv b/completions/dust.elv index f5faf473..a001ccb3 100644 --- a/completions/dust.elv +++ b/completions/dust.elv @@ -34,6 +34,8 @@ set edit:completion:arg-completer[dust] = {|@words| cand --filter 'Only include filepaths matching this regex. For png files type: -e "\.png$" ' cand -w 'Specify width of output overriding the auto detection of terminal width' cand --terminal_width 'Specify width of output overriding the auto detection of terminal width' + cand -o 'Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size' + cand --output-format 'Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size' cand -S 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)' cand --stack-size 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)' cand -p 'Subdirectories will not have their path shortened' @@ -61,8 +63,6 @@ set edit:completion:arg-completer[dust] = {|@words| cand --ignore_hidden 'Do not display hidden files' cand -t 'show only these file types' cand --file_types 'show only these file types' - cand -H 'print sizes in powers of 1000 (e.g., 1.1G)' - cand --si 'print sizes in powers of 1000 (e.g., 1.1G)' cand -P 'Disable the progress indication.' cand --no-progress 'Disable the progress indication.' cand -D 'Only directories will be displayed.' diff --git a/completions/dust.fish b/completions/dust.fish index c36e86e1..5dbd22d6 100644 --- a/completions/dust.fish +++ b/completions/dust.fish @@ -6,6 +6,7 @@ complete -c dust -s z -l min-size -d 'Minimum size file to include in output' -r complete -c dust -s v -l invert-filter -d 'Exclude filepaths matching this regex. To ignore png files type: -v "\\.png$" ' -r complete -c dust -s e -l filter -d 'Only include filepaths matching this regex. For png files type: -e "\\.png$" ' -r complete -c dust -s w -l terminal_width -d 'Specify width of output overriding the auto detection of terminal width' -r +complete -c dust -s o -l output-format -d 'Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size' -r complete -c dust -s S -l stack-size -d 'Specify memory to use as stack size - use if you see: \'fatal runtime error: stack overflow\' (default low memory=1048576, high memory=1073741824)' -r complete -c dust -s p -l full-paths -d 'Subdirectories will not have their path shortened' complete -c dust -s L -l dereference-links -d 'dereference sym links - Treat sym links as directories and go into them' @@ -20,7 +21,6 @@ complete -c dust -l skip-total -d 'No total row will be displayed' complete -c dust -s f -l filecount -d 'Directory \'size\' is number of child files instead of disk size' complete -c dust -s i -l ignore_hidden -d 'Do not display hidden files' complete -c dust -s t -l file_types -d 'show only these file types' -complete -c dust -s H -l si -d 'print sizes in powers of 1000 (e.g., 1.1G)' complete -c dust -s P -l no-progress -d 'Disable the progress indication.' complete -c dust -s D -l only-dir -d 'Only directories will be displayed.' complete -c dust -s F -l only-file -d 'Only files will be displayed. (Finds your largest files)' diff --git a/man-page/dust.1 b/man-page/dust.1 index 7977f875..e0320294 100644 --- a/man-page/dust.1 +++ b/man-page/dust.1 @@ -4,7 +4,7 @@ .SH NAME Dust \- Like du but more intuitive .SH SYNOPSIS -\fBdust\fR [\fB\-d\fR|\fB\-\-depth\fR] [\fB\-n\fR|\fB\-\-number\-of\-lines\fR] [\fB\-p\fR|\fB\-\-full\-paths\fR] [\fB\-X\fR|\fB\-\-ignore\-directory\fR] [\fB\-I\fR|\fB\-\-ignore\-all\-in\-file\fR] [\fB\-L\fR|\fB\-\-dereference\-links\fR] [\fB\-x\fR|\fB\-\-limit\-filesystem\fR] [\fB\-s\fR|\fB\-\-apparent\-size\fR] [\fB\-r\fR|\fB\-\-reverse\fR] [\fB\-c\fR|\fB\-\-no\-colors\fR] [\fB\-b\fR|\fB\-\-no\-percent\-bars\fR] [\fB\-B\fR|\fB\-\-bars\-on\-right\fR] [\fB\-z\fR|\fB\-\-min\-size\fR] [\fB\-R\fR|\fB\-\-screen\-reader\fR] [\fB\-\-skip\-total\fR] [\fB\-f\fR|\fB\-\-filecount\fR] [\fB\-i\fR|\fB\-\-ignore_hidden\fR] [\fB\-v\fR|\fB\-\-invert\-filter\fR] [\fB\-e\fR|\fB\-\-filter\fR] [\fB\-t\fR|\fB\-\-file_types\fR] [\fB\-w\fR|\fB\-\-terminal_width\fR] [\fB\-H\fR|\fB\-\-si\fR] [\fB\-P\fR|\fB\-\-no\-progress\fR] [\fB\-D\fR|\fB\-\-only\-dir\fR] [\fB\-F\fR|\fB\-\-only\-file\fR] [\fB\-S\fR|\fB\-\-stack\-size\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIparams\fR] +\fBdust\fR [\fB\-d\fR|\fB\-\-depth\fR] [\fB\-n\fR|\fB\-\-number\-of\-lines\fR] [\fB\-p\fR|\fB\-\-full\-paths\fR] [\fB\-X\fR|\fB\-\-ignore\-directory\fR] [\fB\-I\fR|\fB\-\-ignore\-all\-in\-file\fR] [\fB\-L\fR|\fB\-\-dereference\-links\fR] [\fB\-x\fR|\fB\-\-limit\-filesystem\fR] [\fB\-s\fR|\fB\-\-apparent\-size\fR] [\fB\-r\fR|\fB\-\-reverse\fR] [\fB\-c\fR|\fB\-\-no\-colors\fR] [\fB\-b\fR|\fB\-\-no\-percent\-bars\fR] [\fB\-B\fR|\fB\-\-bars\-on\-right\fR] [\fB\-z\fR|\fB\-\-min\-size\fR] [\fB\-R\fR|\fB\-\-screen\-reader\fR] [\fB\-\-skip\-total\fR] [\fB\-f\fR|\fB\-\-filecount\fR] [\fB\-i\fR|\fB\-\-ignore_hidden\fR] [\fB\-v\fR|\fB\-\-invert\-filter\fR] [\fB\-e\fR|\fB\-\-filter\fR] [\fB\-t\fR|\fB\-\-file_types\fR] [\fB\-w\fR|\fB\-\-terminal_width\fR] [\fB\-P\fR|\fB\-\-no\-progress\fR] [\fB\-D\fR|\fB\-\-only\-dir\fR] [\fB\-F\fR|\fB\-\-only\-file\fR] [\fB\-o\fR|\fB\-\-output\-format\fR] [\fB\-S\fR|\fB\-\-stack\-size\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIparams\fR] .SH DESCRIPTION Like du but more intuitive .SH OPTIONS @@ -72,9 +72,6 @@ show only these file types \fB\-w\fR, \fB\-\-terminal_width\fR Specify width of output overriding the auto detection of terminal width .TP -\fB\-H\fR, \fB\-\-si\fR -print sizes in powers of 1000 (e.g., 1.1G) -.TP \fB\-P\fR, \fB\-\-no\-progress\fR Disable the progress indication. .TP @@ -84,6 +81,9 @@ Only directories will be displayed. \fB\-F\fR, \fB\-\-only\-file\fR Only files will be displayed. (Finds your largest files) .TP +\fB\-o\fR, \fB\-\-output\-format\fR +Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size +.TP \fB\-S\fR, \fB\-\-stack\-size\fR Specify memory to use as stack size \- use if you see: \*(Aqfatal runtime error: stack overflow\*(Aq (default low memory=1048576, high memory=1073741824) .TP diff --git a/src/cli.rs b/src/cli.rs index 468f93c2..67a88f7f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -162,13 +162,6 @@ pub fn build_cli() -> Command { .value_parser(value_parser!(usize)) .help("Specify width of output overriding the auto detection of terminal width"), ) - .arg( - Arg::new("iso") - .short('H') - .long("si") - .action(clap::ArgAction::SetTrue) - .help("print sizes in powers of 1000 (e.g., 1.1G)") - ) .arg( Arg::new("disable_progress") .short('P') @@ -193,6 +186,13 @@ pub fn build_cli() -> Command { .action(clap::ArgAction::SetTrue) .help("Only files will be displayed. (Finds your largest files)"), ) + .arg( + Arg::new("output_format") + .short('o') + .long("output-format") + .value_parser(value_parser!(String)) + .help("Changes output display size. si will print sizes in powers of 1000. b/bytes kb kib mb mib gb gib will print the whole tree in that size") + ) .arg( Arg::new("stack_size") .short('S') diff --git a/src/config.rs b/src/config.rs index d74528ab..1346fffd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,11 +1,12 @@ use clap::ArgMatches; use config_file::FromConfigFile; +use regex::Regex; use serde::Deserialize; use std::io::IsTerminal; use std::path::Path; use std::path::PathBuf; -use crate::display::UNITS; +use crate::display::get_number_format; #[derive(Deserialize, Default)] #[serde(rename_all = "kebab-case")] @@ -19,7 +20,7 @@ pub struct Config { pub skip_total: Option, pub screen_reader: Option, pub ignore_hidden: Option, - pub iso: Option, + pub output_format: Option, pub min_size: Option, pub only_dir: Option, pub only_file: Option, @@ -56,8 +57,16 @@ impl Config { pub fn get_no_bars(&self, options: &ArgMatches) -> bool { Some(true) == self.no_bars || options.get_flag("no_bars") } - pub fn get_iso(&self, options: &ArgMatches) -> bool { - Some(true) == self.iso || options.get_flag("iso") + pub fn get_output_format(&self, options: &ArgMatches) -> String { + let out_fmt = options.get_one::("output_format"); + (match out_fmt { + None => match &self.output_format { + None => "".to_string(), + Some(x) => x.to_string(), + }, + Some(x) => x.into(), + }) + .to_lowercase() } pub fn get_skip_total(&self, options: &ArgMatches) -> bool { Some(true) == self.skip_total || options.get_flag("skip_total") @@ -72,17 +81,17 @@ impl Config { self.depth.unwrap_or(usize::MAX) } - pub fn get_min_size(&self, options: &ArgMatches, iso: bool) -> Option { + pub fn get_min_size(&self, options: &ArgMatches) -> Option { let size_from_param = options.get_one::("min_size"); - self._get_min_size(size_from_param, iso) + self._get_min_size(size_from_param) } - fn _get_min_size(&self, min_size: Option<&String>, iso: bool) -> Option { - let size_from_param = min_size.and_then(|a| convert_min_size(a, iso)); + fn _get_min_size(&self, min_size: Option<&String>) -> Option { + let size_from_param = min_size.and_then(|a| convert_min_size(a)); if size_from_param.is_none() { self.min_size .as_ref() - .and_then(|a| convert_min_size(a.as_ref(), iso)) + .and_then(|a| convert_min_size(a.as_ref())) } else { size_from_param } @@ -106,36 +115,34 @@ impl Config { } } -fn convert_min_size(input: &str, iso: bool) -> Option { - let chars_as_vec: Vec = input.chars().collect(); - match chars_as_vec.split_last() { - Some((last, start)) => { - let mut starts: String = start.iter().collect::(); - - for (i, u) in UNITS.iter().rev().enumerate() { - if Some(*u) == last.to_uppercase().next() { - return match starts.parse::() { - Ok(pure) => { - let num: usize = if iso { 1000 } else { 1024 }; - let marker = pure * num.pow((i + 1) as u32); - Some(marker) - } - Err(_) => { +fn convert_min_size(input: &str) -> Option { + let re = Regex::new(r"([0-9]+)(\w*)").unwrap(); + + if let Some(cap) = re.captures(input) { + let (_, [digits, letters]) = cap.extract(); + + // Failure to parse should be impossible due to regex match + let digits_as_usize: Option = digits.parse().ok(); + + match digits_as_usize { + Some(parsed_digits) => { + let number_format = get_number_format(&letters.to_lowercase()); + match number_format { + Some((multiple, _)) => Some(parsed_digits * (multiple as usize)), + None => { + if letters.eq("") { + Some(parsed_digits) + } else { eprintln!("Ignoring invalid min-size: {input}"); None } - }; + } } } - starts.push(*last); - starts - .parse() - .map_err(|_| { - eprintln!("Ignoring invalid min-size: {input}"); - }) - .ok() + None => None, } - None => None, + } else { + None } } @@ -169,13 +176,13 @@ mod tests { #[test] fn test_conversion() { - assert_eq!(convert_min_size("55", false), Some(55)); - assert_eq!(convert_min_size("12344321", false), Some(12344321)); - assert_eq!(convert_min_size("95RUBBISH", false), None); - assert_eq!(convert_min_size("10K", false), Some(10 * 1024)); - assert_eq!(convert_min_size("10M", false), Some(10 * 1024usize.pow(2))); - assert_eq!(convert_min_size("10M", true), Some(10 * 1000usize.pow(2))); - assert_eq!(convert_min_size("2G", false), Some(2 * 1024usize.pow(3))); + assert_eq!(convert_min_size("55"), Some(55)); + assert_eq!(convert_min_size("12344321"), Some(12344321)); + assert_eq!(convert_min_size("95RUBBISH"), None); + assert_eq!(convert_min_size("10K"), Some(10 * 1024)); + assert_eq!(convert_min_size("10M"), Some(10 * 1024usize.pow(2))); + assert_eq!(convert_min_size("10MiB"), Some(10 * 1000usize.pow(2))); + assert_eq!(convert_min_size("2G"), Some(2 * 1024usize.pow(3))); } #[test] @@ -184,11 +191,11 @@ mod tests { min_size: Some("1K".to_owned()), ..Default::default() }; - assert_eq!(c._get_min_size(None, false), Some(1024)); - assert_eq!(c._get_min_size(Some(&"2K".into()), false), Some(2048)); + assert_eq!(c._get_min_size(None), Some(1024)); + assert_eq!(c._get_min_size(Some(&"2K".into())), Some(2048)); - assert_eq!(c._get_min_size(None, true), Some(1000)); - assert_eq!(c._get_min_size(Some(&"2K".into()), true), Some(2000)); + assert_eq!(c._get_min_size(Some(&"1kib".into())), Some(1000)); + assert_eq!(c._get_min_size(Some(&"2KiB".into())), Some(2000)); } #[test] diff --git a/src/display.rs b/src/display.rs index 0516f2fd..de828c69 100644 --- a/src/display.rs +++ b/src/display.rs @@ -23,7 +23,7 @@ pub struct InitialDisplayData { pub colors_on: bool, pub by_filecount: bool, pub is_screen_reader: bool, - pub iso: bool, + pub output_format: String, pub bars_on_right: bool, } @@ -142,7 +142,7 @@ pub fn draw_it( let max_size = biggest.size; max_size.separate_with_commas().chars().count() } else { - find_biggest_size_str(root_node, idd.iso) + find_biggest_size_str(root_node, &idd.output_format) }; assert!( @@ -190,10 +190,12 @@ pub fn draw_it( } } -fn find_biggest_size_str(node: &DisplayNode, iso: bool) -> usize { - let mut mx = human_readable_number(node.size, iso).chars().count(); +fn find_biggest_size_str(node: &DisplayNode, output_format: &str) -> usize { + let mut mx = human_readable_number(node.size, output_format) + .chars() + .count(); for n in node.children.iter() { - mx = max(mx, find_biggest_size_str(n, iso)); + mx = max(mx, find_biggest_size_str(n, output_format)); } mx } @@ -375,7 +377,7 @@ fn get_pretty_size(node: &DisplayNode, is_biggest: bool, display_data: &DisplayD let output = if display_data.initial.by_filecount { node.size.separate_with_commas() } else { - human_readable_number(node.size, display_data.initial.iso) + human_readable_number(node.size, &display_data.initial.output_format) }; let spaces_to_add = display_data.num_chars_needed_on_left_most - output.chars().count(); let output = " ".repeat(spaces_to_add) + output.as_str(); @@ -407,19 +409,48 @@ fn get_pretty_name( } } -pub fn human_readable_number(size: u64, iso: bool) -> String { +// If we are working with SI units or not +pub fn get_type_of_thousand(output_str: &str) -> u64 { + let is_si = output_str.contains('i'); // si, KiB, MiB, etc + if is_si { + 1000 + } else { + 1024 + } +} + +pub fn get_number_format(output_str: &str) -> Option<(u64, char)> { + if output_str.starts_with('b') { + return Some((1, 'B')); + } for (i, u) in UNITS.iter().enumerate() { - let num: u64 = if iso { 1000 } else { 1024 }; - let marker = num.pow((UNITS.len() - i) as u32); - if size >= marker { - if size / marker < 10 { - return format!("{:.1}{}", (size as f32 / marker as f32), u); - } else { - return format!("{}{}", (size / marker), u); + 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)); + } + } + None +} + +pub fn human_readable_number(size: u64, output_str: &str) -> String { + match get_number_format(output_str) { + Some((x, u)) => { + 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); + if size >= marker { + if size / marker < 10 { + return format!("{:.1}{}", (size as f32 / marker as f32), u); + } else { + return format!("{}{}", (size / marker), u); + } + } } + format!("{size}B") } } - format!("{size}B") } mod tests { @@ -436,7 +467,7 @@ mod tests { colors_on: false, by_filecount: false, is_screen_reader: false, - iso: false, + output_format: "".into(), bars_on_right: false, }; DisplayData { @@ -503,22 +534,37 @@ mod tests { #[test] fn test_human_readable_number() { - assert_eq!(human_readable_number(1, false), "1B"); - assert_eq!(human_readable_number(956, false), "956B"); - assert_eq!(human_readable_number(1004, false), "1004B"); - assert_eq!(human_readable_number(1024, false), "1.0K"); - assert_eq!(human_readable_number(1536, false), "1.5K"); - assert_eq!(human_readable_number(1024 * 512, false), "512K"); - assert_eq!(human_readable_number(1024 * 1024, false), "1.0M"); - assert_eq!( - human_readable_number(1024 * 1024 * 1024 - 1, false), - "1023M" - ); - assert_eq!(human_readable_number(1024 * 1024 * 1024 * 20, false), "20G"); - assert_eq!( - human_readable_number(1024 * 1024 * 1024 * 1024, false), - "1.0T" - ); + 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"); + } + + #[test] + fn test_human_readable_number_si() { + assert_eq!(human_readable_number(1024 * 100, ""), "100K"); + assert_eq!(human_readable_number(1024 * 100, "si"), "102K"); + } + + #[test] + fn test_human_readable_number_kb() { + let hrn = human_readable_number; + assert_eq!(hrn(1023, "b"), "1023B"); + assert_eq!(hrn(1000 * 1000, "bytes"), "1000000B"); + assert_eq!(hrn(1023, "kb"), "0K"); + assert_eq!(hrn(1023, "kib"), "1K"); + assert_eq!(hrn(1024, "kb"), "1K"); + assert_eq!(hrn(1024 * 512, "kb"), "512K"); + assert_eq!(hrn(1024 * 1024, "kb"), "1024K"); + assert_eq!(hrn(1024 * 1000 * 1000 * 20, "kb"), "20000000K"); + assert_eq!(hrn(1024 * 1024 * 1000 * 20, "mb"), "20000M"); + assert_eq!(hrn(1024 * 1024 * 1024 * 20, "gb"), "20G"); } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs index 0b81002d..31abb8d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -178,13 +178,13 @@ fn main() { .flat_map(|x| simplified_dirs.iter().map(move |d| d.join(&x))) .collect(); - let iso = config.get_iso(&options); + let output_format = config.get_output_format(&options); let ignore_hidden = config.get_ignore_hidden(&options); let mut indicator = PIndicator::build_me(); if !config.get_disable_progress(&options) { - indicator.spawn(iso); + indicator.spawn(output_format.clone()) } let walk_data = WalkData { @@ -208,7 +208,7 @@ fn main() { true => get_all_file_types(&top_level_nodes, number_of_lines), false => { let agg_data = AggregateData { - min_size: config.get_min_size(&options, iso), + min_size: config.get_min_size(&options), only_dir: config.get_only_dir(&options), only_file: config.get_only_file(&options), number_of_lines, @@ -252,8 +252,8 @@ fn main() { is_reversed: !config.get_reverse(&options), colors_on: !no_colors, by_filecount, - iso, is_screen_reader: config.get_screen_reader(&options), + output_format, bars_on_right: config.get_bars_on_right(&options), }; draw_it( diff --git a/src/progress.rs b/src/progress.rs index b4d7a89d..6d5b7bec 100644 --- a/src/progress.rs +++ b/src/progress.rs @@ -77,16 +77,16 @@ pub struct RuntimeErrors { /* -------------------------------------------------------------------------- */ -fn format_preparing_str(prog_char: char, data: &PAtomicInfo, is_iso: bool) -> String { +fn format_preparing_str(prog_char: char, data: &PAtomicInfo, output_display: &str) -> String { let path_in = data.current_path.get(); - let size = human_readable_number(data.total_file_size.load(ORDERING), is_iso); + let size = human_readable_number(data.total_file_size.load(ORDERING), output_display); format!("Preparing: {path_in} {size} ... {prog_char}") } -fn format_indexing_str(prog_char: char, data: &PAtomicInfo, is_iso: bool) -> String { +fn format_indexing_str(prog_char: char, data: &PAtomicInfo, output_display: &str) -> String { let path_in = data.current_path.get(); let file_count = data.num_files.load(ORDERING); - let size = human_readable_number(data.total_file_size.load(ORDERING), is_iso); + let size = human_readable_number(data.total_file_size.load(ORDERING), output_display); let file_str = format!("{file_count} files, {size}"); format!("Indexing: {path_in} {file_str} ... {prog_char}") } @@ -106,7 +106,7 @@ impl PIndicator { } } - pub fn spawn(&mut self, is_iso: bool) { + pub fn spawn(&mut self, output_display: String) { let data = self.data.clone(); let (stop_handler, receiver) = mpsc::channel::<()>(); @@ -125,8 +125,8 @@ impl PIndicator { let prog_char = PROGRESS_CHARS[progress_char_i]; msg = match data.state.load(ORDERING) { - Operation::INDEXING => format_indexing_str(prog_char, &data, is_iso), - Operation::PREPARING => format_preparing_str(prog_char, &data, is_iso), + Operation::INDEXING => format_indexing_str(prog_char, &data, &output_display), + Operation::PREPARING => format_preparing_str(prog_char, &data, &output_display), _ => panic!("Unknown State"), };