From 3b9ddb34a696fd32f5963efca6c09dc5ce0af17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 21 Mar 2024 17:36:37 +0100 Subject: [PATCH 1/3] Fix the hang of the spinner on stop --- pkg/output/tui/spinner.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/output/tui/spinner.go b/pkg/output/tui/spinner.go index 91fd762e..33f57f4c 100644 --- a/pkg/output/tui/spinner.go +++ b/pkg/output/tui/spinner.go @@ -36,6 +36,7 @@ func (w *widgets) NewSpinner(message string) Spinner { return &BubbleSpinner{ InputOutput: output.PrinterFrom(w.ctx), Message: Message{Text: message}, + quitChan: make(chan struct{}), } } @@ -43,8 +44,9 @@ type BubbleSpinner struct { output.InputOutput Message - spin spinner.Model - tea *tea.Program + spin spinner.Model + tea *tea.Program + quitChan chan struct{} } func (b *BubbleSpinner) With(fn func(Spinner) error) error { @@ -80,6 +82,7 @@ func (b *BubbleSpinner) start() { go func() { t := b.tea _, _ = t.Run() + close(b.quitChan) if term.IsTerminal(out) { _ = t.ReleaseTerminal() } @@ -91,7 +94,7 @@ func (b *BubbleSpinner) stop() { return } b.tea.Quit() - b.tea.Wait() + <-b.quitChan b.tea = nil endMsg := fmt.Sprintf("%s %s\n", b.Message.Text, spinnerStyle().Render("Done")) From 0ff3298a553c4fec8c69acfa8ee62a1ed08841e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 21 Mar 2024 18:18:52 +0100 Subject: [PATCH 2/3] Fix the ProgressBar hanging forever at quit --- pkg/output/tui/progress.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/output/tui/progress.go b/pkg/output/tui/progress.go index b9108a38..4bd8703b 100644 --- a/pkg/output/tui/progress.go +++ b/pkg/output/tui/progress.go @@ -78,7 +78,7 @@ type BubbleProgress struct { speed int prevSpeed []int err error - ended chan struct{} + quitChan chan struct{} } func (b *BubbleProgress) With(fn func(ProgressControl) error) error { @@ -235,11 +235,11 @@ func (b *BubbleProgress) start() { tea.WithInput(b.InOrStdin()), tea.WithOutput(out), ) - b.ended = make(chan struct{}) + b.quitChan = make(chan struct{}) go func() { t := b.tea _, _ = t.Run() - close(b.ended) + close(b.quitChan) if term.IsTerminal(out) { if err := t.ReleaseTerminal(); err != nil { panic(err) @@ -252,11 +252,10 @@ func (b *BubbleProgress) stop() { if b.tea == nil { return } - b.tea.Wait() - - <-b.ended + b.tea.Quit() + <-b.quitChan b.tea = nil - b.ended = nil + b.quitChan = nil } func (b *BubbleProgress) onProgress(percent float64) { From dd86562b1fa41df2a034b23ee71e09ec72f88f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 21 Mar 2024 20:23:11 +0100 Subject: [PATCH 3/3] Wait for natural end for progress bar --- pkg/output/tui/progress.go | 16 ++++++++++++---- pkg/output/tui/spinner.go | 5 ++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pkg/output/tui/progress.go b/pkg/output/tui/progress.go index 4bd8703b..cb26f70f 100644 --- a/pkg/output/tui/progress.go +++ b/pkg/output/tui/progress.go @@ -175,17 +175,23 @@ func (b bubbleProgressHandler) speedChange() (tea.Model, tea.Cmd) { } func (b bubbleProgressHandler) percentChange(event percentChange) (tea.Model, tea.Cmd) { - var cmds []tea.Cmd - + cmds := make([]tea.Cmd, 0, 1) cmds = append(cmds, b.prog.SetPercent(float64(event))) if event >= 1.0 { - cmds = append(cmds, tea.Sequence(b.finalPause(), tea.Quit)) + cmds = append(cmds, b.quitSignal()) } return b, tea.Batch(cmds...) } +func (b *BubbleProgress) quitSignal() tea.Cmd { + // The final pause is to give the progress bar a chance to finish its + // animation before quitting. Otherwise, it ends abruptly, and the user + // might not see the progress bar at 100%. + return tea.Sequence(b.finalPause(), tea.Quit) +} + func (b bubbleProgressHandler) progressFrame(event progress.FrameMsg) (tea.Model, tea.Cmd) { progressModel, cmd := b.prog.Update(event) if m, ok := progressModel.(progress.Model); ok { @@ -252,8 +258,10 @@ func (b *BubbleProgress) stop() { if b.tea == nil { return } - b.tea.Quit() + + b.tea.Send(b.quitSignal()) <-b.quitChan + b.tea = nil b.quitChan = nil } diff --git a/pkg/output/tui/spinner.go b/pkg/output/tui/spinner.go index 33f57f4c..438ef358 100644 --- a/pkg/output/tui/spinner.go +++ b/pkg/output/tui/spinner.go @@ -36,7 +36,6 @@ func (w *widgets) NewSpinner(message string) Spinner { return &BubbleSpinner{ InputOutput: output.PrinterFrom(w.ctx), Message: Message{Text: message}, - quitChan: make(chan struct{}), } } @@ -79,6 +78,7 @@ func (b *BubbleSpinner) start() { tea.WithInput(b.InOrStdin()), tea.WithOutput(out), ) + b.quitChan = make(chan struct{}) go func() { t := b.tea _, _ = t.Run() @@ -93,9 +93,12 @@ func (b *BubbleSpinner) stop() { if b.tea == nil { return } + b.tea.Quit() <-b.quitChan + b.tea = nil + b.quitChan = nil endMsg := fmt.Sprintf("%s %s\n", b.Message.Text, spinnerStyle().Render("Done")) _, _ = b.OutOrStdout().Write([]byte(endMsg))