Finally a smart fuzzy file picker for neovim.
FFF stands for freakin fast fuzzy file finder (pick 3) and it is an opinionated fuzzy file picker for neovim. Just for files, but we'll try to solve file picking completely.
It comes with a dedicated rust backend runtime that keep tracks of the file index, your file access and modifications, git status, and provides a comprehensive typo-resistant fuzzy search experience.
- Works out of the box with no additional configuration
- Typo resistant fuzzy search
- Git status integration allowing to take advantage of last modified times within a worktree
- Separate file index maintained by a dedicated backend allows <10 milliseconds search time for 50k files codebase
- Display images in previews (for now requires snacks.nvim)
- Smart in a plenty of different ways hopefully helpful for your workflow
Note
Although we'll try to make sure to keep 100% backward compatibility, by using you should understand that silly bugs and breaking changes may happen. And also we hope for your contributions and feedback to make this plugin ideal for everyone.
FFF.nvim requires:
- Neovim 0.10.0+
- Rust toolchain (requires nightly for building the native backend)
{
"dmtrKovalenko/fff.nvim",
build = "cargo build --release",
-- or if you are using nixos
-- build = "nix run .#release",
opts = {
-- pass here all the options
},
keys = {
{
"ff", -- try it if you didn't it is a banger keybinding for a picker
function()
require("fff").find_files() -- or find_in_git_root() if you only want git files
end,
desc = "Open file picker",
},
},
}FFF.nvim comes with sensible defaults. Here's the complete configuration with all available options:
require('fff').setup({
-- Core settings
base_path = vim.fn.getcwd(), -- Base directory for file indexing
max_results = 100, -- Maximum search results to display
max_threads = 4, -- Maximum threads for fuzzy search
prompt = '🪿 ', -- Input prompt symbol
title = 'FFF Files', -- Window title
ui_enabled = true, -- Enable UI (default: true)
-- Window dimensions
width = 0.8, -- Window width as fraction of screen
height = 0.8, -- Window height as fraction of screen
-- Preview configuration
preview = {
enabled = true, -- Enable preview pane
width = 0.5, -- Preview width as fraction of window
max_lines = 5000, -- Maximum lines to load
max_size = 10 * 1024 * 1024, -- Maximum file size (10MB)
imagemagick_info_format_str = '%m: %wx%h, %[colorspace], %q-bit', -- ImageMagick info format
line_numbers = false, -- Show line numbers in preview
wrap_lines = false, -- Wrap long lines
show_file_info = true, -- Show file info header
binary_file_threshold = 1024, -- Bytes to check for binary detection
filetypes = { -- Per-filetype settings
svg = { wrap_lines = true },
markdown = { wrap_lines = true },
text = { wrap_lines = true },
log = { tail_lines = 100 },
},
},
-- Layout configuration (alternative to width/height)
layout = {
prompt_position = 'top', -- Position of prompt ('top' or 'bottom')
preview_position = 'right', -- Position of preview ('right' or 'left')
preview_width = 0.4, -- Width of preview pane
height = 0.8, -- Window height
width = 0.8, -- Window width
},
-- Keymaps
keymaps = {
close = '<Esc>',
select = '<CR>',
select_split = '<C-s>',
select_vsplit = '<C-v>',
select_tab = '<C-t>',
move_up = { '<Up>', '<C-p>' }, -- Multiple bindings supported
move_down = { '<Down>', '<C-n>' },
preview_scroll_up = '<C-u>',
preview_scroll_down = '<C-d>',
toggle_debug = '<F2>', -- Toggle debug scores display
},
-- Highlight groups
hl = {
border = 'FloatBorder',
normal = 'Normal',
cursor = 'CursorLine',
matched = 'IncSearch',
title = 'Title',
prompt = 'Question',
active_file = 'Visual',
frecency = 'Number',
debug = 'Comment',
},
-- Frecency tracking (track file access patterns)
frecency = {
enabled = true, -- Enable frecency tracking
db_path = vim.fn.stdpath('cache') .. '/fff_nvim', -- Database location
},
-- Logging configuration
logging = {
enabled = true, -- Enable logging
log_file = vim.fn.stdpath('log') .. '/fff.log', -- Log file location
log_level = 'info', -- Log level (debug, info, warn, error)
},
-- UI appearance
ui = {
wrap_paths = true, -- Wrap long file paths in list
wrap_indent = 2, -- Indentation for wrapped paths
max_path_width = 80, -- Maximum path width before wrapping
},
-- Image preview (requires terminal with image support)
image_preview = {
enabled = true, -- Enable image previews
max_width = 80, -- Maximum image width in columns
max_height = 24, -- Maximum image height in lines
},
-- Icons
icons = {
enabled = true, -- Enable file icons
},
-- Debug options
debug = {
enabled = false, -- Enable debug mode
show_scores = false, -- Show scoring information (toggle with F2)
},
})require('fff').find_files() -- Find files in current directory
require('fff').find_in_git_root() -- Find files in the current git repository
require('fff').scan_files() -- Trigger rescan of files in the current directory
require('fff').refresh_git_status() -- Refresh git status for the active file lock
require('fff').find_files_in_dir(path) -- Find files in a specific directory
require('fff').change_indexing_directory(new_path) -- Change the base directory for the file pickerFFF.nvim provides several commands for interacting with the file picker:
:FFFFind [path|query]- Open file picker. Optional: provide directory path or search query:FFFScan- Manually trigger a rescan of files in the current directory:FFFRefreshGit- Manually refresh git status for all files:FFFClearCache [all|frecency|files]- Clear various caches:FFFHealth- Check FFF health status and dependencies:FFFDebug [on|off|toggle]- Toggle debug scores display:FFFOpenLog- Open the FFF log file in a new tab
You can assign multiple key combinations to the same action:
keymaps = {
move_up = { '<Up>', '<C-p>', '<C-k>' }, -- Three ways to move up
close = { '<Esc>', '<C-c>' }, -- Two ways to close
select = '<CR>', -- Single binding still works
}The input field automatically handles multiline clipboard content by joining all lines into a single search query. This is particularly useful when copying file paths from terminal output.
Toggle scoring information display:
- Press
F2while in the picker - Use
:FFFDebugcommand - Enable by default with
debug.show_scores = true
Run :FFFHealth to check the status of FFF.nvim and its dependencies. This will verify:
- File picker initialization status
- Optional dependencies (git, image preview tools)
- Database connectivity
If you encounter issues, check the log file:
:FFFOpenLogOr manually open the log file at ~/.local/state/nvim/log/fff.log (default location).
File picker not initializing:
- Ensure the Rust backend is compiled:
cargo build --releasein the plugin directory - Check that your Neovim version is 0.10.0 or higher
Image previews not working:
- Verify your terminal supports images (kitty, iTerm2, WezTerm, etc.)
- For terminals without native image support, install one of:
chafa,viu, orimg2txt - If using snacks.nvim, ensure it's properly configured
Performance issues:
- Adjust
max_threadsin configuration based on your system - Reduce
preview.max_linesandpreview.max_sizefor large files - Clear cache if it becomes too large:
:FFFClearCache all
Files not being indexed:
- Run
:FFFScanto manually trigger a file scan - Check that the
base_pathis correctly set - Verify you have read permissions for the directory
Enable debug mode to see scoring information and troubleshoot search results:
- Press
F2while in the picker - Run
:FFFDebug onto enable permanently - Set
debug.show_scores = truein configuration