Skip to main content

Reload, Transform, and Live Grep

Live Grep with fzf + ripgrep

The most powerful fzf pattern: use ripgrep to filter, fzf to navigate results:

fzf-live-grep — searchable ripgrep
#!/usr/bin/env bash
# Live grep: results update as you type
rg_fzf() {
local RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case"
local INITIAL_QUERY="${1:-}"

fzf --ansi \
--disabled \
--query="$INITIAL_QUERY" \
--bind "start:reload:$RG_PREFIX {q}" \
--bind "change:reload:sleep 0.2; $RG_PREFIX {q} || true" \
--bind 'ctrl-/:toggle-preview' \
--delimiter=: \
--preview 'bat --color=always --style=numbers --highlight-line={2} {1}' \
--preview-window 'right:60%:hidden:+{2}/2' \
--prompt ' Grep: ' \
--header 'Type to grep | CTRL-/ for preview' \
--color 'hl:-1:underline,hl+:-1:underline:reverse' \
| awk -F: '{print "+"$2" "$1}' # output as "+lineno file" for vim
}

# Open result in vim at exact line
result=$(rg_fzf "$@")
if [ -n "$result" ]; then
vim $result
fi

Usage: rg_fzf "function name" → opens at matching line in vim.

Switching Between Modes with Reload

# Interactive mode switcher: files, git files, git log
git_fzf() {
local mode="files"

fd --type f --hidden --exclude .git | fzf \
--prompt '📄 Files> ' \
--header $'CTRL-G: git files\nCTRL-L: git log\nCTRL-F: all files' \
--bind 'ctrl-g:change-prompt(🔀 Git> )+reload(git ls-files)' \
--bind 'ctrl-l:change-prompt(📋 Log> )+reload(git log --oneline)' \
--bind 'ctrl-f:change-prompt(📄 Files> )+reload(fd --type f --hidden --exclude .git)' \
--preview '
if git log --oneline {1} 2>/dev/null | grep -q .; then
git show --stat --color=always {1}
else
bat --color=always --style=numbers {}
fi
'
}

Transform for Conditional Headers

# Show different instructions based on current mode
find . | fzf \
--header-first \
--header 'MODE: FILES' \
--bind 'ctrl-d:transform(
if [[ $FZF_PROMPT == *"Files"* ]]; then
echo "reload(find . -type d)+change-prompt(DIR> )+change-header(MODE: DIRS)"
else
echo "reload(find . -type f)+change-prompt(FILE> )+change-header(MODE: FILES)"
fi
)'

Dynamic Query-based Reload

# Reload the list based on query text — useful for API or DB queries
fzf_db() {
: | fzf \
--disabled \
--ansi \
--bind 'change:reload(
if [ -n {q} ]; then
sqlite3 mydb.sqlite "SELECT * FROM users WHERE name LIKE '"'"'%{q}%'"'"'" 2>/dev/null
else
echo "Type to search users..."
fi
)' \
--prompt 'DB Search> ' \
--header 'Search users table'
}

Custom Headers and Actions

# Show context-sensitive header based on selection count
ls | fzf \
-m \
--border=rounded \
--bind 'zero:change-header(No matches found)' \
--bind 'load:change-header(Loaded {} items)' \
--bind 'change:transform-header(
if [ $FZF_SELECT_COUNT -gt 0 ]; then
echo "Selected: $FZF_SELECT_COUNT items"
else
echo "Filter and select files"
fi
)'

What's Next