From 5ad904068d87dc509c998502906d3ee538803695 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Mon, 28 Sep 2026 03:34:01 -0400 Subject: [PATCH] change: show decimal places for disk usage info (#2266) The way we're doing this for now is: - If it's less than 100, always show 2 decimal places unless it ends in 0; if so, trim it away - If it's less than 1000, then do the same but with 1 - If it's over 1000, show no decimal places. --- src/utils/data_units.rs | 58 +++++++++++++++++++++++++++++++++++++++ src/widgets/disk_table.rs | 33 +++++++++++++++------- 2 files changed, 81 insertions(+), 10 deletions(-) diff --git a/src/utils/data_units.rs b/src/utils/data_units.rs index ab63c08b..438b8d99 100644 --- a/src/utils/data_units.rs +++ b/src/utils/data_units.rs @@ -101,3 +101,61 @@ pub fn get_unit_prefix(value: u64, base_two: bool) -> (f64, &'static str) { } } } + +/// Format a float value to a string in a format showing a (hopefully) reasonable amount of decimal +/// places. +/// - If the value is < 100, then it will show at most two decimal places; if the decimals have +/// trailing 0s, they will be trimmed. +/// - Likewise, if it is < 1000, then it will show just 1 decimal place at most. +/// - If the value is >= 1000, then it will just omit decimals. +#[inline] +pub fn format_byte_decimal_values(value: f64) -> String { + if value >= 1000.0 { + // Don't show decimals for values with 4 or more digits anyway. + format!("{value:.0}") + } else if value >= 100.0 { + // Note the trim is safe, as `value:.2` will always emit a decimal place. + format!("{value:.1}") + .trim_end_matches('0') + .trim_end_matches('.') + .to_string() + } else { + // Note the trim is safe, as `value:.2` will always emit a decimal place. + format!("{value:.2}") + .trim_end_matches('0') + .trim_end_matches('.') + .to_string() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_format_bytes_value() { + assert_eq!(format_byte_decimal_values(0.0), "0"); + assert_eq!(format_byte_decimal_values(5.0), "5"); + assert_eq!(format_byte_decimal_values(100.0), "100"); + assert_eq!(format_byte_decimal_values(101.0), "101"); + assert_eq!(format_byte_decimal_values(111.0), "111"); + assert_eq!(format_byte_decimal_values(111.04), "111"); + assert_eq!(format_byte_decimal_values(111.06), "111.1"); + assert_eq!( + format_byte_decimal_values(111.05), + "111", + "note that this actually rounds down due to floating point BS :/" + ); + assert_eq!(format_byte_decimal_values(111.6), "111.6"); + assert_eq!(format_byte_decimal_values(128.05), "128.1"); + assert_eq!(format_byte_decimal_values(1234.0), "1234"); + assert_eq!(format_byte_decimal_values(1234.05), "1234"); + assert_eq!(format_byte_decimal_values(1.25), "1.25"); + assert_eq!(format_byte_decimal_values(1.2), "1.2"); + assert_eq!(format_byte_decimal_values(10.4), "10.4"); + assert_eq!(format_byte_decimal_values(356.5), "356.5"); + assert_eq!(format_byte_decimal_values(536.870912), "536.9"); + assert_eq!(format_byte_decimal_values(36.870912), "36.87"); + assert_eq!(format_byte_decimal_values(1.048576), "1.05"); + } +} diff --git a/src/widgets/disk_table.rs b/src/widgets/disk_table.rs index 1ace4d76..1174c0e4 100644 --- a/src/widgets/disk_table.rs +++ b/src/widgets/disk_table.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, cmp::max, num::NonZeroU16}; +use concat_string::concat_string; use serde::Deserialize; use crate::{ @@ -11,7 +12,7 @@ use crate::{ options::config::style::Styles, utils::{ conversion::{bin_bytes_per_second_string, dec_bytes_per_second_string}, - data_units::convert_bytes, + data_units::{convert_bytes, format_byte_decimal_values}, general::sort_partial_fn, }, }; @@ -35,7 +36,11 @@ impl DiskWidgetData { fn total_space(&self) -> Cow<'static, str> { if let Some(total_bytes) = self.total_bytes { let converted_total_space = convert_bytes(total_bytes, self.use_binary_prefix); - format!("{:.0}{}", converted_total_space.0, converted_total_space.1).into() + concat_string!( + format_byte_decimal_values(converted_total_space.0), + converted_total_space.1 + ) + .into() } else { "N/A".into() } @@ -44,7 +49,11 @@ impl DiskWidgetData { fn free_space(&self) -> Cow<'static, str> { if let Some(free_bytes) = self.free_bytes { let converted_free_space = convert_bytes(free_bytes, self.use_binary_prefix); - format!("{:.0}{}", converted_free_space.0, converted_free_space.1).into() + concat_string!( + format_byte_decimal_values(converted_free_space.0), + converted_free_space.1 + ) + .into() } else { "N/A".into() } @@ -52,8 +61,12 @@ impl DiskWidgetData { fn used_space(&self) -> Cow<'static, str> { if let Some(used_bytes) = self.used_bytes { - let converted_free_space = convert_bytes(used_bytes, self.use_binary_prefix); - format!("{:.0}{}", converted_free_space.0, converted_free_space.1).into() + let converted_used_space = convert_bytes(used_bytes, self.use_binary_prefix); + concat_string!( + format_byte_decimal_values(converted_used_space.0), + converted_used_space.1 + ) + .into() } else { "N/A".into() } @@ -453,11 +466,11 @@ mod test { (0, "0B", "0B"), (999, "999B", "999B"), (1000, "1KB", "1000B"), - (1023, "1KB", "1023B"), - (1024, "1KB", "1KiB"), - (MEBI_LIMIT, "1MB", "1MiB"), - (500 * GIBI_LIMIT, "537GB", "500GiB"), - (TEBI_LIMIT, "1TB", "1TiB"), + (1023, "1.02KB", "1023B"), + (1024, "1.02KB", "1KiB"), + (MEBI_LIMIT, "1.05MB", "1MiB"), + (500 * GIBI_LIMIT, "536.9GB", "500GiB"), + (TEBI_LIMIT, "1.1TB", "1TiB"), ] { for (use_binary_prefix, expected) in [(false, decimal), (true, binary)] { let data = disk(Some(bytes), use_binary_prefix);