This content originally appeared on DEV Community and was authored by Peter Benjamin
Table of Contents
Overview
FZF is a great command-line fuzzy-finder and there is fzf.vim plugin that integrates with Vim to provide features, like :Files
to fuzzy search over files and :Rg
to fuzzy search over text using ripgrep
.
Recently, however, I have been experimenting with a plugin-free Vim setup and while :find
is sufficient for some use-cases, I found myself quitting vim and running fzf
to find deeply nested files in new or large projects.
There has to be a simple way to integrate a command-line program with a command-line editor, right?
The Setup
This setup is simple and it leverages a feature in vim called quickfix.
The flow is:
- Call
fzf
- Format the output to make it compatible with
errorformat
- Write the results to a temporary file
- Load the results into Vim's quickfix list with
:cfile
or:cgetfile
, so that we can navigate through the results with:cnext
/:cprevious
or:copen
- Clean up temporary file
Here is what the final vimscript looks like:
function! FZF() abort
let l:tempname = tempname()
" fzf | awk '{ print $1":1:0" }' > file
execute 'silent !fzf --multi ' . '| awk ''{ print $1":1:0" }'' > ' . fnameescape(l:tempname)
try
execute 'cfile ' . l:tempname
redraw!
finally
call delete(l:tempname)
endtry
endfunction
" :Files
command! -nargs=* Files call FZF()
" \ff
nnoremap <leader>ff :Files<cr>
A quick breakdown:
-
let l:tempname = tempname()
- Generate a path to a temporary file and store it in a variable.
- See
:h tempname()
-
execute 'silent !fzf --multi ' . '| awk ''{ print $1":1:0" }'' > ' . fnameescape(l:tempname)
- Call
fzf
with--multi
to allow for selecting multiple files - Pipe to
awk
to append:1:0
to fzf results to make themerrorformat
-compatible. - Note: you can drop this
awk
command if youset errorformat+=%f
in your vimrc, but I found%f
to capture a lot of false-positives from other programs' outputs and therefore:cnext
/:cprevious
don't function on these false-positive results. - Finally, direct the results into the temp file
- Call
-
execute 'cfile ' . l:tempname
- Load results from temp file into quickfix list and jump to the 1st result.
- Note #1: you may use
:cgetfile
to only load results into quickfix list without jumping to the 1st result. - Note #2: you may replace
:cfile
/:cgetfile
with:lfile
/:lgetfile
to use location list instead of quickfix list. Location lists are window-specific, whereas quickfix lists are global. So if you prefer to have different set of results per vim window, then use:lfile
/:lgetfile
.
-
call delete(l:tempname)
- Clean up by deleting the temp file
-
command! -nargs=* Files call FZF()
- Invoke
FZF()
function when we call:Files
in vim
- Invoke
-
nnoremap <leader>ff :Files<cr>
- Normal-mode mapping so that we can trigger this flow with
<leader>ff
- Normal-mode mapping so that we can trigger this flow with
Bonus
While :set grepprg=rg\ --vimgrep
is again sufficient for most of my use-cases, those who have used :Rg
in fzf.vim will appreciate the interactive fuzzy grepping experience and the ability to preview results before opening files in vim.
Well, here is a similar experience with pure vim (obviously, fzf
and rg
binaries are still required):
function! RG(args) abort
let l:tempname = tempname()
let l:pattern = '.'
if len(a:args) > 0
let l:pattern = a:args
endif
" rg --vimgrep <pattern> | fzf -m > file
execute 'silent !rg --vimgrep ''' . l:pattern . ''' | fzf -m > ' . fnameescape(l:tempname)
try
execute 'cfile ' . l:tempname
redraw!
finally
call delete(l:tempname)
endtry
endfunction
" :Rg [pattern]
command! -nargs=* Rg call RG(<q-args>)
" \fs
nnoremap <leader>fs :Rg<cr>
This offers the same experience where:
-
:Rg
without arguments will load all text into vim and allow users to interactively type and preview results before selecting files -
:Rg [pattern]
will pre-filter results to just ones that match[pattern]
before passing them tofzf
for further fuzzy searching.
Caveat
In my testing, I found one major caveat that did not impact me too much, but it is still worth calling out here:
Executing shell commands in vim with bangs, like :!fzf
, is not meant to be interactive (at least, not out of the box). This could be a problem in GVim/MacVim. The vim docs mention the following workaround:
On Unix the command normally runs in a non-interactive shell. If you want an interactive shell to be used (to use aliases) set 'shellcmdflag' to "-ic".
Setting shellcmdflag=-ic
could incur a time penalty, depending on your shell startup/initialization times.
Summary
Vim is extremely versatile and customizable.
With some knowledge of vim concepts (e.g. quickfix, :cfile
/:lfile
) and a little bit of (vim & bash) scripting, you can achieve a richer experience and pleasant integrations to enhance your productivity in a way that suits you and your workflow.
I hope you enjoyed this post and I hope it inspires you to develop and share your productivity tips and tricks in vim.
Happy hacking!
This content originally appeared on DEV Community and was authored by Peter Benjamin

Peter Benjamin | Sciencx (2021-07-25T03:11:02+00:00) Interactive Fuzzy Finding in Vim without Plugins. Retrieved from https://www.scien.cx/2021/07/25/interactive-fuzzy-finding-in-vim-without-plugins/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.