歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Vim之tags 詳解

Vim之tags 詳解

日期:2017/2/28 13:44:45   编辑:Linux教程

  本章要說的是和vim的tags相關的內容. 之所以在跳轉之後就說明tags是因為這個功能相當的重要和實用. 好的東西自然是需要提前分享的.

  首先, 要說的是關於vim使用ctags, cscope的相關教程, 網絡上已經有相當詳盡的文章可以搜索到. 這裡不會在重復大多數網絡上可以搜索到的入門教程了. 並且在此提醒閱讀本篇博客的讀者, 如果你現在對ctags和cscope等並不了解, 那麼請先在網絡裡google所有和他們相關的教程, 花上大約至少一天上的時間認真研究他們的基本用法. 等到對他們有了基本的了解之後再回來看這裡的說明你將會有更大的收獲.

  好了, 廢話我就不再多說, 下面進入真題, 首先要說的是ctags是一個linux上很普遍的源碼分析工具, 可以將代碼中的函數變量等定義的位置記錄在一個名稱為tags的文件. 類似於數據庫記錄功能. tags文件的產出最簡單的方法是在需要生成tags的工程項目的根目錄下執行ctags -R命令, 這會調用tags遞歸的掃描當前目錄以及所有子目錄中可以被tags識別的文件所以文件數據信息都會匯集到tags文件中.這裡總結一下幾個本人暫時知道的幾個需要注意的地方:

  ->Ubuntu在默認系統環境中已經集成了ctags功能, 但這個ctags並不是完整的版本, 為了保證vim可正常的使用tags建議安裝完整的ctags支持, ubuntu完整的ctags被重名為exuberant-ctags但依然可以通過ctags索引到, 安裝命令如下:

  sudo apt-get install ctags

  ->如果你的vim有使用echofunc插件來顯示函數的參數定義, 那麼在使用ctags生產索引文件時需要使用如下附加參數:

  ctags -R --fields=+lS

  ->ctags默認生成的索引文件只包含了對C語言的語法分析, 如果你需要ctags支持對C++語法分析. 需要使用下面的命令:

  ctags -R --c++-kinds=+p --fields=+iaS --extra=+q

  ->如果你在C語言編寫的代碼中使用上面提到的C++命令生成tags, 那麼你將驚訝的發現, 當你希望通過ctags跳轉到光標下函數定義的地方的時候, vim總是跳轉到這個函數定義的地方, 原因是ctags的C++命令增加了額外的語法分析以便支持C++更加復雜的語法結構, 這種額外的語法分析用在C語言中的時候就會出現跳轉默認定位到函數聲明的地方.

  ->ctags默認是支持C和C++的由於本人暫時沒有做過其他語言的開發工作, 所以不清楚ctags是否支持其他編程語言.

  ->請不要每次生成tags的時候都使用上面的命令, 包括以後其他的很多功能的實現都是如此, 命令是實現一個功能的原型, 如果僅僅使用命令在類unix(windows下面也是如此)的操作系統上實現常用的操作和功能, 那麼你的操作將會變得很低效. 個人認為vim的使用也有這個規律, 最普遍的操作最好不要使用長長的命令來實現. 取而代之的方法是設置快捷鍵和命令的簡寫映射.

vim中的tags使用

  vim配置tags使用的過程是, 先在終端中生成一個項目的tags文件, 再在vimrc中告訴vim哪裡去找這個tags. 假如我們有一個項目在/home/boddy/hello/下面, 並且這個目錄下已經生成tags文件.那麼只要在vimrc文件中添加如下語句就可以讓vim在每次啟動的時候自動找到這tags了:

set tags+=/home/boddy/holle/tags

如果你有多個tags需要使用,可以重復上面的語句, 也可以在同一個語句中加入多個路徑,每個路徑用","隔開.

