If the point is to insert the output of fzf
at the current cursor position, properly quoted, it should be something like:
insert-quoted-fzf-output() {
local output
output=$(fzf</dev/tty) && LBUFFER+=${(q-)output}
}
zle -N insert-quoted-fzf-output
bindkey '^X' insert-quoted-fzf-output
That is you need to insert that output at the end of $LBUFFER
(the part of the editing buffer left of the cursor), quoted (here using the q-
parameter expansion flag to minimise the amount of quoting), and you need fzf
to take its input from the terminal. You probably want the widget to return a non-zero exit status if fzf
fails.
Your specific problem about empty fzf
buffer here was about the missing </dev/tty
redirection.
You'll notice the same behaviour of fzf
if you run it as fzf < /dev/null
.
If you run info zsh widgets
(assuming you have the zsh
documentation available in info
format; on some systems, you may need to install a zsh-doc
package), you'll see (emphasis mine):
18.5 User-Defined Widgets
User-defined widgets, being implemented as shell functions, can execute
any normal shell command. They can also run other widgets (whether
built-in or user-defined) using the zle
builtin command. The standard
input of the function is redirected from /dev/null to prevent external
commands from unintentionally blocking ZLE by reading from the terminal,
but read -k
or read -q
can be used to read characters.
When its stdin is not a terminal, fzf
reads it to construct the list of choices to offer to its user. /dev/null
is a special device where any attempt to read anything returns with nothing, which explains why you get an empty buffer. Restoring a terminal there makes it switch back to the mode where instead of reading stdin for the list of choices, it reads the output of a $FZF_DEFAULT_COMMAND
command (some find
command by default).
Another option would be to actually run that find
command by yourself. If you're on a GNU system, you could even improve on it to add a bit more of reliability and efficiency:
output=$(
LC_ALL=C find -L . -name . -o '(' \
-name '.*' -o \
-fstype sysfs -o \
-fstype devfs -o \
-fstype devtmpfs -o \
-fstype proc ')' -prune -o -type f -printf '%P\0' 2> /dev/null |
fzf --read0 --print0
) && output=${output%$'\0'}