diff --git a/crates/nu-command/src/strings/format/filesize.rs b/crates/nu-command/src/strings/format/filesize.rs index 61c540a9e5..753296f735 100644 --- a/crates/nu-command/src/strings/format/filesize.rs +++ b/crates/nu-command/src/strings/format/filesize.rs @@ -101,7 +101,7 @@ fn format_value_impl(val: &Value, arg: &Arguments, span: Span) -> Value { match val { Value::Filesize { val, span } => Value::String { // don't need to concern about metric, we just format units by what user input. - val: format_filesize(*val, &arg.format_value, false), + val: format_filesize(*val, &arg.format_value, None), span: *span, }, other => Value::Error { diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 3f4ee7e0d1..24cc506340 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -3211,25 +3211,35 @@ pub fn format_duration_as_timeperiod(duration: i64) -> (i32, Vec) { pub fn format_filesize_from_conf(num_bytes: i64, config: &Config) -> String { // We need to take into account config.filesize_metric so, if someone asks for KB - // filesize_metric is true, return KiB + // and filesize_metric is false, return KiB format_filesize( num_bytes, config.filesize_format.as_str(), - config.filesize_metric, + Some(config.filesize_metric), ) } -pub fn format_filesize(num_bytes: i64, format_value: &str, filesize_metric: bool) -> String { +// filesize_metric is explicit when printed a value according to user config; +// other places (such as `format filesize`) don't. +pub fn format_filesize( + num_bytes: i64, + format_value: &str, + filesize_metric: Option, +) -> String { // Allow the user to specify how they want their numbers formatted + + // When format_value is "auto" or an invalid value, the returned ByteUnit doesn't matter + // and is always B. let filesize_format_var = get_filesize_format(format_value, filesize_metric); let byte = byte_unit::Byte::from_bytes(num_bytes.unsigned_abs() as u128); - let adj_byte = - if filesize_format_var.0 == byte_unit::ByteUnit::B && filesize_format_var.1 == "auto" { - byte.get_appropriate_unit(!filesize_metric) - } else { - byte.get_adjusted_unit(filesize_format_var.0) - }; + let adj_byte = if filesize_format_var.1 == "auto" { + // When filesize_metric is None, format_value should never be "auto", so this + // unwrap_or() should always work. + byte.get_appropriate_unit(!filesize_metric.unwrap_or(false)) + } else { + byte.get_adjusted_unit(filesize_format_var.0) + }; match adj_byte.get_unit() { byte_unit::ByteUnit::B => { @@ -3258,65 +3268,36 @@ pub fn format_filesize(num_bytes: i64, format_value: &str, filesize_metric: bool } } -fn get_filesize_format(format_value: &str, filesize_metric: bool) -> (ByteUnit, &str) { +fn get_filesize_format(format_value: &str, filesize_metric: Option) -> (ByteUnit, &str) { + macro_rules! either { + ($in:ident, $metric:ident, $binary:ident) => { + ( + // filesize_metric always overrides the unit of + // filesize_format. + match filesize_metric { + Some(true) => byte_unit::ByteUnit::$metric, + Some(false) => byte_unit::ByteUnit::$binary, + None => { + if $in.ends_with("ib") { + byte_unit::ByteUnit::$binary + } else { + byte_unit::ByteUnit::$metric + } + } + }, + "", + ) + }; + } match format_value { "b" => (byte_unit::ByteUnit::B, ""), - "kb" => { - if filesize_metric { - (byte_unit::ByteUnit::KiB, "") - } else { - (byte_unit::ByteUnit::KB, "") - } - } - "kib" => (byte_unit::ByteUnit::KiB, ""), - "mb" => { - if filesize_metric { - (byte_unit::ByteUnit::MiB, "") - } else { - (byte_unit::ByteUnit::MB, "") - } - } - "mib" => (byte_unit::ByteUnit::MiB, ""), - "gb" => { - if filesize_metric { - (byte_unit::ByteUnit::GiB, "") - } else { - (byte_unit::ByteUnit::GB, "") - } - } - "gib" => (byte_unit::ByteUnit::GiB, ""), - "tb" => { - if filesize_metric { - (byte_unit::ByteUnit::TiB, "") - } else { - (byte_unit::ByteUnit::TB, "") - } - } - "tib" => (byte_unit::ByteUnit::TiB, ""), - "pb" => { - if filesize_metric { - (byte_unit::ByteUnit::PiB, "") - } else { - (byte_unit::ByteUnit::PB, "") - } - } - "pib" => (byte_unit::ByteUnit::PiB, ""), - "eb" => { - if filesize_metric { - (byte_unit::ByteUnit::EiB, "") - } else { - (byte_unit::ByteUnit::EB, "") - } - } - "eib" => (byte_unit::ByteUnit::EiB, ""), - "zb" => { - if filesize_metric { - (byte_unit::ByteUnit::ZiB, "") - } else { - (byte_unit::ByteUnit::ZB, "") - } - } - "zib" => (byte_unit::ByteUnit::ZiB, ""), + "kb" | "kib" => either!(format_value, KB, KiB), + "mb" | "mib" => either!(format_value, MB, MiB), + "gb" | "gib" => either!(format_value, GB, GiB), + "tb" | "tib" => either!(format_value, TB, TiB), + "pb" | "pib" => either!(format_value, TB, TiB), + "eb" | "eib" => either!(format_value, EB, EiB), + "zb" | "zib" => either!(format_value, ZB, ZiB), _ => (byte_unit::ByteUnit::B, "auto"), } } diff --git a/crates/nu-protocol/tests/test_config.rs b/crates/nu-protocol/tests/test_config.rs new file mode 100644 index 0000000000..7a1624eb74 --- /dev/null +++ b/crates/nu-protocol/tests/test_config.rs @@ -0,0 +1,51 @@ +use nu_test_support::{nu, nu_repl_code}; + +#[test] +fn filesize_metric_true() { + let code = &[ + r#"let-env config = { filesize: { metric: true, format:"mb" } }"#, + r#"20mib | into string"#, + ]; + let actual = nu!(cwd: ".", nu_repl_code( code )); + assert_eq!(actual.out, "21.0 MB"); +} + +#[test] +fn filesize_metric_false() { + let code = &[ + r#"let-env config = { filesize: { metric: false, format:"mib" } }"#, + r#"20mib | into string"#, + ]; + let actual = nu!(cwd: ".", nu_repl_code( code )); + assert_eq!(actual.out, "20.0 MiB"); +} + +#[test] +fn filesize_metric_overrides_format() { + let code = &[ + r#"let-env config = { filesize: { metric: false, format:"mb" } }"#, + r#"20mib | into string"#, + ]; + let actual = nu!(cwd: ".", nu_repl_code( code )); + assert_eq!(actual.out, "20.0 MiB"); +} + +#[test] +fn filesize_format_auto_metric_true() { + let code = &[ + r#"let-env config = { filesize: { metric: true, format:"auto" } }"#, + r#"[2mb 2gb 2tb] | into string | to nuon"#, + ]; + let actual = nu!(cwd: ".", nu_repl_code( code )); + assert_eq!(actual.out, r#"["2.0 MB", "2.0 GB", "2.0 TB"]"#); +} + +#[test] +fn filesize_format_auto_metric_false() { + let code = &[ + r#"let-env config = { filesize: { metric: false, format:"auto" } }"#, + r#"[2mb 2gb 2tb] | into string | to nuon"#, + ]; + let actual = nu!(cwd: ".", nu_repl_code( code )); + assert_eq!(actual.out, r#"["1.9 MiB", "1.9 GiB", "1.8 TiB"]"#); +} diff --git a/crates/nu-test-support/src/macros.rs b/crates/nu-test-support/src/macros.rs index 9ccf0fb053..3e478c59c1 100644 --- a/crates/nu-test-support/src/macros.rs +++ b/crates/nu-test-support/src/macros.rs @@ -1,4 +1,4 @@ -/// Run a command in nu and get it's output +/// Run a command in nu and get its output /// /// The `nu!` macro accepts a number of options like the `cwd` in which the /// command should be run. It is also possible to specify a different `locale`