Filesize formatting (#456)

* configure the format of filesize

* type-o

* removed some comments

* updated tests

* accomodated filesize_metric better, added test
This commit is contained in:
Darren Schroeder 2021-12-09 13:19:36 -06:00 committed by GitHub
parent a8e5cb871e
commit 3dc19d4179
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 267 additions and 15 deletions

139
Cargo.lock generated
View File

@ -103,6 +103,15 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
dependencies = [
"nodrop",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.5.2" version = "0.5.2"
@ -269,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"arrayvec", "arrayvec 0.5.2",
"constant_time_eq", "constant_time_eq",
] ]
@ -306,6 +315,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bumpalo"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]] [[package]]
name = "byte-unit" name = "byte-unit"
version = "4.0.13" version = "4.0.13"
@ -548,6 +563,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "cstr_core"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "917ba9efe9e1e736671d5a03f006afc4e7e3f32503e2077e0bcaf519c0c8c1d3"
dependencies = [
"cty",
"memchr",
]
[[package]] [[package]]
name = "csv" name = "csv"
version = "1.1.6" version = "1.1.6"
@ -590,6 +615,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "cty"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]] [[package]]
name = "dialoguer" name = "dialoguer"
version = "0.9.0" version = "0.9.0"
@ -1137,6 +1168,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "js-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -1455,6 +1495,12 @@ dependencies = [
"memoffset", "memoffset",
] ]
[[package]]
name = "nodrop"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]] [[package]]
name = "nom" name = "nom"
version = "1.2.4" version = "1.2.4"
@ -1631,8 +1677,10 @@ dependencies = [
"indexmap", "indexmap",
"miette", "miette",
"nu-json", "nu-json",
"num-format",
"serde", "serde",
"serde_json", "serde_json",
"sys-locale",
"thiserror", "thiserror",
"typetag", "typetag",
] ]
@ -1754,6 +1802,16 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-format"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465"
dependencies = [
"arrayvec 0.4.12",
"itoa",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -2660,6 +2718,19 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "sys-locale"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91f89ebb59fa30d4f65fafc2d68e94f6975256fd87e812dd99cb6e020c8563df"
dependencies = [
"cc",
"cstr_core",
"libc",
"web-sys",
"winapi",
]
[[package]] [[package]]
name = "sysinfo" name = "sysinfo"
version = "0.20.5" version = "0.20.5"
@ -2967,7 +3038,7 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
dependencies = [ dependencies = [
"arrayvec", "arrayvec 0.5.2",
"utf8parse", "utf8parse",
"vte_generate_state_changes", "vte_generate_state_changes",
] ]
@ -3003,6 +3074,70 @@ version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasm-bindgen"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "web-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@ -17,6 +17,8 @@ im = "15.0.0"
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
nu-json = { path = "../nu-json" } nu-json = { path = "../nu-json" }
typetag = "0.1.8" typetag = "0.1.8"
num-format = "0.4.0"
sys-locale = "0.1.0"
[features] [features]
plugin = ["serde_json"] plugin = ["serde_json"]

View File

@ -14,6 +14,7 @@ pub struct Config {
pub footer_mode: FooterMode, pub footer_mode: FooterMode,
pub animate_prompt: bool, pub animate_prompt: bool,
pub float_precision: i64, pub float_precision: i64,
pub filesize_format: String,
pub without_color: bool, pub without_color: bool,
} }
@ -28,6 +29,7 @@ impl Default for Config {
footer_mode: FooterMode::Never, footer_mode: FooterMode::Never,
animate_prompt: ANIMATE_PROMPT_DEFAULT, animate_prompt: ANIMATE_PROMPT_DEFAULT,
float_precision: 4, float_precision: 4,
filesize_format: "auto".into(),
without_color: false, without_color: false,
} }
} }
@ -74,7 +76,7 @@ impl Value {
config.use_grid_icons = value.as_bool()?; config.use_grid_icons = value.as_bool()?;
} }
"footer_mode" => { "footer_mode" => {
let val_str = value.as_string()?; let val_str = value.as_string()?.to_lowercase();
config.footer_mode = match val_str.as_ref() { config.footer_mode = match val_str.as_ref() {
"auto" => FooterMode::Auto, "auto" => FooterMode::Auto,
"never" => FooterMode::Never, "never" => FooterMode::Never,
@ -94,6 +96,9 @@ impl Value {
"without_color" => { "without_color" => {
config.without_color = value.as_bool()?; config.without_color = value.as_bool()?;
} }
"filesize_format" => {
config.filesize_format = value.as_string()?.to_lowercase();
}
_ => {} _ => {}
} }
} }

View File

@ -5,13 +5,16 @@ mod range;
mod stream; mod stream;
mod unit; mod unit;
use byte_unit::ByteUnit;
use chrono::{DateTime, FixedOffset}; use chrono::{DateTime, FixedOffset};
use chrono_humanize::HumanTime; use chrono_humanize::HumanTime;
pub use from_value::FromValue; pub use from_value::FromValue;
use indexmap::map::IndexMap; use indexmap::map::IndexMap;
use num_format::{Locale, ToFormattedString};
pub use range::*; pub use range::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub use stream::*; pub use stream::*;
use sys_locale::get_locale;
pub use unit::*; pub use unit::*;
use std::collections::HashMap; use std::collections::HashMap;
@ -1474,16 +1477,114 @@ pub fn format_duration(duration: i64) -> String {
} }
fn format_filesize(num_bytes: i64, config: &Config) -> String { fn format_filesize(num_bytes: i64, config: &Config) -> String {
// Allow the user to specify how they want their numbers formatted
let filesize_format_var = get_config_filesize_format(config);
let byte = byte_unit::Byte::from_bytes(num_bytes as u128); let byte = byte_unit::Byte::from_bytes(num_bytes as u128);
let adj_byte =
if filesize_format_var.0 == byte_unit::ByteUnit::B && filesize_format_var.1 == "auto" {
byte.get_appropriate_unit(!config.filesize_metric)
} else {
byte.get_adjusted_unit(filesize_format_var.0)
};
if byte.get_bytes() == 0u128 { match adj_byte.get_unit() {
return "".to_string(); byte_unit::ByteUnit::B => {
} let locale_string = get_locale().unwrap_or_else(|| String::from("en-US"));
// Since get_locale() and Locale::from_name() don't always return the same items
let byte = byte.get_appropriate_unit(config.filesize_metric); // we need to try and parse it to match. For instance, a valid locale is de_DE
// however Locale::from_name() wants only de so we split and parse it out.
match byte.get_unit() { let locale_string = locale_string.replace("_", "-"); // en_AU -> en-AU
byte_unit::ByteUnit::B => format!("{} B ", byte.get_value()), let locale = match Locale::from_name(&locale_string) {
_ => byte.format(1), Ok(loc) => loc,
_ => {
let all = num_format::Locale::available_names();
let locale_prefix = &locale_string.split('-').collect::<Vec<&str>>();
if all.contains(&locale_prefix[0]) {
// eprintln!("Found alternate: {}", &locale_prefix[0]);
Locale::from_name(locale_prefix[0]).unwrap_or(Locale::en)
} else {
// eprintln!("Unable to find matching locale. Defaulting to en-US");
Locale::en
} }
} }
};
let locale_byte = adj_byte.get_value() as u64;
let locale_byte_string = locale_byte.to_formatted_string(&locale);
if filesize_format_var.1 == "auto" {
format!("{} B", locale_byte_string)
} else {
locale_byte_string
}
}
_ => adj_byte.format(1),
}
}
fn get_config_filesize_format(config: &Config) -> (ByteUnit, &str) {
// We need to take into account config.filesize_metric so, if someone asks for KB
// filesize_metric is true, return KiB
let filesize_format = match config.filesize_format.as_str() {
"b" => (byte_unit::ByteUnit::B, ""),
"kb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::KiB, "")
} else {
(byte_unit::ByteUnit::KB, "")
}
}
"kib" => (byte_unit::ByteUnit::KiB, ""),
"mb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::MiB, "")
} else {
(byte_unit::ByteUnit::MB, "")
}
}
"mib" => (byte_unit::ByteUnit::MiB, ""),
"gb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::GiB, "")
} else {
(byte_unit::ByteUnit::GB, "")
}
}
"gib" => (byte_unit::ByteUnit::GiB, ""),
"tb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::TiB, "")
} else {
(byte_unit::ByteUnit::TB, "")
}
}
"tib" => (byte_unit::ByteUnit::TiB, ""),
"pb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::PiB, "")
} else {
(byte_unit::ByteUnit::PB, "")
}
}
"pib" => (byte_unit::ByteUnit::PiB, ""),
"eb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::EiB, "")
} else {
(byte_unit::ByteUnit::EB, "")
}
}
"eib" => (byte_unit::ByteUnit::EiB, ""),
"zb" => {
if config.filesize_metric {
(byte_unit::ByteUnit::ZiB, "")
} else {
(byte_unit::ByteUnit::ZB, "")
}
}
"zib" => (byte_unit::ByteUnit::ZiB, ""),
_ => (byte_unit::ByteUnit::B, "auto"),
};
filesize_format
}

