@@ -12,6 +12,7 @@ pub(crate) struct BarState {
12
12
pub ( crate ) on_finish : ProgressFinish ,
13
13
pub ( crate ) style : ProgressStyle ,
14
14
pub ( crate ) state : ProgressState ,
15
+ pub ( crate ) tab_width : usize ,
15
16
}
16
17
17
18
impl BarState {
@@ -25,6 +26,7 @@ impl BarState {
25
26
on_finish : ProgressFinish :: default ( ) ,
26
27
style : ProgressStyle :: default_bar ( ) ,
27
28
state : ProgressState :: new ( len, pos) ,
29
+ tab_width : DEFAULT_TAB_WIDTH ,
28
30
}
29
31
}
30
32
@@ -42,7 +44,7 @@ impl BarState {
42
44
if let Some ( len) = self . state . len {
43
45
self . state . pos . set ( len) ;
44
46
}
45
- self . state . message = msg;
47
+ self . state . message = TabExpandedString :: new ( msg, self . tab_width ) ;
46
48
}
47
49
ProgressFinish :: AndClear => {
48
50
if let Some ( len) = self . state . len {
@@ -51,7 +53,9 @@ impl BarState {
51
53
self . state . status = Status :: DoneHidden ;
52
54
}
53
55
ProgressFinish :: Abandon => { }
54
- ProgressFinish :: AbandonWithMessage ( msg) => self . state . message = msg,
56
+ ProgressFinish :: AbandonWithMessage ( msg) => {
57
+ self . state . message = TabExpandedString :: new ( msg, self . tab_width )
58
+ }
55
59
}
56
60
57
61
// There's no need to update the estimate here; once the `status` is no longer
@@ -92,22 +96,24 @@ impl BarState {
92
96
self . update_estimate_and_draw ( now) ;
93
97
}
94
98
95
- pub ( crate ) fn set_message ( & mut self , now : Instant , msg : Cow < ' static , str > ) {
96
- self . state . 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 . change_tab_width ( tab_width) ;
102
+ self . state . prefix . change_tab_width ( tab_width) ;
103
+ self . style . change_tab_width ( tab_width) ;
98
104
}
99
105
100
- pub ( crate ) fn set_prefix ( & mut self , now : Instant , prefix : Cow < ' static , str > ) {
101
- self . state . 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 . change_tab_width ( self . tab_width ) ;
103
109
}
104
110
105
111
pub ( crate ) fn tick ( & mut self , now : Instant ) {
106
112
self . state . tick = self . state . tick . saturating_add ( 1 ) ;
107
113
self . update_estimate_and_draw ( now) ;
108
114
}
109
115
110
- fn update_estimate_and_draw ( & mut self , now : Instant ) {
116
+ pub ( crate ) fn update_estimate_and_draw ( & mut self , now : Instant ) {
111
117
let pos = self . state . pos . pos . load ( Ordering :: Relaxed ) ;
112
118
self . state . est . record ( pos, now) ;
113
119
let _ = self . draw ( false , now) ;
@@ -190,8 +196,8 @@ pub struct ProgressState {
190
196
pub ( crate ) started : Instant ,
191
197
status : Status ,
192
198
est : Estimator ,
193
- pub ( crate ) message : Cow < ' static , str > ,
194
- pub ( crate ) prefix : Cow < ' static , str > ,
199
+ pub ( crate ) message : TabExpandedString ,
200
+ pub ( crate ) prefix : TabExpandedString ,
195
201
}
196
202
197
203
impl ProgressState {
@@ -203,8 +209,8 @@ impl ProgressState {
203
209
status : Status :: InProgress ,
204
210
started : Instant :: now ( ) ,
205
211
est : Estimator :: new ( Instant :: now ( ) ) ,
206
- message : "" . into ( ) ,
207
- prefix : "" . into ( ) ,
212
+ message : TabExpandedString :: NoTabs ( "" . into ( ) ) ,
213
+ prefix : TabExpandedString :: NoTabs ( "" . into ( ) ) ,
208
214
}
209
215
}
210
216
@@ -289,6 +295,55 @@ impl ProgressState {
289
295
}
290
296
}
291
297
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 change_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
+
292
347
/// Estimate the number of seconds per step
293
348
///
294
349
/// Ring buffer with constant capacity. Used by `ProgressBar`s to display `{eta}`,
@@ -486,6 +541,8 @@ pub(crate) enum Status {
486
541
DoneHidden ,
487
542
}
488
543
544
+ pub ( crate ) const DEFAULT_TAB_WIDTH : usize = 8 ;
545
+
489
546
#[ cfg( test) ]
490
547
mod tests {
491
548
use super :: * ;
0 commit comments