@@ -7,11 +7,14 @@ use std::{fmt, io};
7
7
use crate :: draw_target:: ProgressDrawTarget ;
8
8
use crate :: style:: ProgressStyle ;
9
9
10
+ pub ( crate ) const DEFAULT_TAB_WIDTH : usize = 8 ;
11
+
10
12
pub ( crate ) struct BarState {
11
13
pub ( crate ) draw_target : ProgressDrawTarget ,
12
14
pub ( crate ) on_finish : ProgressFinish ,
13
15
pub ( crate ) style : ProgressStyle ,
14
16
pub ( crate ) state : ProgressState ,
17
+ tab_width : usize ,
15
18
}
16
19
17
20
impl BarState {
@@ -25,6 +28,7 @@ impl BarState {
25
28
on_finish : ProgressFinish :: default ( ) ,
26
29
style : ProgressStyle :: default_bar ( ) ,
27
30
state : ProgressState :: new ( len, pos) ,
31
+ tab_width : DEFAULT_TAB_WIDTH ,
28
32
}
29
33
}
30
34
@@ -42,7 +46,7 @@ impl BarState {
42
46
if let Some ( len) = self . state . len {
43
47
self . state . pos . set ( len) ;
44
48
}
45
- self . state . message = msg;
49
+ self . state . message = TabExpandedString :: new ( msg, self . tab_width ) ;
46
50
}
47
51
ProgressFinish :: AndClear => {
48
52
if let Some ( len) = self . state . len {
@@ -51,7 +55,9 @@ impl BarState {
51
55
self . state . status = Status :: DoneHidden ;
52
56
}
53
57
ProgressFinish :: Abandon => { }
54
- ProgressFinish :: AbandonWithMessage ( msg) => self . state . message = msg,
58
+ ProgressFinish :: AbandonWithMessage ( msg) => {
59
+ self . state . message = TabExpandedString :: new ( msg, self . tab_width )
60
+ }
55
61
}
56
62
57
63
// There's no need to update the estimate here; once the `status` is no longer
@@ -93,15 +99,42 @@ impl BarState {
93
99
}
94
100
95
101
pub ( crate ) fn set_message ( & mut self , now : Instant , msg : Cow < ' static , str > ) {
96
- self . state . message = msg;
102
+ self . state . message = TabExpandedString :: new ( msg, self . tab_width ) ;
97
103
self . update_estimate_and_draw ( now) ;
98
104
}
99
105
106
+ // Called in builder context
107
+ pub ( crate ) fn set_message_without_draw ( & mut self , msg : Cow < ' static , str > ) {
108
+ self . state . message = TabExpandedString :: new ( msg, self . tab_width ) ;
109
+ }
110
+
100
111
pub ( crate ) fn set_prefix ( & mut self , now : Instant , prefix : Cow < ' static , str > ) {
101
- self . state . prefix = prefix;
112
+ self . state . prefix = TabExpandedString :: new ( prefix, self . tab_width ) ;
113
+ self . update_estimate_and_draw ( now) ;
114
+ }
115
+
116
+ // Called in builder context
117
+ pub ( crate ) fn set_prefix_without_draw ( & mut self , prefix : Cow < ' static , str > ) {
118
+ self . state . prefix = TabExpandedString :: new ( prefix, self . tab_width ) ;
119
+ }
120
+
121
+ pub ( crate ) fn set_tab_width ( & mut self , now : Instant , tab_width : usize ) {
122
+ self . set_tab_width_without_draw ( tab_width) ;
102
123
self . update_estimate_and_draw ( now) ;
103
124
}
104
125
126
+ pub ( crate ) fn set_tab_width_without_draw ( & mut self , tab_width : usize ) {
127
+ self . tab_width = tab_width;
128
+ self . state . message . change_tab_width ( tab_width) ;
129
+ self . state . prefix . change_tab_width ( tab_width) ;
130
+ self . style . change_tab_width ( tab_width) ;
131
+ }
132
+
133
+ pub ( crate ) fn set_style ( & mut self , style : ProgressStyle ) {
134
+ self . style = style;
135
+ self . style . change_tab_width ( self . tab_width ) ;
136
+ }
137
+
105
138
pub ( crate ) fn tick ( & mut self , now : Instant ) {
106
139
self . state . tick = self . state . tick . saturating_add ( 1 ) ;
107
140
self . update_estimate_and_draw ( now) ;
@@ -190,8 +223,8 @@ pub struct ProgressState {
190
223
pub ( crate ) started : Instant ,
191
224
status : Status ,
192
225
est : Estimator ,
193
- pub ( crate ) message : Cow < ' static , str > ,
194
- pub ( crate ) prefix : Cow < ' static , str > ,
226
+ message : TabExpandedString ,
227
+ prefix : TabExpandedString ,
195
228
}
196
229
197
230
impl ProgressState {
@@ -203,8 +236,8 @@ impl ProgressState {
203
236
status : Status :: InProgress ,
204
237
started : Instant :: now ( ) ,
205
238
est : Estimator :: new ( Instant :: now ( ) ) ,
206
- message : "" . into ( ) ,
207
- prefix : "" . into ( ) ,
239
+ message : TabExpandedString :: NoTabs ( "" . into ( ) ) ,
240
+ prefix : TabExpandedString :: NoTabs ( "" . into ( ) ) ,
208
241
}
209
242
}
210
243
@@ -287,6 +320,71 @@ impl ProgressState {
287
320
pub fn set_len ( & mut self , len : u64 ) {
288
321
self . len = Some ( len) ;
289
322
}
323
+
324
+ pub fn set_message ( & mut self , msg : TabExpandedString ) {
325
+ self . message = msg;
326
+ }
327
+
328
+ pub fn message ( & self ) -> & str {
329
+ self . message . expanded ( )
330
+ }
331
+
332
+ pub fn set_prefix ( & mut self , prefix : TabExpandedString ) {
333
+ self . prefix = prefix;
334
+ }
335
+
336
+ pub fn prefix ( & self ) -> & str {
337
+ self . prefix . expanded ( )
338
+ }
339
+ }
340
+
341
+ #[ derive( Debug , PartialEq , Eq , Clone ) ]
342
+ pub enum TabExpandedString {
343
+ NoTabs ( Cow < ' static , str > ) ,
344
+ WithTabs {
345
+ original : Cow < ' static , str > ,
346
+ expanded : String ,
347
+ tab_width : usize ,
348
+ } ,
349
+ }
350
+
351
+ impl TabExpandedString {
352
+ pub ( crate ) fn new ( s : Cow < ' static , str > , tab_width : usize ) -> Self {
353
+ let expanded = s. replace ( '\t' , & " " . repeat ( tab_width) ) ;
354
+ if s == expanded {
355
+ Self :: NoTabs ( s)
356
+ } else {
357
+ Self :: WithTabs {
358
+ original : s,
359
+ expanded,
360
+ tab_width,
361
+ }
362
+ }
363
+ }
364
+
365
+ pub ( crate ) fn expanded ( & self ) -> & str {
366
+ match & self {
367
+ Self :: NoTabs ( s) => {
368
+ debug_assert ! ( !s. contains( '\t' ) ) ;
369
+ s
370
+ }
371
+ Self :: WithTabs { expanded, .. } => expanded,
372
+ }
373
+ }
374
+
375
+ pub ( crate ) fn change_tab_width ( & mut self , new_tab_width : usize ) {
376
+ if let TabExpandedString :: WithTabs {
377
+ original,
378
+ expanded,
379
+ tab_width,
380
+ } = self
381
+ {
382
+ if * tab_width != new_tab_width {
383
+ * tab_width = new_tab_width;
384
+ * expanded = original. replace ( '\t' , & " " . repeat ( new_tab_width) ) ;
385
+ }
386
+ }
387
+ }
290
388
}
291
389
292
390
/// Estimate the number of seconds per step
0 commit comments