Interactive Fuzzy Finding in Vim without Plugins

Table of Contents

Overview
The Setup
Bonus
Caveat
Summary

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 :R…


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:

  1. Call fzf
  2. Format the output to make it compatible with errorformat
  3. Write the results to a temporary file
  4. 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
  5. 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 them errorformat-compatible.
    • Note: you can drop this awk command if you set 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
  • 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
  • nnoremap <leader>ff :Files<cr>
    • Normal-mode mapping so that we can trigger this flow with <leader>ff

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 to fzf 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


Print Share Comment Cite Upload Translate Updates
APA

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/

MLA
" » Interactive Fuzzy Finding in Vim without Plugins." Peter Benjamin | Sciencx - Sunday July 25, 2021, https://www.scien.cx/2021/07/25/interactive-fuzzy-finding-in-vim-without-plugins/
HARVARD
Peter Benjamin | Sciencx Sunday July 25, 2021 » Interactive Fuzzy Finding in Vim without Plugins., viewed ,<https://www.scien.cx/2021/07/25/interactive-fuzzy-finding-in-vim-without-plugins/>
VANCOUVER
Peter Benjamin | Sciencx - » Interactive Fuzzy Finding in Vim without Plugins. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/07/25/interactive-fuzzy-finding-in-vim-without-plugins/
CHICAGO
" » Interactive Fuzzy Finding in Vim without Plugins." Peter Benjamin | Sciencx - Accessed . https://www.scien.cx/2021/07/25/interactive-fuzzy-finding-in-vim-without-plugins/
IEEE
" » Interactive Fuzzy Finding in Vim without Plugins." Peter Benjamin | Sciencx [Online]. Available: https://www.scien.cx/2021/07/25/interactive-fuzzy-finding-in-vim-without-plugins/. [Accessed: ]
rf:citation
» Interactive Fuzzy Finding in Vim without Plugins | Peter Benjamin | Sciencx | 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.

You must be logged in to translate posts. Please log in or register.