Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎁 Allow to change the message for the spinner #1973

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/output/tui/progress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
)

func TestProgress(t *testing.T) {
t.Parallel()
ctx := context.TestContext(t)
prt := output.NewTestPrinter()
ctx = output.WithContext(ctx, prt)
Expand Down
35 changes: 32 additions & 3 deletions pkg/output/tui/spinner.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
const spinnerColor = lipgloss.Color("205")

type Spinner interface {
Runnable[Spinner]
Runnable[SpinnerControl]
}

func (w *widgets) NewSpinner(message string) Spinner {
Expand All @@ -44,17 +44,27 @@ type BubbleSpinner struct {
output.InputOutput
Message

*updater
spin spinner.Model
tea *tea.Program
quitChan chan struct{}
teaErr error
}

func (b *BubbleSpinner) With(fn func(Spinner) error) error {
// SpinnerControl allows one to control the spinner, for example, to change the
// message.
type SpinnerControl interface {
UpdateMessage(message string)
}

// With will start the spinner and perform long operation within the
// provided fn. The spinner will be automatically shutdown when the provided
// function exits.
func (b *BubbleSpinner) With(fn func(SpinnerControl) error) error {
b.start()
err := func() error {
defer b.stop()
return fn(b)
return fn(b.updater)
}()
return multierr.Combine(err, b.teaErr)
}
Expand All @@ -70,10 +80,20 @@ func (b *BubbleSpinner) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

func (b *BubbleSpinner) View() string {
select {
case m := <-b.updater.messages:
// nil on channel close
if m != nil {
b.Message.Text = *m
}
default:
// nothing
}
return fmt.Sprintf("%s %s", b.Message.Text, b.spin.View())
}

func (b *BubbleSpinner) start() {
b.updater = &updater{make(chan *string)}
b.spin = spinner.New(
spinner.WithSpinner(spinner.Meter),
spinner.WithStyle(spinnerStyle()),
Expand All @@ -94,6 +114,7 @@ func (b *BubbleSpinner) stop() {
return
}

close(b.updater.messages)
b.tea.Quit()
<-b.quitChan

Expand All @@ -111,3 +132,11 @@ func (b *BubbleSpinner) stop() {
func spinnerStyle() lipgloss.Style {
return lipgloss.NewStyle().Foreground(spinnerColor)
}

type updater struct {
messages chan *string
}

func (u updater) UpdateMessage(message string) {
u.messages <- &message
}
14 changes: 11 additions & 3 deletions pkg/output/tui/spinner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
)

func TestSpinner(t *testing.T) {
t.Parallel()
ctx := context.TestContext(t)
prt := output.NewTestPrinter()
ctx = output.WithContext(ctx, prt)
Expand All @@ -35,14 +36,21 @@ func TestSpinner(t *testing.T) {
if s == nil {
t.Errorf("want spinner, got nil")
}
if err := s.With(func(spinner tui.Spinner) error {
time.Sleep(20 * time.Millisecond)
if err := s.With(func(sc tui.SpinnerControl) error {
time.Sleep(3 * time.Millisecond)
sc.UpdateMessage("msg-1")
time.Sleep(3 * time.Millisecond)
sc.UpdateMessage("msg-2")
time.Sleep(3 * time.Millisecond)
return nil
}); err != nil {
t.Errorf("want nil, got %v", err)
}
got := prt.Outputs().Out.String()
want := "\x1b[?25lmessage ▰▱▱\x1b[0D\x1b[2K\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006lmessage Done\n"
want := "\x1b[?25lmessage ▰▱▱\x1b[0D" +
"\x1b[0D\x1b[2Kmsg-1 ▰▰▱\x1b[0D" +
"\x1b[0D\x1b[2Kmsg-2 ▰▰▰\x1b[0D" +
"\x1b[2K\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006lmsg-2 Done\n"
if got != want {
t.Errorf("text missmatch\nwant %q,\n got %q", want, got)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/output/tui/widgets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
)

func TestNewWidgets(t *testing.T) {
t.Parallel()
ctx := context.TestContext(t)
w := tui.NewWidgets(ctx)

Expand All @@ -33,6 +34,7 @@ func TestNewWidgets(t *testing.T) {
}

func TestNewInteractiveWidgets(t *testing.T) {
t.Parallel()
ctx := context.TestContext(t)
w, err := tui.NewInteractiveWidgets(ctx)

Expand Down
Loading