summaryrefslogtreecommitdiff
path: root/src/tui
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2024-05-23 20:08:20 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2024-05-23 21:11:12 +0900
commit3dee8778d073199e0fe1e186e54f7eabc2fdef43 (patch)
tree1c39e76cf456b176cee9c4763ddbd8447e4ce406 /src/tui
parentd4216b0dcc13567479d81cc5ad2adedb1443ea8b (diff)
downloadfzf-3dee8778d073199e0fe1e186e54f7eabc2fdef43.tar.gz
execute: Open separate handles to /dev/tty (in, out, err)
# This will no longer cause 'Vim: Warning: Output is not to a terminal' fzf --bind 'enter:execute:vim {}' > /tmp/foo
Diffstat (limited to 'src/tui')
-rw-r--r--src/tui/light.go8
-rw-r--r--src/tui/light_unix.go38
-rw-r--r--src/tui/tcell_test.go3
-rw-r--r--src/tui/ttyname_unix.go25
-rw-r--r--src/tui/ttyname_windows.go13
5 files changed, 36 insertions, 51 deletions
diff --git a/src/tui/light.go b/src/tui/light.go
index 1181d167..f202899a 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -127,11 +127,7 @@ type LightWindow struct {
bg Color
}
-func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
- in, err := openTtyIn()
- if err != nil {
- return nil, err
- }
+func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) {
out, err := openTtyOut()
if err != nil {
out = os.Stderr
@@ -142,7 +138,7 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
forceBlack: forceBlack,
mouse: mouse,
clearOnExit: clearOnExit,
- ttyin: in,
+ ttyin: ttyin,
ttyout: out,
yoffset: 0,
tabstop: tabstop,
diff --git a/src/tui/light_unix.go b/src/tui/light_unix.go
index 8d5a279b..06099d2f 100644
--- a/src/tui/light_unix.go
+++ b/src/tui/light_unix.go
@@ -7,7 +7,6 @@ import (
"os"
"os/exec"
"strings"
- "sync"
"syscall"
"github.com/junegunn/fzf/src/util"
@@ -15,13 +14,6 @@ import (
"golang.org/x/term"
)
-var (
- tty string
- ttyin *os.File
- ttyout *os.File
- mutex sync.Mutex
-)
-
func IsLightRendererSupported() bool {
return true
}
@@ -53,15 +45,13 @@ func (r *LightRenderer) initPlatform() error {
}
func (r *LightRenderer) closePlatform() {
- // NOOP
+ r.ttyout.Close()
}
func openTty(mode int) (*os.File, error) {
in, err := os.OpenFile(consoleDevice, mode, 0)
if err != nil {
- if len(tty) == 0 {
- tty = ttyname()
- }
+ tty := ttyname()
if len(tty) > 0 {
if in, err := os.OpenFile(tty, mode, 0); err == nil {
return in, nil
@@ -73,31 +63,11 @@ func openTty(mode int) (*os.File, error) {
}
func openTtyIn() (*os.File, error) {
- mutex.Lock()
- defer mutex.Unlock()
-
- if ttyin != nil {
- return ttyin, nil
- }
- in, err := openTty(syscall.O_RDONLY)
- if err == nil {
- ttyin = in
- }
- return in, err
+ return openTty(syscall.O_RDONLY)
}
func openTtyOut() (*os.File, error) {
- mutex.Lock()
- defer mutex.Unlock()
-
- if ttyout != nil {
- return ttyout, nil
- }
- out, err := openTty(syscall.O_WRONLY)
- if err == nil {
- ttyout = out
- }
- return out, err
+ return openTty(syscall.O_WRONLY)
}
func (r *LightRenderer) setupTerminal() {
diff --git a/src/tui/tcell_test.go b/src/tui/tcell_test.go
index 54b9c9b3..217ad048 100644
--- a/src/tui/tcell_test.go
+++ b/src/tui/tcell_test.go
@@ -3,6 +3,7 @@
package tui
import (
+ "os"
"testing"
"github.com/gdamore/tcell/v2"
@@ -20,7 +21,7 @@ func assert(t *testing.T, context string, got interface{}, want interface{}) boo
// Test the handling of the tcell keyboard events.
func TestGetCharEventKey(t *testing.T) {
- if util.ToTty() {
+ if util.IsTty(os.Stdout) {
// This test is skipped when output goes to terminal, because it causes
// some glitches:
// - output lines may not start at the beginning of a row which makes
diff --git a/src/tui/ttyname_unix.go b/src/tui/ttyname_unix.go
index 384115fb..d0350a0b 100644
--- a/src/tui/ttyname_unix.go
+++ b/src/tui/ttyname_unix.go
@@ -4,12 +4,19 @@ package tui
import (
"os"
+ "sync/atomic"
"syscall"
)
var devPrefixes = [...]string{"/dev/pts/", "/dev/"}
+var tty atomic.Value
+
func ttyname() string {
+ if cached := tty.Load(); cached != nil {
+ return cached.(string)
+ }
+
var stderr syscall.Stat_t
if syscall.Fstat(2, &stderr) != nil {
return ""
@@ -27,17 +34,21 @@ func ttyname() string {
continue
}
if stat, ok := info.Sys().(*syscall.Stat_t); ok && stat.Rdev == stderr.Rdev {
- return prefix + file.Name()
+ value := prefix + file.Name()
+ tty.Store(value)
+ return value
}
}
}
return ""
}
-// TtyIn returns terminal device to be used as STDIN, falls back to os.Stdin
-func TtyIn() *os.File {
- if in, err := openTtyIn(); err == nil {
- return in
- }
- return os.Stdin
+// TtyIn returns terminal device to read user input
+func TtyIn() (*os.File, error) {
+ return openTtyIn()
+}
+
+// TtyIn returns terminal device to write to
+func TtyOut() (*os.File, error) {
+ return openTtyOut()
}
diff --git a/src/tui/ttyname_windows.go b/src/tui/ttyname_windows.go
index 39b84f70..0313c608 100644
--- a/src/tui/ttyname_windows.go
+++ b/src/tui/ttyname_windows.go
@@ -2,13 +2,20 @@
package tui
-import "os"
+import (
+ "os"
+)
func ttyname() string {
return ""
}
// TtyIn on Windows returns os.Stdin
-func TtyIn() *os.File {
- return os.Stdin
+func TtyIn() (*os.File, error) {
+ return os.Stdin, nil
+}
+
+// TtyIn on Windows returns nil
+func TtyOut() (*os.File, error) {
+ return nil, nil
}