1. 程式人生 > >vim ctags cscope lookupfile外掛(包括如何自動生成索引tag、自動查詢索引tag)

vim ctags cscope lookupfile外掛(包括如何自動生成索引tag、自動查詢索引tag)

  好長時間沒有上來更新了, 今天趁老闆不再上來休閒一下. 本章要說的是和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在任何呼叫他的工具中正確的找到檔案位置. 唯一的缺點是如果專案移動了, tags必需重新生成, 鑑於我們的專案在自己的電腦中移動的需求很小的同時重新生成一tags的時間也就是幾秒鐘的事情(只要不是超級大的專案,tagseh生成還是很快的), 我個人選擇了在任何時候使用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的索引檔案中記錄的資料的相對路徑的起始位置在那裡, 大多情況下的這個位置是我們專案的根目錄.

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

  cs a E:/project/hello/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的快捷鍵對映

"cscope相關的快捷鍵對映
nmap ff <c-]>
"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相關的快捷鍵對映
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檔案的資訊.

下面是今天的最後一個自動索引功能的實現. 我廢話真的太多了, 寫部落格都寫累了....休息中....

最後一個查詢跳轉型別的資料庫檔案是lookupfile這個外掛.  實際上這個外掛在很大程度上是多餘的, 首先是cscope提供了檔案查詢功能. 其次是如果使用FuzzyFinder外掛可以實現藉助tags檔案來查詢專案檔案. 不過鑑於lookupfile這個外掛遇見的較早, 功能簡單, 查詢優美, 設定好了之後使用也很方便又不和任何其他外掛的衝突, 我還是永久的留下了這個外掛. 下面是這個外掛的相關設定過程:

到http://vim-scripts.org/vim/scripts.html 搜尋lookupfile下載並安裝該外掛.

編寫生成lookupfile索引檔案的指令碼, 這個我也是從網路上抄來的, 內容可以如下:

#!/bin/sh
# generate tag file for lookupfile plugin
echo -e "!_TAG_FILE_SORTED/t2/t/2=foldcase/" > name.tags
find . -not -regex '.*/./(png/|gif/)' -type f -printf "%f/t%p/t1/n" | sort -f >> name.tags

其中的name.tags是生成的的索引檔案的名字, 你可以修改成任何期它的名字, 不過需要注意一定要使用一個字尾名, 不可起如nametags這樣的名字, 這在後面的會說明原因.

將上面的內容儲存為.sh字尾的檔案(如:nametags.sh),將這個shell檔案移動的到一個目錄下並將該目錄新增到環境變數中去. 個人建議是在~/.vim目錄下建立一個bin資料夾, 將nametags.sh移動到這裡, 以後只要是和程式設計有關的shell檔案或自建的批處理等檔案都可以放到這裡來, 這樣在日常備份的時候只要將~/.vim 資料夾和~/.vimrc檔案打包就可以備份很多開發環境了, 本這這個原則, 我個人開發相關的一些其他的內容(如vim的補全列表, 標準專案模板, 個人使用的函式庫等)都會放在.vim資料夾中.bin資料夾下面存在放的都是需要執行的檔案, 因此在第一次使用之前,重灌系統或移動到一臺上使用的時候需要做如下兩個操作:

