Vim: search and highlight but do not jump
The super star (*) key in Vim will search for the word under the cursor and jump forward to the next match. The user can jump to the next matches with the n key. If hlsearch
is enabled, it will also highlight the matches.
I want to be able to press * and get the highlighted matches and be able to navigate the matches using the n key. However, I do not want Vim to jump to the next match when * is pressed, 开发者_运维问答it should remain on the current word. Is there a way to do this?
I would map:
nnoremap * *``
Works exactly like you want, except that it adds a jump in the jump list. To prevent that you need:
nnoremap * :keepjumps normal! mi*`i<CR>
I found this works pretty well, there's no blink and it doesn't need an intermediate register.
nnoremap <silent> * :let @/= '\<' . expand('<cword>') . '\>' <bar> set hls <cr>
Or if you want the g*
behavior:
nnoremap <silent> g* :let @/=expand('<cword>') <bar> set hls <cr>
The best solution:
- don't add a jump to the jump list
- the behavior of the star key is not be changed
so, try the plugin: http://www.vim.org/scripts/script.php?script_id=4335
Much better than:
" a jump adds to the jump list
nnoremap * *``
" I got a dead loop on macvim
nnoremap * :keepjumps normal *``<cr>
" the behavior is changed
nnoremap <silent> <Leader>* :let @/='\<<C-R>=expand("<cword>")<CR>\>'<CR>:set hls<CR>
I haven't seen this one yet:
nmap <silent> * "syiw<Esc>: let @/ = @s<CR>
It's very short and does not involve jumping around which can result in blinking.
Explanation: copy the word under cursor to s
register and then set the search register (/
) to the content of s
register. The search register is not writeable directly, that's why the let is necessary and hence the silent
to keep vim's command line clean.
I have the following in my .vimrc, which I think works better than the other alternatives:
" Put word under cursor into search register and highlight
nnoremap <silent> <Leader>* :let @/='\<<C-R>=expand("<cword>")<CR>\>'<CR>:set hls<CR>
vnoremap <silent> <Leader>* :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy:let @/=substitute(
\escape(@", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>:set hls<CR>
If you want to keep the current view and add the search to the history, try this [not so efficient] solution:
noremap * msHmt`s*`tzt`s
It is using the marks s
(save) and t
(top).
A simple solution came to my mind: put map * *#
in .vimrc
file (it will blink though).
Many answers here outline rather simple mappings that work well for common cases, but may have side effects (like flickering by jumping back and forth) or lack robustness (may break if some regexp characters are defined as keyword characters).
If you're looking for a robust implementation and don't mind installing a plugin, you can choose from a plethora of alternatives, many of which also offer additional search-related improvements:
- My SearchHighlighting plugin changes the
*
command, extends it to visual selections, and offers optional auto-searching of the word under the cursor. - star search changes the behavior of
*
to not jump to the next match, and includes the visual search from the next plugin - vim-visual-star-search provides searching of the visual selection
- visualstar.vim provides searching of the visual selection
- select & search can use either
n/N
or*
in the visual selection, and can avoid jumping. - vim-asterisk provides a
z*
mapping that also doesn't jump, visual*
, more intuitive smartcase handling, and can keep the cursor position when jumping (like,*
) - searchant.vim hooks into the built-in search commands and provides a separate highlighting for the match last jumped to.
The other answers here are good, particularly @rodrigo's, but I wanted to write a solution that preserves scroll position and does so without affecting any of the marks.
This works for me:
function! StarPositionSave()
let g:star_position_cursor = getpos('.')
normal! H
let g:star_position_top = getpos('.')
call setpos('.', g:star_position_cursor)
endfunction
function! StarPositionRestore()
call setpos('.', g:star_position_top)
normal! zt
call setpos('.', g:star_position_cursor)
endfunction
nnoremap <silent> * :call StarPositionSave()<CR>*:call StarPositionRestore()<CR>
Putting normal! *
in the function directly doesn't seem to work, as (at least in neovim) it suppresses search highlighting from being triggered (as if :nohlsearch
was run).
My solution:
nnoremap <silent><expr> * v:count ? '*'
\ : ':silent execute "keepjumps normal! *" <Bar> call winrestview(' . string(winsaveview()) . ')<CR>'
nnoremap <silent><expr> g* v:count ? 'g*'
\ : ':silent execute "keepjumps normal! g*" <Bar> call winrestview(' . string(winsaveview()) . ')<CR>'
Edit: Recent Vim has <Cmd>
mapping, so you can use below to avoid CmdlineEnter/Leave to be fired.
nnoremap <expr> * v:count ? '*'
\ : '<Cmd>silent keepjumps normal! *<CR><Cmd>call winrestview(' .. string(winsaveview()) .. ')<CR>'
nnoremap <expr> g* v:count ? 'g*'
\ : '<Cmd>silent keepjumps normal! g*<CR><Cmd>call winrestview(' .. string(winsaveview()) .. ')<CR>'
Pros:
- No flickering.
- Jump list remains unchanged.
- With a count, it invokes original
*
; you can use1*
if you miss the original*
. - Marks and registers are untouched.
- Using original
*
, its behavior is almost identical with*
(except for jumping).
This means'smartcase'
is ignored as*
do. - No need to install plugins.
Similar to *
we have
[I ..................... it shows where the word under the cursor appears
I also have some useful lines on my vimrc that can, maybe, help you
" When double click a word vim will hightlight all other ocurences
" see CountWordFunction()
" [I shows lines with word under the cursor
nnoremap <silent> <2-LeftMouse> :let @/='\V\<'.escape(expand('<cword>'), '\').'\>'<cr>:set hls<cr>:CountWord<cr>
nnoremap <Leader>* :let @/='\V\<'.escape(expand('<cword>'), '\').'\>'<cr>:set hls<cr>:CountWord<cr>
if !exists('*CountWordFunction')
fun! CountWordFunction()
try
let l:win_view = winsaveview()
exec "%s/" . expand("<cword>") . "//gn"
finally
call winrestview(l:win_view)
endtry
endfun
endif
command! -nargs=0 CountWord :call CountWordFunction()
cnoreabbrev cw CountWord
nnoremap <F3> :CountWord<CR>
I'm adding this answer because I found the other answers either, centered the line in the view (which I found distracting), or seemed overly complicated.
The following command works well for me:
noremap * :let @/ = "\\<<C-r><C-w>\\>"<cr>:set hlsearch<cr>
It simply sets the pattern to the whole word under the cursor and then turns on (or updates) the highlighting for the search pattern.
- NOTE: It doesn't modify the search history (which I prefer but might not be quite what you want).
just do
nnoremap * *N
nnoremap # #n
works with this http://www.vim.org/scripts/script.php?script_id=4335 too like so:
vnoremap * :<C-u>call VisualStarSearchSet('/')<CR>/<C-R>=@/<CR><CR>N
vnoremap # :<C-u>call VisualStarSearchSet('?')<CR>?<C-R>=@/<CR><CR>n
nnoremap <silent> ml :<c-u>let @/ = '\<'.expand('<cword>').'\>'\|set hlsearch<CR>wb
and if you want a visual mode one:
function SetSearchVisualSelection()
let clipboard_original_content=@"
normal gvy " this overwrites clipboard
let raw_search=@"
let @/=substitute(escape(raw_search, '\/.*$^~[]'), "\n", '\\n', "g")
let @"=clipboard_original_content
endfunction
vnoremap ml :call SetSearchVisualSelection()<CR>:set hlsearch<CR>
精彩评论