summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2025-03-03 14:01:53 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2025-03-03 14:04:16 +0900
commit8916cbc6ab198abdfa1e5cb24602c13730cb1987 (patch)
treeaf47becaf47d378971471725a95f92eced5582d2 /src
parent21ce70054f4f65efafcd056d1101f1040187c8d4 (diff)
downloadfzf-8916cbc6ab198abdfa1e5cb24602c13730cb1987.tar.gz
[windows] Prevent fzf from consuming user input while paused
This partly fixes #4260. fzf still can consume the first key stroke.
Diffstat (limited to 'src')
-rw-r--r--src/tui/light.go7
-rw-r--r--src/tui/light_windows.go63
2 files changed, 39 insertions, 31 deletions
diff --git a/src/tui/light.go b/src/tui/light.go
index acd07ab7..3b940646 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -8,6 +8,7 @@ import (
"regexp"
"strconv"
"strings"
+ "sync"
"time"
"unicode/utf8"
@@ -95,7 +96,6 @@ func (r *LightRenderer) flushRaw(sequence string) {
// Light renderer
type LightRenderer struct {
- closed *util.AtomicBool
theme *ColorTheme
mouse bool
forceBlack bool
@@ -120,6 +120,7 @@ type LightRenderer struct {
showCursor bool
// Windows only
+ mutex sync.Mutex
ttyinChannel chan byte
inHandle uintptr
outHandle uintptr
@@ -151,7 +152,6 @@ func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse
out = os.Stderr
}
r := LightRenderer{
- closed: util.NewAtomicBool(false),
theme: theme,
forceBlack: forceBlack,
mouse: mouse,
@@ -775,9 +775,8 @@ func (r *LightRenderer) Close() {
}
r.disableMouse()
r.flush()
- r.closePlatform()
r.restoreTerminal()
- r.closed.Set(true)
+ r.closePlatform()
}
func (r *LightRenderer) Top() int {
diff --git a/src/tui/light_windows.go b/src/tui/light_windows.go
index cf5126ab..f29e018c 100644
--- a/src/tui/light_windows.go
+++ b/src/tui/light_windows.go
@@ -18,6 +18,7 @@ const (
var (
consoleFlagsInput = uint32(windows.ENABLE_VIRTUAL_TERMINAL_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_EXTENDED_FLAGS)
consoleFlagsOutput = uint32(windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | windows.ENABLE_PROCESSED_OUTPUT | windows.DISABLE_NEWLINE_AUTO_RETURN)
+ counter = uint64(0)
)
// IsLightRendererSupported checks to see if the Light renderer is supported
@@ -61,27 +62,11 @@ func (r *LightRenderer) initPlatform() error {
}
r.inHandle = uintptr(inHandle)
- r.setupTerminal()
-
// channel for non-blocking reads. Buffer to make sure
// we get the ESC sets:
r.ttyinChannel = make(chan byte, 1024)
- // the following allows for non-blocking IO.
- // syscall.SetNonblock() is a NOOP under Windows.
- go func() {
- fd := int(r.inHandle)
- b := make([]byte, 1)
- for !r.closed.Get() {
- // HACK: if run from PSReadline, something resets ConsoleMode to remove ENABLE_VIRTUAL_TERMINAL_INPUT.
- _ = windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput)
-
- _, err := util.Read(fd, b)
- if err == nil {
- r.ttyinChannel <- b[0]
- }
- }
- }()
+ r.setupTerminal()
return nil
}
@@ -100,18 +85,42 @@ func openTtyOut() (*os.File, error) {
return os.Stderr, nil
}
-func (r *LightRenderer) setupTerminal() error {
- if err := windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput); err != nil {
- return err
- }
- return windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput)
+func (r *LightRenderer) setupTerminal() {
+ windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput)
+ windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput)
+
+ // The following allows for non-blocking IO.
+ // syscall.SetNonblock() is a NOOP under Windows.
+ current := counter
+ go func() {
+ fd := int(r.inHandle)
+ b := make([]byte, 1)
+ for {
+ if _, err := util.Read(fd, b); err == nil {
+ r.mutex.Lock()
+ // This condition prevents the goroutine from running after the renderer
+ // has been closed or paused.
+ if current != counter {
+ r.mutex.Unlock()
+ break
+ }
+ r.ttyinChannel <- b[0]
+ // HACK: if run from PSReadline, something resets ConsoleMode to remove ENABLE_VIRTUAL_TERMINAL_INPUT.
+ windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput)
+ r.mutex.Unlock()
+ }
+ }
+ }()
}
-func (r *LightRenderer) restoreTerminal() error {
- if err := windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput); err != nil {
- return err
- }
- return windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput)
+func (r *LightRenderer) restoreTerminal() {
+ r.mutex.Lock()
+ counter++
+ // We're setting ENABLE_VIRTUAL_TERMINAL_INPUT to allow escape sequences to be read during 'execute'.
+ // e.g. fzf --bind 'enter:execute:less {}'
+ windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput|windows.ENABLE_VIRTUAL_TERMINAL_INPUT)
+ windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput)
+ r.mutex.Unlock()
}
func (r *LightRenderer) Size() TermSize {