View File

@ -1148,19 +1148,28 @@ fn multi_word_imports() -> TestResult {
} }
#[test] #[test]
fn config_var_1() -> TestResult { fn config_filesize_format_with_metric_true() -> TestResult {
// Note: this tests both the config variable and that it is properly captured into a block // Note: this tests both the config variable and that it is properly captured into a block
run_test( run_test(
r#"let config = {"filesize_metric": $true }; do { 40kb | into string } "#, r#"let config = {"filesize_metric": $true "filesize_format": "kib" }; do { 40kb | into string } "#,
"39.1 KiB", "39.1 KiB",
) )
} }
#[test] #[test]
fn config_var_2() -> TestResult { fn config_filesize_format_with_metric_false_kib() -> TestResult {
// Note: this tests both the config variable and that it is properly captured into a block // Note: this tests both the config variable and that it is properly captured into a block
run_test( run_test(
r#"let config = {"filesize_metric": $false }; do { 40kb | into string } "#, r#"let config = {"filesize_metric": $false "filesize_format": "kib" }; do { 40kb | into string } "#,
"39.1 KiB",
)
}
#[test]
fn config_filesize_format_with_metric_false_kb() -> TestResult {
// Note: this tests both the config variable and that it is properly captured into a block
run_test(
r#"let config = {"filesize_metric": $false "filesize_format": "kb" }; do { 40kb | into string } "#,
"40.0 KB", "40.0 KB",
) )
} }