VIM - map # (number sign) to "search selected" in visual mode - vim

I'm struggling to map # to search selected in visual. What I've tried so far was vnoremap <silent> <#> y<ESC>/^R0<CR> (y ank selected, search / from ^R egister 0 and hit CR ), but it does not work. What is the right way to do this?

vnoremap # y/<C-r>0<CR>
# instead of <#>, <Esc> is redundant after y, and ^R should be <C-r>.

Related

Can Vim apply shiftround to a block as a whole instead of linewise?

I generally like the shiftround option in Vim, but there are a couple of
situations where it doesn't work very well. For instance, take this example:
f(x,
y)
Selecting the two lines and shifting with > and the two lines selected gives
me (and shiftwidth set to 4):
f(x,
y)
When I really wanted:
f(x,
y)
In other words, Vim advanced each line of the block to the next tabstop, when I
really wanted it to insert the same amount of inserted on each line--but I want
the least indented line to end up on the next tabstop.
Is there an easy way to get this behavior in Vim? My goal is to have this work
for < and > (with a visual selection) rather than other workarounds.
Ctrl+V, select vertical column before the text you need to shift (j in your case of just two lines), Shift+I, insert needed number of tabs or spaces, Esc.
You can actually use this method to insert arbitrary text, for example you can insert # or // to comment some code. More info in :help blockwise-operators.
I would solve this via a separate set of mappings that enclose the >> commands with a temporary clearing of 'shiftround'. Here's an implementation:
" g>> Shift [count] lines one 'shiftwidth' rightwards, without
" 'shiftround'.
"{Visual}[count]> Shift the highlighted lines [count] 'shiftwidth'
" rightwards (for {Visual} see |Visual-mode|), without
" 'shiftround'.
" g<<, {Visual}[count]<
function! s:Shift( command )
let s:save_shiftround = &shiftround
set noshiftround
return a:command
endfunction
function! s:RestoreShiftRound()
let &shiftround = s:save_shiftround
return ''
endfunction
nnoremap <expr> <SID>(RestoreShiftRound) <SID>RestoreShiftRound()
nnoremap <expr> <SID>(ShiftRight) <SID>Shift('>>')
xnoremap <expr> <SID>(ShiftRight) <SID>Shift('>')
nnoremap <expr> <SID>(ShiftLeft) <SID>Shift('<<')
xnoremap <expr> <SID>(ShiftLeft) <SID>Shift('<')
nnoremap <silent> <script> <Plug>(ShiftRightNoRound) <SID>(ShiftRight)<SID>(RestoreShiftRound)
xnoremap <silent> <script> <Plug>(ShiftRightNoRoundSelection) <SID>(ShiftRight)<SID>(RestoreShiftRound)
nnoremap <silent> <script> <Plug>(ShiftLeftNoRound) <SID>(ShiftLeft)<SID>(RestoreShiftRound)
xnoremap <silent> <script> <Plug>(ShiftLeftNoRoundSelection) <SID>(ShiftLeft)<SID>(RestoreShiftRound)
nmap g>> <Plug>(ShiftRightNoRound)
xmap g> <Plug>(ShiftRightNoRoundSelection)
nmap g<< <Plug>(ShiftLeftNoRound)
xmap g< <Plug>(ShiftLeftNoRoundSelection)
I didn't cover the >{motion} command, as that would be more complex.

Is it possible to use vimgrep for a visual selection of the current file?

I would like to search with vimgrep only within a visual selection of the current file and not the whole file. Is that possible and how? I couldn't find something for this case with Google or in vim help.
The reason why I want this is because I need the result in the quicklist (copen) and :g/FOO which is showing the matching lines at the bottom is not doing this job.
Yes, you can, as Vim has special regular expression atoms for mark positions, and the start and end of the visual selection is marked by '< and '>. As there are atoms for on / before / after a mark, we need to combine those to cover the entire range of selected lines:
On the selection start | after the selection start and before the selection end | on the selection end.
To limit the search to the current file, the special % keyword is used.
:vimgrep/\%(\%'<\|\%>'<\%<'>\|\%'>\)FOO/ %
You are on the right path with using :g command. The basic idea is do something like this:
:g/FOO/caddexpr expand("%") . ":" . line(".") . ":" . getline(".")
Now lets make it a command
command! -range -nargs=+ VisualSeach cgetexpr []|<line1>,<line2>g/<args>/caddexpr expand("%") . ":" . line(".") . ":" . getline(".")
Now you can do :VisualSearch FOO and it will add the searches to the quickfix list.
Note that the issue w/ this is only finds one match per line.
This is from Steve Losh's vimrc. It makes * work on the visual selection. I've gotten pretty dependent on it.
" Visual Mode */# from Scrooloose {{{
function! s:VSetSearch()
let temp = ##
norm! gvy
let #/ = '\V' . substitute(escape(##, '\'), '\n', '\\n', 'g')
let ## = temp
endfunction
vnoremap * :<C-u>call <SID>VSetSearch()<CR>//<CR><c-o>
vnoremap # :<C-u>call <SID>VSetSearch()<CR>??<CR><c-o>

