Bash – Populate Selected Candidates to Terminal After Fuzzy Search with fzf via Keybinding

bashcommand lineshell-scriptzsh

With this plugin we can fuzzy search through candidates of apt packages.

the output of running it as below:

# apt zzuf zziplib-bin zytrax

The code in the link (I put if [[ "${BASH_<...> fi to a function my-fuzzy-test):

#!/usr/bin/env bash
function insert_stdin {
    # if this wouldn't be an external script
    # we could use 'print -z' in zsh to edit the line buffer
    stty -echo
    perl -e 'ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV;' \
        "$@"
}
function my-fuzzy-test() {
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    packages="$(apt list --verbose 2>/dev/null | \
        # remove "Listing..."
        tail --lines +2 | \
        # place the description on the same line
        # separate the description and the other information
        # with a ^
        sd $'\n {2}([^ ])' $'^$1' | \
        # place the package information and the package description
        # in a table with two columns
        column -t -s^ | \
        # select packages with fzf
        fzf --multi | \
        # remove everything except the package name
        cut --delimiter '/' --fields 1 | \
        # escape selected packages (to avoid unwanted code execution)
        # and remove line breaks
        xargs --max-args 1 --no-run-if-empty printf "%q ")"

    if [[ -n "${packages}" ]]; then
        insert_stdin "# apt ${@}" "${packages}"
    fi
fi
}

I put above code in ~/.zshrc and map my-fuzzy-test to a keybinding:

zle -N my-fuzzy-test
bindkey "^[k" my-fuzzy-test

as press alt-k to trigger my-fuzzy-test function, it showed nothing when press alt-k.
If I remove line if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then and fi at the end, then it can trigger the function but it can't display expected output as above and echoes error stty: 'standard input': Inappropriate ioctl for device

I know we can populate candidates into terminal's prompt as in this code as below:

# CTRL-R - Paste the selected command from history into the command line
fzf-history-widget() {
  local selected num
  setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
  selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\s+(.*)/, $1)}++' |
    FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
  local ret=$?
  if [ -n "$selected" ]; then
    num=$selected[1]
    if [ -n "$num" ]; then
      zle vi-fetch-history -n $num
    fi
  fi
  zle reset-prompt
  return $ret
}
zle     -N   fzf-history-widget
bindkey '^R' fzf-history-widget

So how can I correctly populate candidate to terminal's prompt with my-fuzzy-test?

Best Answer

That Ctrl-R widget uses zle vi-fetch-history to insert history matches, which is not applicable to what you're doing here.

What you need to do is insert the matches you've generated into the editing buffer, as is done by another widget in the same code over here: https://github.com/junegunn/fzf/blob/master/shell/key-bindings.zsh#L62

That widget inserts the matches echoed by the function __fsel into the right side of the left part of the buffer (meaning, it inserts them into the current position of the cursor and then, afterwards, the cursor will end up to the right of what's inserted):

LBUFFER="${LBUFFER}$(__fsel)"
Related Question