Make fzf immediately quit when failed to read /dev/tty

Close #798
This commit is contained in:
Junegunn Choi 2017-01-11 02:12:32 +09:00
parent 0c127cfdc1
commit 996dcb14a3
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
4 changed files with 32 additions and 19 deletions

View File

@ -111,8 +111,10 @@ func (r *LightRenderer) defaultTheme() *ColorTheme {
return Default16 return Default16
} }
func stty(cmd string) string { func (r *LightRenderer) stty(cmd string) string {
out, err := util.ExecCommand("stty " + cmd + " < /dev/tty").Output() proc := util.ExecCommand("stty " + cmd)
proc.Stdin = r.ttyin
out, err := proc.Output()
if err != nil { if err != nil {
// Not sure how to handle this // Not sure how to handle this
panic("stty " + cmd + ": " + err.Error()) panic("stty " + cmd + ": " + err.Error())
@ -164,8 +166,8 @@ func (r *LightRenderer) Init() {
} }
r.escDelay = delay r.escDelay = delay
r.ostty = stty("-g") r.ostty = r.stty("-g")
stty("raw") r.stty("raw")
r.updateTerminalSize() r.updateTerminalSize()
initTheme(r.theme, r.defaultTheme(), r.forceBlack) initTheme(r.theme, r.defaultTheme(), r.forceBlack)
@ -210,7 +212,7 @@ func (r *LightRenderer) origin() {
} }
func (r *LightRenderer) updateTerminalSize() { func (r *LightRenderer) updateTerminalSize() {
sizes := strings.Split(stty("size"), " ") sizes := strings.Split(r.stty("size"), " ")
if len(sizes) < 2 { if len(sizes) < 2 {
r.width = defaultWidth r.width = defaultWidth
r.height = r.maxHeightFunc(defaultHeight) 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) b := make([]byte, 1)
util.SetNonblock(r.ttyin, nonblock) util.SetNonblock(r.ttyin, nonblock)
_, err := r.ttyin.Read(b) _, err := r.ttyin.Read(b)
if err != nil { if err != nil {
return -1 return 0, false
} }
return int(b[0]) return int(b[0]), true
} }
func (r *LightRenderer) getBytes() []byte { func (r *LightRenderer) getBytes() []byte {
@ -235,7 +237,11 @@ func (r *LightRenderer) getBytes() []byte {
} }
func (r *LightRenderer) getBytesInternal(buffer []byte) []byte { func (r *LightRenderer) getBytesInternal(buffer []byte) []byte {
c := r.getch(false) c, ok := r.getch(false)
if !ok {
r.Close()
errorExit()
}
retries := 0 retries := 0
if c == ESC { if c == ESC {
@ -244,8 +250,8 @@ func (r *LightRenderer) getBytesInternal(buffer []byte) []byte {
buffer = append(buffer, byte(c)) buffer = append(buffer, byte(c))
for { for {
c = r.getch(true) c, ok = r.getch(true)
if c == -1 { if !ok {
if retries > 0 { if retries > 0 {
retries-- retries--
time.Sleep(escPollInterval * time.Millisecond) time.Sleep(escPollInterval * time.Millisecond)
@ -479,13 +485,13 @@ func (r *LightRenderer) mouseSequence(sz *int) Event {
} }
func (r *LightRenderer) Pause() { func (r *LightRenderer) Pause() {
stty(fmt.Sprintf("%q", r.ostty)) r.stty(fmt.Sprintf("%q", r.ostty))
r.csi("?1049h") r.csi("?1049h")
r.flush() r.flush()
} }
func (r *LightRenderer) Resume() bool { func (r *LightRenderer) Resume() bool {
stty("raw") r.stty("raw")
r.csi("?1049l") r.csi("?1049l")
r.flush() r.flush()
// Should redraw // Should redraw
@ -518,7 +524,7 @@ func (r *LightRenderer) Close() {
r.csi("A") r.csi("A")
} }
r.flush() r.flush()
stty(fmt.Sprintf("%q", r.ostty)) r.stty(fmt.Sprintf("%q", r.ostty))
} }
func (r *LightRenderer) MaxX() int { func (r *LightRenderer) MaxX() int {

View File

@ -110,12 +110,12 @@ func (r *FullscreenRenderer) Init() {
tty := C.c_tty() tty := C.c_tty()
if tty == nil { if tty == nil {
fmt.Println("Failed to open /dev/tty") fmt.Println("Failed to open /dev/tty")
os.Exit(2) errorExit()
} }
_screen = C.c_newterm(tty) _screen = C.c_newterm(tty)
if _screen == nil { if _screen == nil {
fmt.Println("Invalid $TERM: " + os.Getenv("TERM")) fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
os.Exit(2) errorExit()
} }
C.set_term(_screen) C.set_term(_screen)
if r.mouse { if r.mouse {
@ -375,7 +375,9 @@ func (r *FullscreenRenderer) GetChar() Event {
c := C.getch() c := C.getch()
switch c { switch c {
case C.ERR: case C.ERR:
return Event{Invalid, 0, nil} // Unexpected error from blocking read
r.Close()
errorExit()
case C.KEY_UP: case C.KEY_UP:
return Event{Up, 0, nil} return Event{Up, 0, nil}
case C.KEY_DOWN: case C.KEY_DOWN:

View File

@ -124,11 +124,11 @@ func (r *FullscreenRenderer) initScreen() {
s, e := tcell.NewScreen() s, e := tcell.NewScreen()
if e != nil { if e != nil {
fmt.Fprintf(os.Stderr, "%v\n", e) fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(2) errorExit()
} }
if e = s.Init(); e != nil { if e = s.Init(); e != nil {
fmt.Fprintf(os.Stderr, "%v\n", e) fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(2) errorExit()
} }
if r.mouse { if r.mouse {
s.EnableMouse() s.EnableMouse()

View File

@ -1,6 +1,7 @@
package tui package tui
import ( import (
"os"
"strconv" "strconv"
"time" "time"
) )
@ -275,6 +276,10 @@ func EmptyTheme() *ColorTheme {
Border: colUndefined} Border: colUndefined}
} }
func errorExit() {
os.Exit(2)
}
func init() { func init() {
Default16 = &ColorTheme{ Default16 = &ColorTheme{
Fg: colDefault, Fg: colDefault,