修改ctags讓fzf.vim外掛顯示C,C++方法宣告的標籤

2023-02-20 18:00:20

背景

在 vim 中使用 fzf.vim 外掛可以進行方便的搜尋檔案, 原始碼TAG, GIT 記錄等, 最近抽空看了下 BTags 命令在 c, c++ 檔案中, 無法顯示標頭檔案中的函數宣告 標籤問題.

比如在標頭檔案中有如下一個函數宣告, 使用 BTags 命令是無法顯示出這個函數原型的.


/*=========================================================================
函 數 名: IMGVideoAlgOpen
功    能: 演演算法初始化
演演算法實現: 無
參    數: pvHandle                    演演算法控制程式碼[in]
emIMGAlgType                演演算法型別[in]
pvOpen                      初始化結構體指標[in]
返 回 值: 返回函數呼叫資訊
===========================================================================*/
int IMGVideoAlgOpen(void** pvHandle,
                                                EMIMGAlgType emIMGAlgType,
                                               void* pvOpen);

分析

通過程式碼定位, 在 ~/.vim/bundle/fzf.vim/autoload/fzf/vim.vim 檔案中, 可以看到 BTags 是通過 ctags 生成的標籤.

" query, [tag commands], [spec (dict)], [fullscreen (bool)]
function! fzf#vim#buffer_tags(query, ...)
  ...
  let sort = has('unix') && !has('win32unix') && executable('sort') ? '| sort -s -k 5' : ''
  let tag_cmds = (len(args) > 1 && type(args[0]) != type({})) ? remove(args, 0) : [
    \ printf('ctags -f - --sort=yes --excmd=number --language-force=%s %s 2> %s %s', get({ 'cpp': 'c++' }, &filetype, &filetype), escaped, null, sort),
    \ printf('ctags -f - --sort=yes --excmd=number %s 2> %s %s', escaped, null, sort)]
  ...
endfunction

通過在命令列執行 ctags 命令, 確實是沒有生成函數宣告的標籤.

$ ctags -f - --sort=yes --excmd=number --language-force=c  include/VideoAlg.h | grep IMGVideoAlgInit

# output nothing 

通過查詢 ctags 檔案瞭解到, 每個語言生成標籤時, 都有預設的標籤型別列表.
可以通過 --kinds-(<LANG>|all)=[+|-](<kinds>|*) 引數去控制, 比如我需要控制 c 語言的生成標籤型別, 可以寫成這樣: --kinds-C=+型別.

具體的標籤型別可以通過 ctags --list-kinds-full 進行檢視, 如下.

$ ctags --list-kinds-full

# output
#LANGUAGE            LETTER NAME                  ENABLED REFONLY NROLES MASTER DESCRIPTION
...
C                    D      macroparam            no      no      0      C      parameters inside macro definitions
C                    L      label                 no      no      0      C      goto labels
C                    d      macro                 yes     no      1      C      macro definitions
C                    e      enumerator            yes     no      0      C      enumerators (values inside an enumeration)
C                    f      function              yes     no      0      C      function definitions
C                    g      enum                  yes     no      0      C      enumeration names
C                    h      header                yes     yes     2      C      included header files
C                    l      local                 no      no      0      C      local variables
C                    m      member                yes     no      0      C      struct, and union members
C                    p      prototype             no      no      0      C      function prototypes
C                    s      struct                yes     no      0      C      structure names
C                    t      typedef               yes     no      0      C      typedefs
C                    u      union                 yes     no      0      C      union names
C                    v      variable              yes     no      0      C      variable definitions
C                    x      externvar             no      no      0      C      external and forward variable declarations
C                    z      parameter             no      no      0      C      function parameters inside function definitions
...

由上 ENABLED 列可知, 預設 ctags 為 c 語言生成的 tags 是不包含 prototype 的, 如果需要支援生成 prototype, 需要使用引數加上.

解決

修改 ~/.vim/bundle/fzf.vim/autoload/fzf/vim.vim 檔案, 增加 ctags --kinds-C=+p 引數來支援 prototype 方法簽名.


    \ printf('ctags -f - --sort=yes --kinds-C=+p --excmd=number --language-force=%s %s 2> %s %s', get({ 'cpp': 'c++' }, &filetype, &filetype), escaped, null, sort),
    \ printf('ctags -f - --sort=yes --kinds-C=+p --excmd=number %s 2> %s %s', escaped, null, sort)]

搞定收工, 同時也提交了 PR 到 github , 不知道是否會採納.

總結

如果需要其它語言額外的標籤型別, 可以基於類似的方法新增.回想了一下 ctag 之所以預設不提供 prototype 型別的標籤, 可能是因為一個檔案中如果有宣告和定義, 可能會有兩個相同的標籤影響檢視. 我這邊是做了標籤選擇預覽的, 所以不存在這個問題.

參考