junegunn / fzf

:cherry_blossom: A command-line fuzzy finder
https://junegunn.github.io/fzf/
MIT License
63.72k stars 2.37k forks source link

Cannot use custom commands when `fzf` outputs to a variable or array #2604

Open Kabouik opened 3 years ago

Kabouik commented 3 years ago

Info

Problem / Steps to reproduce

I am working on a project in which I need to print several json files through jq after selecting them with fzf. For that, I'm creating an array with the fzf selection and then loop on it. My problem is whenever I enclose the command in ( $( ) ) (for an array) or even just $( ), the fzf custom commands associated with keybindings cease working. fzf just flashes but then comes back to the preview. Contrariwise, if I just run the code without enclosing it in an array or variable, then custom fzf commands work, but then of course I cannot loop through the files fzf returns when I press Return.

See below my code (several options are irrelevant to the issue but I left them in case there is actually something wrong with one of them):

cod=( $(find . -type f -printf '%f\n' | sort | \
        fzf --ansi \
            --header=$'C-p  print & exit
C-e  edit
C-x  edit beautified
     dep: kakoune
C-v  view table/json
C-r  ripgrep
     dep: rga-fzf
?    toggle preview\n\n' \
            --preview="cat {} | jq" \
            --preview-window="right:80%:wrap:cycle" --delimiter / --with-nth -1 \
            --bind="?:toggle-preview" \
            --bind="ctrl-r:execute(rga-fzf {} '')" \
            --bind="ctrl-e:execute(${EDITOR:-vim --not-a-term} {} </dev/tty)" \
            --bind="ctrl-x:execute(kak -e 'execute-keys <%><|>jq<ret><g><e>' {} </dev/tty)" \
            --bind="ctrl-p:execute(cat {} | jq)+abort" \
            --bind="ctrl-v:execute(cat {} | jq | jtbl -t | less -SN)" \
            --height=100% \
            --layout=reverse \
            --cycle \
            --border \
            --marker='*' \
            --multi) )
for i in "${cod[@]}"
      do printf "\n$i\n--------\n"
      jq < "$i"
done

I have read the manual and did some research before opening this issue, I hope I did not miss something.

Is there something I am doing wrong or is there actually a conflict between custom commands and having fzf enclosed into a variable or array for later steps?

junegunn commented 3 years ago

Have you tried putting ... < /dev/tty > /dev/tty?

Kabouik commented 3 years ago

Thanks for the answer @junegunn. This indeed seems to restore the functionality of the execute() commands but it breaks the for loop after it because when I select items in fzf and press enter, it just prints their filenames. In fact, it seems to mimic the behaviour of the code block when I remove the ( $( ) ).

In case I misunderstood, here's where I added the tty part, but I don't really understand how that works so please excuse me if this is not what you meant:

cod=( $(find . -type f -printf '%f\n' | sort | \
        fzf --ansi \
            --header=$'C-p  print & exit
C-e  edit
C-x  edit beautified
     dep: kakoune
C-v  view table/json
C-r  ripgrep
     dep: rga-fzf
?    toggle preview\n\n' \
            --preview="cat {} | jq" \
            --preview-window="right:80%:wrap:cycle" --delimiter / --with-nth -1 \
            --bind="?:toggle-preview" \
            --bind="ctrl-r:execute(rga-fzf {} '')" \
            --bind="ctrl-e:execute(${EDITOR:-vim --not-a-term} {} </dev/tty)" \
            --bind="ctrl-x:execute(kak -e 'execute-keys <%><|>jq<ret><g><e>' {} </dev/tty)" \
            --bind="ctrl-p:execute(cat {} | jq)+abort" \
            --bind="ctrl-v:execute(cat {} | jq | jtbl -t | less -SN)" \
            --height=100% \
            --layout=reverse \
            --cycle \
            --border \
            --marker='*' \
            --multi < /dev/tty > /dev/tty) )
for i in "${cod[@]}"
      do printf "\n$i\n--------\n"
      jq < "$i"
done
junegunn commented 3 years ago

I meant

--bind="ctrl-e:execute(${EDITOR:-vim --not-a-term} {} < /dev/tty > /dev/tty)"
Kabouik commented 3 years ago

Perfect, that was it! Thank you very much. I admit I don't exactly understand how this works but I couldn't find that in the manual or in the help, do you think this would be worth a mention in the manual, or is it too much of a corner case?

On 2021-09-01 09:04 Junegunn Choi @.***> wrote:

I meant

--bind="ctrl-e:execute(${EDITOR:-vim --not-a-term} {} < /dev/tty >
/dev/tty)"

--
You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub: https://github.com/junegunn/fzf/issues/2604#issuecomment-909984174

vapniks commented 2 years ago

For the benefit of others; if your child command receives input from a pipe, remove the </dev/tty redirection. I tried this at first:

--bind "alt-v:execute(${cmd} ${file} | less </dev/tty >/dev/tty)"

but less froze after pressing the g key. Removing </dev/tty fixed the problem:

--bind "alt-v:execute(${cmd} ${file} | less >/dev/tty)"