mirror of
https://github.com/charmbracelet/gum
synced 2024-05-09 17:56:37 +02:00
feat(Spin): Option to show live output (#303)
* Added live output buffer and option flag * Update Spin on README.md * Returned output formatting to previous version. * Separated the showOutput and liveOutput flags. Both flags can now be used at once. * Removed liveOutout flag showOutput flag is now realtime * (spin) Consolodated stderr and stdout * (spin) Consolodated stdout and stderr * (spin) If being piped, writes to stdout * Added error check and did some housekeeping * No longer outputs to tea.View if piped * Cleaned up the combining of stderr and stdout * Fixed spinner alignment. Updated Readme
This commit is contained in:
parent
f1b99f0aa4
commit
f048bd8d87
|
@ -294,6 +294,8 @@ gum pager < README.md
|
|||
Display a spinner while running a script or command. The spinner will
|
||||
automatically stop after the given command exits.
|
||||
|
||||
To view or pipe the command's output, use the `--show-output` flag.
|
||||
|
||||
```bash
|
||||
gum spin --spinner dot --title "Buying Bubble Gum..." -- sleep 5
|
||||
```
|
||||
|
|
|
@ -15,14 +15,19 @@ import (
|
|||
// Run provides a shell script interface for the spinner bubble.
|
||||
// https://github.com/charmbracelet/bubbles/spinner
|
||||
func (o Options) Run() error {
|
||||
var isTTY bool
|
||||
info, err := os.Stdout.Stat()
|
||||
isTTY = info.Mode()&os.ModeCharDevice == os.ModeCharDevice
|
||||
|
||||
s := spinner.New()
|
||||
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.ShowOutput && isTTY,
|
||||
}
|
||||
p := tea.NewProgram(m, tea.WithOutput(os.Stderr))
|
||||
mm, err := p.Run()
|
||||
|
@ -32,15 +37,23 @@ func (o Options) Run() error {
|
|||
return fmt.Errorf("failed to run spin: %w", err)
|
||||
}
|
||||
|
||||
if o.ShowOutput {
|
||||
fmt.Fprint(os.Stdout, m.stdout)
|
||||
fmt.Fprint(os.Stderr, m.stderr)
|
||||
}
|
||||
|
||||
if m.aborted {
|
||||
return exit.ErrAborted
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to access stdout: %w", err)
|
||||
}
|
||||
|
||||
if o.ShowOutput {
|
||||
if !isTTY {
|
||||
_, err := os.Stdout.WriteString(m.stdout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write to stdout: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(m.status)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ 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 or pipe output of command during execution" default:"false" env:"GUM_SPIN_SHOW_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"`
|
||||
|
|
36
spin/spin.go
36
spin/spin.go
|
@ -20,23 +20,25 @@ import (
|
|||
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
spinner spinner.Model
|
||||
title string
|
||||
align string
|
||||
command []string
|
||||
aborted bool
|
||||
|
||||
status int
|
||||
stdout string
|
||||
stderr string
|
||||
spinner spinner.Model
|
||||
title string
|
||||
align string
|
||||
command []string
|
||||
aborted bool
|
||||
status int
|
||||
stdout string
|
||||
showOutput bool
|
||||
}
|
||||
|
||||
var outbuf strings.Builder
|
||||
var errbuf strings.Builder
|
||||
|
||||
type finishCommandMsg struct {
|
||||
stdout string
|
||||
stderr string
|
||||
status int
|
||||
}
|
||||
|
||||
|
@ -48,7 +50,6 @@ func commandStart(command []string) tea.Cmd {
|
|||
}
|
||||
cmd := exec.Command(command[0], args...) //nolint:gosec
|
||||
|
||||
var outbuf, errbuf strings.Builder
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
|
||||
|
@ -62,7 +63,6 @@ func commandStart(command []string) tea.Cmd {
|
|||
|
||||
return finishCommandMsg{
|
||||
stdout: outbuf.String(),
|
||||
stderr: errbuf.String(),
|
||||
status: status,
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,16 @@ func (m model) Init() tea.Cmd {
|
|||
)
|
||||
}
|
||||
func (m model) View() string {
|
||||
var header string
|
||||
if m.align == "left" {
|
||||
return m.spinner.View() + " " + m.title
|
||||
header = m.spinner.View() + " " + m.title
|
||||
} else {
|
||||
header = m.title + " " + m.spinner.View()
|
||||
}
|
||||
|
||||
return m.title + " " + m.spinner.View()
|
||||
if !m.showOutput {
|
||||
return header
|
||||
}
|
||||
return lipgloss.JoinVertical(lipgloss.Top, header, errbuf.String(), outbuf.String())
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
|
@ -87,7 +92,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
switch msg := msg.(type) {
|
||||
case finishCommandMsg:
|
||||
m.stdout = msg.stdout
|
||||
m.stderr = msg.stderr
|
||||
m.status = msg.status
|
||||
return m, tea.Quit
|
||||
case tea.KeyMsg:
|
||||
|
|
Loading…
Reference in a new issue