->將bin目錄下所有的檔案賦予執行許可權: sudo chmod 775 ~/.vim/bin/*

->將~/.vim/bin目錄新增到環境變數中去. 這個操作有很多中方式, 每個linux版本也不是太一樣, 可以自行百度解決.

  nametags.sh在賦予可執行許可權和新增環境變數操作之後就可以在任何目錄執行了, 執行的結果是nametags.sh 索引當前目錄的所有的子目錄, 將.c .h等原始檔排序後新增到當前目錄的name.tags檔案來.這name.tags相當與tags檔案, 只是他的功能只能用來查詢專案檔案而已.

  在專案根目錄執行nametags.sh之後我們需要向ctags和cscope一樣通過vimrc來告訴vim的lookupfile外掛那裡去找這個專案檔案的索引,當然, 我們也需要實現vim自動對name.tags檔案的自動遞迴查詢. 這個功能在網路上可就沒有現成的方法了, 因為很少有人會想到這個需求, 同時實現起來也很困難, 因為沒有多少人對vim瞭解到會編寫腳步的地步, 我至今還不太會編寫比較複雜的vim指令碼檔案. 好在大多數複雜的功能都已經被大神和前輩們實現了, 而我們需要做的就是讓這些功能更加的便捷並定製成符合自己需求的樣子就可以了.

  在看過了lookupfile的幫助文件和查閱了一些vim腳步資料之後, 在我不斷的嘗試性的編寫下竟然讓我實現了lookupfile的遞迴查詢name.tags的功能. 這個算的上是我完全獨立實現的功能啦. 有紀念意義哦....

  在vimrc中新增如下兩條語句,將實現lookupfile的自動遞迴查詢name.tags檔案:

let g:name_file=findfile("name.tags", ".;")
let g:LookupFile_TagExpr='g:name_file'

  第一句的findfile函式實現了遞迴查詢,注意:findfile函式似乎有一個神奇的特點, 如果你查詢的是諸如name.tags這種帶有後綴名的檔案, 那麼它會返回一個絕對路徑的檔名字串,可是如果你查詢的是諸如nametags這樣沒有後綴名的檔案, findfile依然可以正確的找到這個檔案, 但返回的東西就很坑爹了, 直接是nametags, 路徑全部被吞掉了!!!

   第二句是將第一句查詢的結果連同路徑一起賦值給LookupFile_TagExpr變數, 這裡似乎必須在name_file前面新增一個g:或s:才能正確的被vim識別.

為更家便捷的使用lookupfile查詢檔案,我在vimrc設定瞭如下的對lookupfile的設定和快捷鍵的對映並從網路找到了一個可以實現lookupfile查詢時忽略大小寫的功能函式:

let g:LookupFile_MinPatLength=2
let g:LookupFile_PreserveLastPattern=0
let g:LookupFile_PreservePatternHistory=1
let g:LookupFile_AlwaysAcceptFirst=1
let g:LookupFile_AllowNewFiles=0
let g:indentLine_color_gui='#4e5656'

nmap ,l :LUTags<cr> "最常用
nmap ,kk :LUBufs<cr>
nmap ,kl :LUWalk<cr>

"LookupFile搜尋時不區分大小寫
func! LookupFile_IgnoreCaseFunc(pattern)
let _tags = &tags
try
let &tags = eval(g:LookupFile_TagExpr)
let newpattern = '/c' . a:pattern
let tags = taglist(newpattern)
catch
echohl ErrorMsg | echo "Exception: " . v:exception | echohl NONE
return ""
finally
let &tags = _tags
endtry
let files = map(tags, 'v:val["filename"]')
return files
endfunc
let g:LookupFile_LookupFunc = 'LookupFile_IgnoreCaseFunc'

  由於這三個索引功能的檔案都不會在專案檔案發生修改的時候自動更新, 因此需要我們手動的在需要更新的時候一個一個的更新他們,事實上這樣的更新在我們檢視別人的專案和linux核心檔案的時候並不是太過頻繁,有時甚至很少. 例如在檢視linux核心原始檔的時候我幾乎只需要建立一次索引就可以了, 重點這是一個很幸運的事情, 因為linux的核心檔案是相當的龐大的, 對它建立tags和cscope.out以及name.tags檔案加一起更新一次就需要近十來分鐘. 這三個資料庫檔案都不支援增量更新. 即便我們只改動了整個專案的很小的一部分核心, 重新構建tags的時候依然需要對整個專案進去完全的檢索. 從這一點來看ctags和cscope並不適合超大型專案的頻繁構建. 之所以說這是一個幸運是因為我們很少會參與諸如linux核心這樣的專案構建. 即便公司真的有一個超大的專案, 分配到我們身上的大多是很小的一部分或一個模組功能. ctags和cscope建立的速度還相當快了, linux核心產生的ctags可以達到100多兆, cscope.out更是達到300-400兆. 這樣的資料在幾分鐘內完成,可想而知, 不是超級巨型的專案, tags建立基本可以在十妙內完成.

  現在還剩下最後一個問題, 雖然既然我們很幸運的可以正常使用他們, 但是在開發一個常規專案的時候頻繁的重新構建tags,cscope.out和name.tags是正常的操作之一, 這些索引資料都是通過命令建立的.每個命令又不是那麼簡短. 編碼時,如果希望重新整理tags的時候就跑到專案根目錄挨個執行一通他們的命令肯定是一件沒幾個人能接受的事情. 好在這些tags的構建名利幾乎都是固定的. vim提供了直接執行shell命令的能力. 再加上快捷鍵對映功能和專案的遞迴特性. 我們便有辦法將tags的更新簡化到一鍵操作, 一鍵操作是一個很了不起的能力, 因為除了全自動的操作, 應該沒有比一鍵操作還要簡潔高效的了. 

  下面是實現ctags, cscope,和lookupfile的一鍵重新整理功能的設定:

  ->在專案的根目錄新建一個空的檔名為TOP的檔案. 這個檔案用來標識專案根目錄所在位置.(你可以將這個空檔案做為你的專案標準模板的一部分)

  ->在vimrc中新增如下的函式和設定:

"nmap <f12> <esc>:call Go_top()<cr>:!ctags -R --c++-kinds=+p --fields=+iaS
"/ --extra=+q $PWD<cr>:call Do_CsTag()<cr>:!nametags.sh<cr><cr>:call Go_curr()<cr>
"imap <f12> <esc>:call Go_top()<cr>:!ctags -R --c++-kinds=+p --fields=+iaS
"/ --extra=+q $PWD<cr>:call Do_CsTag()<cr>:!nametags.sh<cr><cr>:call Go_curr()<cr>
"nmap <a-f12> <esc>:!ctags -R --fields=+lS $PWD<cr><cr>
"/:!cscope -Rbkq<cr><cr>:!nametags.sh<cr><cr>
"imap <a-f12> <esc>:!ctags -R --fields=+lS $PWD<cr><cr>
"/:!cscope -Rbkq<cr><cr>:!nametags.sh<cr><cr>

nmap <f12> <esc>:call Go_top()<cr>:!ctags -R --fields=+lS $PWD<cr><cr>
/:!cscope -Rbkq<cr><cr>:!nametags.sh<cr><cr>:call Go_curr()<cr>
imap <f12> <esc>:call Go_top()<cr>:!ctags -R --fields=+lS $PWD<cr><cr>
/:!cscope -Rbkq<cr><cr>:!nametags.sh<cr><cr>:call Go_curr()<cr>

func! Go_top()
  wall
  let g:Curr_dir=getcwd()
  let i = 1
  while i < 10
    if filereadable("TOP")
      return
    else
      cd ..
     let i += 1
    endif
  endwhile
  exec 'cd'.g:Curr_dir

endfunc

func! Go_curr()
  exec 'cd'.g:Curr_dir
endfunc

func! Do_CsTag()
  silent! exec "!find . -name '*.h' -o -name '*.c' -o -name '*.cpp'
  / -o -name 'Makefile' -o -name 'makefile' -o -name 'make*'
  / -o -name '*.cc' -o -name '*.C'-o -name '*.s'-o -name '*.S'>cscope.files"
  silent! exec"!cscope -Rbkq -i cscope.files"
  silent! exec"!cscope -Rbkq"
endfunc

說明:

  ->前面幾行用 " 注視掉的內容是對C++的支援, 在使用C++的時候可以解除他們的註釋並將下面C語言使用的對映添加註釋.

  ->整個對<F12>鍵的對映在看完上面的介紹之後應該可以看懂, 需要注意的是vim中命令模式下執行!開頭的內容會被送往vim所在的shell中執行並且很多時候在終端執行完vim傳遞的命令之後終端會給出一個提示說明執行完畢,並要求鍵入一個enter鍵才能返回到vim,vim的對映中的<cr>可以被自動傳送到終端中去, 因此只要在呼叫終端命令之後在額外的新增一個<cr>就可以實現讓vim自動在終端中鍵入一個<enter>鍵. 另外, 其實這裡的對映本來完全可以封裝在一個函式中完成的. 可是我自己無法實現在vim腳步的函式中向終端傳送<enter>鍵的功能, 因此不得已才通過這種在對映中新增<cr>的方式實現自動互動的功能.

  ->對映中在執行ctags -R的時候額外的傳遞了一個$PWD變數, 這個變數在vim表示的是vim的當前工作目錄, 由於在執行ctags前已經呼叫Go_top()將當前目錄更改為專案的根目錄, 所以這裡傳遞的實際上就專案的跟目錄, 這個變數的作用在之前說過, 它可是讓ctags生成的檔案使用絕對路徑, 這會保證幾乎所有呼叫的tags的外掛都可以正常的工作.

  ->Go_top()函式首先記錄下當前目錄位置然後遞迴的查詢當前目錄所以父目錄下是否存在TOP檔案, 如果存在就定位到那個目錄並返回, 如果不存在通過之前記錄的目錄返回到之前的目錄, 這樣做的好處是的即便沒有找到TOP標識,vim的當前目標也不至於跑到系統的根目錄上去.

  ->Go_curr()函式實現vim在成功找到TOP標識並在TOP所在目錄執行完所有命令之後通過g:Curr_dir記錄的全域性變數來讓vim的當前目錄中回到執行命令前的狀態.

  ->Do_Cstags()函式是一個可選函式, 他的功能是可以在生成cscope的時候過濾掉一些不需要建立索引的檔案. 事實上, 這個功能並是經常用到, 因為專案資料夾中的的檔案大多和專案相關. 不相關的一些說明檔案cscope也可能對其建立索引.為了讓所有可能建立索引的特殊檔案(如:makefile)也可以實現跳轉.我自己並沒有過濾任何檔案.

  當上面所有的設定都正確工作了之後, 恭喜, vim和tags相關的配置就算告一段落了. 以後你要做的就是在專案根目錄建立TOP檔案.在任何專案目錄中開啟vim按下f12鍵, vim將會自動為你建立所需的所有tags檔案. 之後只要你在任意專案目錄中開啟vim屬於這個專案的所有tags檔案都會被vim自動載入並正確工作. 在你編輯程式碼的任何時刻, 你都可以通過一個f12鍵迅速的更新整個專案的所有tags索引. 你可以通過ctrl+]和ctrl+t來呼叫ctags, 在普通模式下通過"f"打頭快捷鍵呼叫cscope查詢,通過 ",l" 來呼叫lookupfile查詢專案檔案. 這篇文章中提到到所有功能最終被濃縮到一個f12鍵上. 這種一勞永逸並可以大幅提高效率的感覺會讓你覺得付出的一切的是那麼的值得. 這也是為什麼我願意花掉整個下午的時間來寫這篇部落格的原因. 希望這幾千的說明可以被更多願意使用vim的人看到. 也希望有其他的vim愛好者能夠和我更多的交流學習....

from: http://blog.csdn.net/kang99827765/article/details/39430433