Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Vim: Creating your own ack.vim/ag.vim

Creating your own ag.vim

Vim provides built-in mechanisms to search through projects in the form of the grep command. However, on large projects, grep is known to be slow; and hence people have been switching to simpler searchers like ack, and faster, parallel (metal?) searchers like ag and pt. Correspondingly, several plugins have been created that integrate these tools in vim: ack.vim, ag.vim, etc.

However, it's actually very easy to get the functionalities these plugins provide (faster search, results in quickfix-window, jumps, previews, and so on) in vanilla Vim itself; in fact, Vim already populates the grep-search results in a quickfix window. We just need to tell Vim to do the following things (use-case: ag):

  • Use ag as the default grep program
  • Open quickfix window by default
  • Create mappings to easily navigate among the search-results

So let us build our ag-based lightweight grepper. Note that ag (aka 'the silver searcher') needs to be installed on your PC.

Set ag as the default grep program

This just requires adding the following simple lines to your vimrc:

if executable('ag')
  set grepprg=ag\ --nogroup\ --nocolor
endif

That's it! The next time you do a 'grep', Vim will actually use 'ag' (if installed on your PC) and show the results blazingly fast.

If you wish to display column numbers like vimgrep (a built-in but slightly slower grep), you can add --vimgrep to the grepprg option, and modify the grepformat option to display the column numbers properly. Thus, the updated version will look as follows:

if executable('ag')
  set grepprg=ag\ --nogroup\ --nocolor\ --vimgrep
  set grepformat^=%f:%l:%c:%m   " file:line:column:message
endif

Open quickfix window by default

Let us do this in an elegant way using a function. Say we wish to define a new command called Search that takes a word, greps it, and shows the results in a quickfix-window. The function to do the same can be something like this:

function! MySearch()
  let grep_term = input("Enter search term: ")
  if !empty(grep_term)
    execute 'silent grep' grep_term | copen
  else
    echo "Empty search term"
  endif
  redraw!
endfunction

The function MySearch:

  • prompts for the term to be grepped
  • checks whether the user pressed Enter without giving a search term; if yes, displays an error
  • if the search-term is valid, greps it using the default grep-program
  • opens the result in a quickfix-window
  • redraws the screen in order to avoid any distortion

Note that you can navigate across the results of the quickfix-window using :cnext and :cprevious, and close it using :cclose. Or, you can move to the quickfix-window and jump to any of the results using the arrow (or any vim-movement) keys and pressing Enter.

The next task is to define a command to call the above function:

command! Search call MySearch()

Done! Now just type :Search in Vim's command-line, and press Enter to grep a term using ag.

Custom mappings

You can also create a custom mapping for the Search command:

nnoremap <leader>s :Search<CR>    " Default leader is '\' (backslash)

If you have used ack.vim and ag.vim, and want custom mappings for the quickfix-window, such as closing it using q and jumping to a result directly whie closing the quickfix-window using O, then add the following mappings to the file .vim/ftplugin/qf.vim:

nnoremap <buffer><silent> q :cclose<CR>
nnoremap <buffer><silent> O <CR>:cclose<CR>

You can similarly create maps to open a result in a new tab, in a new split, etc., as the plugins do, if you need.

Grep the word under cursor

There are two ways to achieve this:

  1. Vim allows the word under the cursor to be put in the command-line mode using Ctrl-R followed by Ctrl-W. Thus, typing this sequence after :Search<CR>, and pressing Enter, will allow you to search the word under the cursor.
  2. The word under the cursor can be referred using <cword> in Vimscript. Thus, you can grep the word under the cursor using the map <leader>* as follows:
nnoremap <leader>* :silent grep <cword> \| copen<CR><C-l>   " <C-l> redraws the screen

This finishes your personal, Vim-native, lightweight ag.vim script. References: :help grepprg, :help grepformat, :help quickfix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment