Render UI directly to /dev/tty

See https://github.com/junegunn/fzf/discussions/3792

This allows us to separately capture the standard error from fzf and its
child processes, and there's less chance of user errors of redirecting
the error stream and hiding fzf.
This commit is contained in:
Junegunn Choi 2024-05-14 16:29:22 +09:00
parent 6432f00f0d
commit d274d093af
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
3 changed files with 28 additions and 5 deletions

View File

@ -73,7 +73,7 @@ func (r *LightRenderer) csi(code string) string {
func (r *LightRenderer) flush() {
if r.queued.Len() > 0 {
fmt.Fprint(os.Stderr, "\x1b[?7l\x1b[?25l"+r.queued.String()+"\x1b[?25h\x1b[?7h")
fmt.Fprint(r.ttyout, "\x1b[?7l\x1b[?25l"+r.queued.String()+"\x1b[?25h\x1b[?7h")
r.queued.Reset()
}
}
@ -88,6 +88,7 @@ type LightRenderer struct {
prevDownTime time.Time
clicks [][2]int
ttyin *os.File
ttyout *os.File
buffer []byte
origState *term.State
width int
@ -131,6 +132,10 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
if err != nil {
return nil, err
}
out, err := openTtyOut()
if err != nil {
out = os.Stderr
}
r := LightRenderer{
closed: util.NewAtomicBool(false),
theme: theme,
@ -138,6 +143,7 @@ func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop in
mouse: mouse,
clearOnExit: clearOnExit,
ttyin: in,
ttyout: out,
yoffset: 0,
tabstop: tabstop,
fullscreen: fullscreen,

View File

@ -14,6 +14,8 @@ import (
"golang.org/x/term"
)
var tty string
func IsLightRendererSupported() bool {
return true
}
@ -48,12 +50,14 @@ func (r *LightRenderer) closePlatform() {
// NOOP
}
func openTtyIn() (*os.File, error) {
in, err := os.OpenFile(consoleDevice, syscall.O_RDONLY, 0)
func openTty(mode int) (*os.File, error) {
in, err := os.OpenFile(consoleDevice, mode, 0)
if err != nil {
tty := ttyname()
if len(tty) == 0 {
tty = ttyname()
}
if len(tty) > 0 {
if in, err := os.OpenFile(tty, syscall.O_RDONLY, 0); err == nil {
if in, err := os.OpenFile(tty, mode, 0); err == nil {
return in, nil
}
}
@ -62,6 +66,14 @@ func openTtyIn() (*os.File, error) {
return in, nil
}
func openTtyIn() (*os.File, error) {
return openTty(syscall.O_RDONLY)
}
func openTtyOut() (*os.File, error) {
return openTty(syscall.O_WRONLY)
}
func (r *LightRenderer) setupTerminal() {
term.MakeRaw(r.fd())
}

View File

@ -96,6 +96,11 @@ func openTtyIn() (*os.File, error) {
return nil, nil
}
func openTtyOut() (*os.File, error) {
// not used
return nil, nil
}
func (r *LightRenderer) setupTerminal() error {
if err := windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput); err != nil {
return err