From 6329dbb3cff69da13fb98c5bde195c1bffb54863 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 30 Dec 2021 17:15:12 +0000 Subject: [PATCH 1/2] Add HumanCount and template keys to print position and length with commas. #339 --- src/format.rs | 29 +++++++++++++++++++++++++++++ src/lib.rs | 12 ++++++++++-- src/style.rs | 10 +++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/format.rs b/src/format.rs index 556a7f70..3bb5ef73 100644 --- a/src/format.rs +++ b/src/format.rs @@ -30,6 +30,10 @@ pub struct DecimalBytes(pub u64); #[derive(Debug)] pub struct BinaryBytes(pub u64); +/// Formats counts for human readability using commas +#[derive(Debug)] +pub struct HumanCount(pub u64); + impl fmt::Display for FormattedDuration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut t = self.0.as_secs(); @@ -125,6 +129,23 @@ impl fmt::Display for BinaryBytes { } } +impl fmt::Display for HumanCount { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use fmt::Write; + + let num = self.0.to_string(); + let mut i = num.len(); + for c in num.chars() { + f.write_char(c)?; + i -= 1; + if i > 0 && i % 3 == 0 { + f.write_char(',')?; + } + } + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -250,4 +271,12 @@ mod tests { assert_eq!("3 weeks", format!("{}", HumanDuration(3 * WEEK))); assert_eq!("3 years", format!("{}", HumanDuration(3 * YEAR))); } + + #[test] + fn human_count() { + assert_eq!("42", format!("{}", HumanCount(42))); + assert_eq!("7,654", format!("{}", HumanCount(7654))); + assert_eq!("12,345", format!("{}", HumanCount(12345))); + assert_eq!("1,234,567,890", format!("{}", HumanCount(1234567890))); + } } diff --git a/src/lib.rs b/src/lib.rs index 6b3408e1..e97d736b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ //! * [`DecimalBytes`](struct.DecimalBytes.html) for formatting bytes using SI prefixes //! * [`BinaryBytes`](struct.BinaryBytes.html) for formatting bytes using ISO/IEC prefixes //! * [`HumanDuration`](struct.HumanDuration.html) for formatting durations +//! * [`HumanCount`](struct.HumanCount.html) for formatting large counts //! //! # Progress Bars and Spinners //! @@ -168,7 +169,11 @@ //! * `wide_msg`: like `msg` but always fills the remaining space and truncates. It should not be used //! with `wide_bar`. //! * `pos`: renders the current position of the bar as integer +//! * `human_pos`: renders the current position of the bar as an integer, with commas as the +//! thousands separator. //! * `len`: renders the total length of the bar as integer +//! * `human_len`: renders the total length of the bar as an integer, with commas as the thousands +//! separator. //! * `bytes`: renders the current position of the bar as bytes. //! * `percent`: renders the current position of the bar as a percentage of the total length. //! * `total_bytes`: renders the total length of the bar as bytes. @@ -195,10 +200,11 @@ //! //! ```rust //! # use std::time::Duration; -//! use indicatif::{HumanDuration, HumanBytes}; +//! use indicatif::{HumanBytes, HumanCount, HumanDuration}; //! //! assert_eq!("3.00MiB", HumanBytes(3*1024*1024).to_string()); //! assert_eq!("8 seconds", HumanDuration(Duration::from_secs(8)).to_string()); +//! assert_eq!("33,857,009", HumanCount(33857009).to_string()); //! ``` //! //! # Feature Flags @@ -216,7 +222,9 @@ mod state; mod style; pub use crate::draw_target::{MultiProgressAlignment, ProgressDrawTarget}; -pub use crate::format::{BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanDuration}; +pub use crate::format::{ + BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanCount, HumanDuration, +}; pub use crate::iter::{ProgressBarIter, ProgressIterator}; pub use crate::progress_bar::{MultiProgress, ProgressBar, WeakProgressBar}; pub use crate::style::{ProgressFinish, ProgressStyle}; diff --git a/src/style.rs b/src/style.rs index e4d05122..f446e145 100644 --- a/src/style.rs +++ b/src/style.rs @@ -7,7 +7,9 @@ use console::{measure_text_width, Style}; #[cfg(feature = "improved_unicode")] use unicode_segmentation::UnicodeSegmentation; -use crate::format::{BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanDuration}; +use crate::format::{ + BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanCount, HumanDuration, +}; use crate::state::ProgressState; /// Controls the rendering style of progress bars @@ -267,7 +269,13 @@ impl ProgressStyle { "msg" => buf.push_str(state.message()), "prefix" => buf.push_str(state.prefix()), "pos" => buf.write_fmt(format_args!("{}", state.pos)).unwrap(), + "human_pos" => buf + .write_fmt(format_args!("{}", HumanCount(state.pos))) + .unwrap(), "len" => buf.write_fmt(format_args!("{}", state.len)).unwrap(), + "human_len" => buf + .write_fmt(format_args!("{}", HumanCount(state.len))) + .unwrap(), "percent" => buf .write_fmt(format_args!("{:.*}", 0, state.fraction() * 100f32)) .unwrap(), From 34e2755449897d53c9fb46aa20d5898957bffb20 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 30 Dec 2021 22:28:52 +0000 Subject: [PATCH 2/2] Write the HumanCount implementation with enumerate() --- src/format.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/format.rs b/src/format.rs index 3bb5ef73..16943ba0 100644 --- a/src/format.rs +++ b/src/format.rs @@ -134,11 +134,11 @@ impl fmt::Display for HumanCount { use fmt::Write; let num = self.0.to_string(); - let mut i = num.len(); - for c in num.chars() { + let len = num.len(); + for (idx, c) in num.chars().enumerate() { + let pos = len - idx - 1; f.write_char(c)?; - i -= 1; - if i > 0 && i % 3 == 0 { + if pos > 0 && pos % 3 == 0 { f.write_char(',')?; } }