diff --git a/src/tui/light.go b/src/tui/light.go index 574d161..b9e90d6 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -111,8 +111,10 @@ func (r *LightRenderer) defaultTheme() *ColorTheme { return Default16 } -func stty(cmd string) string { - out, err := util.ExecCommand("stty " + cmd + " < /dev/tty").Output() +func (r *LightRenderer) stty(cmd string) string { + proc := util.ExecCommand("stty " + cmd) + proc.Stdin = r.ttyin + out, err := proc.Output() if err != nil { // Not sure how to handle this panic("stty " + cmd + ": " + err.Error()) @@ -164,8 +166,8 @@ func (r *LightRenderer) Init() { } r.escDelay = delay - r.ostty = stty("-g") - stty("raw") + r.ostty = r.stty("-g") + r.stty("raw") r.updateTerminalSize() initTheme(r.theme, r.defaultTheme(), r.forceBlack) @@ -210,7 +212,7 @@ func (r *LightRenderer) origin() { } func (r *LightRenderer) updateTerminalSize() { - sizes := strings.Split(stty("size"), " ") + sizes := strings.Split(r.stty("size"), " ") if len(sizes) < 2 { r.width = defaultWidth r.height = r.maxHeightFunc(defaultHeight) @@ -220,14 +222,14 @@ func (r *LightRenderer) updateTerminalSize() { } } -func (r *LightRenderer) getch(nonblock bool) int { +func (r *LightRenderer) getch(nonblock bool) (int, bool) { b := make([]byte, 1) util.SetNonblock(r.ttyin, nonblock) _, err := r.ttyin.Read(b) if err != nil { - return -1 + return 0, false } - return int(b[0]) + return int(b[0]), true } func (r *LightRenderer) getBytes() []byte { @@ -235,7 +237,11 @@ func (r *LightRenderer) getBytes() []byte { } func (r *LightRenderer) getBytesInternal(buffer []byte) []byte { - c := r.getch(false) + c, ok := r.getch(false) + if !ok { + r.Close() + errorExit() + } retries := 0 if c == ESC { @@ -244,8 +250,8 @@ func (r *LightRenderer) getBytesInternal(buffer []byte) []byte { buffer = append(buffer, byte(c)) for { - c = r.getch(true) - if c == -1 { + c, ok = r.getch(true) + if !ok { if retries > 0 { retries-- time.Sleep(escPollInterval * time.Millisecond) @@ -479,13 +485,13 @@ func (r *LightRenderer) mouseSequence(sz *int) Event { } func (r *LightRenderer) Pause() { - stty(fmt.Sprintf("%q", r.ostty)) + r.stty(fmt.Sprintf("%q", r.ostty)) r.csi("?1049h") r.flush() } func (r *LightRenderer) Resume() bool { - stty("raw") + r.stty("raw") r.csi("?1049l") r.flush() // Should redraw @@ -518,7 +524,7 @@ func (r *LightRenderer) Close() { r.csi("A") } r.flush() - stty(fmt.Sprintf("%q", r.ostty)) + r.stty(fmt.Sprintf("%q", r.ostty)) } func (r *LightRenderer) MaxX() int { diff --git a/src/tui/ncurses.go b/src/tui/ncurses.go index b160692..f6feefc 100644 --- a/src/tui/ncurses.go +++ b/src/tui/ncurses.go @@ -110,12 +110,12 @@ func (r *FullscreenRenderer) Init() { tty := C.c_tty() if tty == nil { fmt.Println("Failed to open /dev/tty") - os.Exit(2) + errorExit() } _screen = C.c_newterm(tty) if _screen == nil { fmt.Println("Invalid $TERM: " + os.Getenv("TERM")) - os.Exit(2) + errorExit() } C.set_term(_screen) if r.mouse { @@ -375,7 +375,9 @@ func (r *FullscreenRenderer) GetChar() Event { c := C.getch() switch c { case C.ERR: - return Event{Invalid, 0, nil} + // Unexpected error from blocking read + r.Close() + errorExit() case C.KEY_UP: return Event{Up, 0, nil} case C.KEY_DOWN: diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 460bfd5..b6f0819 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -124,11 +124,11 @@ func (r *FullscreenRenderer) initScreen() { s, e := tcell.NewScreen() if e != nil { fmt.Fprintf(os.Stderr, "%v\n", e) - os.Exit(2) + errorExit() } if e = s.Init(); e != nil { fmt.Fprintf(os.Stderr, "%v\n", e) - os.Exit(2) + errorExit() } if r.mouse { s.EnableMouse() diff --git a/src/tui/tui.go b/src/tui/tui.go index 11ac1e7..eb504f8 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -1,6 +1,7 @@ package tui import ( + "os" "strconv" "time" ) @@ -275,6 +276,10 @@ func EmptyTheme() *ColorTheme { Border: colUndefined} } +func errorExit() { + os.Exit(2) +} + func init() { Default16 = &ColorTheme{ Fg: colDefault,