Skip to content

Commit

Permalink
feat: add panic handler and kill the program from the outside
Browse files Browse the repository at this point in the history
* Add Kill() to force kill the program from the outside
* Allow passing a custom panic handler when CatchPanics is enabled
  • Loading branch information
aymanbagabas authored and meowgorithm committed Feb 4, 2022
1 parent 9a06319 commit 1d190f1
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
8 changes: 8 additions & 0 deletions options.go
Expand Up @@ -130,3 +130,11 @@ func WithANSICompressor() ProgramOption {
p.startupOptions |= withANSICompressor
}
}

// WithPanicHandler sets the program's panic handler. This won't have any effect
// if the WithoutCatchPanics option was enabled.
func WithPanicHandler(f func(*Program)) ProgramOption {
return func(p *Program) {
p.panicHandler = f
}
}
37 changes: 29 additions & 8 deletions tea.go
Expand Up @@ -97,6 +97,9 @@ type Program struct {
// is on by default.
CatchPanics bool

panicHandler func(*Program)
killc chan bool

console console.Console

// Stores the original reference to stdin for cases where input is not a
Expand Down Expand Up @@ -248,6 +251,8 @@ func NewProgram(model Model, opts ...ProgramOption) *Program {
input: os.Stdin,
msgs: make(chan Msg),
CatchPanics: true,
panicHandler: defaultPanicHandler(),
killc: make(chan bool, 1),
}

// Apply all options to the program.
Expand Down Expand Up @@ -349,14 +354,7 @@ func (p *Program) StartReturningModel() (Model, error) {
}()

if p.CatchPanics {
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.panicHandler(p)
}

// Check if output is a TTY before entering raw mode, hiding the cursor and
Expand Down Expand Up @@ -486,6 +484,8 @@ func (p *Program) StartReturningModel() (Model, error) {
// Handle updates and draw.
for {
select {
case <-p.killc:
return nil, nil
case err := <-errs:
cancelContext()
waitForGoroutines(cancelReader.Cancel())
Expand Down Expand Up @@ -577,6 +577,16 @@ func (p *Program) Quit() {
p.Send(Quit())
}

// Kill stops the program immediately and restores the former terminal state.
// This final render than you would normally see when quitting will be skipped.
//
// This method is currently provisional. The method signature may alter
// slightly, or it may be removed in a future version of this package.
func (p *Program) Kill() {
p.killc <- true
p.shutdown(true)
}

// shutdown performs operations to free up resources and restore the terminal
// to its original state.
func (p *Program) shutdown(kill bool) {
Expand Down Expand Up @@ -671,3 +681,14 @@ func (p *Program) DisableMouseAllMotion() {
defer p.mtx.Unlock()
fmt.Fprintf(p.output, te.CSI+te.DisableMouseAllMotionSeq)
}

func defaultPanicHandler() func(*Program) {
return func(p *Program) {
if r := recover(); r != nil {
p.shutdown(true)
fmt.Printf("Caught panic:\n\n%s\n\nRestoring terminal...\n\n", r)
debug.PrintStack()
return
}
}
}

0 comments on commit 1d190f1

Please sign in to comment.