How do I move to the next capital letter?

In vim I can use f followed by a character to go to the next occurrence of that character on the current line. For example, if I have the following (cursor position marked with |):
m|akeBinExprNode = undefined
I can use fB to move to B and dtE to delete until before the E, leaving me with:
make|ExprNode = undefined
I wonder if there's a way to do this that doesn't involve typing the exact character, i.e. some kind of motion that means "go to the next capital letter" and/or "go to right before the next capital letter".
When I searched for that I would be happy to just have the "native" solution: just enter in command mode:
/\u
which stands for "search for an uppercase letter". After that just move between capital letters with n and N (shift + n).
I would recommand the following script : camelcasemotion. It allows you to jump , delete inner 'camel case words', using ,+ normal navigation [w,b,e] etc...
I have found this vim tip for moving within CamelCaseWords that might be useful:
" Use one of the following to define the camel characters.
" Stop on capital letters.
let g:camelchar = "A-Z"
" Also stop on numbers.
let g:camelchar = "A-Z0-9"
" Include '.' for class member, ',' for separator, ';' end-statement,
" and <[< bracket starts and "'` quotes.
let g:camelchar = "A-Z0-9.,;:{([`'\""
nnoremap <silent><C-Left> :<C-u>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%^','bW')<CR>
nnoremap <silent><C-Right> :<C-u>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%$','W')<CR>
inoremap <silent><C-Left> <C-o>:call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%^','bW')<CR>
inoremap <silent><C-Right> <C-o>:call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%$','W')<CR>
vnoremap <silent><C-Left> :<C-U>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%^','bW')<CR>v`>o
vnoremap <silent><C-Right> <Esc>`>:<C-U>call search('\C\<\<Bar>\%(^\<Bar>[^'.g:camelchar.']\#<=\)['.g:camelchar.']\<Bar>['.g:camelchar.']\ze\%([^'.g:camelchar.']\&\>\#!\)\<Bar>\%$','W')<CR>v`<o
wilhelmtell's answer will work unless 'ignorecase' parameter is set. If 'smartcase' is activated or 'noignorecase' then it is okay.
However a pattern that can replace [A-Z] is \u (see :help /\u or more globally :help pattern). Therefore you can replace your mapping with:
:nnoremap <leader>C /\u<CR>:nohlsearch<CR>
:nmap <leader>C /[A-Z]<CR>:nohlsearch<CR>
Then in normal mode <leader>C (which by default means \C)

Setting to skip over punctuation when moving forwards and backwards words

