diff --git a/choose/choose.go b/choose/choose.go index c7d13a636..4e4e74b52 100644 --- a/choose/choose.go +++ b/choose/choose.go @@ -112,7 +112,6 @@ type model struct { numSelected int currentOrder int paginator paginator.Model - aborted bool timedOut bool showHelp bool help help.Model @@ -199,9 +198,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m = m.deselectAll() } case key.Matches(msg, km.Abort): - m.aborted = true m.quitting = true - return m, tea.Quit + return m, tea.Interrupt case key.Matches(msg, km.Toggle): if m.limit == 1 { break // no op diff --git a/choose/command.go b/choose/command.go index 395a3e455..591aad0a4 100644 --- a/choose/command.go +++ b/choose/command.go @@ -118,12 +118,12 @@ func (o Options) Run() error { keymap: defaultKeymap(), }, tea.WithOutput(os.Stderr)).Run() if err != nil { - return fmt.Errorf("failed to start tea program: %w", err) + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } + return fmt.Errorf("unable to pick selection: %w", err) } m := tm.(model) - if m.aborted { - return exit.ErrAborted - } if m.timedOut { return exit.ErrTimeout } diff --git a/confirm/command.go b/confirm/command.go index e31dd9fa7..1b5b5d7f5 100644 --- a/confirm/command.go +++ b/confirm/command.go @@ -2,6 +2,7 @@ package confirm import ( "errors" + "fmt" "os" "github.com/charmbracelet/bubbles/help" @@ -29,16 +30,16 @@ func (o Options) Run() error { promptStyle: o.PromptStyle.ToLipgloss(), }, tea.WithOutput(os.Stderr)).Run() if err != nil { - return err + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } + return fmt.Errorf("unable to confirm: %w", err) } m := tm.(model) if m.timedOut { return exit.ErrTimeout } - if m.aborted { - return exit.ErrAborted - } if m.confirmation { return nil } diff --git a/confirm/confirm.go b/confirm/confirm.go index 62da0bfa4..ff1f381c7 100644 --- a/confirm/confirm.go +++ b/confirm/confirm.go @@ -91,7 +91,6 @@ type model struct { affirmative string negative string quitting bool - aborted bool hasTimeout bool showHelp bool help help.Model @@ -121,8 +120,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch { case key.Matches(msg, m.keys.Abort): m.confirmation = false - m.aborted = true - fallthrough + m.quitting = true + return m, tea.Interrupt case key.Matches(msg, m.keys.Quit): m.confirmation = false m.quitting = true diff --git a/file/command.go b/file/command.go index 6c6d26e29..82b3a5ccf 100644 --- a/file/command.go +++ b/file/command.go @@ -50,7 +50,6 @@ func (o Options) Run() error { filepicker: fp, timeout: o.Timeout, hasTimeout: o.Timeout > 0, - aborted: false, showHelp: o.ShowHelp, help: help.New(), keymap: defaultKeymap(), @@ -58,12 +57,12 @@ func (o Options) Run() error { tm, err := tea.NewProgram(&m, tea.WithOutput(os.Stderr)).Run() if err != nil { + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } return fmt.Errorf("unable to pick selection: %w", err) } m = tm.(model) - if m.aborted { - return exit.ErrAborted - } if m.timedOut { return exit.ErrTimeout } diff --git a/file/file.go b/file/file.go index e8d43ca42..de1111838 100644 --- a/file/file.go +++ b/file/file.go @@ -60,7 +60,6 @@ func (k keymap) ShortHelp() []key.Binding { type model struct { filepicker filepicker.Model selectedPath string - aborted bool timedOut bool quitting bool timeout time.Duration @@ -82,9 +81,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch { case key.Matches(msg, keyAbort): - m.aborted = true m.quitting = true - return m, tea.Quit + return m, tea.Interrupt case key.Matches(msg, keyQuit): m.quitting = true return m, tea.Quit diff --git a/filter/command.go b/filter/command.go index 8b6a26837..42d83a48d 100644 --- a/filter/command.go +++ b/filter/command.go @@ -104,12 +104,12 @@ func (o Options) Run() error { tm, err := p.Run() if err != nil { - return fmt.Errorf("unable to run filter: %w", err) + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } + return fmt.Errorf("unable to pick selection: %w", err) } m := tm.(model) - if m.aborted { - return exit.ErrAborted - } if m.timedOut { return exit.ErrTimeout } diff --git a/filter/filter.go b/filter/filter.go index 676911a7f..ebd946c8d 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -264,9 +264,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { km := m.keymap switch { case key.Matches(msg, km.Abort): - m.aborted = true m.quitting = true - return m, tea.Quit + return m, tea.Interrupt case key.Matches(msg, km.Submit): m.quitting = true return m, tea.Quit diff --git a/go.mod b/go.mod index cb29197a7..7e49a9fd5 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.21 require ( github.com/alecthomas/kong v1.5.1 github.com/alecthomas/mango-kong v0.1.0 - github.com/charmbracelet/bubbles v0.20.0 - github.com/charmbracelet/bubbletea v1.2.4 + github.com/charmbracelet/bubbles v0.19.0 + github.com/charmbracelet/bubbletea v1.2.5-0.20241205214244-9306010a31ee github.com/charmbracelet/glamour v0.8.0 github.com/charmbracelet/lipgloss v1.0.0 github.com/charmbracelet/log v0.4.0 @@ -24,6 +24,7 @@ require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect + github.com/charmbracelet/x/windows v0.2.0 // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect @@ -38,12 +39,13 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/mango v0.2.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.4 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/net v0.27.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/text v0.16.0 // indirect ) diff --git a/go.sum b/go.sum index 28e9e2ca8..a27ec0e24 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,12 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= -github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= -github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= -github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= +github.com/charmbracelet/bubbles v0.19.0 h1:gKZkKXPP6GlDk6EcfujDK19PCQqRjaJZQ7QRERx1UF0= +github.com/charmbracelet/bubbles v0.19.0/go.mod h1:WILteEqZ+krG5c3ntGEMeG99nCupcuIk7V0/zOP0tOA= +github.com/charmbracelet/bubbletea v0.27.1-0.20241202144817-18bbd7ae5810 h1:+0jQnFwehsG0391XrekBzujaBYfRZNtY9+koS4FBwg8= +github.com/charmbracelet/bubbletea v0.27.1-0.20241202144817-18bbd7ae5810/go.mod h1:RYka31SjvShLlaYsbsBSiXnneU2JUEoKvI3nrOUaJuw= +github.com/charmbracelet/bubbletea v1.2.5-0.20241205214244-9306010a31ee h1:xNijbIIsd6zADvvqrQj3kfKmLqJshZpCspKAfspXkFU= +github.com/charmbracelet/bubbletea v1.2.5-0.20241205214244-9306010a31ee/go.mod h1:Hbk5+oE4a7cDyjfdPi4sHZ42aGTMYcmHnVDhsRswn7A= github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs= github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw= github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= @@ -36,6 +38,8 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b h1:MnAM github.com/charmbracelet/x/exp/golden v0.0.0-20240815200342-61de596daa2b/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/charmbracelet/x/windows v0.2.0 h1:ilXA1GJjTNkgOm94CLPeSz7rar54jtFatdmoiONPuEw= +github.com/charmbracelet/x/windows v0.2.0/go.mod h1:ZibNFR49ZFqCXgP76sYanisxRyC+EYrBE7TTknD8s1s= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= @@ -85,6 +89,8 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= @@ -96,13 +102,17 @@ golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/input/command.go b/input/command.go index 9ce22caad..34f9fe76d 100644 --- a/input/command.go +++ b/input/command.go @@ -1,6 +1,7 @@ package input import ( + "errors" "fmt" "os" @@ -45,7 +46,6 @@ func (o Options) Run() error { p := tea.NewProgram(model{ textinput: i, - aborted: false, header: o.Header, headerStyle: o.HeaderStyle.ToLipgloss(), timeout: o.Timeout, @@ -57,13 +57,13 @@ func (o Options) Run() error { }, tea.WithOutput(os.Stderr)) tm, err := p.Run() if err != nil { - return fmt.Errorf("failed to run input: %w", err) + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } + return fmt.Errorf("unable to input: %w", err) } m := tm.(model) - if m.aborted { - return exit.ErrAborted - } if m.timedOut { return exit.ErrTimeout } diff --git a/input/input.go b/input/input.go index 22388de37..62e00c1b2 100644 --- a/input/input.go +++ b/input/input.go @@ -98,11 +98,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case tea.KeyMsg: switch msg.String() { - case "ctrl+c", "esc": + case "ctrl+c": m.quitting = true - m.aborted = true - return m, tea.Quit - case "enter": + return m, tea.Interrupt + case "esc", "enter": m.quitting = true return m, tea.Quit } diff --git a/spin/command.go b/spin/command.go index a706c4077..de50d700e 100644 --- a/spin/command.go +++ b/spin/command.go @@ -1,6 +1,7 @@ package spin import ( + "errors" "fmt" "os" @@ -30,13 +31,13 @@ func (o Options) Run() error { hasTimeout: o.Timeout > 0, }, tea.WithOutput(os.Stderr)).Run() if err != nil { - return fmt.Errorf("failed to run spin: %w", err) + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } + return fmt.Errorf("unable to run action: %w", err) } m := tm.(model) - if m.aborted { - return exit.ErrAborted - } if m.timedOut { return exit.ErrTimeout } diff --git a/spin/spin.go b/spin/spin.go index 30fd95d95..c6d639f84 100644 --- a/spin/spin.go +++ b/spin/spin.go @@ -35,7 +35,6 @@ type model struct { align string command []string quitting bool - aborted bool timedOut bool status int stdout string @@ -95,7 +94,7 @@ func commandAbort() tea.Msg { if executing != nil && executing.Process != nil { _ = executing.Process.Signal(syscall.SIGINT) } - return nil + return tea.InterruptMsg{} } func (m model) Init() tea.Cmd { @@ -149,7 +148,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch msg.String() { case "ctrl+c": - m.aborted = true return m, commandAbort } } diff --git a/write/command.go b/write/command.go index 97a806f77..c04e72e17 100644 --- a/write/command.go +++ b/write/command.go @@ -1,6 +1,7 @@ package write import ( + "errors" "fmt" "os" "strings" @@ -60,13 +61,13 @@ func (o Options) Run() error { }, tea.WithOutput(os.Stderr), tea.WithReportFocus()) tm, err := p.Run() if err != nil { - return fmt.Errorf("failed to run write: %w", err) - } - m := tm.(model) - if m.aborted { - return exit.ErrAborted + if errors.Is(err, tea.ErrInterrupted) { + return exit.ErrAborted + } + return fmt.Errorf("unable to write: %w", err) } + m := tm.(model) fmt.Println(m.textarea.Value()) return nil } diff --git a/write/write.go b/write/write.go index 57fdc0748..0623d6c43 100644 --- a/write/write.go +++ b/write/write.go @@ -66,7 +66,6 @@ func defaultKeymap() keymap { type model struct { autoWidth bool - aborted bool header string headerStyle lipgloss.Style quitting bool @@ -109,18 +108,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, openEditor(msg.path, msg.lineno) case editorFinishedMsg: if msg.err != nil { - m.aborted = true m.quitting = true - return m, tea.Quit + return m, tea.Interrupt } m.textarea.SetValue(msg.content) case tea.KeyMsg: km := m.keymap switch { case key.Matches(msg, km.Quit): - m.aborted = true m.quitting = true - return m, tea.Quit + return m, tea.Interrupt case key.Matches(msg, km.Submit): m.quitting = true return m, tea.Quit