diff --git a/src/format.rs b/src/format.rs index 556a7f70..16943ba0 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 len = num.len(); + for (idx, c) in num.chars().enumerate() { + let pos = len - idx - 1; + f.write_char(c)?; + if pos > 0 && pos % 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(),