448 lines
9.6 KiB
Markdown
448 lines
9.6 KiB
Markdown
# fzf Integrations Reference
|
|
|
|
Recipes for integrating fzf with other tools.
|
|
|
|
## Table of Contents
|
|
|
|
- [ripgrep Integration](#ripgrep-integration)
|
|
- [fd Integration](#fd-integration)
|
|
- [bat Integration](#bat-integration)
|
|
- [Git Integration](#git-integration)
|
|
- [Docker Integration](#docker-integration)
|
|
- [Kubernetes Integration](#kubernetes-integration)
|
|
- [tmux Integration](#tmux-integration)
|
|
- [Shell Function Recipes](#shell-function-recipes)
|
|
|
|
## ripgrep Integration
|
|
|
|
### Basic Search with Preview
|
|
|
|
```bash
|
|
# Search and preview with syntax highlighting
|
|
rg --line-number --no-heading --color=always '' |
|
|
fzf --ansi \
|
|
--delimiter : \
|
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
|
|
```
|
|
|
|
### Open Result in Editor
|
|
|
|
```bash
|
|
# Search and open in vim at matching line
|
|
rg --line-number --no-heading --color=always '' |
|
|
fzf --ansi --delimiter : \
|
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
|
--bind 'enter:become(vim {1} +{2})'
|
|
```
|
|
|
|
### Interactive ripgrep (fzf as Frontend)
|
|
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
# Save as 'rfv' and make executable
|
|
|
|
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case"
|
|
INITIAL_QUERY="${*:-}"
|
|
|
|
fzf --ansi --disabled --query "$INITIAL_QUERY" \
|
|
--bind "start:reload:$RG_PREFIX {q}" \
|
|
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
|
--delimiter : \
|
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
|
--bind 'enter:become(vim {1} +{2})'
|
|
```
|
|
|
|
### Toggle Between ripgrep and fzf Mode
|
|
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
# CTRL-R for ripgrep mode, CTRL-F for fzf mode
|
|
|
|
rm -f /tmp/rg-fzf-{r,f}
|
|
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case"
|
|
|
|
fzf --ansi --disabled --query "${*:-}" \
|
|
--bind "start:reload($RG_PREFIX {q})+unbind(ctrl-r)" \
|
|
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
|
|
--bind "ctrl-f:unbind(change,ctrl-f)+change-prompt(fzf> )+enable-search+rebind(ctrl-r)+transform-query(echo {q} > /tmp/rg-fzf-r; cat /tmp/rg-fzf-f)" \
|
|
--bind "ctrl-r:unbind(ctrl-r)+change-prompt(rg> )+disable-search+reload($RG_PREFIX {q} || true)+rebind(change,ctrl-f)+transform-query(echo {q} > /tmp/rg-fzf-f; cat /tmp/rg-fzf-r)" \
|
|
--prompt 'rg> ' \
|
|
--delimiter : \
|
|
--header 'CTRL-R (ripgrep) / CTRL-F (fzf)' \
|
|
--preview 'bat --color=always {1} --highlight-line {2}' \
|
|
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
|
|
--bind 'enter:become(vim {1} +{2})'
|
|
```
|
|
|
|
## fd Integration
|
|
|
|
### File Search with Preview
|
|
|
|
```bash
|
|
# Find files with preview
|
|
fd --type f --hidden --follow --exclude .git |
|
|
fzf --preview 'bat --color=always {}' \
|
|
--bind 'enter:become(vim {})'
|
|
```
|
|
|
|
### Set as Default Command
|
|
|
|
```bash
|
|
# In ~/.bashrc or ~/.zshrc
|
|
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
|
|
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
|
|
export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'
|
|
```
|
|
|
|
### Toggle Files/Directories
|
|
|
|
```bash
|
|
fd --type f |
|
|
fzf --prompt 'Files> ' \
|
|
--header 'CTRL-D: Dirs / CTRL-F: Files' \
|
|
--bind 'ctrl-d:change-prompt(Dirs> )+reload(fd --type d)' \
|
|
--bind 'ctrl-f:change-prompt(Files> )+reload(fd --type f)'
|
|
```
|
|
|
|
### Filter by Extension
|
|
|
|
```bash
|
|
# Find Python files
|
|
fd --extension py | fzf --preview 'bat --color=always {}'
|
|
|
|
# Multiple extensions
|
|
fd --extension js --extension ts | fzf
|
|
```
|
|
|
|
## bat Integration
|
|
|
|
### Preview with Syntax Highlighting
|
|
|
|
```bash
|
|
fzf --preview 'bat --color=always --style=numbers --line-range :500 {}'
|
|
```
|
|
|
|
### Highlight Specific Line
|
|
|
|
```bash
|
|
# With line number from grep/rg
|
|
fzf --preview 'bat --color=always {1} --highlight-line {2}' --delimiter :
|
|
```
|
|
|
|
### Preview Window Settings
|
|
|
|
```bash
|
|
# Show first 500 lines with header
|
|
fzf --preview 'bat --color=always --style=header,numbers --line-range :500 {}'
|
|
|
|
# Plain output for speed
|
|
fzf --preview 'bat --color=always --style=plain {}'
|
|
```
|
|
|
|
## Git Integration
|
|
|
|
### Select Branches
|
|
|
|
```bash
|
|
# Checkout branch
|
|
git branch --all | fzf | xargs git checkout
|
|
|
|
# With preview of recent commits
|
|
git branch --all |
|
|
fzf --preview 'git log --oneline -20 {}' |
|
|
sed 's/^[* ]*//' | sed 's/remotes\/origin\///' |
|
|
xargs git checkout
|
|
```
|
|
|
|
### Select Commits
|
|
|
|
```bash
|
|
# Copy commit hash
|
|
git log --oneline |
|
|
fzf --preview 'git show --color=always {1}' |
|
|
cut -d' ' -f1
|
|
|
|
# Interactive rebase from selected commit
|
|
git log --oneline |
|
|
fzf --preview 'git show --color=always {1}' |
|
|
cut -d' ' -f1 |
|
|
xargs -I {} git rebase -i {}^
|
|
```
|
|
|
|
### Stage Files Interactively
|
|
|
|
```bash
|
|
# Select unstaged files to add
|
|
git status --short |
|
|
fzf --multi --preview 'git diff --color=always {2}' |
|
|
awk '{print $2}' |
|
|
xargs git add
|
|
```
|
|
|
|
### View Changed Files
|
|
|
|
```bash
|
|
# Open changed files
|
|
git status --short |
|
|
fzf --multi --preview 'git diff --color=always {2}' |
|
|
awk '{print $2}' |
|
|
xargs -o vim
|
|
```
|
|
|
|
### Stash Management
|
|
|
|
```bash
|
|
# Select and apply stash
|
|
git stash list |
|
|
fzf --preview 'git stash show -p {1}' --delimiter : |
|
|
cut -d: -f1 |
|
|
xargs git stash apply
|
|
```
|
|
|
|
### fzf-git.sh Key Bindings
|
|
|
|
Highly recommended: [fzf-git.sh](https://github.com/junegunn/fzf-git.sh)
|
|
|
|
Provides keybindings:
|
|
- `CTRL-G CTRL-F` - Files from git status
|
|
- `CTRL-G CTRL-B` - Branches
|
|
- `CTRL-G CTRL-T` - Tags
|
|
- `CTRL-G CTRL-R` - Remotes
|
|
- `CTRL-G CTRL-H` - Commit hashes
|
|
- `CTRL-G CTRL-S` - Stashes
|
|
- `CTRL-G CTRL-L` - Reflogs
|
|
- `CTRL-G CTRL-W` - Worktrees
|
|
- `CTRL-G CTRL-E` - Each ref (git for-each-ref)
|
|
|
|
## Docker Integration
|
|
|
|
### Select Containers
|
|
|
|
```bash
|
|
# Attach to running container
|
|
docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}' |
|
|
fzf --delimiter '\t' --with-nth 1,2,3 |
|
|
cut -f1 |
|
|
xargs -o docker attach
|
|
```
|
|
|
|
### Select Images
|
|
|
|
```bash
|
|
# Remove images
|
|
docker images --format '{{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.Size}}' |
|
|
fzf --multi --delimiter '\t' |
|
|
cut -f2 |
|
|
xargs docker rmi
|
|
```
|
|
|
|
### View Logs
|
|
|
|
```bash
|
|
# Follow container logs
|
|
docker ps --format '{{.Names}}' |
|
|
fzf --preview 'docker logs --tail 50 {}' |
|
|
xargs -o docker logs -f
|
|
```
|
|
|
|
## Kubernetes Integration
|
|
|
|
### Select Pods
|
|
|
|
```bash
|
|
# Get shell in pod
|
|
kubectl get pods --all-namespaces -o wide |
|
|
fzf --header-lines=1 |
|
|
awk '{print "-n", $1, $2}' |
|
|
xargs -o kubectl exec -it -- /bin/sh
|
|
```
|
|
|
|
### Pod Logs with Follow
|
|
|
|
```bash
|
|
pods() {
|
|
kubectl get pods --all-namespaces |
|
|
fzf --info=inline --layout=reverse --header-lines=1 \
|
|
--prompt "$(kubectl config current-context)> " \
|
|
--header $'CTRL-O: logs | CTRL-R: reload\n' \
|
|
--bind 'start,ctrl-r:reload:kubectl get pods --all-namespaces' \
|
|
--bind 'ctrl-o:execute:kubectl logs --namespace {1} {2} | less' \
|
|
--preview-window up:follow \
|
|
--preview 'kubectl logs --follow --tail=100 --namespace {1} {2}'
|
|
}
|
|
```
|
|
|
|
### Context Switching
|
|
|
|
```bash
|
|
# Switch context
|
|
kubectl config get-contexts -o name |
|
|
fzf --preview 'kubectl config view -o jsonpath="{.contexts[?(@.name==\"{}\")]}"' |
|
|
xargs kubectl config use-context
|
|
```
|
|
|
|
## tmux Integration
|
|
|
|
### Select Sessions
|
|
|
|
```bash
|
|
# Attach to session
|
|
tmux list-sessions -F '#S' |
|
|
fzf --preview 'tmux capture-pane -pt {}' |
|
|
xargs tmux switch-client -t
|
|
```
|
|
|
|
### Select Windows
|
|
|
|
```bash
|
|
# Switch to window
|
|
tmux list-windows -a -F '#S:#W' |
|
|
fzf --preview 'tmux capture-pane -pt {}' |
|
|
xargs tmux switch-client -t
|
|
```
|
|
|
|
### tmux Popup
|
|
|
|
```bash
|
|
# Use fzf in tmux popup
|
|
fzf --tmux center,80%
|
|
```
|
|
|
|
## Shell Function Recipes
|
|
|
|
### Interactive cd
|
|
|
|
```bash
|
|
# cd with preview
|
|
fcd() {
|
|
local dir
|
|
dir=$(fd --type d --hidden --follow --exclude .git |
|
|
fzf --preview 'tree -C {} | head -50') &&
|
|
cd "$dir"
|
|
}
|
|
```
|
|
|
|
### Edit Recent Files
|
|
|
|
```bash
|
|
# Edit recent git files
|
|
vg() {
|
|
local files
|
|
files=$(git ls-files --modified --others --exclude-standard |
|
|
fzf --multi --preview 'bat --color=always {}') &&
|
|
vim $files
|
|
}
|
|
```
|
|
|
|
### Kill Process
|
|
|
|
```bash
|
|
# Interactive process killer
|
|
fkill() {
|
|
local pid
|
|
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')
|
|
if [ -n "$pid" ]; then
|
|
echo "$pid" | xargs kill -9
|
|
fi
|
|
}
|
|
```
|
|
|
|
### Search History
|
|
|
|
```bash
|
|
# Enhanced history search
|
|
fh() {
|
|
eval $(history | fzf +s --tac | sed 's/ *[0-9]* *//')
|
|
}
|
|
```
|
|
|
|
### Open GitHub PR
|
|
|
|
```bash
|
|
# Select and open PR
|
|
gpr() {
|
|
gh pr list |
|
|
fzf --preview 'gh pr view {1}' |
|
|
awk '{print $1}' |
|
|
xargs gh pr checkout
|
|
}
|
|
```
|
|
|
|
### Man Page Viewer
|
|
|
|
```bash
|
|
# Browse man pages
|
|
fman() {
|
|
man -k . |
|
|
fzf --prompt='Man> ' --preview 'man {1}' |
|
|
awk '{print $1}' |
|
|
xargs man
|
|
}
|
|
```
|
|
|
|
### Environment Variables
|
|
|
|
Add to your shell config:
|
|
|
|
```bash
|
|
# Better defaults
|
|
export FZF_DEFAULT_OPTS='
|
|
--height 40%
|
|
--layout reverse
|
|
--border
|
|
--info inline
|
|
--preview-window right,50%,border-left
|
|
'
|
|
|
|
# CTRL-T with preview
|
|
export FZF_CTRL_T_OPTS="
|
|
--preview 'bat --color=always --style=numbers --line-range :500 {}'
|
|
--bind 'ctrl-/:change-preview-window(down|hidden|)'
|
|
"
|
|
|
|
# CTRL-R with preview
|
|
export FZF_CTRL_R_OPTS="
|
|
--preview 'echo {}'
|
|
--preview-window up:3:hidden:wrap
|
|
--bind 'ctrl-/:toggle-preview'
|
|
--bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort'
|
|
--header 'CTRL-Y to copy'
|
|
"
|
|
|
|
# ALT-C with tree preview
|
|
export FZF_ALT_C_OPTS="
|
|
--preview 'tree -C {} | head -100'
|
|
"
|
|
```
|
|
|
|
## Tips
|
|
|
|
### Performance
|
|
|
|
- Avoid `--ansi` in `FZF_DEFAULT_OPTS` (slows scanning)
|
|
- Use `--nth` sparingly (requires tokenization)
|
|
- Prefer string delimiter over regex
|
|
- Use `fd` instead of `find` for file listing
|
|
|
|
### Debugging
|
|
|
|
```bash
|
|
# Test preview command
|
|
echo "test.txt" | fzf --preview 'bat --color=always {}'
|
|
|
|
# See what fzf receives
|
|
fzf --preview 'echo {} | cat -v'
|
|
```
|
|
|
|
### Escaping
|
|
|
|
```bash
|
|
# Escape special characters in queries
|
|
fzf --query 'foo\ bar' # Literal space
|
|
|
|
# In shell scripts, quote properly
|
|
fzf --bind "enter:execute(vim '{}')"
|
|
```
|