@@ -30,48 +30,50 @@ fn style_with_width(
3030}
3131
3232fn download_row ( state : & ProgressState , message : & str , available : usize ) -> Str {
33+ let has_total = state. len ( ) . is_some ( ) ;
34+ let message_width = measure_text_width ( message) ;
3335 let bytes = HumanBytes ( state. pos ( ) ) ;
34- let counts = match state. len ( ) {
36+ let mut compact_stats = match state. len ( ) {
3537 Some ( total) => format ! ( "{bytes}/{}" , HumanBytes ( total) ) ,
3638 None => format ! ( "{bytes}" ) ,
3739 } ;
3840 let speed = HumanBytes ( state. per_sec ( ) as u64 ) ;
39- let details = match state. len ( ) {
40- Some ( _) => format ! ( "{counts} ({speed}/s, {:#})" , HumanDuration ( state. eta( ) ) ) ,
41- None => format ! ( "{counts} ({speed}/s)" ) ,
41+ let detailed_stats = if has_total {
42+ format ! ( "{compact_stats} ({speed}/s, {:#})" , HumanDuration ( state. eta( ) ) )
43+ } else {
44+ format ! ( "{compact_stats} ({speed}/s)" )
4245 } ;
43- let fixed_width = measure_text_width ( message) + measure_text_width ( & details) + 2 ;
44- if state. len ( ) . is_some ( ) {
45- // Keep a useful bar only when the full message and statistics fit.
46- // The leading space, brackets, and trailing space use three columns
47- // in addition to the two spaces included in `fixed_width`.
48- let bar_width = available. saturating_sub ( fixed_width + 3 ) ;
46+ let text_width = message_width + measure_text_width ( & detailed_stats) ;
47+ if has_total {
48+ // Reserve three spaces and two brackets, plus at least four bar columns.
49+ let bar_width = available. saturating_sub ( text_width + 5 ) ;
4950 if bar_width >= 4 {
5051 let filled = ( state. fraction ( ) * bar_width as f32 ) as usize ;
5152 let remaining = bar_width - filled;
5253 let bar = format ! ( "{}{}" , "#" . repeat( filled) , if remaining > 0 { ">" } else { "" } ) ;
5354 return format ! (
54- " {message} [{}{}] {details }" ,
55+ " {message} [{}{}] {detailed_stats }" ,
5556 style( bar) . blue( ) ,
5657 style( "-" . repeat( remaining. saturating_sub( 1 ) ) ) . white( ) ,
5758 ) ;
5859 }
59- } else if fixed_width <= available {
60- return format ! ( " {message} {details }" ) ;
60+ } else if text_width + 2 <= available {
61+ return format ! ( " {message} {detailed_stats }" ) ;
6162 }
6263
6364 // On narrow terminals, omit the bar, speed, and ETA before shortening the
6465 // message. For very small panes, prefer a percentage to two byte counts.
65- let counts = if state. len ( ) . is_some ( )
66- && measure_text_width ( & counts) + 2 + measure_text_width ( message) . min ( 8 ) > available
67- {
68- format ! ( "{:.0}%" , state. fraction( ) * 100.0 )
66+ let compact_width = measure_text_width ( & compact_stats) + 2 + message_width. min ( 8 ) ;
67+ if has_total && compact_width > available {
68+ compact_stats = format ! ( "{:.0}%" , state. fraction( ) * 100.0 ) ;
69+ }
70+ let available_message_width = available. saturating_sub ( measure_text_width ( & compact_stats) + 2 ) ;
71+ let message = truncate_str ( message, available_message_width, "" ) ;
72+ if message. is_empty ( ) {
73+ format ! ( " {compact_stats}" )
6974 } else {
70- counts
71- } ;
72- let message_width = available. saturating_sub ( measure_text_width ( & counts) + 2 ) ;
73- let message = truncate_str ( message, message_width, "" ) ;
74- if message. is_empty ( ) { format ! ( " {counts}" ) } else { format ! ( " {message} {counts}" ) }
75+ format ! ( " {message} {compact_stats}" )
76+ }
7577}
7678
7779#[ cfg( test) ]
@@ -114,19 +116,9 @@ mod tests {
114116 for position in [ 0 , 5 * 1024 * 1024 , 25 * 1024 * 1024 , total] {
115117 progress. set_elapsed ( Duration :: from_secs ( 2 ) ) ;
116118 progress. set_position ( position) ;
117- for reset_speed in [ false , true ] {
118- if reset_speed {
119- progress. reset_eta ( ) ;
120- }
121- progress. force_draw ( ) ;
122- let screen = term. contents ( ) ;
123- let lines: Vec < _ > = screen. lines ( ) . collect ( ) ;
124- assert_eq ! ( lines. len( ) , 2 , "width {width}: {screen}" ) ;
125- assert_eq ! ( lines[ 0 ] , earlier) ;
126- assert ! ( measure_text_width( lines[ 1 ] ) <= usize :: from( width) ) ;
127- let moves = term. moves_since_last_check ( ) ;
128- assert ! ( !moves. contains( "Up(" ) , "width {width}: {moves}" ) ;
129- }
119+ assert_progress_row ( & progress, & term, earlier) ;
120+ progress. reset_eta ( ) ;
121+ assert_progress_row ( & progress, & term, earlier) ;
130122 }
131123 }
132124
@@ -140,6 +132,18 @@ mod tests {
140132 }
141133 }
142134
135+ fn assert_progress_row ( progress : & ProgressBar , term : & InMemoryTerm , earlier : & str ) {
136+ progress. force_draw ( ) ;
137+ let width = term. width ( ) ;
138+ let screen = term. contents ( ) ;
139+ let lines: Vec < _ > = screen. lines ( ) . collect ( ) ;
140+ assert_eq ! ( lines. len( ) , 2 , "width {width}: {screen}" ) ;
141+ assert_eq ! ( lines[ 0 ] , earlier) ;
142+ assert ! ( measure_text_width( lines[ 1 ] ) <= usize :: from( width) ) ;
143+ let moves = term. moves_since_last_check ( ) ;
144+ assert ! ( !moves. contains( "Up(" ) , "width {width}: {moves}" ) ;
145+ }
146+
143147 #[ test]
144148 fn compact_layout_preserves_download_counts ( ) {
145149 for ( width, has_bar) in [ ( 40 , false ) , ( 60 , false ) , ( 80 , true ) , ( 138 , true ) ] {
0 commit comments