Skip to content

Commit

Permalink
fix: recover from panics within cmds
Browse files Browse the repository at this point in the history
We should recover from panics within a cmd. Currently, Bubble Tea only
recovers from panics within the eventLoop. This makes it so that it also
recovers from panics within cmd go routines.

Supersedes: #846
Fixes: #234
  • Loading branch information
aymanbagabas committed Sep 11, 2024
1 parent 7ca1b0b commit 0589921
Showing 1 changed file with 16 additions and 8 deletions.
24 changes: 16 additions & 8 deletions tea.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ func (p *Program) handleCommands(cmds chan Cmd) chan struct{} {
// possible to cancel them so we'll have to leak the goroutine
// until Cmd returns.
go func() {
// Recover from panics.
if !p.startupOptions.has(withoutCatchPanics) {
defer p.recoverFromPanic()
}

msg := cmd() // this can be long.
p.Send(msg)
}()
Expand Down Expand Up @@ -512,14 +517,7 @@ func (p *Program) Run() (Model, error) {

// Recover from panics.
if !p.startupOptions.has(withoutCatchPanics) {
defer func() {
if r := recover(); r != nil {
p.shutdown(true)
fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r)
debug.PrintStack()
return
}
}()
defer p.recoverFromPanic()
}

// If no renderer is set use the standard one.
Expand Down Expand Up @@ -691,6 +689,16 @@ func (p *Program) shutdown(kill bool) {
p.finished <- struct{}{}
}

// recoverFromPanic recovers from a panic, prints the stack trace, and restores
// the terminal to a usable state.
func (p *Program) recoverFromPanic() {
if r := recover(); r != nil {
p.shutdown(true)
fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r)
debug.PrintStack()
}
}

// ReleaseTerminal restores the original terminal state and cancels the input
// reader. You can return control to the Program with RestoreTerminal.
func (p *Program) ReleaseTerminal() error {
Expand Down

0 comments on commit 0589921

Please sign in to comment.