Use Multiple Patterns in Vimgrep in Key Mapping - vim

In my vimrc I had a mapping to find all line with TODO in them and put them in the quickfix window:
nnoremap <leader>f :vimgrep /TODO/j % \| :cw<CR>
I now want to add the alternative pattern FIXME in the same way. So I tried
nnoremap <leader>f :vimgrep /TODO\|FIXME/j % \| :cw<CR>
and
nnoremap <leader>f :vimgrep /TODO<bar>FIXME/j % \| :cw<CR>
but neither return any results.
vimgrep /TODO|FIXME/j %
works at the : prompt when typed manually. So far my work-around is this:
function! FindFixme()
vimgrep /TODO\|FIXME/j %
cw
endfunction
nnoremap <leader>f :call FindFixme()<CR>
But I don't really understand why I can't get it to work as a single map command.
Thanks.

The regular expression item for alternation is \|, and you indeed need to escape a | so that it doesn't end the mapping command. Taken together, you need two backslashes: one for escaping and one to remain for the item:
nnoremap <leader>f :vimgrep /TODO\\|FIXME/j % \| :cw<CR>
But I would prefer the <Bar> notation, maybe even combined with <Bslash>:
nnoremap <leader>f :vimgrep /TODO<Bslash><Bar>FIXME/j % <Bar> :cw<CR>
You can further shorten this to:
nnoremap <leader>f :vimgrep /TODO<Bslash><Bar>FIXME/j %<Bar>cw<CR>

Related

use specific search with no highlight

