Skip to content

Instantly share code, notes, and snippets.

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

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

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
    echo "Empty search term"

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.


This comment has been minimized.

Copy link

@voyeg3r voyeg3r commented Jan 3, 2017

Following your tip I figured out that I did not have a snippet for new vim commands, and here we are:
#ultisnip for new vim commands

snippet 'com(mand)?' "define a new vim command" !r
command! -nargs=${1:0} ${2:command name} :${3:execution}

By the way, I was wondering how can I change the search function to give it a patter at once, like this:
:Search grep


This comment has been minimized.

Copy link
Owner Author

@manasthakur manasthakur commented Jan 3, 2017

Hi @voyeg3r,

snippet 'com(mand)?'

Cool 👍

:Search grep

If I understood your question correctly, you can supply the term to search by modifying
(a) the Search command to:

command! -nargs=1 Search call MySearch(<q-args>)

(b) the MySearch function to:

function! MySearch(grep_term)
" upper logic
  execute 'silent grep' a:grep_term | copen
" lower logic

This comment has been minimized.

Copy link

@vcavallo vcavallo commented Jan 3, 2017

👍 This serves as a really nice introduction to the basics of vim functions and commands, as well :)


This comment has been minimized.

Copy link

@bjoernwibben bjoernwibben commented Jun 23, 2017

If you get the Error E194, for example if you search for a CSS color with a #-Sign you have to escape the grep_term:
execute 'silent grep' escape(grep_term, "%#!") | copen
Now you can search for special characters too.

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