Replies: 1 comment
-
|
$(cat <<'ENDOFBODY' Your top-level model owns a slice of progress bars and a log buffer. Each download is its own type model struct {
bars []progressModel
logs []string
width int
}
type progressModel struct {
id int
name string
progress float64
done bool
}What actually makes this work is a custom message type for progress updates. Each download goroutine sends these back through type progressMsg struct {
id int
progress float64
}
type logMsg struct {
text string
}
func runDownload(id int, name string, p *tea.Program) {
for pct := 0.0; pct <= 1.0; pct += 0.01 {
time.Sleep(50 * time.Millisecond)
p.Send(progressMsg{id: id, progress: pct})
}
p.Send(logMsg{text: fmt.Sprintf("✓ %s complete", name)})
}Your func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case progressMsg:
m.bars[msg.id].progress = msg.progress
if msg.progress >= 1.0 {
m.bars[msg.id].done = true
}
case logMsg:
m.logs = append(m.logs, msg.text)
case tea.KeyMsg:
if msg.String() == "q" || msg.String() == "ctrl+c" {
return m, tea.Quit
}
}
return m, nil
}For the func (m model) View() string {
var b strings.Builder
for _, bar := range m.bars {
filled := int(bar.progress * float64(m.width))
empty := m.width - filled
status := fmt.Sprintf("%-20s [%s%s] %3.0f%%",
bar.name,
strings.Repeat("█", filled),
strings.Repeat("░", empty),
bar.progress*100,
)
b.WriteString(status + "\n")
}
b.WriteString("\n")
// show last N log lines so it doesn't scroll forever
start := len(m.logs)
if start > 5 {
start = len(m.logs) - 5
}
for _, log := range m.logs[start:] {
b.WriteString(log + "\n")
}
return b.String()
}Kick off the downloads in your func (m model) Init() tea.Cmd {
return func() tea.Msg {
for i, bar := range m.bars {
go runDownload(i, bar.name, m.program)
}
return nil
}
}The key thing — don't try to use |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I happen to be working on a package manager supporting parallel operations, which is an exceptionally common use case in go (what with goroutines and all). This has made the progress bars very tricky, as I need to show multiple, and append new ones as previous ones finish. I have something working but it's not perfect. I would be very curious to see how bubbletea team would handle a case like this (or anyone else who has done this).
Also, bonus points if you can handle printing log messages in real time after each operation compmletes without breaking the progress bars. It's REALLY hard.
Beta Was this translation helpful? Give feedback.
All reactions