:cherry_blossom: A command-line fuzzy finder
$ time wc data
5513620 37997130 547840920 data
real 0m0.822s
user 0m0.764s
sys 0m0.052s
$ hyperfine -L bin fzf-0.48.1,fzf '{bin} --sync --bind load:accept < data'
Benchmark 1: fzf-0.48.1 --sync --bind load:accept < data
Time (mean ± σ): 440.3 ms ± 4.9 ms [User: 501.8 ms, System: 117.0 ms]
Range (min … max): 432.8 ms … 446.1 ms 10 runs
Benchmark 2: fzf --sync --bind load:accept < data
Time (mean ± σ): 303.3 ms ± 4.5 ms [User: 320.1 ms, System: 108.6 ms]
Range (min … max): 296.6 ms … 311.4 ms 10 runs
Summary
fzf --sync --bind load:accept < data ran
1.45 ± 0.03 times faster than fzf-0.48.1 --sync --bind load:accept < data
--info=hidden
and --info=inline-right
will no longer hide the horizontal separator by default. This gives you more flexibility in customizing the layout.
fzf --border --info=inline-right
fzf --border --info=inline-right --separator ═
fzf --border --info=inline-right --no-separator
fzf --border --info=hidden
fzf --border --info=hidden --separator ━
fzf --border --info=hidden --no-separator
FZF_PREVIEW_LABEL
FZF_BORDER_LABEL
# Use the current value of $FZF_PREVIEW_LABEL to determine which actions to perform
git ls-files |
fzf --header 'Press CTRL-P to change preview mode' \
--bind='ctrl-p:transform:[[ $FZF_PREVIEW_LABEL =~ cat ]] \
&& echo "change-preview(git log --color=always \{})+change-preview-label([[ log ]])" \
|| echo "change-preview(bat --color=always \{})+change-preview-label([[ cat ]])"'
track
action to track-current
to highlight the difference between the global tracking state set by --track
and a one-off tracking action
track
is still available as an aliasuntrack-current
and toggle-track-current
actions
*-current
actions are no-op when the global tracking state is setFZF_CTRL_T_COMMAND
and FZF_ALT_C_COMMAND
to empty strings respectively when sourcing the script
# bash
FZF_CTRL_T_COMMAND= FZF_ALT_C_COMMAND= eval "$(fzf --bash)"
# zsh
FZF_CTRL_T_COMMAND= FZF_ALT_C_COMMAND= eval "$(fzf --zsh)"
# fish
fzf --fish | FZF_CTRL_T_COMMAND= FZF_ALT_C_COMMAND= source
# Set up fzf key bindings and fuzzy completion
eval "$(fzf --bash)"
# Set up fzf key bindings and fuzzy completion
eval "$(fzf --zsh)"
# Set up fzf key bindings
fzf --fish | source
Option | Description | Default |
---|---|---|
--walker=OPTS |
Walker options ([file][,dir][,follow][,hidden] ) |
file,follow,hidden |
--walker-root=DIR |
Root directory from which to start walker | . |
--walker-skip=DIRS |
Comma-separated list of directory names to skip | .git,node_modules |
# Built-in walker is only used by standalone fzf when $FZF_DEFAULT_COMMAND is not set
unset FZF_DEFAULT_COMMAND
fzf # default: --walker=file,follow,hidden --walker-root=. --walker-skip=.git,node_modules
fzf --walker=file,dir,hidden,follow --walker-skip=.git,node_modules,target
# Walker options in $FZF_DEFAULT_OPTS
export FZF_DEFAULT_OPTS="--walker=file,dir,hidden,follow --walker-skip=.git,node_modules,target"
fzf
# Reading from STDIN; --walker is ignored
seq 100 | fzf --walker=dir
# Reading from $FZF_DEFAULT_COMMAND; --walker is ignored
export FZF_DEFAULT_COMMAND='seq 100'
fzf --walker=dir
$FZF_DEFAULT_COMMAND
set.
devtmpfs
or proc
types$FZF_DEFAULT_OPTS_FILE
to allow managing default options in a file
$FZF_DEFAULT_OPTS_FILE
$FZF_DEFAULT_OPTS
result
- triggered when the filtering for the current query is complete and the result list is readyresize
- triggered when the terminal size is changedVariable | Description |
---|---|
FZF_LINES |
Number of lines fzf takes up excluding padding and margin |
FZF_COLUMNS |
Number of columns fzf takes up excluding padding and margin |
FZF_TOTAL_COUNT |
Total number of items |
FZF_MATCH_COUNT |
Number of matched items |
FZF_SELECT_COUNT |
Number of selected items |
FZF_QUERY |
Current query string |
FZF_PROMPT |
Prompt string |
FZF_ACTION |
The name of the last action performed |
# Script to dynamically resize the preview window
transformer='
# 1 line for info, another for prompt, and 2 more lines for preview window border
lines=$(( FZF_LINES - FZF_MATCH_COUNT - 4 ))
if [[ $FZF_MATCH_COUNT -eq 0 ]]; then
echo "change-preview-window:hidden"
elif [[ $lines -gt 3 ]]; then
echo "change-preview-window:$lines"
elif [[ $FZF_PREVIEW_LINES -ne 3 ]]; then
echo "change-preview-window:3"
fi
'
seq 10000 | fzf --preview 'seq {} 10000' --preview-window up \
--bind "result:transform:$transformer" \
--bind "resize:transform:$transformer"
{fzf:prompt}
and {fzf:action}
--ambidouble
if your terminal displays ambiguous width characters (e.g. box-drawing characters for borders) as 2 columnsRUNEWIDTH_EASTASIAN=1
is still respected for backward compatibility, but it's recommended that you use this new option insteadtransform
action to conditionally perform a series of actions
# Disallow selecting an empty line
echo -e "1. Hello\n2. Goodbye\n\n3. Exit" |
fzf --height '~100%' --reverse --header 'Select one' \
--bind 'enter:transform:[[ -n {} ]] && echo accept || echo "change-header:Invalid selection"'
# Move cursor past the empty line
echo -e "1. Hello\n2. Goodbye\n\n3. Exit" |
fzf --height '~100%' --reverse --header 'Select one' \
--bind 'enter:transform:[[ -n {} ]] && echo accept || echo "change-header:Invalid selection"' \
--bind 'focus:transform:[[ -n {} ]] && exit; [[ {fzf:action} =~ up$ ]] && echo up || echo down'
# A single key binding to toggle between modes
fd --type file |
fzf --prompt 'Files> ' \
--header 'CTRL-T: Switch between Files/Directories' \
--bind 'ctrl-t:transform:[[ ! {fzf:prompt} =~ Files ]] &&
echo "change-prompt(Files> )+reload(fd --type file)" ||
echo "change-prompt(Directories> )+reload(fd --type directory)"'
{fzf:action}
- The name of the last action performed{fzf:prompt}
- Prompt string (including ANSI color codes){fzf:query}
- Synonym for {q}
# Terminal height minus 1, so you can still see the command line
fzf --height=-1
--height=$(($(tput lines) - 1))
accept-or-print-query
action that acts like accept
but prints the current query when there's no match for the query
# You can make CTRL-R paste the current query when there's no match
export FZF_CTRL_R_OPTS='--bind enter:accept-or-print-query'
# 'become' is apparently more versatile but it's not available on Windows.
export FZF_CTRL_R_OPTS='--bind "enter:become:if [ -z {} ]; then echo {q}; else echo {}; fi"'
# Using the new 'transform' action
export FZF_CTRL_R_OPTS='--bind "enter:transform:[ -z {} ] && echo print-query || echo accept"'
show-header
and hide-header
actionsfocus
event(Experimental) Sixel image support in preview window (not available on Windows)
fzf --preview='fzf-preview.sh {}'
(Experimental) iTerm2 inline image protocol support in preview window (not available on Windows)
# Using https://iterm2.com/utilities/imgcat
fzf --preview 'imgcat -W $FZF_PREVIEW_COLUMNS -H $FZF_PREVIEW_LINES {}'
HTTP server can be configured to accept remote connections
# FZF_API_KEY is required for a non-localhost listen address
export FZF_API_KEY="$(head -c 32 /dev/urandom | base64)"
fzf --listen 0.0.0.0:6266
--listen-unsafe
instead
(execute*
, reload*
, become
, preview
, change-preview
, transform-*
)
fzf --listen-unsafe 0.0.0.0:6266
Bug fixes
(Experimental) Added support for Kitty image protocol in the preview window (currently not supported on Windows)
fzf --preview='
if file --mime-type {} | grep -qF image/; then
# --transfer-mode=memory is the fastest option but if you want fzf to be able
# to redraw the image on terminal resize or on "change-preview-window",
# you need to use --transfer-mode=stream.
kitty icat --clear --transfer-mode=memory --stdin=no --place=${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@0x0 {} | sed \$d
else
bat --color=always {}
fi
'
(Experimental) --listen
server can report program state in JSON format (GET /
)
# fzf server started in "headless" mode
fzf --listen 6266 2> /dev/null
# Get program state
curl localhost:6266 | jq .
# Increase the number of items returned (default: 100)
curl localhost:6266?limit=1000 | jq .
--listen
server can be secured by setting $FZF_API_KEY
environment
variable.
export FZF_API_KEY="$(head -c 32 /dev/urandom | base64)"
# Server
fzf --listen 6266
# Client
curl localhost:6266 -H "x-api-key: $FZF_API_KEY" -d 'change-query(yo)'
Added toggle-header
action
Added mouse events for --bind
scroll-up
(bound to up
)scroll-down
(bound to down
)shift-scroll-up
(bound to toggle+up
)shift-scroll-down
(bound to toggle+down
)shift-left-click
(bound to toggle
)shift-right-click
(bound to toggle
)preview-scroll-up
(bound to preview-up
)preview-scroll-down
(bound to preview-down
)# Twice faster scrolling both in the main window and the preview window
fzf --bind 'scroll-up:up+up,scroll-down:down+down' \
--bind 'preview-scroll-up:preview-up+preview-up' \
--bind 'preview-scroll-down:preview-down+preview-down' \
--preview 'cat {}'
Added offset-up
and offset-down
actions
# Scrolling will behave similarly to CTRL-E and CTRL-Y of vim
fzf --bind scroll-up:offset-up,scroll-down:offset-down \
--bind ctrl-y:offset-up,ctrl-e:offset-down \
--scroll-off=5
Shell extensions
--scheme=path
for better ordering of the resultBug fixes and improvements