Browse Source

fix rendering and variable width issues on progress bar

Jeffrey Morgan 1 year ago
parent
commit
aabd71aede
1 changed files with 34 additions and 15 deletions
  1. 34 15
      progress/bar.go

+ 34 - 15
progress/bar.go

@@ -42,6 +42,19 @@ func NewBar(message string, maxValue, initialValue int64) *Bar {
 	}
 	}
 }
 }
 
 
+// formatDuration limits the rendering of a time.Duration to 2 units
+func formatDuration(d time.Duration) string {
+	if d >= 100*time.Hour {
+		return "99h+"
+	}
+
+	if d >= time.Hour {
+		return fmt.Sprintf("%dh%dm", int(d.Hours()), int(d.Minutes())%60)
+	}
+
+	return d.Round(time.Second).String()
+}
+
 func (b *Bar) String() string {
 func (b *Bar) String() string {
 	termWidth, _, err := term.GetSize(int(os.Stderr.Fd()))
 	termWidth, _, err := term.GetSize(int(os.Stderr.Fd()))
 	if err != nil {
 	if err != nil {
@@ -65,39 +78,43 @@ func (b *Bar) String() string {
 	}
 	}
 
 
 	fmt.Fprintf(&pre, "%3.0f%% ", math.Floor(b.percent()))
 	fmt.Fprintf(&pre, "%3.0f%% ", math.Floor(b.percent()))
+
 	fmt.Fprintf(&suf, "(%s/%s", format.HumanBytes(b.currentValue), format.HumanBytes(b.maxValue))
 	fmt.Fprintf(&suf, "(%s/%s", format.HumanBytes(b.currentValue), format.HumanBytes(b.maxValue))
 
 
 	stats := b.Stats()
 	stats := b.Stats()
-	rate := int64(stats.rate)
-	if rate > 0 {
-		fmt.Fprintf(&suf, ", %s/s", format.HumanBytes(rate))
+	rate := stats.rate
+	if stats.value > b.initialValue && stats.value < b.maxValue {
+		fmt.Fprintf(&suf, ", %s/s", format.HumanBytes(int64(rate)))
 	}
 	}
 
 
 	fmt.Fprintf(&suf, ")")
 	fmt.Fprintf(&suf, ")")
 
 
 	elapsed := time.Since(b.started)
 	elapsed := time.Since(b.started)
-	if b.percent() < 100 && rate > 0 {
-		fmt.Fprintf(&suf, " [%s:%s]", elapsed.Round(time.Second), stats.remaining)
-	} else {
-		fmt.Fprintf(&suf, "        ")
+	var timing string
+	if stats.value > b.initialValue && stats.value < b.maxValue {
+		timing = fmt.Sprintf("[%s:%s]", formatDuration(elapsed), formatDuration(stats.remaining))
 	}
 	}
 
 
-	mid.WriteString("▕")
+	// 44 is the maximum width for the stats on the right of the progress bar
+	if suf.Len() < 44 {
+		suf.WriteString(strings.Repeat(" ", 44-suf.Len()-len(timing)))
+	}
+
+	suf.WriteString(timing)
 
 
 	// add 3 extra spaces: 2 boundary characters and 1 space at the end
 	// add 3 extra spaces: 2 boundary characters and 1 space at the end
 	f := termWidth - pre.Len() - suf.Len() - 3
 	f := termWidth - pre.Len() - suf.Len() - 3
 	n := int(float64(f) * b.percent() / 100)
 	n := int(float64(f) * b.percent() / 100)
 
 
-	if n > 0 {
+	if f > 0 {
+		mid.WriteString("▕")
 		mid.WriteString(strings.Repeat("█", n))
 		mid.WriteString(strings.Repeat("█", n))
+		if f-n > 0 {
+			mid.WriteString(strings.Repeat(" ", f-n))
+		}
+		mid.WriteString("▏")
 	}
 	}
 
 
-	if f-n > 0 {
-		mid.WriteString(strings.Repeat(" ", f-n))
-	}
-
-	mid.WriteString("▏")
-
 	return pre.String() + mid.String() + suf.String()
 	return pre.String() + mid.String() + suf.String()
 }
 }
 
 
@@ -140,6 +157,8 @@ func (b *Bar) Stats() Stats {
 		var remaining time.Duration
 		var remaining time.Duration
 		if rate > 0 {
 		if rate > 0 {
 			remaining = time.Second * time.Duration((float64(b.maxValue-b.currentValue))/(float64(rate)))
 			remaining = time.Second * time.Duration((float64(b.maxValue-b.currentValue))/(float64(rate)))
+		} else {
+			remaining = time.Duration(math.MaxInt64)
 		}
 		}
 
 
 		b.stats = Stats{
 		b.stats = Stats{