乐趣区

vim 的 grep 插件`Leaderf rg`:grep 和模糊匹配的完美结合

前言
vim 有很多著名的 grep 插件,我使用过的有 ack.vim,ag.vim 和 ctrlsf.vim,它们应该也是目前用户最多的几个了。
ack.vim
起步比较早,早期后端 grep 工具是 ack,后来也支持 ag(the_silver_searcher),pt(the_platinum_searcher),rg(ripgrep) 等工具了。它是一个比较传统的 grep 插件,不支持异步,要等到 grep 结束后才能显示结果,在大的项目中 grep 会卡好一阵子。它貌似也不再维护,我 N 久前提交的 pull request 还挂在那,它最近的代码更新在 11 个月前。
ag.vim
它其实是抄袭 ack.vim,没错,是抄袭。在早期 ack.vim 还不支持 ag 时,它的作者在 ack.vim 代码的基础上稍微改了改,支持了 ag。后来被 ack.vim 的作者给怼了,就放弃了对 ag.vim 的维护。目前功能上小于 ack.vim。
ctrlsf.vim
这是国人开发的一个插件, 后端 grep 工具支持 ack/ag/pt/rg,同时也支持异步,不过需要 Vim 8.0.1039+ 或者 NeoVim 才支持异步。这个插件很好用,在我开发 Leaderf rg 之前一直使用的是它。
Leaderf rg 顾名思义,后端基于 rg,由于是 LeaderF 的子功能,基因上就决定它完美支持异步。同时 LeaderF 又是一个非著名的模糊查找插件,这使它可以在 grep 结果的基础上再通过模糊匹配的方式进行二次过滤,来帮助用户更快地锁定目标,这是目前上面提到的插件所不具备的。
为什么选择 rg(ripgrep)
快速 grep 工具目前有 ag, rg, pt, sift, ucg 等。我选择 rg 有以下几点原因:

速度比较快,rg 的 README 上有作者的对比,我实测也是 rg 快点。
Windows 上 bug 少(bug 到目前还没发现),ag 和 pt 都遇到过 bug。
作者很活跃,提的 issue 能很快得到回复。
rg 功能相对多些,可以从 rg –help 看出来。

Leaderf rg 使用介绍
Leaderf rg 的使用也比较简单,只要 Leaderf[!] + rg 命令和选项(同命令行上一样)就可以了。具体使用方法可以用:Leaderf rg - h 来查看。
usage: Leaderf[!] rg [-h] [-e <PATTERN>…] [-F] [-i] [-L] [-P] [-S] [-s] [-v]
[-w] [-x] [–hidden] [–no-config] [–no-ignore]
[–no-ignore-global] [–no-ignore-parent]
[–no-ignore-vcs] [–no-pcre2-unicode] [-E <ENCODING>]
[-M <NUM>] [-m <NUM>] [–max-depth <NUM>]
[–max-filesize <NUM+SUFFIX?>]
[–path-separator <SEPARATOR>] [–sort <SORTBY>]
[–sortr <SORTBY>] [-f <PATTERNFILE>…] [-g <GLOB>…]
[–iglob <GLOB>…] [–ignore-file <PATH>…]
[–type-add <TYPE_SPEC>…] [-t <TYPE>…] [-T <TYPE>…]
[–current-buffer | –all-buffers] [–recall] [–append]
[–reverse] [–stayOpen] [–input <INPUT> | –cword]
[–top | –bottom | –left | –right | –belowright | –aboveleft | –fullScreen]
[–nameOnly | –fullPath | –fuzzy | –regexMode] [–nowrap]
[<PATH> [<PATH> …]]

optional arguments:
-h, –help show this help message and exit

specific arguments:
-e <PATTERN>…, –regexp <PATTERN>…
A pattern to search for. This option can be provided multiple times, where all
patterns given are searched.
-F, –fixed-strings Treat the pattern as a literal string instead of a regular expression.
-i, –ignore-case Searches case insensitively.
-L, –follow Follow symbolic links while traversing directories.
-P, –pcre2 When this flag is present, rg will use the PCRE2 regex engine instead of its
default regex engine.
-S, –smart-case Searches case insensitively if the pattern is all lowercase, case sensitively
otherwise.
-s, –case-sensitive Searches case sensitively.
-v, –invert-match Invert matching. Show lines that do not match the given patterns.
-w, –word-regexp Only show matches surrounded by word boundaries. This is roughly equivalent to
putting \b before and after all of the search patterns.
-x, –line-regexp Only show matches surrounded by line boundaries.
–hidden Search hidden files and directories. By default, hidden files and directories
are skipped.
–no-config Never read configuration files. When this flag is present, rg will not respect
the RIPGREP_CONFIG_PATH environment variable.
–no-ignore Don’t respect ignore files (.gitignore, .ignore, etc.). This implies
–no-ignore-parent and –no-ignore-vcs.
–no-ignore-global Don’t respect ignore files that come from ‘global’ sources such as git’s
`core.excludesFile` configuration option (which defaults to
`$HOME/.config/git/ignore`).
–no-ignore-parent Don’t respect ignore files (.gitignore, .ignore, etc.) in parent directories.
–no-ignore-vcs Don’t respect version control ignore files (.gitignore, etc.).
–no-pcre2-unicode When PCRE2 matching is enabled, this flag will disable
Unicode mode, which is otherwise enabled by default.
-E <ENCODING>, –encoding <ENCODING>
Specify the text encoding that rg will use on all files searched.
-M <NUM>, –max-columns <NUM>
Don’t print lines longer than this limit in bytes.
-m <NUM>, –max-count <NUM>
Limit the number of matching lines per file searched to NUM.
–max-depth <NUM> Limit the depth of directory traversal to NUM levels beyond the paths given.
–max-filesize <NUM+SUFFIX?>
Ignore files larger than NUM in size. This does not apply to directories.
–path-separator <SEPARATOR>
Set the path separator to use when printing file paths.
–sort <SORTBY> This flag enables sorting of results in ascending order.
–sortr <SORTBY> This flag enables sorting of results in descending order.
-f <PATTERNFILE>…, –file <PATTERNFILE>…
Search for patterns from the given file, with one pattern per line.
(This option can be provided multiple times.)
-g <GLOB>…, –glob <GLOB>…
Include or exclude files and directories for searching that match the given
glob.(This option can be provided multiple times.)
–iglob <GLOB>… Include or exclude files and directories for searching that match the given glob.
Globs are matched case insensitively.(This option can be provided multiple times.)
–ignore-file <PATH>…
Specifies a path to one or more .gitignore format rules files.
–type-add <TYPE_SPEC>…
Add a new glob for a particular file type.
-t <TYPE>…, –type <TYPE>…
Only search files matching TYPE. Multiple type flags may be provided.
-T <TYPE>…, –type-not <TYPE>…
Do not search files matching TYPE. Multiple type-not flags may be provided.
<PATH> A file or directory to search. Directories are searched recursively. Paths
specified on the command line override glob and ignore rules.
–current-buffer Searches in current buffer.
–all-buffers Searches in all listed buffers.
–recall Recall last search. If the result window is closed, reopen it.
–append Append to the previous search results.

