@@ -12,6 +12,7 @@ pub(crate) struct BarState {
1212 pub ( crate ) on_finish : ProgressFinish ,
1313 pub ( crate ) style : ProgressStyle ,
1414 pub ( crate ) state : ProgressState ,
15+ pub ( crate ) tab_width : usize ,
1516}
1617
1718impl BarState {
@@ -25,6 +26,7 @@ impl BarState {
2526 on_finish : ProgressFinish :: default ( ) ,
2627 style : ProgressStyle :: default_bar ( ) ,
2728 state : ProgressState :: new ( len, pos) ,
29+ tab_width : DEFAULT_TAB_WIDTH ,
2830 }
2931 }
3032
@@ -42,7 +44,7 @@ impl BarState {
4244 if let Some ( len) = self . state . len {
4345 self . state . pos . set ( len) ;
4446 }
45- self . style . message = msg;
47+ self . state . message = TabExpandedString :: new ( msg, self . tab_width ) ;
4648 }
4749 ProgressFinish :: AndClear => {
4850 if let Some ( len) = self . state . len {
@@ -51,7 +53,9 @@ impl BarState {
5153 self . state . status = Status :: DoneHidden ;
5254 }
5355 ProgressFinish :: Abandon => { }
54- ProgressFinish :: AbandonWithMessage ( msg) => self . style . message = msg,
56+ ProgressFinish :: AbandonWithMessage ( msg) => {
57+ self . state . message = TabExpandedString :: new ( msg, self . tab_width )
58+ }
5559 }
5660
5761 // There's no need to update the estimate here; once the `status` is no longer
@@ -92,22 +96,24 @@ impl BarState {
9296 self . update_estimate_and_draw ( now) ;
9397 }
9498
95- pub ( crate ) fn set_message ( & mut self , now : Instant , msg : Cow < ' static , str > ) {
96- self . style . message = msg;
97- self . update_estimate_and_draw ( now) ;
99+ pub ( crate ) fn set_tab_width ( & mut self , tab_width : usize ) {
100+ self . tab_width = tab_width;
101+ self . state . message . set_tab_width ( tab_width) ;
102+ self . state . prefix . set_tab_width ( tab_width) ;
103+ self . style . set_tab_width ( tab_width) ;
98104 }
99105
100- pub ( crate ) fn set_prefix ( & mut self , now : Instant , prefix : Cow < ' static , str > ) {
101- self . style . prefix = prefix ;
102- self . update_estimate_and_draw ( now ) ;
106+ pub ( crate ) fn set_style ( & mut self , style : ProgressStyle ) {
107+ self . style = style ;
108+ self . style . set_tab_width ( self . tab_width ) ;
103109 }
104110
105111 pub ( crate ) fn tick ( & mut self , now : Instant ) {
106112 self . state . tick = self . state . tick . saturating_add ( 1 ) ;
107113 self . update_estimate_and_draw ( now) ;
108114 }
109115
110- fn update_estimate_and_draw ( & mut self , now : Instant ) {
116+ pub ( crate ) fn update_estimate_and_draw ( & mut self , now : Instant ) {
111117 let pos = self . state . pos . pos . load ( Ordering :: Relaxed ) ;
112118 self . state . est . record ( pos, now) ;
113119 let _ = self . draw ( false , now) ;
@@ -190,6 +196,8 @@ pub struct ProgressState {
190196 pub ( crate ) started : Instant ,
191197 status : Status ,
192198 est : Estimator ,
199+ pub ( crate ) message : TabExpandedString ,
200+ pub ( crate ) prefix : TabExpandedString ,
193201}
194202
195203impl ProgressState {
@@ -201,6 +209,8 @@ impl ProgressState {
201209 status : Status :: InProgress ,
202210 started : Instant :: now ( ) ,
203211 est : Estimator :: new ( Instant :: now ( ) ) ,
212+ message : TabExpandedString :: NoTabs ( "" . into ( ) ) ,
213+ prefix : TabExpandedString :: NoTabs ( "" . into ( ) ) ,
204214 }
205215 }
206216
@@ -285,6 +295,55 @@ impl ProgressState {
285295 }
286296}
287297
298+ #[ derive( Debug , PartialEq , Eq , Clone ) ]
299+ pub ( crate ) enum TabExpandedString {
300+ NoTabs ( Cow < ' static , str > ) ,
301+ WithTabs {
302+ original : Cow < ' static , str > ,
303+ expanded : String ,
304+ tab_width : usize ,
305+ } ,
306+ }
307+
308+ impl TabExpandedString {
309+ pub ( crate ) fn new ( s : Cow < ' static , str > , tab_width : usize ) -> Self {
310+ let expanded = s. replace ( '\t' , & " " . repeat ( tab_width) ) ;
311+ if s == expanded {
312+ Self :: NoTabs ( s)
313+ } else {
314+ Self :: WithTabs {
315+ original : s,
316+ expanded,
317+ tab_width,
318+ }
319+ }
320+ }
321+
322+ pub ( crate ) fn expanded ( & self ) -> & str {
323+ match & self {
324+ Self :: NoTabs ( s) => {
325+ debug_assert ! ( !s. contains( '\t' ) ) ;
326+ s
327+ }
328+ Self :: WithTabs { expanded, .. } => expanded,
329+ }
330+ }
331+
332+ pub ( crate ) fn set_tab_width ( & mut self , new_tab_width : usize ) {
333+ if let TabExpandedString :: WithTabs {
334+ original,
335+ expanded,
336+ tab_width,
337+ } = self
338+ {
339+ if * tab_width != new_tab_width {
340+ * tab_width = new_tab_width;
341+ * expanded = original. replace ( '\t' , & " " . repeat ( new_tab_width) ) ;
342+ }
343+ }
344+ }
345+ }
346+
288347/// Estimate the number of seconds per step
289348///
290349/// Ring buffer with constant capacity. Used by `ProgressBar`s to display `{eta}`,
@@ -482,6 +541,8 @@ pub(crate) enum Status {
482541 DoneHidden ,
483542}
484543
544+ pub ( crate ) const DEFAULT_TAB_WIDTH : usize = 8 ;
545+
485546#[ cfg( test) ]
486547mod tests {
487548 use super :: * ;
0 commit comments