V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Yggdroot
V2EX  ›  Vim

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

  •  1
     
  •   Yggdroot · 2019-01-14 22:13:08 +08:00 · 4951 次点击
    这是一个创建于 1919 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    vim 有很多著名的 grep 插件,我使用过的有 ack.vim ,ag.vim 和 ctrlsf.vim ,它们应该也是目前用户最多的几个了。

    1. ack.vim
      起步比较早,早期后端 grep 工具是 ack,后来也支持 ag(the_silver_searcher),pt(the_platinum_searcher),rg(ripgrep)等工具了。它是一个比较传统的 grep 插件,不支持异步,要等到 grep 结束后才能显示结果,在大的项目中 grep 会卡好一阵子。它貌似也不再维护,我 N 久前提交的 pull request 还挂在那,它最近的代码更新在 11 个月前。
    2. ag.vim
      它其实是抄袭 ack.vim ,没错,是抄袭。在早期 ack.vim 还不支持 ag 时,它的作者在 ack.vim 代码的基础上稍微改了改,支持了 ag。后来被 ack.vim 的作者给怼了,就放弃了对 ag.vim 的维护。目前功能上小于 ack.vim 。
    3. 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 有以下几点原因:

    1. 速度比较快,rg 的 README 上有作者的对比,我实测也是 rg 快点。
    2. Windows 上 bug 少( bug 到目前还没发现),ag 和 pt 都遇到过 bug。
    3. 作者很活跃,提的 issue 能很快得到回复。
    4. 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,可以在这些平台上很容易安装。再者,由于作者比较懒,不想再实现重复的功能。

    15 条回复    2019-02-26 21:39:17 +08:00
    iam070
        1
    iam070  
       2019-01-14 22:16:56 +08:00
    插件作者都来发帖了,必须支持。
    我记得 WIN 上的 GVIM 好像还需要 python 支持,就没有安装了:)
    xiaotianhu
        2
    xiaotianhu  
       2019-01-14 23:33:12 +08:00 via iPhone
    好东西 有空试试
    jdhao
        3
    jdhao  
       2019-01-15 00:08:09 +08:00
    为啥有 LeaderF 了还要再开发 LeaderF rg 呢。。
    Yggdroot
        4
    Yggdroot  
    OP
       2019-01-15 09:19:35 +08:00 via Android
    @jdhao Leaderf rg 只是 LeaderF 的一个功能。
    skyzone
        5
    skyzone  
       2019-01-18 08:59:21 +08:00
    LeaderF 确实好用,最近一直在用,赞一个

    我是 win7 远程 linux 用,有一点不太友好,就是查询输入只能手打
    常常 window 下复制了,粘贴不进去~只能粘贴进第一个字符
    还有输入时虽然支持 Ctrl-V,使用系统粘贴板,但是我的 linux 没有桌面,不能用粘贴板,Ctrl-V 也没用
    后面就把代码中 @*改成用 @0 了,就可以用 Ctrl-V 了,
    顺便写了个插件,使用 @0 时,远程同步 windows 系统下的粘贴板,才方便从 window 上直接复制粘贴内容
    hanxiV2EX
        6
    hanxiV2EX  
       2019-01-23 08:01:53 +08:00 via Android
    支持,我已经放弃 greper 插件,改用 rg 这个了,二次过滤太强大了。
    hanxiV2EX
        7
    hanxiV2EX  
       2019-01-23 08:07:29 +08:00 via Android
    @skyzone 你需要 lemonade 配合 neovim 使用,无缝共享粘贴板。

    https://github.com/lemonade-command/lemonade

    你可以参加我的配置,windows 下启动 lemonade server,linux 里配好 client,neovim 会自动检测出来,也可以像我这样配置。

    https://github.com/hanxi/dotfiles
    dangoron
        8
    dangoron  
       2019-01-23 14:20:44 +08:00
    跟 fzf 的 Rg 对比有什么优势呢?
    https://github.com/junegunn/fzf.vim#advanced-customization
    Yggdroot
        9
    Yggdroot  
    OP
       2019-01-23 15:51:53 +08:00   ❤️ 1
    @dangoron 我没有深入使用过 fzf 的 Rg,做一下评论,如果不对请纠正。
    fzf rg 有以下不足:
    1. 没有 normal mode,查看结果不是很方便。
    2. 不支持只在当前 buffer 以及所有打开的 buffer 中搜索。
    3. 如果已经搜索一个串'abc',按回车跳到 buffer 中去后,无法再打开上一次的搜索结果,需要重新搜索'abc'; Leaderf rg 可以用文章中提到的`Leaderf! rg --recall`来打开上一次的搜索结果。
    4. 不支持把当前搜索结果追加到上一次的搜索结果上。
    5. 不支持跳到某个搜索位置后仍保持搜索窗口打开状态,就像 quickfix 窗口一样。Leaderf rg 有`--stayOpen`
    6. Leaderf rg 可以像使用 rg 命令一样来用,比如某一次搜索只想搜索 aaa 和 bbb 目录,可以用`Leaderf rg -e xxx aaa bbb`; 某一次不想搜索 src 目录,可以用`Leaderf rg -e xxx -g=!src/`; 而 fzf rg 做不到这么方便,它需要每一种情况都要定义一个命令。
    dangoron
        10
    dangoron  
       2019-01-23 16:06:17 +08:00
    @Yggdroot 可能目前还没有这么复杂的需求,只在当前打开的 buffer 中搜索这个倒是很不错,谢谢你的回复
    skywind3000
        11
    skywind3000  
       2019-01-23 22:44:44 +08:00
    @Yggdroot 对了,Leaderf rg 搜索当前项目目录怎么弄? root marker 那个。
    pony279
        12
    pony279  
       2019-01-24 00:55:31 +08:00
    暂时还没有时间研究搜索插件,我现在对 FZF 的 complain 主要有两点:

    1. 每次使用后,vim 的 buffer number 就会递增, 后面开的 buffer number 很容易增长到几十甚至上百
    2. :FZF 启动后在 terminal 里面 on the fly filter, 这意味着 vim 无法记住我上一次 filter 用的关键字,每次需要重新输入,效率略低
    Yggdroot
        13
    Yggdroot  
    OP
       2019-01-24 07:43:00 +08:00 via Android
    @skywind3000 那个只是给 Leaderf file 用的,默认是在 cwd 开始搜索,还没有 root marker 那个功能。
    Yggdroot
        14
    Yggdroot  
    OP
       2019-01-24 10:20:45 +08:00
    @pony279 第二条与我上面说的第三条类似,这对于 fzf 来说确实很难实现。
    Yggdroot
        15
    Yggdroot  
    OP
       2019-02-26 21:39:17 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1006 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 20:04 · PVG 04:04 · LAX 13:04 · JFK 16:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.