When I'm using vim I generally never want to move to a punctuation mark when I press w or b to go forwards or backwards. So I'm wondering if there's a setting or something to change this functionality?
e.g. If I've got some code like
object.method(args)
and my cursor is at the [o] in "object" then I want w to move to the [m] in "method", and another w to move to the [a] in "args". I don't want it to land on the [.] or the [(]. If I've ever wanted to move to a punctuation char I've always used f or F to jump straight to it. I've never personally wanted to move to a punctuation char when I move through words and I just realized this is really bugging me.
I too find that I would like a movement that is more inclusive that w, but not as inclusive as W. In particular, I would like a movement that only considers tokens beginning with alphanumeric characters as significant.
So I came up with the following:
" <SPACE> : forward to next word beginning with alphanumeric char
" <S-SPACE> : backward to prev word beginning with alphanumeric char
" <C-SPACE> : same as above (as <S-SPACE> not available in console Vim
" <BS> : back to prev word ending with alphanumeric char
function! <SID>GotoPattern(pattern, dir) range
let g:_saved_search_reg = #/
let l:flags = "We"
if a:dir == "b"
let l:flags .= "b"
endif
for i in range(v:count1)
call search(a:pattern, l:flags)
endfor
let #/ = g:_saved_search_reg
endfunction
nnoremap <silent> <SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'f')<CR>
vnoremap <silent> <SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv/\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <S-SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'b')<CR>
vnoremap <silent> <S-SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv?\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <BS> :call <SID>GotoPattern('[A-Za-z0-9_]\(\>\\|$\)', 'b')<CR>
vnoremap <silent> <BS> :<C-U>let g:_saved_search_reg=#/<CR>gv?[A-Za-z0-9_]\(\>\\|$\)<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
" Redundant mapping of <C-SPACE> to <S-SPACE> so that
" above mappings are available in console Vim.
"noremap <C-#> <C-B>
if has("gui_running")
map <silent> <C-Space> <S-SPACE>
else
if has("unix")
map <Nul> <S-SPACE>
else
map <C-#> <S-SPACE>
endif
endif
I have had this for a long time now, and I find that I use <SPACE>/<C-SPACE> movements so much more than w and W; it just seems more useful when coding. You can, of course, map the commands to whatever keys you find useful or more appropriate.
Even running the risk of creating a script for something that's built-in (like
I did last time), here is a little function that may help accomplishing
this.
function! JumpToNextWord()
normal w
while strpart(getline('.'), col('.')-1, 1) !~ '\w'
normal w
endwhile
endfunction
Basically, what it does is executing the standard w and repeating it
if the character under the cursor is not in a word character (feel free to
change that pattern.
If you add that and a little map in your .vimrc:
nnoremap <silent> ,w :call JumpToNextWord()<CR>
It should work.

How to paste over without overwriting register

Does anyone know of a way to paste over a visually selected area without having the selection placed in the default register?
I know I can solve the problem by always pasting from an explicit register. But it's a pain in the neck to type "xp instead of just p
Use the following:
xnoremap p pgvy
this will reselect and re-yank any text that is pasted in visual mode.
Edit: in order this to work with "xp you can do:
xnoremap p pgv"#=v:register.'y'<cr>
v:register expands to the last register name used in a normal mode command.
I don't like the default vim behavior of copying all text deleted with d, D, c, or C into the default register.
I've gotten around it by mapping d to "_d, c to "_c, and so on.
From my .vimrc:
"These are to cancel the default behavior of d, D, c, C
" to put the text they delete in the default register.
" Note that this means e.g. "ad won't copy the text into
" register a anymore. You have to explicitly yank it.
nnoremap d "_d
vnoremap d "_d
nnoremap D "_D
vnoremap D "_D
nnoremap c "_c
vnoremap c "_c
nnoremap C "_C
vnoremap C "_C
"{register}p won't work as you describe. It will replace the selection with the content of the register. You will have instead to do something like:
" I haven't found how to hide this function (yet)
function! RestoreRegister()
let #" = s:restore_reg
return ''
endfunction
function! s:Repl()
let s:restore_reg = #"
return "p#=RestoreRegister()\<cr>"
endfunction
" NB: this supports "rp that replaces the selection by the contents of #r
vnoremap <silent> <expr> p <sid>Repl()
Which should be fine as long as you don't use a plugin that has a non-nore vmap to p, and that expects a register to be overwritten.
This code is available as a script there. Ingo Karkat also defined a plugin solving the same issue.
In your .vimrc
xnoremap p "_dP
I found this from a response on a similar thread, but the original source was http://vim.wikia.com/wiki/Replace_a_word_with_yanked_text. It mentions some drawbacks, however it works fine for me.
Luc Hermitte's solution works like a charm. I was using it for about a week or so. Then I discovered a solution from Steve Losh's .vimrc that works nicely if YankRing is part of your plugin/bundle lineup:
function! YRRunAfterMaps()
" From Steve Losh, Preserve the yank post selection/put.
vnoremap p :<c-u>YRPaste 'p', 'v'<cr>gv:YRYankRange 'v'<cr>
endfunction
Try this in your ~/.vimrc:
xnoremap <expr> p 'pgv"'.v:register.'y'
xnoremap means that this is only for Visual mode, not Visual + Select modes.
<expr> means that {rhs} of the xnoremap {lhs} {rhs} setting is evaluated as an expression.
In this case, our expression of 'pgv"'.v:register.'y' is using . for concatenation.
v:register is evaluated to the register being used during the fulfillment of the mapping.
The result of "xp would evaluate to pgv"xy, where x is the register.
I was helped by an answer to this stackoverflow question: Vim - mapping with an optional register prefix
in conjunction with Benoit's answer on this page
Luc's function worked well for me after I made a change to support the fact that I have clipboard=unnamed set:
function! RestoreRegister()
let #" = s:restore_reg
if &clipboard == "unnamed"
let #* = s:restore_reg
endif
return ''
endfunction
Use P to paste without yanking the deleted text.
:help v_P
With P the unnamed register is not changed (and neither the selection or clipboard), you can repeat the same change.
This behavior was introduced in v8.2.4242 (2022-01-28) and refined in v8.2.4881 (2022-05-06).
Or if your muscle memory is too strong:
xnoremap p P
Luc Hermitte's did the trick! Really good. Here's his solution put in a toggle function, so you can switch between normal behavior and no-replace-register put.
the command ,u toggles the behavior
let s:putSwap = 1
function TogglePutSwap()
if s:putSwap
vnoremap <silent> <expr> p <sid>Repl()
let s:putSwap = 0
echo 'noreplace put'
else
vnoremap <silent> <expr> p p
let s:putSwap = 1
echo 'replace put'
endif
return
endfunction
noremap ,p :call TogglePutSwap()<cr>
This is my solution.
vnoremap p p:let #+=#0<CR>
vnoremap P P:let #+=#0<CR>
I find out after paste, the old content is still stored in "0 register.
Just restore it to current clipboard by
:let #+=#0
duct-tape programming, but works for me:
nmap viwp viwpyiw
nmap vi'p vi'pyi'
nmap vi"p vi"pyi"
nmap vi(p vi(pyi(
nmap vi[p vi[pyi[
nmap vi<p vi<pyi<
Select the text and paste by P(uppercase).
Example:
viwP
See h: v_P for more infomation.
try -
:set guioptions-=a
:set guioptions-=A

Resources