common arguments:
–reverse show results in bottom-up order
–stayOpen don’t quit LeaderF after accepting an entry
–input <INPUT> specifies INPUT as the pattern inputted in advance
–cword current word under cursor is inputted in advance
–top the LeaderF window is at the top of the screen
–bottom the LeaderF window is at the bottom of the screen
–left the LeaderF window is at the left of the screen
–right the LeaderF window is at the right of the screen
–belowright the LeaderF window is at the belowright of the screen
–aboveleft the LeaderF window is at the aboveleft of the screen
–fullScreen the LeaderF window takes up the full screen
–nameOnly LeaderF is in NameOnly mode by default
–fullPath LeaderF is in FullPath mode by default
–fuzzy LeaderF is in Fuzzy mode by default
–regexMode LeaderF is in Regex mode by default
–nowrap long lines in the LeaderF window won’t wrap

If [!] is given, enter normal mode directly.
注意:如果:Leaderf 后面有感叹号,会直接进入 normal 模式;如果没有感叹号,则是输入模式,此时可以输入字符来进行模糊匹配过滤。可以用 tab 键在两个模式间来回切换。
Leaderf rg 基本支持 rg 所有的必要选项,用户如果对 rg 命令比较熟悉,可以在 vim 命令行内输入:Leaderf, 然后手敲 rg 命令,命令选项还可以通过 tab 来补全。当然,更聪明的做法是定义一些快捷键。例如:
” search word under cursor, the pattern is treated as regex, and enter normal mode directly
noremap <C-F> :<C-U><C-R>=printf(“Leaderf! rg -e %s “, expand(“<cword>”))<CR>

” search word under cursor, the pattern is treated as regex,
” append the result to previous search results.
noremap <C-G> :<C-U><C-R>=printf(“Leaderf! rg –append -e %s “, expand(“<cword>”))<CR>

” search word under cursor literally only in current buffer
noremap <C-B> :<C-U><C-R>=printf(“Leaderf! rg -F –current-buffer -e %s “, expand(“<cword>”))<CR>

” search word under cursor literally in all listed buffers
noremap <C-D> :<C-U><C-R>=printf(“Leaderf! rg -F –all-buffers -e %s “, expand(“<cword>”))<CR>

” search visually selected text literally, don’t quit LeaderF after accepting an entry
xnoremap gf :<C-U><C-R>=printf(“Leaderf! rg -F –stayOpen -e %s “, leaderf#Rg#visual())<CR>

” recall last search. If the result window is closed, reopen it.
noremap go :<C-U>Leaderf! rg –recall<CR>

” search word under cursor in *.h and *.cpp files.
noremap <Leader>a :<C-U><C-R>=printf(“Leaderf! rg -e %s -g *.h -g *.cpp”, expand(“<cword>”))<CR>
” the same as above
noremap <Leader>a :<C-U><C-R>=printf(“Leaderf! rg -e %s -g *.{h,cpp}”, expand(“<cword>”))<CR>

” search word under cursor in cpp and java files.
noremap <Leader>b :<C-U><C-R>=printf(“Leaderf! rg -e %s -t cpp -t java”, expand(“<cword>”))<CR>

” search word under cursor in cpp files, exclude the *.hpp files
noremap <Leader>c :<C-U><C-R>=printf(“Leaderf! rg -e %s -t cpp -g !*.hpp”, expand(“<cword>”))<CR>
参考:rg 的 glob 语法。
顺便说一下,直接在 vim 命令行敲:Leaderf rg,就会有传说中的 ”grep on the fly” 的功能哦,同时支持 fuzzy 和 regex 两种模式。
会不会支持 ag 等其他 grep 工具
不会。首先,ripgrep 已经足够强大,基本不存在别的工具有而 ripgrep 没有的功能。其次,ripgrep 有编译好的 Windows、Linux 和 MacOS 上的 binary,可以在这些平台上很容易安装。再者,由于作者比较懒,不想再实现重复的功能。

退出移动版