tools

VIM: Better grepping (in Windows)

Several times I noticed that grepping in VIM (finding in files) does not work very well comparing to Visual Studio or VSCode at least. I felt it pretty hard last time when I tried to search in a medium-size web project. It took over 23 seconds to search for files and another 55 seconds to render the list of results. I’ve never experienced something similar in any other editor.  Another think that bothered me was the quality of results which frequently showed binary files, multi-line records or everything else what I could call “rubbish” in the context of file search option:

2017-04-08_22-41-56

The first guess is that alternative editors just skip files that are not source code. And that’s the thing (at least looking at Visual Studio Code file search):

2017-04-08_22-54-55

Unfortunately there is no easy way to tell VIM grepper to exclude locations from search (at least in Windows). The default findstr (you can find more about it in my previous post) does not have such option. Nevertheless there is a way to achieve such behaviour. Just add this snippet to your $VIMRC file:

function! FastGrep(what, ...) abort
 let where = a:0
 if where == ""
    let where = "*.*"
 endif
 let command = "silent ! dir /s/b/a:-d"
 let command = command . " | findstr /v \\node_modules\\"
 let command = command . " | findstr /v \\dist\\"
 let command = command . " | findstr /v \\\.git\\"
 let command = command . " | findstr /v \.map$"
 let command = command . " | findstr /v \.swp$"
 let command = command . " | findstr /v \.ts\.html$"
 let command = command . " | findstr /v ~$"
 " add excludes here ------^
 let command = command . " > \\%home\\%\\solution_files.tmp"
 execute comma              nd
 execute "grep /f:\\%home\\%\\solution_files.tmp ".a:what." ".where
endfunction

:command! -nargs=+ -complete=command Grep2 call FastGrep(<q-args>)

The idea behind the snippet is the following: get list of all the files in the working folder, remove the locations you want to exclude, and then pass the list of files to “findstr” command (/f switch allows to pass the list of input files).

Here’s a quick list of tricks used in the snippet:

execute              - run vim command
!                    - execute shell command
silent               - skip "Press ENTER to continue" after running shell
dir /s/b/a:-d        - get a raw list (/b) of files only (/a:-d) 
                       in all subdirectories (/s) 
findstr /v \.git\    - find lines that does not containing "\.git\"
%home%               - user home directory (i.e. c:\users\user_1)
FastGrep(what, ...)  - function taking one named argument and array of 
                       unnamed arguments
a:0                  - first unnamed argument
:command!            - define VIM command alias
-nargs=+             - alias must have arguments (any number)
<q-args>             - list of arguments passed to the alias

Now in order to execute such command you just need to run:

:Grep2 myFunction1
:Grep2 myFunction2 *.js

The same operation that took initially 23 seconds was executed in less than 1 second (with rendering results). Of course it showed less records, but only the meaningful ones (a side note: my medium-size web application contained 996 folders inside /node_modules !!).

Remember that you can extend it by your own excludes.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s