`Leaderf gtags`:模糊匹配与最强静态符号索引工具的完美结合

2019-05-06 18:03:11 +08:00
 Yggdroot

Gtags

Gtags 也就是GNU GLOBAL,是一个非常强大的源码符号索引工具。它通过建立索引数据库,不但可以查找函数的定义,还可以查找函数的所有引用(被调用的地方);而且它还可以增量地更新索引数据库,当代码有所改变时,它可以在很短的时间内更新索引数据库,保持索引数据库和代码同步。
韦大的 Vim 8 中 C/C++ 符号索引:GTags 篇 对 gtags 有比较详细的介绍,本文再做一些补充。

  1. GLOBAL-6.6.3 released Gtags 的最新版本已经是 6.6.3,该版本 fix 了韦大文中提到的 Windows 下面文件名大小写的 bug。
  2. 在 Linux 上,不配置let $GTAGSCONF = '/path/to/share/gtags/gtags.conf'也可以正常工作。
  3. 当项目文件的路径包含非 ASCII 字符时,使用 pygments 会报UnicodeEncodeError: 'latin-1' codec can't encode characters in position 5-8: ordinal not in range(256)

自动生成 Gtags 索引数据库

LeaderF 可以自己管理 gtags 数据库( GTAGS,GRTAGS,GPATH ),它不会在你的项目目录下生成任何额外的文件或目录。gtags 数据库文件存储在$HOME/.LfCache/gtags/%PATH%OF%YOUR%PROJECT/下面, %PATH%OF%YOUR%PROJECT 是把你项目路径中的 \/ 替换成 %
只要设置let g:Lf_GtagsAutoGenerate = 1,LeaderF 就会在打开第一个文件时自动生成 gtags 数据库。当代码有更改并且已经有 gtags 数据库生成时,更改的代码会自动同步到 gtags 数据库(即使g:Lf_GtagsAutoGenerate是 0 )。
只有在项目根目录下有g:Lf_RootMarkers(默认值是['.git', '.hg', '.svn'])里面指定的文件或目录时,LeaderF 才会自动生成 gtags 数据库;否则只能手动生成 gtags 数据库:Leaderf gtags --update,但是当代码有更改时,gtags 数据库依然可以自动更新。

Leaderf gtags 使用介绍

具体使用方法可以用:Leaderf gtags -h来查看。

