Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 9 additions & 8 deletions spin/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ func (o Options) Run() error {
s.Style = o.SpinnerStyle.ToLipgloss()
s.Spinner = spinnerMap[o.Spinner]
m := model{
spinner: s,
title: o.TitleStyle.ToLipgloss().Render(o.Title),
command: o.Command,
align: o.Align,
showStdout: (o.ShowOutput || o.ShowStdout) && isOutTTY,
showStderr: (o.ShowOutput || o.ShowStderr) && isErrTTY,
showError: o.ShowError,
isTTY: isErrTTY,
spinner: s,
title: o.TitleStyle.ToLipgloss().Render(o.Title),
command: o.Command,
align: o.Align,
showStdout: (o.ShowOutput || o.ShowStdout) && isOutTTY,
showStderr: (o.ShowOutput || o.ShowStderr) && isErrTTY,
showError: o.ShowError,
showElapsed: o.ShowElapsed,
isTTY: isErrTTY,
}

ctx, cancel := timeout.Context(o.Timeout)
Expand Down
1 change: 1 addition & 0 deletions spin/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Options struct {
ShowError bool `help:"Show output of command only if the command fails" default:"false" env:"GUM_SPIN_SHOW_ERROR"`
ShowStdout bool `help:"Show STDOUT output" default:"false" env:"GUM_SPIN_SHOW_STDOUT"`
ShowStderr bool `help:"Show STDERR errput" default:"false" env:"GUM_SPIN_SHOW_STDERR"`
ShowElapsed bool `help:"Show elapsed timer" default:"false"`
Spinner string `help:"Spinner type" short:"s" type:"spinner" enum:"line,dot,minidot,jump,pulse,points,globe,moon,monkey,meter,hamburger" default:"dot" env:"GUM_SPIN_SPINNER"`
SpinnerStyle style.Styles `embed:"" prefix:"spinner." set:"defaultForeground=212" envprefix:"GUM_SPIN_SPINNER_"`
Title string `help:"Text to display to user while spinning" default:"Loading..." env:"GUM_SPIN_TITLE"`
Expand Down
67 changes: 52 additions & 15 deletions spin/spin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ package spin
import (
"bytes"
"context"
"fmt"
"io"
"os"
"os/exec"
"runtime"
"syscall"
"time"

"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
Expand All @@ -30,20 +32,22 @@ import (
)

type model struct {
spinner spinner.Model
title string
align string
command []string
quitting bool
isTTY bool
status int
stdout string
stderr string
output string
showStdout bool
showStderr bool
showError bool
err error
spinner spinner.Model
title string
align string
command []string
quitting bool
isTTY bool
status int
stdout string
stderr string
output string
showStdout bool
showStderr bool
showError bool
showElapsed bool
err error
started time.Time
}

var (
Expand All @@ -56,6 +60,10 @@ var (

type errorMsg error

type startMsg struct {
started time.Time
}

type finishCommandMsg struct {
stdout string
stderr string
Expand Down Expand Up @@ -137,10 +145,31 @@ func commandAbort() tea.Msg {
return tea.InterruptMsg{}
}

func formatDuration(d time.Duration) string {
days := int(d.Hours()) / 24
hours := int(d.Hours()) % 24
minutes := int(d.Minutes()) % 60
seconds := int(d.Seconds()) % 60

if days > 0 {
return fmt.Sprintf("(%dd %dh %dm)", days, hours, minutes)
} else if hours > 0 {
return fmt.Sprintf("(%dh %dm)", hours, minutes)
} else if minutes > 0 {
return fmt.Sprintf("(%dm %ds)", minutes, seconds)
}
return fmt.Sprintf("(%ds)", seconds)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this provide enough additional value over plain Sprintf? 🤔

fmt.Sprintf("duration: %s", d)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean showing only the seconds? or formatting time.Now()?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean formatting the duration. I realize we should round, but this:

var start = time.Now()
for true {
  time.Sleep(100 * time.Millisecond)
  fmt.Printf("%s\n", time.Since(start).Round(100*time.Millisecond))
}

creates output like

59.6s
59.7s
59.9s
1m0s
1m0.1s
1m0.2s
1m0.3s

Which is basically what you propose, sans the spaces. Hence my question, if you think the visual difference justifies the additional code.

(Not my call, just a thought.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not aware of this format specifier.
I would say since Gum is reliant on being User Friendly and good looking.
a 10 line function would justify it. I could make the formatting better too, if you have something in mind.
Its up to you though. So let me know and Ill change it.


func (m model) Init() tea.Cmd {
return tea.Batch(
m.spinner.Tick,
commandStart(m.command),
func() tea.Msg {
return startMsg{
started: time.Now(),
}
},
)
}

Expand All @@ -161,17 +190,25 @@ func (m model) View() string {
return m.title
}

elapsed := ""
if m.showElapsed {
elapsed = formatDuration(time.Since(m.started))
}

var header string
if m.align == "left" {
header = m.spinner.View() + " " + m.title
} else {
header = m.title + " " + m.spinner.View()
}
return header + "\n" + out
return header + elapsed + "\n" + out
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case startMsg:
m.started = msg.started
return m, nil
case finishCommandMsg:
m.stdout = msg.stdout
m.stderr = msg.stderr
Expand Down