Search code examples
regexvimgrepvictags

Show all matching grep results in new tab in Vim


I am attempting to map a hotkey to do the following in Vim:

  1. Match the current c-word currently marked by the cursor
  2. Generate a list of all found occurrences in current project
  3. Open a new tab showing the results

So, one example I have that uses CTAGS opens the declaration of a variable/function in a new tab like so:

map <C-\> :split<CR>:exec("tag ".expand("<cword>"))<CR>

When it hit CTRL-\, a new tab is opened with the declaration of the variable/function the cursor is on.

The command I am trying to map is shown below:

:lvim /\<\(text_i_want_to_find\)\>/gj *.c
:lw

When I run this command, a new tab is opened showing a list of all .c files containing the text text_i_want_to_find. I need to modify this to do two things different from what it does now:

  1. Search all files with extensions of .c, .h, .cpp, .mk, instead of just .c, and also search files named "Makefile"
  2. Search for the c-word under the cursor like the CTRL-\ mapping I have shown above, as opposed to having to manually type in the text text_i_want_to_find

Here is the code in my .vimrc file for the mapping. I'm not entirely sure if CTRL-/ can be mapped at all, so there's one more problem for me to solve.

map <C-/> :split<CR>:lvim /\<\(.expand("<cword>")\)\>/gj *.c *.h *.cpp *.mk Makefile

Does anyone have any tips on fixing this Vim mapping?


EDIT:

After reviewing the answers provided to me, here's the final version of my code:

command! -nargs=1 SearchAll execute " grep -srnw --binary-files=without-match --exclude={*~,tags} --exclude-dir=.svn  . -e " . expand("<args>") . " " <bar> cwindow
map <C-g> :SearchAll <cword><CR>

I mapped it to CTRL+g. I can also invoke it like so as a colon command:

:SearchAll my_text_to_search_for

Hope this helps others as well!


Solution

  • Of course, it does not work: you forgot :execute, :lvimgrep command on its own does not accept expressions, so you are searching for expand("<cword>") that is not followed by a keyword character (\>) and preceded by any character that does not follow keyword character (\<.). \( and \) are useless here. Other notes:

    1. Don’t use map: you need neither this mapping working in visual and operator-pending modes nor ability to use other mappings.
    2. Some patterns can be merged: *.[ch] *.cpp *.mk Makefile or even *.{[ch],cpp,mk} Makefile.
    3. <C-\> can be mapped, but not <C-/> (I hope only currently, but no real work on fixing it is done): \ is 0x5C and <C-\> is 0x5C-0x40=0x1C. But / is 0x2F and 0x2F-0x40<0. On my system pressing <C-/> in terminal transforms into <C-_>, so does <C-->.
    4. :split command does not open a new tab, it opens a new window. Prepend it with :tab to do this.
    5. :lvimgrep is not going to show you the results. It is not either going to jump to the first result unless you remove the j flag.
    6. You forgot final <CR> as well as :lw<CR>. I use :lopen below, in this context they produce just the same result.
    7. You forgot <C-u> after first : or <C-\><C-n> before: it is needed to discard count.
    8. You don’t really need :execute in either of your mappings because there is <C-r>=expand("cword")<CR>, or a default shortcut <C-r><C-w>.
    9. Don’t write :exec(str): it is confusing because :execute is not a function and this syntax encourages others to think it is. Use :execute str.

    Thus the final mapping is:

    nnoremap <C-\> :<C-u>tab split \| lvimgrep /\V\<<C-r><C-w>\>/gj *.{[ch],cpp,mk} Makefile \| lopen<CR>
    

    . Replace it with

    nnoremap <C-\> :<C-u>lvimgrep /\V\<<C-r><C-w>\>/gj *.{[ch],cpp,mk} Makefile \| tab lopen<CR>
    

    if you don’t want to see the current file in a newly opened tab.

    Both mappings assume you have neither / nor \ in 'iskeyword' option, if you do replace <C-r><C-w> with <C-r>=escape(expand('<cword>'), '/\')<CR>.