usage:
Leaderf[!] gtags [-h] [--remove] [--recall]
Leaderf[!] gtags --update [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [--accept-dotfiles]
                 [--skip-unreadable] [--skip-symlink [<TYPE>]] [--gtagslibpath <PATH> [<PATH> ...]]
Leaderf[!] gtags [--current-buffer | --all-buffers | --all] [--result <FORMAT>] [COMMON_OPTIONS]
Leaderf[!] gtags -d <PATTERN> [--auto-jump [<TYPE>]] [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>]
                 [--append] [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
Leaderf[!] gtags -r <PATTERN> [--auto-jump [<TYPE>]] [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>]
                 [--append] [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
Leaderf[!] gtags -s <PATTERN> [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>] [--append]
                 [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
Leaderf[!] gtags -g <PATTERN> [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>] [--append]
                 [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
Leaderf[!] gtags --by-context [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>] [--append]
                 [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]

[COMMON_OPTIONS]: [--reverse] [--stayOpen] [--input <INPUT> | --cword]
                  [--top | --bottom | --left | --right | --belowright | --aboveleft | --fullScreen]
                  [--nameOnly | --fullPath | --fuzzy | --regexMode] [--nowrap]
 

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

specific arguments:
  --update              Create tag files if tag files do not exist, update the tag files otherwise.
  --remove              Remove the tag files generated.
  --accept-dotfiles     Accept files and directories whose names begin with a dot. By default, gtags
                        ignores them.
  --skip-unreadable     Skip unreadable files.
  --gtagsconf <FILE>    Set environment variable GTAGSCONF to <FILE>.
  --gtagslabel <LABEL>  Set environment variable GTAGSLABEL to <LABEL>.
  --skip-symlink [<TYPE>]
                        Skip symbolic links. If type is 'f' then skip only symbolic links for file, else
                        if 'd' then skip only symbolic links for directory. The default value of type is
                        'a' (all symbolic links).
  --gtagslibpath <PATH> [<PATH> ...]
                        Specify the paths to search for library functions.
  -d <PATTERN>, --definition <PATTERN>
                        Show locations of definitions.
  -r <PATTERN>, --reference <PATTERN>
                        Show reference to a symbol which has definitions.
  -s <PATTERN>, --symbol <PATTERN>
                        Show reference to a symbol which has no definition.
  -g <PATTERN>, --grep <PATTERN>
                        Show all lines which match to the <PATTERN>.
  --by-context          Decide tag type by context at cursor position. If the context is a definition of
                        the pattern then use -r, else if there is at least one definition of the pattern
                        then use -d, else use -s. Regular expression is not allowed for pattern.
  -i, --ignore-case     Ignore case distinctions in the pattern.
  --literal             Execute literal search instead of regular expression search.
  --path-style <FORMAT>
                        Show path names using <FORMAT>, which may be one of: `relative`, `absolute`,
                        `shorter`, `abslib` or `through`. `relative` means relative path. `absolute`
                        means absolute path. `shorter` means the shorter one of relative and absolute
                        path. `abslib` means absolute path for libraries (GTAGSLIBPATH) and relative path
                        for the rest. `through` means the relative path from the project root directory
                        (internal format of GPATH). The default is `relative`.
  -S <DIR>, --scope <DIR>
                        Show only tags which exist under <DIR> directory.
  --recall              Recall last search. If the result window is closed, reopen it.
  --match-path          Match the file path when fuzzy searching.
  --append              Append to the previous search results.
  --current-buffer      Show tags in current buffer.
  --all-buffers         Show tags in all listed buffers.
  --all                 Show tags in the whole project.
  --result <FORMAT>     Show result using format, which may be one of: `ctags`(default), `ctags-x`,
                        `ctags-mod`.
  --auto-jump [<TYPE>]  Jump to the tag directly when there is only one match. <TYPE> can be 'h', 'v' or
                        't', which mean jump to a horizontally, vertically split window, or a new tabpage
                        respectively. If <TYPE> is omitted, jump to a position in current window.

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
  --next                Jump to the next result.
  --previous            Jump to the previous result.

If [!] is given, enter normal mode directly.

注意:如果:Leaderf后面有感叹号,会直接进入 normal 模式;如果没有感叹号,则是输入模式,此时可以输入字符来进行模糊匹配过滤。可以用 tab 键在两个模式间来回切换。

手动生成 gtags 数据库

Leaderf[!] gtags --update [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [--accept-dotfiles]
                 [--skip-unreadable] [--skip-symlink [<TYPE>]] [--gtagslibpath <PATH> [<PATH> ...]]

此命令完全异步,不会卡住你的 UI。

  1. --gtagsconf <FILE>

    用来指定 gtags.conf 文件的路径,一般情况下不需要指定,默认值就可以很好地工作。对于 Windows 上,如果相对于gtags.exe所在路径有../share/gtags/gtags.conf,也不需要指定该选项。如果需要用户自己特有的针对 gtags 的配置,可以指定用户的配置文件。

    也可以在vimrc里设置g:Lf_Gtagsconf达到同样的目的。

  2. --gtagslabel <LABEL>

    用来指定 gtagslabel,如果不指定,默认值是 'default'<LABEL>gtags.conf 中的:

    • default
      使用内置 parser,只支持 6 种语言( C,C++,Java,PHP4,Yacc,汇编)。
    • ctags
      使用 exuberant-ctags 作为语言 parser,支持 40+ 种语言,只能生成定义索引不能生成引用索引。
    • new-ctags
      使用 universal-ctags 作为语言 parser,支持 100+ 种语言,只能生成定义索引不能生成引用索引。虽然貌似 universal-ctags 已经支持生成引用 tags,但是依然不能配合 gtags 工作(见这里),我也试了各种操作都没成功,也许是因为这个 PR没有被 merge。
    • pygments
      使用pygments作为语言 parser,号称支持 300+种语言。
    • native-pygments
      对于原生支持的 6 种语言使用内置 parser,其他语言使用 pygments 作为 parser。
    • 等等

    也可以在vimrc里设置g:Lf_Gtagslabel达到同样的目的。

  3. --gtagslibpath <PATH> [<PATH> ...]

    用来指定项目所用 library 的 Paths,这样就可以生成 library 的索引,查找定义或引用时可以跳转到 library 代码中去。后面指定的路径还可以是一个或多个其他项目路径,跳转时可以跳到其他项目中的文件。

查找 tags

Leaderf[!] gtags [--current-buffer | --all-buffers | --all] [--result <FORMAT>] [COMMON_OPTIONS]

此命令可以列出当前 buffer、所有打开的 buffer 或者整个项目的 tags。

  1. Leaderf[!] gtags等同于Leaderf[!] gtags --all,列出整个项目的 tags。
  2. --result <FORMAT> 指定显示格式,可以是ctags(default), ctags-x或者ctags-mod
    • ctags 格式
    • ctags-x 格式
    • ctags-mod 格式

查找定义、引用

Leaderf[!] gtags -d <PATTERN> [--auto-jump [<TYPE>]] [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>]
                 [--append] [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
Leaderf[!] gtags -r <PATTERN> [--auto-jump [<TYPE>]] [-i] [--literal] [--path-style <FORMAT>] [-S <DIR>]
                 [--append] [--match-path] [--gtagsconf <FILE>] [--gtagslabel <LABEL>] [COMMON_OPTIONS]
  1. <PATTERN>可以是正则表达式。
  2. --auto-jump [<TYPE>] 意思是如果只有一个结果直接跳过去。

其他

  1. Leaderf[!] gtags -g <PATTERN>功能已被Leaderf rg包含。
  2. Leaderf gtags --nextLeaderf gtags --previous相当于 quickfix 的:cnext:cprevious命令,在 LeaderF 结果窗口关闭的情况下也可以使用。
  3. 更多内容请参考:Leaderf gtags -h 和 doc。

使用示例

let g:Lf_GtagsAutoGenerate = 1
let g:Lf_Gtagslabel = 'native-pygments'
noremap <leader>fr :<C-U><C-R>=printf("Leaderf! gtags -r %s --auto-jump", expand("<cword>"))<CR><CR>
noremap <leader>fd :<C-U><C-R>=printf("Leaderf! gtags -d %s --auto-jump", expand("<cword>"))<CR><CR>
noremap <leader>fo :<C-U><C-R>=printf("Leaderf! gtags --recall %s", "")<CR><CR>
noremap <leader>fn :<C-U><C-R>=printf("Leaderf gtags --next %s", "")<CR><CR>
noremap <leader>fp :<C-U><C-R>=printf("Leaderf gtags --previous %s", "")<CR><CR>
4116 次点击
所在节点    Vim
8 条回复
tamlok
2019-05-06 18:44:32 +08:00
能用 gutentags 产生的数据库吗?还是说这个能完全替代 gutentags ?
tamlok
2019-05-06 18:47:31 +08:00
另外,再次请求在 leaderf 模式下面,输入的时候能支持 Ctrl-R 读取指定寄存器的值。

在 nvim-qt 下面,Shift-Insert 是无法插入系统剪切板的,这时候读取一个寄存器的值就很有必要。

谢谢!
Yggdroot
2019-05-06 18:59:50 +08:00
@tamlok 不能,不清楚,我只知道 gutentags 能自动维护 gtags、ctags,还有没有其他功能就不知道了。Leaderf 只能维护 gtags,不维护 ctags。
tamlok
2019-05-06 19:08:31 +08:00
@Yggdroot 如果和 gutentags 一起使用会不会冲突呢?不过,强迫症患者忍受不了两份 gtags 数据库。
Yggdroot
2019-05-06 19:12:49 +08:00
@tamlok 不会冲突。
hanxiV2EX
2019-05-06 20:26:32 +08:00
@tamlok 我已经弃用 gutentags 了,LeaderF 实现的了一样的功能。
congeec
2019-05-07 08:48:34 +08:00
rtags
visysl
2020-09-14 09:30:07 +08:00
你好,我用 Leaderf 和 gtags 生成 python 的符号索引。如果不配置 GTAGSLABEL 和 GTAGSCONF 是不能生成符号索引的。添加了环境变量之后在生成的三个文件中有了 python 的索引。但是用 Leaderf gtags 命令还是列不出 python 的索引,只能列出项目中 c/c++代码的索引。请问这种情况怎么解决?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/561549

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX