diff --git a/spin/command.go b/spin/command.go index 46ca5d5..c1b524b 100644 --- a/spin/command.go +++ b/spin/command.go @@ -19,12 +19,13 @@ 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, + spinner: s, + title: o.TitleStyle.ToLipgloss().Render(o.Title), + command: o.Command, + align: o.Align, + showOutput: (o.LiveOutput && o.ShowOutput), } - p := tea.NewProgram(m, tea.WithOutput(os.Stderr)) + p := tea.NewProgram(m) mm, err := p.Run() m = mm.(model) @@ -32,7 +33,7 @@ func (o Options) Run() error { return fmt.Errorf("failed to run spin: %w", err) } - if o.ShowOutput { + if o.ShowOutput && !o.LiveOutput { fmt.Fprint(os.Stdout, m.stdout) fmt.Fprint(os.Stderr, m.stderr) } diff --git a/spin/options.go b/spin/options.go index 920e788..34610a5 100644 --- a/spin/options.go +++ b/spin/options.go @@ -6,7 +6,8 @@ import "github.com/charmbracelet/gum/style" type Options struct { Command []string `arg:"" help:"Command to run"` - ShowOutput bool `help:"Show output of command" default:"false" env:"GUM_SPIN_SHOW_OUTPUT"` + ShowOutput bool `help:"Show output of command after its completion" default:"false" env:"GUM_SPIN_SHOW_OUTPUT"` + LiveOutput bool `help:"Show output of command in realtime" default:"false" env:"GUM_SPIN_LIVE_OUTPUT"` 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"` diff --git a/spin/spin.go b/spin/spin.go index f1dffea..bc26359 100644 --- a/spin/spin.go +++ b/spin/spin.go @@ -22,12 +22,15 @@ import ( tea "github.com/charmbracelet/bubbletea" ) +var liveBuffer strings.Builder + type model struct { - spinner spinner.Model - title string - align string - command []string - aborted bool + spinner spinner.Model + title string + align string + command []string + aborted bool + showOutput bool status int stdout string @@ -40,7 +43,7 @@ type finishCommandMsg struct { status int } -func commandStart(command []string) tea.Cmd { +func commandStart(command []string, showOutput bool) tea.Cmd { return func() tea.Msg { var args []string if len(command) > 1 { @@ -49,7 +52,11 @@ func commandStart(command []string) tea.Cmd { cmd := exec.Command(command[0], args...) //nolint:gosec var outbuf, errbuf strings.Builder - cmd.Stdout = &outbuf + if showOutput { + cmd.Stdout = &liveBuffer + } else { + cmd.Stdout = &outbuf + } cmd.Stderr = &errbuf _ = cmd.Run() @@ -71,15 +78,15 @@ func commandStart(command []string) tea.Cmd { func (m model) Init() tea.Cmd { return tea.Batch( m.spinner.Tick, - commandStart(m.command), + commandStart(m.command, m.showOutput), ) } func (m model) View() string { if m.align == "left" { - return m.spinner.View() + " " + m.title + return m.spinner.View() + " " + m.title + "\n" + liveBuffer.String() } - return m.title + " " + m.spinner.View() + return m.title + " " + m.spinner.View() + "\n" + liveBuffer.String() } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {