Skip to content

Add "reload" action for dynamically updating the input list #1750

Closed
@junegunn

Description

@junegunn

See devel branch for the progress.

Summary

Add bindable reload action that can start an arbitrary program and dynamically replace the input list of fzf with its result without restarting fzf.

Rationale

fzf was designed to be a Unix filter that consumes input only once. However, due to the interactive nature of it, some users want to update the input without restarting fzf altogether (using esoteric --no-clear option).

For example,

  • Input comes from a REST API that generates dynamic content, and you want to see the updated list by pressing a special key such as CTRL-R (R for refresh or reload).
  • You want to press a set of keys to dynamically switch between different sets of inputs; CTRL-F for a list of files, and CTRL-D for a list of directories.
  • You use fzf as the secondary filter to the result of a primary filter program such as ripgrep or silver searcher. And you want to restart the primary filter program with an updated query string you typed on fzf because they are much more efficient than fzf for searching through the file contents.
    • You may even want to restart the primary filter program every time you change the query string on fzf. In this case, you probably want to use fzf only as a selector interface rather than a secondary "fuzzy filter", especially because of the incompatible search syntax. The search is completely done by the primary filter as you use the new --phony option (No-filter search option #1723).

Instead of introducing a separate mode of execution as suggested in #751 and #1736. I'd like to add a special action called reload that can be bound to a key or change event using the good old --bind.

Examples

1. Update the list of processes by pressing CTRL-R

ps -ef | fzf --bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' \
             --header-lines=1 --layout=reverse

2. Switch between sources by pressing CTRL-D or CTRL-F

find . -type f |
  fzf --bind 'ctrl-d:reload(find . -type d),ctrl-f:reload(find . -type f)'

There are two problems here:

  • We're repeating find . -type f command twice
  • The initial find process may take a long time to finish. Since fzf cannot kill the process behind the standard input, the process will keep running even after we hit CTRL-D.

To work around the issues, we set $FZF_DEFAULT_COMMAND to the initial find command, so fzf can start the process and kill it when it has to.

FZF_DEFAULT_COMMAND='find . -type f' fzf \
  --bind 'ctrl-d:reload(find . -type d),ctrl-f:reload($FZF_DEFAULT_COMMAND)'

3. Ripgrep integration

The following example uses fzf as the selector interface for ripgrep. We bound reload action to change event, so every time you type on fzf, ripgrep process will restart with the updated query string denoted by the placeholder expression {q}. Also, note that we used --phony option so that fzf doesn't perform any secondary filtering.

RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
INITIAL_QUERY=""
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \
  fzf --bind "change:reload:$RG_PREFIX {q} || true" \
      --ansi --phony --query "$INITIAL_QUERY"

If ripgrep doesn't find any matches, it will exit with a non-zero exit status, and fzf will warn you about it. To suppress the warning message, we added || true to the command, so that it always exits with 0.

4. Ripgrep integration with fzf.vim

function! RipgrepFzf(query, fullscreen)
  let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case %s || true'
  let initial_command = printf(command_fmt, shellescape(a:query))
  let reload_command = printf(command_fmt, '{q}')
  let spec = {'options': ['--phony', '--query', a:query, '--bind', 'change:reload:'.reload_command]}
  call fzf#vim#grep(initial_command, 1, fzf#vim#with_preview(spec), a:fullscreen)
endfunction

command! -nargs=* -bang Rg call RipgrepFzf(<q-args>, <bang>0)

Metadata

Metadata

Assignees

Labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions

    Add "reload" action for dynamically updating the input list · Issue #1750 · junegunn/fzf