using variable and expressions in search and replace command - vim

I am trying to set some key mapping/macros to comment/uncomment blocks of text in my .vimrc but I can't manage to make it work.
I define some variables:
let g:comment_id='~'
autocmd BufRead,BufNewFile *.c,*.cpp,*.cxx,*.h,*.hpp,*.hxx,*.ipp let b:comment_open='//'
autocmd BufRead,BufNewFile *.f90,*.F90 let b:comment_open='!'
And then I try differents ways to use them but everytime it fails:
noremap <silent> ,cc :s/^/<C-R>=(b:comment_open.g:comment_id)/<CR>:nohlsearch<CR>
noremap <silent> ,uc :s/<C-R>=(b:comment_open.g:comment_id)//<CR>:nohlsearch<CR>
->
E15: Invalid expression: /,
E15: Invalid expression: (b:comment_open.g:comment_id)//
noremap <silent> ,cc :s/^/<C-R>=(b:comment_open.g:comment_id)<CR>/<CR>:nohlsearch<CR>
noremap <silent> ,uc :s/<C-R>=(b:comment_open.g:comment_id)<CR>//<CR>:nohlsearch<CR>
->
E488: Trailing characters
noremap <silent> ,cc :s/^/\=(b:comment_open.g:comment_id)/<CR>:nohlsearch<CR>
noremap <silent> ,uc :s/\=(b:comment_open.g:comment_id)//<CR>:nohlsearch<CR>
->
cc: ok,
uc:
E64: \= follows nothing,
E476: Invalid command
I fact I can't understand how 'C-R' and \= work and mean...
Thanks for your help

Use:
nnoremap <silent> ,cc :s/^/\=b:comment_open.g:comment_id/<CR>:nohlsearch<CR>
nnoremap <silent> ,uc :s#\V<c-r>=escape(b:comment_open.g:comment_id,'\#')<cr>##<cr>:nohlsearch<cr>
Reference: :help sub-replace-expression
It is necessary in the pattern to turn verynomagic on to escape all special characters, and even with that you need to escape both the delimiter and the backslash.

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 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.

vim : <silent> nmap

In vim I have this nmap
nmap <silent> ,mu : marks ABCDEFGHIJKLMNOPQRSTUVWXYZ<CR>
If I donĀ“t have Upper marks and try ,mu I get
E283: No marks matching "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
why don't show the Error output ?
Try
nnoremap <silent> ,mu :execute "try\nmarks ABCDEFGHIJKLMNOPQRSTUVWXYZ\ncatch /\\V\\^Vim(marks):E283:/\nendtry"<CR>
By the way, is there a reason for writing :nmap instead of :nnoremap? You should not do this if you don't have a reason unless you want to run in the situation where you can't predict what will be the result of adding another mapping (directly to vimrc or by installing a plugin).
Edit (sehe)
To make things more readable, I'd suggest using a snippet like this in your $MYVIMRC:
function! ShowGlobalMarks()
try
marks ABCDEFGHIJKLMNOPQRSTUVWXYZ
catch /E283:/
endtry
endfu
nnoremap <silent> ,mu :call ShowGlobalMarks()<CR>

Vim: remap key to toggle line numbering

I added:
set number
nnoremap <F2> :set nonumber!
to my vimrc file. Basically what it's supposed to do is let me press F2 to toggle line numbering but it's not working. What have I done wrong?
In your .vimrc, add this:
set number
nnoremap <F2> :set nonumber!<CR>
Then pressing F2 will toggle line numbering.
This is what I use (with a different key binding):
nmap <f2> :set number! number?<cr>
The "number!" toggles the setting and "number?" reports the state.
nmap <silent> <F11> :exec &nu==&rnu? "se nu!" : "se rnu!"<CR>
In new vim you can set both relative number and number at once, this way:
set nu rnu
This is one method:
map <silent> <F2> :if &number <Bar>
\set nonumber <Bar>
\else <Bar>
\set number <Bar>
\endif<cr>
(this one is nice 'cause I usually put foldcolumn in there as well)
This is another:
map <silent> <F2> :set invnumber<cr>
(direct method)
I use this to toggle between relativenumber ( with current absolute line number) and no line numbering
nnoremap <silent> <leader>l :set relativenumber! <bar> set nu!<CR>

Resources