fzf
fzf copied to clipboard
fzf --height hangs on FreeBSD virtual terminals
- [x] I have read through the manual page (
man fzf
) - [x] I have the latest version of fzf
- [x] I have searched through the existing issues
Info
- OS
- [ ] Linux
- [ ] Mac OS X
- [ ] Windows
- [x] Etc.
- Shell
- [ ] bash
- [x] zsh
- [ ] fish
Problem / Steps to reproduce
In FreeBSD's virtual terminals, things like Ctrl+T have always hung for me until I typed a few characters. I tracked it down today.
fzf
by itself works fine, but fzf --height=40%
hangs. The issue is the findOffset()
call: https://github.com/junegunn/fzf/blob/885cd8ff04e73d61279f0ac58011f74613e809dd/src/tui/light.go#L162
findOffset()
basically does write("\033[6n")
and then read()
s the response from the terminal: https://github.com/junegunn/fzf/blob/885cd8ff04e73d61279f0ac58011f74613e809dd/src/tui/light_unix.go#L85-L90
nonblock
is set to tries > 0
, so the first read attempt is blocking. Unfortunately, FreeBSD VTs never respond to any escape sequences, so the first read hangs until I press a key. The next offsetPollTries - 1 == 9
reads are non-blocking, so they time out eventually.
I tried a simple patch:
@@ -87,7 +87,7 @@ func (r *LightRenderer) findOffset() (row int, col int) {
r.flush()
bytes := []byte{}
for tries := 0; tries < offsetPollTries; tries++ {
- bytes = r.getBytesInternal(bytes, tries > 0)
+ bytes = r.getBytesInternal(bytes, true)
offsets := offsetRegexp.FindSubmatch(bytes)
if len(offsets) > 3 {
// Add anything we skipped over to the input buffer
and now instead of hanging I just get a ~1s delay at startup. The delay can be reduced by decreasing offsetPollTries
, but I don't know if that's likely to break anything.
Rather than a retry loop, I think the best way to implement writing a terminal command and reading the response is something like
- set raw mode
- read tty until EOF, save to buffer
- write
\033[6n
to tty -
poll()
forPOLLIN
with a timeout- if successful
- read from tty
- parse an escape sequence, if present
- buffer anything else
- if successful
But I don't know enough Go to try implementing that.