Bot releases are hidden (Show)
$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.Published by junegunn 6 months ago
$ 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'
Published by junegunn 7 months ago
$ 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 setPublished by junegunn 7 months ago
FZF_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
Published by junegunn 7 months ago
# 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
Published by junegunn 7 months ago
$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
Published by junegunn 9 months ago
Published by junegunn 9 months ago
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 insteadPublished by junegunn 10 months ago
transform
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
actionsPublished by junegunn 11 months ago
focus
eventPublished by junegunn 11 months ago
(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
insteadexecute*
, reload*
, become
, preview
, change-preview
, transform-*
)
fzf --listen-unsafe 0.0.0.0:6266
Bug fixes
Published by junegunn about 1 year ago
(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
Published by junegunn over 1 year ago
--info=right
--info=inline-right
thinblock
which uses symbols for legacy computing one eighth block elements
block
, this style is suitable when using a different background color because the window is completely contained within the border.thinblock
BAT_THEME=GitHub fzf --info=right --border=thinblock --preview-window=border-thinblock \
--margin=3 --scrollbar=▏▕ --preview='bat --color=always --style=numbers {}' \
--color=light,query:238,fg:238,bg:251,bg+:249,gutter:251,border:248,preview-bg:253
block
BAT_THEME=GitHub fzf --info=right --border=block --preview-window=border-block \
--margin=3 --scrollbar=▌▐ --separator=━ --preview='bat --color=always --style=numbers {}' \
--color=light,query:238,fg:238,bg:251,bg+:249,gutter:251,border:248,preview-bg:253,preview-border:252
Published by junegunn over 1 year ago
--disabled
is set andchange:reload
bindingPublished by junegunn over 1 year ago
Added color name preview-border
and preview-scrollbar
Added new border style block
which uses block elements
--scrollbar
can take two characters, one for the main window, the other
for the preview window
Putting it altogether:
fzf-tmux -p 80% --padding 1,2 --preview 'bat --style=plain --color=always {}' \
--color 'bg:237,bg+:235,gutter:237,border:238,scrollbar:236' \
--color 'preview-bg:235,preview-border:236,preview-scrollbar:234' \
--preview-window 'border-block' --border block --scrollbar '▌▐'
Bug fixes and improvements
Published by junegunn over 1 year ago
zero
event that is triggered when there's no matchtrack
action which makes fzf track the current item when the# Narrow down the list with a query, point to a command,
# and hit CTRL-T to see its surrounding commands.
export FZF_CTRL_R_OPTS="
--preview 'echo {}' --preview-window up:3:hidden:wrap
--bind 'ctrl-/:toggle-preview'
--bind 'ctrl-t:track+clear-query'
--bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort'
--color header:italic
--header 'Press CTRL-Y to copy command into clipboard'"
change-header(...)
transform-header(...)
toggle-track
action--track
behavior when used with --tac
--track
with --tac
is not recommended. The resultingPublished by junegunn over 1 year ago
one
event that is triggered when there's only one match
# Automatically select the only match
seq 10 | fzf --bind one:accept
--track
option that makes fzf track the current selection when thegit log --oneline --graph --color=always | nl |
fzf --ansi --track --no-sort --layout=reverse-list
--listen
option without a port number fzf will automatically$FZF_PORT
environment# Automatic port assignment
fzf --listen --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port'
# Say hello
curl "localhost:$(cat /tmp/fzf-port)" -d 'preview:echo Hello, fzf is listening on $FZF_PORT.'
printf "foo\rbar\nbaz" | fzf --read0 --preview 'echo {}'
fzf --preview 'head -1000 /dev/random'
Published by junegunn over 1 year ago
become(...)
- Replace the current fzf process with the specified command using execve(2)
system call.# Open selected files in Vim
fzf --multi --bind 'enter:become(vim {+})'
# Open the file in Vim and go to the line
git grep --line-number . |
fzf --delimiter : --nth 3.. --bind 'enter:become(vim {1} +{2})'
show-preview
hide-preview
--preview-window 0,hidden
should not execute the preview command until toggle-preview
action is triggeredPublished by junegunn over 1 year ago
fzf --info 'inline: ╱ ' --prompt '╱ ' --color prompt:bright-yellow
focus
- Triggered when the focus changes due to a vertical cursorfzf --bind 'focus:transform-preview-label:echo [ {} ]' --preview 'cat {}'
# Any action bound to the event runs synchronously and thus can make the interface sluggish
# e.g. lolcat isn't one of the fastest programs, and every cursor movement in
# fzf will be noticeably affected by its execution time
fzf --bind 'focus:transform-preview-label:echo [ {} ] | lolcat -f' --preview 'cat {}'
# Beware not to introduce an infinite loop
seq 10 | fzf --bind 'focus:up' --cycle
change-border-label
change-preview-label
transform-border-label
transform-preview-label
Published by junegunn almost 2 years ago
--listen=HTTP_PORT
option to start HTTP server. It allows external# Start HTTP server on port 6266
fzf --listen 6266
# Send actions to the server
curl localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )'
# Hide scrollbar
fzf --no-scrollbar
# Customize scrollbar
fzf --scrollbar ┆ --color scrollbar:blue
load
event that is triggered when the input stream is complete# Change the prompt to "loaded" when the input stream is complete
(seq 10; sleep 1; seq 11 20) | fzf --prompt 'Loading> ' --bind 'load:change-prompt:Loaded> '
# You can use it instead of 'start' event without `--sync` if asynchronous
# trigger is not an issue.
(seq 10; sleep 1; seq 11 20) | fzf --bind 'load:last'
pos(...)
action to move the cursor to the numeric position
first
and last
are equivalent to pos(1)
and pos(-1)
respectively# Put the cursor on the 10th item
seq 100 | fzf --sync --bind 'start:pos(10)'
# Put the cursor on the 10th to last item
seq 100 | fzf --sync --bind 'start:pos(-10)'
reload-sync(...)
action which replaces the current list only after# You can still filter and select entries from the initial list for 3 seconds
seq 100 | fzf --bind 'load:reload-sync(sleep 3; seq 1000)+unbind(load)'
next-selected
and prev-selected
actions to move between selected# `next-selected` will move the pointer to the next selected item below the current line
# `prev-selected` will move the pointer to the previous selected item above the current line
seq 10 | fzf --multi --bind ctrl-n:next-selected,ctrl-p:prev-selected
# Both actions respect --layout option
seq 10 | fzf --multi --bind ctrl-n:next-selected,ctrl-p:prev-selected --layout reverse
change-query(...)
action that simply changes the query string to the--listen
.
curl localhost:6266 -d "change-query:$(date)"
transform-prompt(...)
action for transforming the prompt string# Press space to change the prompt string using an external command
# (only the first line of the output is taken)
fzf --bind 'space:reload(ls),load:transform-prompt(printf "%s> " "$(date)")'
transform-query(...)
action for transforming the query string using# Press space to convert the query to uppercase letters
fzf --bind 'space:transform-query(tr "[:lower:]" "[:upper:]" <<< {q})'
# Bind it to 'change' event for automatic conversion
fzf --bind 'change:transform-query(tr "[:lower:]" "[:upper:]" <<< {q})'
# Can only type numbers
fzf --bind 'change:transform-query(sed "s/[^0-9]//g" <<< {q})'
put
action can optionally take an argument string
# a will put 'alpha' on the prompt, ctrl-b will put 'bravo'
fzf --bind 'a:put+put(lpha),ctrl-b:put(bravo)'
preview-label
for --preview-label
(defaults to label
--border-label
)RUNEWIDTH_EASTASIAN
environment variable to 1
.
&ambiwidth
is double
{q}
even when it's empty. If you prefer the old behavior,{q}
is empty in your command.
# This will show // even when the query is empty
: | fzf --preview 'echo /{q}/'
# But if you don't want it,
: | fzf --preview '[ -n {q} ] || exit; echo /{q}/'
double-click
will behave the same as enter
unless otherwise specified,--bind
in most cases.
# No need to bind 'double-click' to the same action
fzf --bind 'enter:execute:less {}' # --bind 'double-click:execute:less {}'
separator
is not specified, it will default to theborder
. Same holds true for scrollbar
. This is to reducefollow
flag is specified in --preview-window
option, fzf willsharp
because somerounded
border