:cherry_blossom: A command-line fuzzy finder
$FZF_POS
exported to the child processes. It's the vertical position of the cursor in the list starting from 1.
# Toggle selection to the top or to the bottom
seq 30 | fzf --multi --bind 'load:pos(10)' \
--bind 'shift-up:transform:for _ in $(seq $FZF_POS $FZF_MATCH_COUNT); do echo -n +toggle+up; done' \
--bind 'shift-down:transform:for _ in $(seq 1 $FZF_POS); do echo -n +toggle+down; done'
--with-shell
option to start child processes with a custom shell command and flags
gem list | fzf --with-shell 'ruby -e' \
--preview 'pp Gem::Specification.find_by_name({1})' \
--bind 'ctrl-o:execute-silent:
spec = Gem::Specification.find_by_name({1})
[spec.homepage, *spec.metadata.filter { _1.end_with?("uri") }.values].uniq.each do
system "open", _1
end
'
change-multi
action for dynamically changing --multi
option
change-multi
- enable multi-select mode with no limitchange-multi(NUM)
- enable multi-select mode with a limitchange-multi(0)
- disable multi-select modebecome
action is now supported on Windows
execve(2)
. Instead it spawns a new process and waits for it to finish, so the exact behavior may differ.$ rg --line-number --no-heading --smart-case . > $DATA
$ wc < $DATA
5520118 26862362 897487793
$ hyperfine -w 1 -L bin fzf-0.49.0,fzf-7ce6452,fzf-a5447b8,fzf '{bin} --filter "///" < $DATA | head -30'
Summary
fzf --filter "///" < $DATA | head -30 ran
1.16 ± 0.03 times faster than fzf-a5447b8 --filter "///" < $DATA | head -30
1.23 ± 0.03 times faster than fzf-7ce6452 --filter "///" < $DATA | head -30
1.52 ± 0.03 times faster than fzf-0.49.0 --filter "///" < $DATA | head -30
jump
and jump-cancel
events that are triggered when leaving jump
mode
# Default behavior
fzf --bind space:jump
# Same as jump-accept action
fzf --bind space:jump,jump:accept
# Accept on jump, abort on cancel
fzf --bind space:jump,jump:accept,jump-cancel:abort
# Change header on jump-cancel
fzf --bind 'space:change-header(Type jump label)+jump,jump-cancel:change-header:Jump cancelled'
$FZF_KEY
exported to the child processes. It's the name of the last key pressed.
fzf --bind 'space:jump,jump:accept,jump-cancel:transform:[[ $FZF_KEY =~ ctrl-c ]] && echo abort'
$ 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