Skip to content

Commit

Permalink
fix: timeouts
Browse files Browse the repository at this point in the history
  • Loading branch information
caarlos0 committed Dec 5, 2024
1 parent 7d50339 commit bd3638f
Show file tree
Hide file tree
Showing 15 changed files with 58 additions and 42 deletions.
5 changes: 3 additions & 2 deletions choose/choose.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import (
"strings"
"time"

"github.com/charmbracelet/gum/timeout"

"github.com/charmbracelet/bubbles/paginator"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/gum/timeout"
"github.com/charmbracelet/lipgloss"
)

Expand All @@ -36,6 +35,7 @@ type model struct {
currentOrder int
paginator paginator.Model
aborted bool
timedOut bool

// styles
cursorStyle lipgloss.Style
Expand Down Expand Up @@ -63,6 +63,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case timeout.TickTimeoutMsg:
if msg.TimeoutValue <= 0 {
m.quitting = true
m.timedOut = true
// If the user hasn't selected any items in a multi-select.
// Then we select the item that they have pressed enter on. If they
// have selected items, then we simply return them.
Expand Down
3 changes: 3 additions & 0 deletions choose/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ func (o Options) Run() error {
if m.aborted {
return exit.ErrAborted
}
if m.timedOut {
return exit.ErrTimeout
}
if o.Ordered && o.Limit > 1 {
sort.Slice(m.items, func(i, j int) bool {
return m.items[i].order < m.items[j].order
Expand Down
22 changes: 13 additions & 9 deletions confirm/command.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package confirm

import (
"errors"
"os"

"github.com/charmbracelet/gum/internal/exit"
Expand All @@ -11,7 +12,7 @@ import (
// Run provides a shell script interface for prompting a user to confirm an
// action with an affirmative or negative answer.
func (o Options) Run() error {
m, err := tea.NewProgram(model{
tm, err := tea.NewProgram(model{
affirmative: o.Affirmative,
negative: o.Negative,
confirmation: o.Default,
Expand All @@ -24,16 +25,19 @@ func (o Options) Run() error {
promptStyle: o.PromptStyle.ToLipgloss(),
}, tea.WithOutput(os.Stderr)).Run()
if err != nil {
return exit.Handle(err, o.Timeout)
return err
}

if m.(model).aborted {
os.Exit(exit.StatusAborted)
} else if m.(model).confirmation {
os.Exit(0)
m := tm.(model)
if m.timedOut {
return exit.ErrTimeout
}
if m.aborted {
return exit.ErrAborted
}
if m.confirmation {
return nil
}

os.Exit(1)

return nil
return errors.New("not confirmed")
}
3 changes: 2 additions & 1 deletion confirm/confirm.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type model struct {
timeout time.Duration

confirmation bool
timedOut bool

defaultSelection bool

Expand Down Expand Up @@ -75,10 +76,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, tea.Quit
}
case timeout.TickTimeoutMsg:

if msg.TimeoutValue <= 0 {
m.quitting = true
m.confirmation = m.defaultSelection
m.timedOut = true
return m, tea.Quit
}

Expand Down
5 changes: 4 additions & 1 deletion file/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ func (o Options) Run() error {
if m.aborted {
return exit.ErrAborted
}
if m.timedOut {
return exit.ErrTimeout
}
if m.selectedPath == "" {
os.Exit(1)
return errors.New("no file selected")
}

fmt.Println(m.selectedPath)
Expand Down
3 changes: 2 additions & 1 deletion file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type model struct {
filepicker filepicker.Model
selectedPath string
aborted bool
timedOut bool
quitting bool
timeout time.Duration
hasTimeout bool
Expand All @@ -48,7 +49,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case timeout.TickTimeoutMsg:
if msg.TimeoutValue <= 0 {
m.quitting = true
m.aborted = true
m.timedOut = true
return m, tea.Quit
}
m.timeout = msg.TimeoutValue
Expand Down
3 changes: 3 additions & 0 deletions filter/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ func (o Options) Run() error {
if m.aborted {
return exit.ErrAborted
}
if m.timedOut {
return exit.ErrTimeout
}

isTTY := term.IsTerminal(os.Stdout.Fd())

Expand Down
3 changes: 2 additions & 1 deletion filter/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type model struct {
unselectedPrefix string
height int
aborted bool
timedOut bool
quitting bool
headerStyle lipgloss.Style
matchStyle lipgloss.Style
Expand Down Expand Up @@ -161,7 +162,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case timeout.TickTimeoutMsg:
if msg.TimeoutValue <= 0 {
m.quitting = true
m.aborted = true
m.timedOut = true
return m, tea.Quit
}
m.timeout = msg.TimeoutValue
Expand Down
5 changes: 4 additions & 1 deletion input/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@ func (o Options) Run() error {
if err != nil {
return fmt.Errorf("failed to run input: %w", err)
}
m := tm.(model)

m := tm.(model)
if m.aborted {
return exit.ErrAborted
}
if m.timedOut {
return exit.ErrTimeout
}

fmt.Println(m.textinput.Value())
return nil
Expand Down
3 changes: 2 additions & 1 deletion input/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type model struct {
headerStyle lipgloss.Style
textinput textinput.Model
quitting bool
timedOut bool
aborted bool
timeout time.Duration
hasTimeout bool
Expand Down Expand Up @@ -51,7 +52,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case timeout.TickTimeoutMsg:
if msg.TimeoutValue <= 0 {
m.quitting = true
m.aborted = true
m.timedOut = true
return m, tea.Quit
}
m.timeout = msg.TimeoutValue
Expand Down
14 changes: 1 addition & 13 deletions internal/exit/exit.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package exit

import (
"errors"
"fmt"
"time"
)
import "errors"

// StatusTimeout is the exit code for timed out commands.
const StatusTimeout = 124
Expand All @@ -17,11 +13,3 @@ var ErrAborted = errors.New("user aborted")

// ErrTimeout is the error returned when the timeout is reached.
var ErrTimeout = errors.New("timeout")

// Handle handles the error.
func Handle(err error, d time.Duration) error {
if errors.Is(err, ErrTimeout) {
return fmt.Errorf("%w after %s", ErrTimeout, d)
}
return err
}
12 changes: 9 additions & 3 deletions pager/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/gum/internal/exit"
"github.com/charmbracelet/gum/internal/stdin"
)

Expand All @@ -29,7 +30,7 @@ func (o Options) Run() error {
}
}

model := model{
tm, err := tea.NewProgram(model{
viewport: vp,
helpStyle: o.HelpStyle.ToLipgloss(),
content: o.Content,
Expand All @@ -41,10 +42,15 @@ func (o Options) Run() error {
matchHighlightStyle: o.MatchHighlightStyle.ToLipgloss(),
timeout: o.Timeout,
hasTimeout: o.Timeout > 0,
}
_, err := tea.NewProgram(model, tea.WithAltScreen()).Run()
}, tea.WithAltScreen()).Run()
if err != nil {
return fmt.Errorf("unable to start program: %w", err)
}

m := tm.(model)
if m.timedOut {
return exit.ErrTimeout
}

return nil
}
2 changes: 2 additions & 0 deletions pager/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type model struct {
maxWidth int
timeout time.Duration
hasTimeout bool
timedOut bool
}

func (m model) Init() tea.Cmd {
Expand All @@ -40,6 +41,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case timeout.TickTimeoutMsg:
if msg.TimeoutValue <= 0 {
m.timedOut = true
return m, tea.Quit
}
m.timeout = msg.TimeoutValue
Expand Down
12 changes: 6 additions & 6 deletions spin/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (o Options) Run() error {
s := spinner.New()
s.Style = o.SpinnerStyle.ToLipgloss()
s.Spinner = spinnerMap[o.Spinner]
m := model{
tm, err := tea.NewProgram(model{
spinner: s,
title: o.TitleStyle.ToLipgloss().Render(o.Title),
command: o.Command,
Expand All @@ -28,18 +28,18 @@ func (o Options) Run() error {
showError: o.ShowError,
timeout: o.Timeout,
hasTimeout: o.Timeout > 0,
}
p := tea.NewProgram(m, tea.WithOutput(os.Stderr))
mm, err := p.Run()
m = mm.(model)

}, tea.WithOutput(os.Stderr)).Run()
if err != nil {
return fmt.Errorf("failed to run spin: %w", err)
}

m := tm.(model)
if m.aborted {
return exit.ErrAborted
}
if m.timedOut {
return exit.ErrTimeout
}

// If the command succeeds, and we are printing output and we are in a TTY then push the STDOUT we got to the actual
// STDOUT for piping or other things.
Expand Down
5 changes: 2 additions & 3 deletions spin/spin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"syscall"
"time"

"github.com/charmbracelet/gum/internal/exit"
"github.com/charmbracelet/gum/timeout"
"github.com/charmbracelet/x/term"

Expand All @@ -37,6 +36,7 @@ type model struct {
command []string
quitting bool
aborted bool
timedOut bool
status int
stdout string
stderr string
Expand Down Expand Up @@ -134,8 +134,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if msg.TimeoutValue <= 0 {
// grab current output before closing for piped instances
m.stdout = outbuf.String()

m.status = exit.StatusAborted
m.timedOut = true
return m, tea.Quit
}
m.timeout = msg.TimeoutValue
Expand Down

0 comments on commit bd3638f

Please sign in to comment.