16

Is there any way to configure VIM to interactively search inside every file for an entire project?

By interactive, I mean updating each keystroke.

Something like Emacs counsel-git-grep, see: example demo.

3
  • I don't use it personally so I'm not 100% sure but I think ctrl-p or a similar plugin is what you are looking for. Note that unite.vim should also be able to do that but I wouldn't recommend it because in my opinion it is a pretty heavy and bug-creating plugin.
    – statox
    Commented Dec 21, 2016 at 10:33
  • Does ctrl-p have a way to interactively search the file contents? I've only ever used it to interactively search for files based on their names.
    – ideasman42
    Commented Dec 21, 2016 at 12:05
  • I think it is possible but as I said I don't use it so maybe I'm wrong
    – statox
    Commented Dec 21, 2016 at 12:23

1 Answer 1

15

I'm not sure this is what you're looking for, but maybe you could try fzf and fzf.vim.

If you use vim-plug as a plugin manager, all you should have to do to install them, is to add these lines in your vimrc:

Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'

... somewhere between the lines:

call plug#begin('~/.vim/plugged')

and:

call plug#end()

Then execute :PlugInstall.


Among various commands and mappings provided by fzf.vim (whose only purpose seems to be to install mappings and commands asking fzf to fuzzy search through predefined sources), there is the command :Ag.

To be able to use it, you need to install the shell command ag. On debian based distributions, it can be done with the following command:

apt-get install silversearcher-ag

The project on github explains how to install it on MacOS:

brew install the_silver_searcher

:Ag is a wrapper around $ ag, and allows you to fuzzy search a pattern in the files of the current directory (the one displayed when you type :pwd). The matches are updated after every keystroke.

You can:

  • cycle forward and backward through the matches with C-n and C-p
  • select the current match and move to the next/previous one with Tab/S-Tab
  • select or deselect all the matches with M-a or M-d

If you select one or several matches, after hitting Enter, they will populate the quickfix list. From there you'll be able to navigate through them with default Vim commands / mappings, such as :cnext and :cprevious.

enter image description here

If you want to add a prefix to all the commands installed by fzf.vim, and avoid overriding existing commands, you can add this in your vimrc:

let g:fzf_command_prefix = 'your_prefix'

I use Fzf as a prefix, that's why I didn't type :Ag but :FzfAg.


If you prefer to use git grep instead of ag, it seems you could install your own custom wrapper around it, :GGrep, like this:

command! -bang -nargs=* GGrep
  \ call fzf#vim#grep('git grep --line-number '.shellescape(<q-args>), 0, <bang>0)

It's explained in :h fzf-vim-customization.

Also, if fzf opens a pane in tmux, and you would prefer it takes the whole screen instead, you can append a bang to all the commands (:Ag!, :GGrep!, ...).


As you said in your last comment, by default fzf changes the configuration of your shell. For example, if you use bash, it will add the following line in your ~/.bashrc:

[ -f ~/.fzf.bash ] && source ~/.fzf.bash

This will source the file ~/.fzf.bash. The latter contains some code:

# Setup fzf
# ---------
if [[ ! "$PATH" == */home/user/.fzf/bin* ]]; then
  export PATH="$PATH:/home/user/.fzf/bin"
fi

# Auto-completion
# ---------------
[[ $- == *i* ]] && source "/home/user/.fzf/shell/completion.bash" 2> /dev/null

# Key bindings
# ------------
source "/home/user/.fzf/shell/key-bindings.bash"

This code appends a path to the environment variable $PATH: /home/user/.fzf/bin ; which is the folder containing the fzf program.

It also sources 2 other files:

/home/user/.fzf/shell/completion.bash
/home/user/.fzf/shell/key-bindings.bash

The first one seems to define completion functions, while the second installs key bindings.

Unfortunately, the key bindings may override default readline functions.
For example, fzf binds the function fzf-file-widget to C-t. This key is usually used by readline to execute the transpose-chars function.

If you don't want this, one possible solution would be to restore the key bindings inside your ~/.bashrc, after fzf has sourced its configuration. For example, if you wanted C-t to keep its old behavior, that is transposing the 2 characters around the cursor, and bind fzf-file-widget to another key, let's say C-x C-t, you could add these lines at the end of ~/.bashrc:

bind -x '"\C-x\C-t": fzf-file-widget'
bind '"\C-t": transpose-chars'

The same thing applies to the zsh shell, but the syntax to install a key binding is a little different:

bindkey '^X^T' fzf-file-widget
bindkey '^T' transpose-chars

If one of the shell key binding you were used to has been overridden by fzf, you want to restore it, but don't know what's the exact name of the function which was executed, you could try the following thing.

First, inside your ~/.bashrc, temporarily comment out the line which sources the fzf configuration. Then, reopen a terminal, and have a look at the output of the bind -P command, which you can read in a Vim buffer:

bind -P | vim -R -

I'm not sure, but I think it should display most or all the readline key bindings. If you're looking for the name of the readline function bound to the C-t key, in the Vim buffer, you would search \\C-t. And if you were looking for the one bound to M-c (meta / alt key), you would search \\ec (\e stands for the escape key and it seems M-c produces the same keycodes as escape + c).

You can do the same thing in zsh by looking at the output of the bindkey command. But this time, ^[ stands for the meta/alt modifier key, while a single caret (^) character stands for the control key.


Currently, I found 4 key bindings executing functions containing the fzf keyword in their name. They use the key sequences C-i (same as Tab), C-r, C-t and M-c. They are bound to the following functions:

C-i    fzf-completion
C-r    fzf-history-widget
C-t    fzf-file-widget
M-c    fzf-cd-widget

On my system, originally, readline (the library used by bash to edit the command line) bound those keys to these functions:

C-i     complete
C-r     reverse-search-history
C-t     transpose-chars
M-c     capitalize-word

And zle (the line editor used by zsh), bound them to:

C-i     expand-or-complete
C-r     history-incremental-search-backward
C-t     transpose-chars
M-c     capitalize-word
4
  • 2
    Is ag a separate plugin/tool that needs to be installed?
    – ideasman42
    Commented Dec 21, 2016 at 12:41
  • @ideasman42 Yes, sorry about that, I forgot that the shell command ag was also necessary. I updated the answer. Commented Dec 21, 2016 at 12:51
  • 1
    Probably worth noting these tools are quite intrusive, replacing your bash and zsh configurations by default.
    – ideasman42
    Commented Jan 12, 2017 at 15:12
  • @ideasman42 You're right, I updated the answer to mention this problem. Commented Jan 12, 2017 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.