--- name: fzf description: Command-line fuzzy finder for interactive filtering of any list. Use when interactively selecting files, searching command history (CTRL-R), creating selection interfaces in scripts, building interactive menus, or integrating fuzzy search with tools like ripgrep, fd, and git. Triggers on mentions of fzf, fuzzy finder, ** completion, interactive filtering, or shell keybindings CTRL-T/CTRL-R/ALT-C. --- # fzf - Command-Line Fuzzy Finder ## Overview fzf is a general-purpose command-line fuzzy finder. It reads a list of items from STDIN, allows interactive selection using fuzzy matching, and outputs the selected item(s) to STDOUT. Think of it as an interactive grep. **Key characteristics:** - **Fast**: Processes millions of items instantly - **Portable**: Single binary, works everywhere - **Versatile**: Customizable via event-action binding mechanism - **Integrated**: Built-in shell integrations for bash, zsh, and fish ## When to Use This Skill Use fzf when: - **Selecting files interactively**: `vim $(fzf)` or fuzzy completion with `**` - **Searching command history**: CTRL-R for fuzzy history search - **Navigating directories**: ALT-C to cd into selected directory - **Building interactive scripts**: Create selection menus for any list - **Filtering output**: Pipe any command output through fzf - **Integrating with other tools**: ripgrep, fd, git, etc. ## Prerequisites **CRITICAL**: Before proceeding, you MUST verify that fzf is installed: ```bash fzf --version ``` **If fzf is not installed:** - **DO NOT** attempt to install it automatically - **STOP** and inform the user that fzf is required - **RECOMMEND** manual installation with the following instructions: ```bash # macOS brew install fzf # Debian/Ubuntu sudo apt install fzf # Arch Linux sudo pacman -S fzf # From source git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf ~/.fzf/install # Other systems: see https://github.com/junegunn/fzf#installation ``` **If fzf is not available, exit gracefully and do not proceed with the workflow below.** ## Shell Integration fzf provides shell integration that enables powerful keybindings (CTRL-T, CTRL-R, ALT-C) and fuzzy completion (`**`). These features require the user to configure their shell. **Note:** Shell integration setup is the user's responsibility. If keybindings don't work, **RECOMMEND** the user add the appropriate line to their shell config: ```bash # Bash (~/.bashrc) eval "$(fzf --bash)" # Zsh (~/.zshrc) source <(fzf --zsh) # Fish (~/.config/fish/config.fish) fzf --fish | source ``` ### Key Bindings (requires shell integration) | Key | Function | Description | |-----|----------|-------------| | `CTRL-T` | File selection | Paste selected files/directories onto command line | | `CTRL-R` | History search | Fuzzy search command history | | `ALT-C` | Directory jump | cd into selected directory | **CTRL-R extras:** - Press `CTRL-R` again to toggle sort by relevance - Press `ALT-R` to toggle raw mode (see surrounding items) - Press `CTRL-/` or `ALT-/` to toggle line wrapping ### Fuzzy Completion (`**`) Trigger fuzzy completion with `**` followed by TAB: ```bash # Files under current directory vim ** # Files under specific directory vim ../fzf** # Directories only cd ** # Process IDs (for kill) kill -9 ** # SSH hostnames ssh ** # Environment variables export ** ``` ## Search Syntax fzf uses extended-search mode by default. Multiple search terms are separated by spaces. | Token | Match Type | Description | |-------|------------|-------------| | `sbtrkt` | Fuzzy match | Items matching `sbtrkt` | | `'wild` | Exact match | Items containing `wild` exactly | | `'wild'` | Exact boundary | Items with `wild` at word boundaries | | `^music` | Prefix match | Items starting with `music` | | `.mp3$` | Suffix match | Items ending with `.mp3` | | `!fire` | Inverse match | Items NOT containing `fire` | | `!^music` | Inverse prefix | Items NOT starting with `music` | | `!.mp3$` | Inverse suffix | Items NOT ending with `.mp3` | **OR operator**: Use `|` to match any of several patterns: ```bash # Files starting with 'core' and ending with go, rb, or py ^core go$ | rb$ | py$ ``` **Escape spaces**: Use `\ ` to match literal space characters. ## Basic Usage ### Simple Selection ```bash # Select a file and open in vim vim $(fzf) # Safer with xargs (handles spaces, cancellation) fzf --print0 | xargs -0 -o vim # Using become() action (best approach) fzf --bind 'enter:become(vim {})' ``` ### Multi-Select ```bash # Enable multi-select with -m fzf -m # Select with TAB, deselect with Shift-TAB # Selected items printed on separate lines ``` ### Preview Window ```bash # Basic preview fzf --preview 'cat {}' # With syntax highlighting (requires bat) fzf --preview 'bat --color=always {}' # Customize preview window position/size fzf --preview 'cat {}' --preview-window=right,50% fzf --preview 'cat {}' --preview-window=up,40%,border-bottom ``` ## Display Modes ### Height Mode ```bash # Use 40% of terminal height fzf --height 40% # Adaptive height (shrinks for small lists) seq 5 | fzf --height ~100% # With layout options fzf --height 40% --layout reverse --border ``` ### tmux Mode ```bash # Open in tmux popup (requires tmux 3.3+) fzf --tmux center # Center, 50% width/height fzf --tmux 80% # Center, 80% width/height fzf --tmux left,40% # Left side, 40% width fzf --tmux bottom,30% # Bottom, 30% height ``` ## Essential Options ### Layout and Appearance ```bash --height=HEIGHT[%] # Non-fullscreen mode --layout=reverse # Display from top (default: bottom) --border[=STYLE] # rounded, sharp, bold, double, block --margin=MARGIN # Margin around finder --padding=PADDING # Padding inside border --info=STYLE # default, inline, hidden ``` ### Search Behavior ```bash -e, --exact # Exact match (disable fuzzy) -i # Case-insensitive +i # Case-sensitive --scheme=SCHEME # default, path, history --algo=TYPE # v2 (quality), v1 (performance) ``` ### Input/Output ```bash -m, --multi # Enable multi-select --read0 # Read NUL-delimited input --print0 # Print NUL-delimited output --ansi # Enable ANSI color processing ``` ### Field Processing ```bash --delimiter=STR # Field delimiter (default: AWK-style) --nth=N[,..] # Limit search to specific fields --with-nth=N[,..] # Transform display of each line ``` ## Event Bindings Customize behavior with `--bind`: ```bash # Basic syntax fzf --bind 'KEY:ACTION' fzf --bind 'EVENT:ACTION' fzf --bind 'KEY:ACTION1+ACTION2' # Chain actions # Examples fzf --bind 'ctrl-a:select-all' fzf --bind 'ctrl-d:deselect-all' fzf --bind 'ctrl-/:toggle-preview' fzf --bind 'enter:become(vim {})' ``` ### Key Actions (Selection) | Action | Description | |--------|-------------| | `accept` | Accept current selection | | `abort` | Abort and exit | | `toggle` | Toggle selection of current item | | `select-all` | Select all matches | | `deselect-all` | Deselect all | | `toggle-all` | Toggle all selections | ### Useful Actions | Action | Description | |--------|-------------| | `reload(cmd)` | Reload list from command | | `become(cmd)` | Replace fzf with command | | `execute(cmd)` | Run command, return to fzf | | `execute-silent(cmd)` | Run command silently | | `preview(cmd)` | Change preview command | | `toggle-preview` | Show/hide preview | | `change-prompt(str)` | Change prompt string | ### Events | Event | Triggered When | |-------|----------------| | `start` | fzf starts | | `load` | Input loading completes | | `change` | Query string changes | | `focus` | Focused item changes | | `result` | Result list updates | For complete action reference, see [references/actions.md](references/actions.md). ## Environment Variables ### Core Configuration ```bash # Default command when input is TTY export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git' # Default options (applied to all fzf invocations) export FZF_DEFAULT_OPTS='--height 40% --layout reverse --border' # Options file (alternative to FZF_DEFAULT_OPTS) export FZF_DEFAULT_OPTS_FILE=~/.fzfrc ``` ### Shell Integration Variables ```bash # CTRL-T options export FZF_CTRL_T_COMMAND="fd --type f" export FZF_CTRL_T_OPTS="--preview 'bat --color=always {}'" # CTRL-R options export FZF_CTRL_R_OPTS="--bind 'ctrl-y:execute-silent(echo -n {2..} | pbcopy)+abort'" # ALT-C options export FZF_ALT_C_COMMAND="fd --type d" export FZF_ALT_C_OPTS="--preview 'tree -C {}'" ``` ### Completion Customization ```bash # Change trigger sequence (default: **) export FZF_COMPLETION_TRIGGER='~~' # Completion options export FZF_COMPLETION_OPTS='--border --info=inline' ``` ## Common Patterns ### Find and Edit Files ```bash # Using fd for better performance fd --type f | fzf --preview 'bat --color=always {}' | xargs -o vim # Or with become() fd --type f | fzf --preview 'bat --color=always {}' --bind 'enter:become(vim {})' ``` ### Search File Contents (with ripgrep) ```bash # Basic ripgrep integration rg --line-number . | fzf --delimiter : --preview 'bat --color=always {1} --highlight-line {2}' # Open result in vim at line rg --line-number . | fzf --delimiter : --bind 'enter:become(vim {1} +{2})' ``` ### Git Integration ```bash # Select git branch git branch | fzf | xargs git checkout # Select commit git log --oneline | fzf --preview 'git show {1}' | cut -d' ' -f1 # Stage files interactively git status -s | fzf -m | awk '{print $2}' | xargs git add ``` ### Dynamic List Reloading ```bash # Reload process list with CTRL-R ps -ef | fzf --bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' # Toggle between files and directories fd | fzf --bind 'ctrl-d:reload(fd --type d)' --bind 'ctrl-f:reload(fd --type f)' ``` ### Interactive ripgrep Launcher ```bash # fzf as ripgrep frontend (search updates on typing) RG_PREFIX="rg --column --line-number --no-heading --color=always" fzf --ansi --disabled \ --bind "start:reload:$RG_PREFIX ''" \ --bind "change:reload:$RG_PREFIX {q} || true" \ --bind 'enter:become(vim {1} +{2})' \ --delimiter : ``` ## Placeholders Use in `--preview`, `--bind`, etc.: | Placeholder | Description | |-------------|-------------| | `{}` | Current selection (quoted) | | `{+}` | All selected items (space-separated) | | `{q}` | Current query string | | `{n}` | Zero-based index of current item | | `{1}`, `{2}`, etc. | Nth field (with --delimiter) | | `{-1}` | Last field | | `{1..3}` | Fields 1 through 3 | | `{2..}` | Fields 2 to end | **Flags:** - `{+}` - All selected items - `{f}` - Write to temp file (for large lists) - `{r}` - Raw (unquoted) output ## Advanced Topics For detailed documentation on advanced features, see: - [references/actions.md](references/actions.md) - Complete list of bindable actions - [references/options.md](references/options.md) - Full options reference - [references/integrations.md](references/integrations.md) - ripgrep, fd, git, bat integrations ## Troubleshooting **"Command not found: fzf"** - fzf is not installed. See Prerequisites section for manual installation instructions - Do NOT attempt automatic installation **Shell keybindings not working (CTRL-T, CTRL-R, ALT-C):** - Shell integration must be configured by the user - RECOMMEND adding the appropriate line to shell config (see Shell Integration section) - For bash, must be sourced after any PS1 modifications **Performance issues:** - Avoid `--ansi` in `FZF_DEFAULT_OPTS` (slows initial scan) - Use `--nth` sparingly (requires tokenization) - Prefer string `--delimiter` over regex **Preview not showing:** - Check preview command syntax - Use `{}` placeholder for current selection - Test preview command manually first **CTRL-R not finding old commands:** - fzf searches shell history, not history file - Increase `HISTSIZE` and `HISTFILESIZE` ## Resources - **Man page**: `man fzf` or `fzf --man` - **Wiki examples**: https://github.com/junegunn/fzf/wiki/examples - **Advanced examples**: https://github.com/junegunn/fzf/blob/master/ADVANCED.md - **Theme playground**: https://vitormv.github.io/fzf-themes/ - **fzf-git.sh**: https://github.com/junegunn/fzf-git.sh (git keybindings)