12-搜索…
第 12 章 搜索…
令人惊讶的是,我们竟然在没有涉及搜索的情况下走到了这一步。Vim 中的查找和替换一直比大多数编辑器(它们只给你一个带有三个字段的小对话框,如果幸运的话,还有一个指定正则表达式的复选框)强大得多,也细致得多。
LazyVim 扩展了 Neovim 强大的搜索功能,使其更易于使用且更美观。你已经了解了用于导航到和选择你能看到的对象的可视化 Seek (s
) 和 TreeSitter (S
) 模式,以及它们对应的远程操作符待决对象:r
和 R
。当你要查找的文本当前可见时,这些都很好用。然而,当你需要搜索一个文件并让它自动滚动到搜索结果时,它们就不够用了。
12.1. 在当前文件中搜索
要在 Vim 中搜索模式,请在普通模式下使用 /
命令。助记符是 /
键也是问号键,而搜索某物是一种提问。
译者注:
/
向下搜索,?
向上搜索。
许多不被认为是模态编辑的工具已经采用了 Vi 的 /
作为调用搜索的命令。例如,卓越的 Linear 任务跟踪工具使用 /
开始搜索,无处不在的 GitHub 也是如此。
当你第一次在普通模式下输入 /
时,你可能会丢失光标!它不会弹出新窗口。相反,/
会接管当前文件的状态栏,并显示一个放大镜图标:
o
图 54. 搜索 “dat”
在这张图片中,我输入了 /dat
。/
启动了搜索模式,然后我搜索了 dat
。我的光标在搜索框中。
如你所见,LazyVim 已经很贴心地高亮了所有(可见的)“dat”匹配项。“主要"结果将始终是你按下 /
时光标位置之后的第一个匹配结果。
如果你按 Enter
确认搜索,你的光标将跳转到主要结果。像往常一样,按 Escape
取消搜索。
此时,你回到了普通模式,可以正常编辑缓冲区。然而,在此之前,请注意所有高亮的结果仍然是高亮的。你可以使用 n
(代表 next,下一个)键轻松跳转到下一个结果。这个命令接受计数,所以你可以使用 3n
跳转到当前光标位置之后的第三个结果。
如果没有更多匹配结果在底部,搜索将环绕到文档顶部。如果你知道需要跳转多远,你也可以对 /
命令使用计数,例如 3/something
向前跳转到第三个 something
。不过,弄清楚你需要跳转多远需要一些思维敏捷性,所以通常使用 Seek 模式更快。
如果你用 n
跳得太远,你可以使用 Shift-N
将光标移动到上一个结果。如果你知道你需要向后搜索到上一个结果,你可以用 ?
(即 Shift-/
)而不是仅仅 /
来启动搜索。
如果你以前用过 Vim,我应该提醒你,n
和 N
的这种行为与默认的 Neovim 行为不同。它们过去是“重复上一次的 /
或 ?
命令”,所以如果你用 ?
开始,n
会继续向文档上方移动。LazyVim 的模型更容易记住;n
总是表示“下一个向下”,N
总是表示“上一个向上”。
12.2. 忽略大小写
如果你输入的搜索词全部是小写字母,LazyVim 默认会忽略大小写,但如果你在搜索词中包含一个大写字母,它将启用大小写敏感。所以搜索 in
会匹配 in
和 In
,但搜索 In
只会匹配 In
。
译者注: 这是通过
smartcase
选项实现的,LazyVim 默认开启。
如果你明确只想搜索仅小写匹配项,你可以通过在搜索词中的某处插入两个字符 \C
(那个 C
是大写的)来修改搜索词。
译者注:
\C
强制后续模式进行大小写敏感匹配。
方便的是,它不必在搜索词的开头;如果搜索字符串中的任何位置有 \C
,它将使整个搜索大小写敏感。所以,假设你正在寻找小写单词“initiate”。如果你开始输入 in
并意识到它匹配了一堆不必要的 In
因为忽略大小写已启用,你可以在输入 iti
之前附加 \C
(所以你最终得到 in\C
)切换到大小写敏感模式(所以总的搜索字符串是 in\Citi
)。
如果你想暂时禁用忽略大小写,请输入冒号命令 :set noignorecase
。这只持续到你退出 Neovim,或者用 :set ignorecase
再次明确启用它为止。
如果你想让这个更改永久生效,打开你的 options.lua
文件并在其中某处添加 vim.opt.ignorecase = false
。注意,现在如果你想让任何特定的搜索大小写不敏感,你需要在搜索短语中使用小写的 \c
而不是 \C
。
译者注:
\c
强制后续模式进行大小写不敏感匹配。
\C
的技巧起初看起来有点奇怪,但当你想到大多数代码编辑器中使用的替代方法,即你必须将手移到鼠标上,用瞄准一个像是Aa
的小复选框并点击它,然后重新聚焦搜索框并继续输入时,你可能会觉得 \C
更快。
12.3. 正则表达式
Vim 搜索默认使用正则表达式。但它们是有点奇怪的正则表达式。
好吧,我承认所有正则表达式都有点奇怪。Vim 的正则表达式只是与大多数现代编程语言中常见的 PCRE 风格的正则表达式相比才显得奇怪。幸运的是,如果你只是搜索文本,你可能不需要 Perl 兼容表达式提供的全部复杂性。
译者注: Vim 的正则表达式语法有其自己的“怪癖”,特别是关于哪些元字符需要反斜杠转义。它有两种主要模式:
magic
(默认) 和very magic
(\v
)。very magic
更接近 PCRE。
我这本书没有空间来指导正则表达式语法,所以我只提一些主要的常用法,剩下的留给你自己查找:
.
匹配任何单个字符。如果你需要搜索字面上的句点,请用\.
转义它。\s
匹配任何空白字符。(译者注:原文漏了\s
,补充上)。\S
匹配任何非空白字符。*
字符匹配前面的表达式零次或多次。值得注意的是,.*
将匹配任意长度的任何字符串。\+
字符串匹配前面的表达式一次或多次。(这与我见过的大多数正则表达式解析器显著不同,在那些解析器中你不需要在+
前加\
来匹配一次或多次)。它可以与例如\S
结合来匹配任何不含空格的单词:\S\+
。\=
可以用来匹配前面的模式零次或一次。对于像https\=:
这样 “s” 是可选的情况很有用。这个模式在大多数正则表达式引擎中通常是?
,实际上\?
也能达到这个效果。然而,当用?
调用向后搜索命令时,这会使 Vim 混淆,所以\=
胜出。(译者注:\?
确实在 Vim 正则中表示 0 或 1 次匹配,但用它搜索时确实需要注意。)\\
匹配字面上的反斜杠,\/
匹配字面上的正斜杠。
**译者注:**你会在未来的时间里面多次反复学习正则表达式的。
总的来说,如果你了解 PCRE 风格的正则表达式,你会发现在 Vim 中你需要更多的反斜杠。话虽如此,绝大多数代码编辑器的搜索都包含在上述范围内了。
如果你想为特定搜索“禁用”正则表达式匹配,请在行的开头放置 \V
(或者如果你只需要为搜索的剩余部分禁用它,则放在行的中间)。“V”代表“very nomagic”(非常无魔法),如果你想被极度搞糊涂,请输入 :help magic
。它实际上是如此令人困惑,以至于你会宁愿学习直接使用正则表达式(是的,我知道这有多么令人困惑,纯粹的Vim黑魔法)。
译者注: 使用
\v
(very magic) 开启更接近 PCRE 的模式,通常比默认的magic
或\V
(very nomagic) 更容易使用。例如,在\v
模式下,+
,?
,|
,()
等元字符不需要反斜杠。
如果你迫切需要一个正则表达式来做某件事,你可以让 ChatGPT 帮助你浏览 :help regular expressions
来找到你需要的语法。你最终要么恍然大悟,要么感到沮丧。
12.4. 在项目中搜索
如果你需要跨整个代码库搜索一个词,而不仅仅是在一个文件中,请使用命令 <Space>/
而不是仅仅 /
。它会弹出那个非常熟悉的选择器,这次是 live_grep
模式。
译者注:
<Space> /
通常映射到 Telescope 或类似插件的实时 grep (live grep) 功能。
确保你安装了 ripgrep 并可在你的路径中以 rg
的形式使用,因为这是选择器底层使用的工具。
输入你正在寻找的字符串。结果将显示在左侧,文件将在右侧的预览中显示,这样你就可以找到正确的那个了:
图 55. Live Grep 选择器
记住,你可以通过按 Alt-s
给选择器结果添加标签。我发现在 live_grep
窗口中这更有用,因为与大多数选择器不同,live_grep
中的空格会被作为字面上的空格发送给 ripgrep
,而不是让我通过搜索行中更早的内容来缩小搜索结果范围。
因为这是一个选择器,你可以在它打开时按 Alt-t
将所有搜索结果放入 Trouble 窗口,这样你就可以在编辑时导航它们(使用 ]q
和 [q
)。
令人烦恼的是,这种搜索模式与 Vim 的内置搜索完全不同。它只是将你的模式传递给 ripgrep
并按照 ripgrep
的方式行事。而 ripgrep
不知道 Vim 奇怪的正则表达式引擎之类的东西。它确实支持正则表达式,但它们使用的语法与 Vim 的截然不同,令人抓狂。也就是说,与几乎所有非 Vim 的东西使用的语法相同。在这里令人抓狂的是 Vim,而不是 ripgrep
。只是为了让大家都清楚。
译者注: ripgrep 使用 Rust 的正则表达式引擎,语法更接近 PCRE。
12.5. 总结
本章全部是关于搜索:进入搜索模式的 /
快捷键,以及进入项目中查找模式的 <Space>/
快捷键。后者可能不够强大,所以我们还设置了 telescope-live-grep-args
插件(译者注:原文在此处提到这个插件,但在前面配置部分未提及,可能是在后面章节或作者个人配置中),让我们对项目范围的搜索有更多的控制。
当然,搜索只是故事的一半。在下一章中,我们将介绍替换文本,既作为搜索操作的一部分,也在更广泛的项目层面上进行。