這種方法是我最初使用tags的的方式, 缺點顯而易見, 每當我們開始新的項目的時候,不得不重新修改set tags後面的路徑, 雖然這樣的修改並不麻煩, 也不需要經常操作. 但不免還是讓人覺得太死板不智能.

  為了讓vim對tags的支持更加自動話, 首先想到的方法是在vimrc中添加 settags+=./tags語句, 這樣當前目錄下的tags就不需要我們手動添加了.但我們不可能永遠在項目的根目錄操作. 如果在項目的子目錄裡操作, 這個方法將會失效. 事實上, 任何一個項目文件夾都有一個顯著的特點: 任何子目錄遞歸向上都可以到達項目的根目錄. 這個特點將會在下面的實踐中大顯身手, 讓我們從各種和項目整體相關的操作中解脫出來. 這包括ctags cscope lookupfile等相關索引文件的自動添加和隨時更新. 在項目任意子目錄下的任意時刻對項目的自動make和make clean等. 這些最頻繁操作要麼是自動完成的要麼是通過vimrc的map功能映射到不同的快捷鍵上, 這會讓我們的vim具有所以IDE所具有的便捷性的同時保持了vim在編碼方面無比的高校性和在功能定制方便的無比的可定制性. 我想這就是我為什麼寧願選擇折騰vim而沒有使用成熟的IDE的原因.

  上面提到工程項目的目錄遞歸特性, 實際上, 我們需要使用一個tags最典型的需求是希望在一個項目中快速的找到函數,變量,宏等定義的地方. 這些查找大多是在項目文件夾內完成. 因此, 只要我們能上vim實現對當前所在目錄的遞歸查找功能, 這個需求就會滿足. 只要項目的根目錄下存在tags文件, 任何時候任在任何一個項目的子目錄下使用vim都可以正確的找到這個tags, 同時如果我們的電腦中存在多個項目, 當我們切換到另一個項目的子目錄的時候, vim遞歸查找到永遠是當前項目根目錄下面的tags(前提是tags存在於項目根目錄), 無意間就實現tags的自動切換功能.

  實現vim對tags的自動遞歸查找其實很簡單, 因為vim已經實現了這個功能, 只是默認沒有開啟. 在vimrc添加下面兩行配置, 就會是見證奇跡的時刻:

  set autochdir
  set tags=tags;

  set autochdir表示自動切換目錄的意思, set tags=tags;表示自動查找, 這兩句同時設置vim即可實現遞歸的tags查找, 注意: set tags=tags;這一句的最後有一個分號, 這個分號是不能省略的. vim的配置文件使用的是vim自己的腳步語言. 這裡是少數幾個在行尾需要使用分號的地方之一.

  最後需要說明的一點: ctags在默認的命令下生成的tags中使用的是相對路徑的存放所有查找結果, 這在多數情況下是一個優點, 因為相對路徑不依賴於項目的根目錄所在位置. 這樣在整個項目轉移到別的位置的時候, 相對路徑的tags依然可以正常的實現跳轉. 不過相對路徑的tags並不是沒有缺點, 如果你的vim中使用了FuzzyFinder來作為查找項目文件的工具, 你將驚訝的發現如果你在項目根目錄的子目錄下執行項目文件查找,在找到了想要的文件並最後回車跳轉的時候如果tags使用的是相對路徑, 這一步將會失敗, 因為FuzzyFinder無法正確的通過當前的目錄(不是項目根目錄)加上tags中的相對路徑計算出正確的文件位置. 解決的辦法是在ctags生產tags文件的時候使用絕對路徑, 使用方法是在ctags -R 的命令後面添加項目根目錄的絕對路徑, 如: ctags -R /home/boddy/hello/ , 使用絕對路徑可以保證tags在任何調用他的工具中正確的找到文件位置. 還有一個需要注意的是, 如果現在有下面的需求,我們需要對/usr/include下面所以文件和子目錄bits/做tags處理, 如果你按照上面的語法推導應該得出命令為(當前位置已經在/usr/include): ctags * bits/ /usr/include/, 可是讓我們失望的是這個樣執行沒有出錯但產生的結果竟然是相對路徑, 實際上這種情況下生成絕對路徑的命令寫法應該是: ctags /usr/include/* /usr/include/bits/* . 使用絕對路徑唯一的缺點是如果項目移動了, tags必需重新生成, 鑒於我們的項目在自己的電腦中移動的需求很小的同時重新生成一tags的時間也就是幾秒鐘的事情(只要不是超級大的項目,tags生成還是很快的), 我個人選擇了在任何時候使用ctags都使用絕對路徑, 當然這個功能是在vim中通過參數自動實現的, 本文的最後將會提到.

  好了, vim對tags的自動查找功能實現了, 只是一個開始哦. 下面的介紹將會進一步增強vim在代碼跳轉和搜索上的能力.

  ctags的優點是使用簡單, 生成的tags文件比較小, 使用時對tags的檢索也相對比較快, 對c語言的函數和宏定義跳轉相當准確高效. 他的缺點功能相對單一, 沒辦法實現對一個關鍵字出現位置的統計, 一個函數被調用的位置統計, 局部變量的定義跳轉往往沒有效果等. 我們在編碼的時候除了隨時查看函數定義的需求以外, 另一個比較常用的需求是對一個函數在項目中出現位置查找. 這個功能ctags是沒有的, 為了讓vim實現這個功能, 我們需要借助另一tags索引工具:cscope

  網絡上對cscope的用法說明也很多, cscope的使用要不ctags復雜的不少,因為一樣的, 請先自行google cscope相關的教程提前了解.

  cscope的用法和上面的ctags的用法很相似, 不同的地方有:

  ->生成索引文件的命令不同: cscope -Rbkq

  -> 索引文件的名字不同: 一共有三個, 主要的文件是cscope.out, 另外兩個cscope.in.out cscope.po.out 是在生成命令中使用q參數才會有的文件, 這兩個文件可以加速cscope的查找速度, 注意 : windows下面也可以使用tags和ecscope的,但cscope的-q參數並不支持, 因為windows下面將不會有cscope.in.out 和 cscope.po.out文件

  ->vim中用法不同: ctags 默認在vim中典型的用法是ctrl+] 跳轉到光標下的關鍵字的定義處, ctrl+t跳轉回來. cscope在vim下面並沒有映射快捷鍵. 因為cscope的查找模式有近八種之多, 因此和vim配合使用的時候,默認是通過一組:cs find 開頭的命令來實現的. cscope的官方網站上有一份在vim中使用的建議快捷鍵映射配置. 個人覺得cscope雖然查找方式眾多, 但真正經常用到的也就三到四個. 可以試著將其分配到容易操作的鍵位上來. 官方的那個映射還是稍微有點難按了點.

  ->ubuntu默認系統下完全不支持cscope, 需要通過下面的命令安裝cscope:

  sudo apt-get install cscope

  cscope是一個ctags的增強版本, 可以提供上面提到的各種查找功能. 其實我們完全可以不用ctags而只用cscope的, 因為cscope可以做到所有ctags的功能. 但出於ctags在c語言函數等定義上跳轉的高效和准確性. 我個人是兩個同時使用的, 定義的跳轉通過ctrl+]和ctrl+t實現, 只要在需要其他查找的時候才會動用:cs find 命令.

  好了, 既然實現了ctags的自動查找, cscope自然也要實現, 不能輸入人家ctags啊. 不過在vim中實現cscope的遞歸查找就比較麻煩. 首先要注意的一點是:簡單的在vimrc添加cscope路徑有兩種寫法:

  linux的終端版本的vim7.3中需要使用如下的寫法vim才能正確的識別cscope的tags文件

  cs add /home/boddy/hello/cscope.out /home/boddy/hello/

   第二個參數是告訴vim cscope的索引文件中記錄的數據的相對路徑的起始位置在哪裡, 大多情況下的這個位置是我們項目的根目錄. 因為我們告訴了vim這個相對路徑的起始位置, 因此cscope默認使用相對路徑產生的數據庫總是可以正確的跳轉.

  windows下面的gvim7.3需要使用如下的寫法gvim才能正確識別cscope

  cs a E:\project\hello\cscope.out

  這裡不需要添加相對路徑的起始位置, 具體原因不清楚, 可能windows下的gvim默認把cscope.out所在路徑解析成相對路徑的起始路徑了吧. 不過就是這個問題導致我在windows下面使用vim在很長一段時間中沒能正確的使用cscope.

上面說的注意事項是我在vim學習之初遇到的問題, 下面實現的遞歸索引功能將不會關注這個問題, 但依然需要注意這個事項.

  vim中實現cscope的遞歸查找有兩種方式, 要麼自己在vimrc中寫一個簡單函數讓vim啟動的時候去遞歸查找並添加cscope.out, 要麼使用插件. 通過簡單函數的實現在網絡上可以搜索到, 同時我在最初也是用這種方法實現的, 不過在後來的某一天偶然讓我發現了vim有一個實現遞歸查找cscope的插件後就刪除了這個在vimrc中的函數,並使用插件來實現. 這樣可是簡化vimrc的篇幅的同時別人寫的插件肯定比簡單的函數要完善.

  到下面的網站中搜索autoload_cscope.vim即可下載到這個插件.

  http://vim-scripts.org/vim/scripts.html

針對這個插件有如下的說明:

這個插件只有一個腳步文件, 放到你的~/.vim/plugin目下即可使用, 該插件默認情況下是在我們打開.h/.c/.cpp文件的時候才會自動遞歸查找並添加cscope.out文件的,個人覺得既然我們在已經在項目子目錄下了, 大多時候都是希望cscope可用的, 即便我們是在編輯一個.txt文件我們可能希望手動搜索一個當前項目的關鍵字等. 另外即便是cscope.out文件我們用不到,但將其添加到當前編輯文件中來在性能上幾乎是沒有影響的. 因此, 我人為的修改了這個插件,以便讓它實現在打開任何文件的時候(包括新建空文件)都遞歸查找cscope.out

修改方法如下:

打開autoload_cscope.vim定位到文件的最後幾行,你將看到:

au BufEnter *.[chly] call <SID>Cycle_csdb() | call <SID>Cycle_macros_menus()
au BufEnter *.cc call <SID>Cycle_csdb() | call <SID>Cycle_macros_menus()
au BufUnload *.[chly] call <SID>Unload_csdb() | call <SID>Cycle_macros_menus()
au BufUnload *.cc call <SID>Unload_csdb() | call <SID>Cycle_macros_menus()

將他們修改為下面內容即可

au BufEnter * call <SID>Cycle_csdb() | call <SID>Cycle_macros_menus()
au BufUnload * call <SID>Unload_csdb() | call <SID>Cycle_macros_menus()

另外可以在vimrc中選擇性的添加如下內容:

set nocst "在cscope數據庫添加成功的時候不在命令欄現實提示信息.
set cspc=6 "cscope的查找結果在格式上最多顯示6層目錄.
let g:autocscope_menus=0 "關閉autocscope插件的快捷健映射.防止和我們定義的快捷鍵沖突.

"cscope相關的快捷鍵映射
nmap ff <c-]> "ff映射到ctrl+],這將中調用ctags的數據庫跳轉,在速度上會快一點. 如果發現ff無法實現跳轉,可以試著使用fg, 這個會調用cscope的數據庫實現跳轉.

nmap ss <c-t> "ss映射到ctrl+t , 在使用ff跳轉的使用通過ss跳轉回來,純屬個人在功能映射上的多余之舉.

"s:查找即查找C語言符號出現的地方
nmap fs :cs find s <C-R>=expand("<cword>")<CR><CR>
"g:查找函數、宏、枚舉等定義的位置
nmap fg :cs find g <C-R>=expand("<cword>")<CR><CR>
"c:查找光標下的函數被調用的地方
nmap fc :cs find c <C-R>=expand("<cword>")<CR><CR>
"t: 查找指定的字符串出現的地方
nmap ft :cs find t <C-R>=expand("<cword>")<CR><CR>
"e:egrep模式查找,相當於egrep功能
nmap fe :cs find e <C-R>=expand("<cword>")<CR><CR>
"f: 查找文件名,相當於lookupfile
nmap fn :cs find f <C-R>=expand("<cfile>")<CR><CR>
"i: 查找當前文件名出現過的地方
nmap fi :cs find i <C-R>=expand("<cfile>")<CR><CR>
"d: 查找本當前函數調用的函數
nmap fd :cs find d <C-R>=expand("<cword>")<CR><CR>

  好了, cscope的自動化使用到此也大功告成,如果你想在vim中查看auto_cscope是否成功為你自動加載了cscope.out,可以在vim中執行 ":cs s" (這s是show的縮寫) 來查看與當前vim窗口關聯的所有cscope文件的信息.

Copyright © Linux教程網 All Rights Reserved