如何在Vim中进行类似Emacs的增量搜索?

12
在 Vim 中使用增量搜索时,只要您输入搜索词,光标就会立即跳转到下一个匹配项。Emacs 也有类似的增量搜索功能。但是,我发现 Emacs 的 isearch 功能具有非常有用的特性,希望在 Vim 中也能够实现。在 Emacs 中,如果你输入:

<ctrl-s>word

它会立即跳转到 "word",就像 Vim 增量搜索一样。在 Emacs 中,您现在可以继续键入额外的 <ctrl-s> 来查找下一个 "word" 出现的位置,在 Emacs 中这不会结束您的增量搜索会话。要在 Vim 中实现相同的操作,您必须按下 <cr> 结束搜索词,然后按下 n 跳转到下一个搜索结果。因为 Emacs 不会结束搜索会话,所以您可以做以下操作:

<ctrl-s>word<ctrl-s><ctrl-s>more

这让您可以"缩小范围"并逐渐接近想要到达的位置,非常有用!

有没有办法让 Vim 实现同样的功能呢?


这个序列怎么样:1)/word,2)<CR>,3)n,...,n,4)/,5)<UP>?你会回到搜索命令,即 /word。然后你可以继续输入 more - Ruslan Osmanov
是的,那个方法可行(而且大致上就是我现在所做的),只是它比emacs版本不太方便。Vim应该始终比emacs更方便!;-) - 00prometheus
当然,最难的部分是按 <UP> 键,你可以尝试使用 <C-r>/ 来插入搜索寄存器,其中包含你以前搜索过的项目。 - dNitro
'/' - 用于启动搜索'Ctrl-l' - 使用光标后的字符扩展搜索模式(类似于emacs中的'Ctrl-w')。 - maximk
4个回答

16
最近版本的Vim提供了命令行模式的内置映射,可以完全满足您的需求。
您可以在帮助文件中找到此内容:帮助:

CTRL-G

当设置了'incsearch'时,输入"/""?"进行搜索模式,并且当前匹配项会被显示,然后按下CTRL-G将移动到下一个匹配项。(不考虑搜索偏移量)。使用CTRL-T可以移动到上一个匹配项。提示:在普通键盘上,T位于G上面。

参考补丁号码,因为并非所有安装都有这些映射:
  • 补丁 7.4.2259 可以使Ctrl-N/Ctrl-P像Emacs中的Ctrl-S/Ctrl-R一样工作。

  • 补丁 7.4.2268 更改了映射方式为Ctrl-G/Ctrl-T(最初使用的映射具有不同的目的)。


我升级了vim,现在它可以工作了!然而,yolenoyer和Ruslan的按键映射实际上更好:它们让我可以继续旧搜索!Ctrl-T/Ctrl-G不能在先前的搜索上追加,这是我想要的核心。 - 00prometheus
1
@00prometheus,你说你不能附加到以前的搜索,这是什么意思?对我来说,模式仍然存在,我可以继续编辑它。 - xaizek
1
抱歉,我现在明白了!只需搜索,按下 <ctrl-g>/<ctrl-t> 并输入更多内容以精确定位,而无需离开搜索。完美! - 00prometheus

6
以下两个映射使我可以在增量搜索时按<Tab><S-Tab>,以跳转到下一个或上一个匹配项而不离开搜索状态:
" needed for mapping <Tab> in command-line mode
set wildcharm=<C-z>

cnoremap <expr> <Tab>   getcmdtype() == "/" \|\| getcmdtype() == "?" ? "<CR>/<C-r>/" : "<C-z>"
cnoremap <expr> <S-Tab> getcmdtype() == "/" \|\| getcmdtype() == "?" ? "<CR>?<C-r>/" : "<S-Tab>"

相比于简单的键映射,getcmdtype条件有什么优势呢?这个问题涉及到了比我平常所熟悉的vim更深层次的内容。 - 00prometheus
现在,在我的 .vimrc 文件中,我有以下映射: nnoremap <C-s> /<UP> cnoremap <C-s> <CR>/<UP> cnoremap <C-z> <CR>?<UP>。这使我可以使用ctrl-s向前跳转,使用ctrl-z向后跳转。 - 00prometheus
@00prometheus:这是对 xaizek 的答案在旧版本的 Vim 中的很好的仿真。 - Ingo Karkat
如果在第一个<CR>后添加zv,它也会在需要时打开折叠。例如:cnoremap <expr> <Tab> getcmdtype() == "/" \|\| getcmdtype() == "?" ? "<CR>zv/<C-r>/" : "<C-z>" - Von

1
你可以使用按键映射:

nnoremap <C-s> /<Up>

(正常模式)

如果您想保留上一个匹配项(而不是移动到下一个匹配项),您可以在/<Up>之后返回到上一个匹配项:

nnoremap <C-s> N/<Up>

用法:

  1. /word<CR> - 开始搜索 word
  2. n, ..., n - 移动到下一个匹配项
  3. <C-s>,即 Control + s - 调用上一次搜索(1)
  4. 输入 more - 开始搜索 /wordmore

这样做已经接近目标了!我还尝试添加 :cnoremap <C-s> <CR>n/<Up>,这样我就可以按 ctrl-s 轻松跳转到下一个匹配项,而无需离开搜索,但是它每次会跳过两个结果。有什么办法可以避免这种情况吗? - 00prometheus
@00prometheus,nnoremap <C-s> N/<Up> 怎么样? - Ruslan Osmanov
@yolenoyer已经解决了问题,请看他的回答! - 00prometheus
@00prometheus,他的解决方案对我不起作用。但是我的映射正如问题描述的那样工作。 - Ruslan Osmanov
奇怪,对我而言它是有效的。我现在正在使用nnoremap <C-s> /<Up>cnoremap <c-s> <cr>/<up>在我的 .vimrc 文件中,它的效果很好!现在我只需要找到一个空闲键来进行反向搜索即可! :-) - 00prometheus
如果你还添加了 cnoremap <C-z> <CR>?<Up>,你就可以使用Ctrl-Z回退,以及Ctrl-S前进(在命令模式下不使用Ctrl-Z)。 - 00prometheus

1

用相同的思路:

:cnoremap <c-s> <cr>/<up>

通过这种映射,搜索时使用Ctrl-L会更加有用。


我也尝试过这个,但是当我这样做时,搜索结果会跳过两个。你得到了不同的结果吗? - 00prometheus
如果你将@Ruslans的映射更改为nnoremap <C-s> /<Up>,那么它似乎可以工作! - 00prometheus

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