Make rendering panic-friendly

Raise a panic from un-recovered .Buffer() call will leave your terminal messed up. Add recover to internal rendering chan to close termui before program exit.
This commit is contained in:
Zack Guo 2016-11-03 13:10:55 -04:00
parent d29684eba4
commit 806f4377c8

View File

@ -6,9 +6,19 @@ package termui
import ( import (
"image" "image"
"io"
"sync" "sync"
"time" "time"
"fmt"
"os"
"runtime/debug"
"bytes"
"github.com/maruel/panicparse/stack"
tm "github.com/nsf/termbox-go" tm "github.com/nsf/termbox-go"
) )
@ -89,7 +99,26 @@ func TermHeight() int {
// Render renders all Bufferer in the given order from left to right, // Render renders all Bufferer in the given order from left to right,
// right could overlap on left ones. // right could overlap on left ones.
func render(bs ...Bufferer) { func render(bs ...Bufferer) {
defer func() {
if e := recover(); e != nil {
Close()
fmt.Fprintf(os.Stderr, "Captured a panic(value=%v) when rendering Bufferer. Exit termui and clean terminal...\nPrint stack trace:\n\n", e)
//debug.PrintStack()
gs, err := stack.ParseDump(bytes.NewReader(debug.Stack()), os.Stderr)
if err != nil {
debug.PrintStack()
os.Exit(1)
}
p := &stack.Palette{}
buckets := stack.SortBuckets(stack.Bucketize(gs, stack.AnyValue))
srcLen, pkgLen := stack.CalcLengths(buckets, false)
for _, bucket := range buckets {
io.WriteString(os.Stdout, p.BucketHeader(&bucket, false, len(buckets) > 1))
io.WriteString(os.Stdout, p.StackLines(&bucket.Signature, srcLen, pkgLen, false))
}
os.Exit(1)
}
}()
for _, b := range bs { for _, b := range bs {
buf := b.Buffer() buf := b.Buffer()