Skip to content

Commit 0f7db63

Browse files
committed
refactor: dynamic progress bar width based on terminal size
1 parent c0542c7 commit 0f7db63

4 files changed

Lines changed: 72 additions & 12 deletions

File tree

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/openbootdotdev/openboot
22

3-
go 1.22
3+
go 1.24.0
44

55
require (
66
github.com/charmbracelet/bubbles v0.20.0
@@ -32,6 +32,7 @@ require (
3232
github.com/rivo/uniseg v0.4.7 // indirect
3333
github.com/spf13/pflag v1.0.5 // indirect
3434
golang.org/x/sync v0.8.0 // indirect
35-
golang.org/x/sys v0.25.0 // indirect
35+
golang.org/x/sys v0.40.0 // indirect
36+
golang.org/x/term v0.39.0 // indirect
3637
golang.org/x/text v0.18.0 // indirect
3738
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
5757
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5858
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
5959
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
60+
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
61+
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
62+
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
63+
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
6064
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
6165
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
6266
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

internal/installer/installer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func Run(cfg *config.Config) error {
2727

2828
func runInstall(cfg *config.Config) error {
2929
fmt.Println()
30-
ui.Header("OpenBoot Installer v0.9.3")
30+
ui.Header("OpenBoot Installer v0.9.4")
3131
fmt.Println()
3232

3333
if cfg.DryRun {

internal/ui/progress.go

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,22 @@ package ui
22

33
import (
44
"fmt"
5+
"os"
56
"strings"
67
"sync"
78
"time"
89

910
"github.com/charmbracelet/lipgloss"
11+
"golang.org/x/term"
12+
)
13+
14+
const (
15+
minBarWidth = 20
16+
defaultBarWidth = 40
17+
minPkgWidth = 10
18+
defaultPkgWidth = 25
19+
statusWidth = 16 // " 48/48 (100%)"
20+
etaWidth = 8 // "~10m30s "
1021
)
1122

1223
var (
@@ -30,7 +41,8 @@ type ProgressTracker struct {
3041
total int
3142
completed int
3243
active map[string]bool
33-
width int
44+
barWidth int
45+
pkgWidth int
3446
startTime time.Time
3547
mu sync.Mutex
3648
spinnerIdx int
@@ -40,10 +52,21 @@ type ProgressTracker struct {
4052

4153
var spinnerFrames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
4254

55+
func getTerminalWidth() int {
56+
if w, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil && w > 0 {
57+
return w
58+
}
59+
return 80
60+
}
61+
4362
func NewProgressTracker(total int) *ProgressTracker {
63+
termWidth := getTerminalWidth()
64+
barWidth, pkgWidth := calculateWidths(termWidth)
65+
4466
p := &ProgressTracker{
4567
total: total,
46-
width: 40,
68+
barWidth: barWidth,
69+
pkgWidth: pkgWidth,
4770
startTime: time.Now(),
4871
active: make(map[string]bool),
4972
spinnerStop: make(chan bool),
@@ -70,6 +93,28 @@ func NewProgressTracker(total int) *ProgressTracker {
7093
return p
7194
}
7295

96+
func calculateWidths(termWidth int) (barWidth, pkgWidth int) {
97+
fixed := statusWidth + etaWidth
98+
available := termWidth - fixed - 2
99+
100+
if available < minBarWidth+minPkgWidth {
101+
return minBarWidth, minPkgWidth
102+
}
103+
104+
barWidth = available * 55 / 100
105+
pkgWidth = available - barWidth
106+
107+
if barWidth > defaultBarWidth {
108+
barWidth = defaultBarWidth
109+
pkgWidth = available - barWidth
110+
}
111+
if pkgWidth > defaultPkgWidth+10 {
112+
pkgWidth = defaultPkgWidth + 10
113+
}
114+
115+
return barWidth, pkgWidth
116+
}
117+
73118
func (p *ProgressTracker) SetCurrent(pkgName string) {
74119
p.mu.Lock()
75120
defer p.mu.Unlock()
@@ -88,10 +133,20 @@ func (p *ProgressTracker) Complete(pkgName string) {
88133
p.render()
89134
}
90135

136+
func truncate(s string, maxLen int) string {
137+
if len(s) <= maxLen {
138+
return s
139+
}
140+
if maxLen <= 3 {
141+
return s[:maxLen]
142+
}
143+
return s[:maxLen-3] + "..."
144+
}
145+
91146
func (p *ProgressTracker) render() {
92147
percent := float64(p.completed) / float64(p.total)
93-
filled := int(percent * float64(p.width))
94-
empty := p.width - filled
148+
filled := int(percent * float64(p.barWidth))
149+
empty := p.barWidth - filled
95150

96151
bar := progressBarStyle.Render(strings.Repeat("█", filled)) +
97152
progressBgStyle.Render(strings.Repeat("░", empty))
@@ -115,13 +170,13 @@ func (p *ProgressTracker) render() {
115170
break
116171
}
117172
}
118-
if len(activeDisplay) > 20 {
119-
activeDisplay = activeDisplay[:17] + "..."
173+
suffixLen := 0
174+
if activeCount > 1 {
175+
suffixLen = len(fmt.Sprintf(" +%d", activeCount-1))
120176
}
177+
activeDisplay = truncate(activeDisplay, p.pkgWidth-suffixLen)
121178
if activeCount > 1 {
122-
activeDisplay = fmt.Sprintf("%-20s +%d", activeDisplay, activeCount-1)
123-
} else {
124-
activeDisplay = fmt.Sprintf("%-20s", activeDisplay)
179+
activeDisplay = fmt.Sprintf("%s +%d", activeDisplay, activeCount-1)
125180
}
126181
}
127182

0 commit comments

Comments
 (0)