Vim:搜索并高亮但不跳转

64

超级星号(*键在Vim中将搜索光标下的单词并跳转到下一个匹配。用户可以使用n键跳转到下一个匹配项。如果启用了hlsearch,它还会突出显示匹配项。

我希望能够按下*并获得突出显示的匹配项,并能使用n键浏览匹配项。但是,当按下*时,我不希望Vim跳转到下一个匹配项,而应该停留在当前单词上。有什么办法可以做到这一点吗?


另一种选择是分割(:sp)窗口,然后在新窗口中执行超级启动(*)搜索。这样可以有效地获得相同的“信息”,并保留原始光标位置。 - Kenny Evitt
14个回答

47
我会进行映射:
nnoremap * *``

这段代码的作用和你所期望的一模一样,但会在跳转列表中增加一个跳转。要避免这个问题,你需要:

nnoremap * :keepjumps normal! mi*`i<CR>

20
第二个不适用于我,当我按*键时,它会显示:“E169:命令过于递归”。 - Deqing
3
在第二个命令中需要使用normal!normal相当于nnoremap,而normal!相当于nmap - Keith Smiley
18
由于某种原因,“``”未按预期工作,因此我不得不对此进行修改为:nnoremap * :keepjumps normal! mi*`i<CR>`。请注意,修改后的代码与原始代码含义相同。 - Keith Smiley
更好的方式是 nnoremap * *#,避免闪烁。 - coderek
2
首先,将“normal”更改为“normal!”。其次,keepjumps不会设置“”标记。我使用```nnoremap * m:keepjumps normal! *``<cr>。稍微不同的方法是使用nnoremap * m`:keepjumps normal! *<cr>```。 - doraemon
显示剩余7条评论

12

我发现这很有效,没有闪烁,也不需要中间寄存器。

nnoremap <silent> * :let @/= '\<' . expand('<cword>') . '\>' <bar> set hls <cr>

或者如果你想要 g* 行为:

nnoremap <silent> g* :let @/=expand('<cword>') <bar> set hls <cr>

这是我认为最优秀的解决方案。没有跳转,不会添加到跳转列表中,也不会添加到任何可能需要的复制寄存器中。 - Leon S.

7

我还没有见过这个:

nmap <silent> * "syiw<Esc>: let @/ = @s<CR>

它非常简短,不涉及跳转,因此不会导致闪烁。

解释:复制光标下的单词到寄存器 s,然后将搜索寄存器(/)设置为寄存器 s 的内容。搜索寄存器不能直接写入,这就是为什么需要使用 let 以及 silent 以保持 Vim 命令行的干净。


它对我来说运行得非常好,没有闪烁问题。屏幕保持稳定。 - Lazureus
相同,没有闪烁/跳跃问题。 - Gipsy King
不错,我稍微修改了一下,现在可以将内容复制到未命名的(工作)寄存器中。 nmap <silent> * yiw<Esc>: let @/ = @""<CR> - run_the_race

7

最佳解决方案:

  1. 不要将跳转添加到跳转列表中
  2. 不要更改星号键的行为

因此,请尝试使用插件:http://www.vim.org/scripts/script.php?script_id=4335

比以下方式好得多:

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

很棒的插件,另一个有用的功能是你可以在可视模式下使用“*”来搜索所选文本。缺点是,如果你在单词中间,它会将光标移动到单词开头。 - Deqing
1
第三个选项对我来说最好。它可以突出显示,而且屏幕和光标都不会移动。 - Dmitry Teslenko
1
行为是如何改变的?第三个选项对我来说似乎非常好,而此问题中的其他(非插件)选项都不太好(特别是第二个选项的变体可能会将高亮单词重置到屏幕中央,这很令人不舒服)。 - Connor

5

如果您想保留当前视图并将搜索添加到历史记录中,请尝试此[不太高效的]解决方案:

noremap * msHmt`s*`tzt`s

这里使用了标记 s(保存)和 t(置顶)。


5

我在我的 .vimrc 文件中加入了以下内容,我认为这比其他替代方案更好:

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

3
我想到了一个简单的解决方案:将map * *#放入.vimrc文件中(尽管会闪烁)。

1
为什么不使用“*”符号,使光标回到完全相同的位置? - mb14
@mb14 它有什么 # 没有的好处吗? - khachik
它可以工作;-) #如果您在中间,则将光标移动到单词开头,如果设置了nowrapscan并从单词的最后一次出现开始搜索,则会变得更糟#将您移至上一个单词(因为*没有跳转到任何地方) - mb14
2
*#和`*``都存在闪烁问题。 - Thomson

3
许多答案在这里概述了相当简单的映射,适用于常见情况,但可能会有副作用(如来回跳动引起闪烁)或缺乏健壮性(如果一些正则表达式字符被定义为关键字字符,则可能会中断)。如果您正在寻找一个强大的实现,并且不介意安装插件,那么您可以从众多的替代方案中选择,其中许多还提供了额外的搜索相关改进。
  • 我的SearchHighlighting插件更改了*命令,将其扩展到可视选择,并提供了可选的自动搜索光标下单词的功能。
  • star search更改了*的行为,不跳到下一个匹配项,并包括来自下一个插件的可视搜索
  • vim-visual-star-search提供了可视选择的搜索功能
  • visualstar.vim提供了可视选择的搜索功能
  • select & search可以在可视选择中使用n/N*,并可以避免跳转。
  • vim-asterisk提供了一个z*映射,也不跳跃,可视*,更直观的智能大小写处理,并且可以在跳转时保持光标位置(例如,*
  • searchant.vim钩入内置搜索命令,并为最后一次跳转到的匹配项提供单独的高亮显示。

1
这里的其他答案都很好,特别是 @rodrigo 的,但我想写一个解决方案,可以保留滚动位置,并且不会影响任何标记。
这对我有效:
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>

normal! *直接放在函数中似乎不起作用,因为(至少在neovim中),它会抑制搜索高亮显示的触发(就像运行了:nohlsearch一样)。

1
我添加这个答案是因为我发现其他答案要么将行居中显示(我觉得很分散注意力),要么过于复杂。以下命令对我来说效果很好:
noremap * :let @/ = "\\<<C-r><C-w>\\>"<cr>:set hlsearch<cr>

它只是将模式设置为光标下的整个单词,然后打开(或更新)搜索模式的高亮显示。

  • 注意:它不会修改搜索历史记录(这是我喜欢的,但可能不完全符合您的要求)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接