For example I'm in python code and want to jump between classes:
nnoremap <buffer> [c /^\s*class\ <CR>
How to prevent them from highlight in more elegant way than :nohl at the end of command each time?
You can avoid highlighting search matches by using the :help search() function or writing your own function.
With search()
nnoremap <buffer> <silent> [c :<C-u>call search('^\s*\zsclass\s')<CR>
With your own function
" with ':help :normal'
function! JumpToNextClass()
normal! /^\s*\zsclass\s
endfunction
" with ':help search()'
function! JumpToNextClass()
call search('^\s*\zsclass\s')
endfunction
nnoremap <buffer> <silent> [c :<C-u>call JumpToNextClass()<CR>
But none of that really matters since Vim already comes with ]] and [[.

How to make 'intelligent' key mappings in Vim?

At present I have the following mappings in my Vimrc:
" Quick Buffer switch mappings {{{
" The idea is to press <leader> and then the number from normal mode to switch
" e.g. `,2` would switch to the second buffer (listed at the top of the
" airline strip
nnoremap <Leader>1 :1b<CR>
nnoremap <Leader>2 :2b<CR>
nnoremap <Leader>3 :3b<CR>
nnoremap <Leader>4 :4b<CR>
nnoremap <Leader>5 :5b<CR>
nnoremap <Leader>6 :6b<CR>
nnoremap <Leader>7 :7b<CR>
nnoremap <Leader>8 :8b<CR>
nnoremap <Leader>9 :9b<CR>
nnoremap <Leader>10 :10b<CR>
nnoremap <Leader>11 :11b<CR>
nnoremap <Leader>12 :12b<CR>
nnoremap <Leader>13 :13b<CR>
nnoremap <Leader>14 :14b<CR>
nnoremap <Leader>15 :15b<CR>
nnoremap <Leader>16 :16b<CR>
" Quick Buffer wipe/delete keys. Press <Leader> and then d and buffer number
" e.g. `,d2` would wipe buffer 2
nnoremap <Leader>d1 :Bdelete 1<CR>
nnoremap <Leader>d2 :Bdelete 2<CR>
nnoremap <Leader>d3 :Bdelete 3<CR>
nnoremap <Leader>d4 :Bdelete 4<CR>
nnoremap <Leader>d5 :Bdelete 5<CR>
nnoremap <Leader>d6 :Bdelete 6<CR>
nnoremap <Leader>d7 :Bdelete 7<CR>
nnoremap <Leader>d8 :Bdelete 8<CR>
nnoremap <Leader>d9 :Bdelete 9<CR>
nnoremap <Leader>d10 :Bdelete 10<CR>
nnoremap <Leader>d11 :Bdelete 11<CR>
nnoremap <Leader>d12 :Bdelete 12<CR>
nnoremap <Leader>d13 :Bdelete 13<CR>
nnoremap <Leader>d14 :Bdelete 14<CR>
nnoremap <Leader>d15 :Bdelete 15<CR>
nnoremap <Leader>d16 :Bdelete 16<CR>
" }}}
They work great but I can't help thinking this should be smarter/DRYer in the vimrc. What about if I open a buffer with number 17 for example.
Is there a way of intelligently mapping these so that a user could enter and then any buffer number to have the buffer open?
You can use meta-programming with :execute to automate the creation of those mappings:
for i in range(1, 99)
execute printf('nnoremap <Leader>%d :%db<CR>', i, i)
endfor
It is also possible to define a single mapping (with just a prefix), that then queries the number via getchar(). The challenge here is to determine when to end this, something that you get for free (due to 'timeout') with the separate mappings. That's why I would prefer the first solution here.
<c-6> switches to the previous buffer. However you can also provide a count which will be used to switch to that buffer. E.g. 6<c-6> is equivalent to :b 6.
I still can't help but think these buffer commands are a bit awkward because have to keep buffer numbers and files straight in your head. I think using some of :b native features could be of some help to you:
:b command can take a partial filenames. e.g. :b foo
:b can use globs so you can add some fuzziness. e.g. :b foo*bar.c
<tab> to complete the filenames
<c-d> for listing out the buffer names
split with the :sb command which takes all the same arguments as :b
I find :bdelete a bit dangerous they way you have it. I would suggest you just switch to a buffer and then do :bd to delete the current buffer. However :bd can take partial filenames and globs as well just like :b.
I have also seen ~/.vimrc files where people use a mapping to call :ls and then start the prompt with :b. Think of more of a menu based approach.
nnoremap <leader>b :ls<cr>:b<space>
For more help see:
:h ctrl-6
:h :b
:h :sb
:h :bd
:h :ls
Here is a slightly different strategy that only uses a single mapping:
:nnoremap <silent> <key> :<C-u>try \| execute "b" . v:count \| catch \| endtry<CR>
Now you can do 3<key> to go to buffer number 3. I'll leave it up to you to find the right <key>.

How to escape "<CR>" in a mapping in vimscript

I want to construct a command line within a mapping, using the :execute normal "commandstring" techinique. But I can't do it from within a mapping as vim immediately interprets the "" as a keypress. So this doesn't work:
nnoremap <leader>jj :execute "normal :tabnew foo.txt\<cr>"<cr>
I tried doubly escaping the backslash, to no effect:
nnoremap <leader>jj :execute "normal :tabnew foo.txt\\<cr>"<cr>
Now vim types in the backslash and then interprets the as a keypress.
Any way out of this?
That's indeed tricky. You have to escape the < character as <lt>, so that the <cr> is not parsed as special key notation:
nnoremap <leader>jj :execute "normal :tabnew foo.txt\<lt>cr>"<cr>
Note that your example doesn't need any of this; :normal :...<CR> is the same as ...
nnoremap <leader>jj :tabnew foo.txt<cr>

vim: visual star search not working as expected

I copied this function to visually search with * and #:
function! s:VSetSearch(cmdtype)
let temp = #s
norm! gv"sy
let #/ = '\V' . substitute(escape(#s, a:cmdtype.'\'), '\n', '\\n', 'g')
let #s = temp
endfunction
xnoremap * :<C-u>call <SID>VSetSearch('/')<CR>/<C-R>=#/<CR><CR>
xnoremap # :<C-u>call <SID>VSetSearch('?')<CR>?<C-R>=#/<CR><CR>
The # mapping works fine but the * mapping doesn't exit visual selection (it extends the range of the visual selection until the next searched word). I don't understand why this is happening. Is there a solution?
EDIT: To reproduce the problem save the code snippet, download the MS Installer, open cmd.exe and start vim vim -u NONE, then do :set nocp and finally source the saved code. In fact, the following simple mapping doesn't work either:
nnoremap * *<C-o>
EDIT 2: Can someone else reproduce this issue? Should it be reported?
EDIT 3: I believe that the problem (bug?) is that the * (star) key cannot be remapped: if I start vim with vim -N -u NONE (Vim 7.4 with patches 1-274) and run the command :noremap * :echo "star"<CR> and press *, vim tries to perform a search. I also reported this to the vim dev group.
The following is what I use :
function! s:Vword()
return getline('.')[col("'<")-1:col("'>")-1]
endfunction
xnoremap <silent> * <Esc>/\v<<C-R>=<SID>Vword()<CR>><CR>
xnoremap <silent> g* <Esc>/\v<C-R>=<SID>Vword()<CR><CR>
xnoremap <silent> # o<Esc>?\v<<C-R>=<SID>Vword()<CR>><CR>
xnoremap <silent> g# o<Esc>?\v<C-R>=<SID>Vword()<CR><CR>
nnoremap <silent> g// :grep -w <cword> <C-R>=getcwd()<CR><CR>
nnoremap <silent> g/* :grep <cword> <C-R>=getcwd()<CR><CR>
xnoremap <silent> g// :<C-U>grep -w <C-R>=<SID>Vword()<CR> <C-R>=getcwd()<CR><CR>
xnoremap <silent> g/* :<C-U>grep <C-R>=<SID>Vword()<CR> <C-R>=getcwd()<CR><CR>
I have also additionally added nice mappings for g* & similarly g# and also a bunch of mappings for invoking grep that I find very useful.
Edit: minor fixes to code.
Mapping <kMultiply> instead of * solved the problem. Really strange since I do not use the keypad multiply key.

Vimgrep mapping not working

If I run manually the command
:vimgrep /\CTODO:\|FIXME:\|NOTE:/ %
everything works as expected. However when i try the following mapping:
nnoremap <leader>tl :vimgrep /\CTODO:\|FIXME:\|NOTE:/ %<CR>
I get the error:
E480: No match: \CTODO:|FIXME:|NOTE:
I don't why the map is not working.
| is used to separated vim commands. You have escaped the | to treat the pipe as one command however this changes regex into \CTODO:|FIXME:|NOTE: Look at the mapping via :nmap to see how the mapping has changed.
I suggest you use <bar> instead of the pipe symbol in your mapping:
nnoremap <leader>tl :vimgrep /\CTODO:\<bar>FIXME:\<bar>NOTE:/ %<CR>

Resources