Ctags比較詳細的使用說明

創建tags文件,shell下執行ctags -R
在vi中設定當前使用tags,:set tags=tags 注意:後面的那個tags是文件名

vim+ctags用法(轉載)

[/home/brimmer/src]$ ctags -R

"-R"表示遞歸創建,也就包括源代碼根目錄下的所有子目錄下的源程序。"tags"文件中包
括這些對象的列表:

l 用#define定義的宏

l 枚舉型變量的值

l 函數的定義、原型和聲明

l 名字空間(namespace)

l 類型定義(typedefs)

l 變量(包括定義和聲明)

l 類(class)、結構(struct)、枚舉類型(enum)和聯合(union)

l 類、結構和聯合中成員變量或函數

VIM用這個"tags"文件來定位上面這些做了標記的對象,下面介紹一下定位這些對象的方法
:

1) 用命令行。在運行vim的時候加上"-t"參數,例如:

[/home/brimmer/src]$ vim -t foo_bar

這個命令將打開定義"foo_bar"(變量或函數或其它)的文件,並把光標定位到這一行。


2) 在vim編輯器內用":ta"命令,例如:

:ta foo_bar

3) 最方便的方法是把光標移到變量名或函數名上,然後按下"Ctrl-]"。用"Ctrl-o"退回原
來的地方。

注意:運行vim的時候,必須在"tags"文件所在的目錄下運行。否則,運行vim的時候還要
用":set tags="命令設定"tags"文件的路徑,這樣vim

才能找到"tags"文件。

在函數中移動光標
[{ 轉到上一個位於第一列的"{"

}] 轉到下一個位於第一列的"{"

{ 轉到上一個空行

} 轉到下一個空行

gd 轉到當前光標所指的局部變量的定義

* 轉到當前光標所指的單詞下一次出現的地方

# 轉到當前光標所指的單詞上一次出現的地方

Vim 的創造者是一名計算機程序員,因此這就不奇怪 Vim 中有許多幫助編寫程序的功能:

跳轉到標識符被定義和使用的地方;在另一個窗口中預覽有關的聲明等等。在下一章中還

會介紹更多的功能。

*29.1* 使用標籤什麼是標籤?
標籤就是一個標識符被定義的地方。一個例子就是 C 或者 C++ 程序中的函數定義。標籤
列表可以保存在一個標籤文件中。Vim 可以通過它來

從任何地方跳轉到該標籤,也就是一個標識符被定義的地方。 在當前目錄下爲所有的 C 
文件生成標籤文件,使用下面的這個命令: ctags

*.c"ctags" 是一個獨立的程序。大多數 Unix 系統上都已經安裝了它。如果你還沒有安裝
,可以在這裏找到 "Exuberant ctags":

http://ctags.sf.net 現在你可以使用下面的命令跳轉到一個函數定義的地方: :tag st
artlist這個命令會找到函數 "startlist",即使該函

數是在另一個文件中。 CTRL-] 命令會跳轉到當前光標下單詞的標籤。這樣瀏覽毫無頭緒
的 C 代碼會變得更容些易。舉個例子,假設你在函數

"write_block" 中。你可以看到它調用了函數"write_line"。但 "write_line" 做了什麼
呢?將光標置於調用 "write_line" 的地方然後按

CTRL-],你就跳轉到了這個函數的定義的地方了。 "write_line" 函數調用了 "write_ch
ar"。
你需要知道它做了什麼。將光標定位到調用 "write_char" 的地方然後按 CTRL-],你就到
了定義"write_char" 的地方。
+--+ |
void write_block(char **s; int cnt) | |
{ | | int i; | | for (i = 0; i < cnt; ++i)
| | write_line(s[i]); | |} | | +----|----+ | CTRL-] | | +-------+ +-->
|void write_line(char *s) | |{ | | while (*s != 0) | | write_char(*s++); | |} 
| | +-|-----+ | CTRL-] | | +-+ +--> |void

write_char(char c) | |{ | | putchar((int)(unsigned char)c); | |} |
+-+":tags" 命令顯示你經過的標籤列表: :tags # TO tag FROM line in file/text 1 
1 write_line 8 write_block.c 2 1 write_char 7

write_line.c >
現在介紹向回跳轉。 CTRL-T 命令跳轉到上一個標籤。在上例中,你會回到 "write_line
"函數調用 "write_char" 的地方。 這個命令接受一

個計數參數,用來表示跳轉回去的標籤個數。你已經向前跳轉,現在又跳轉了回去。現在
我們再一次向前跳轉。下面的命令跳轉到標籤列表中

最上面的標籤: :tag你可以在前面加上要向前跳轉的標籤個數。比如:":3tag"。 CTRL-
T 同樣可以加上一個計數參數。 通過這些命令,你可

以用 CTRL-] 延着調用樹向前跳轉, 用 CTRL-T 向回跳轉,用":tags" 命令顯示當前位置
。分 割 窗 口":tag" 命令會將當前窗口的文件替換

爲包含新函數的文件。怎樣才能同時查看兩個文件呢?你可以使用 ":split" 命令將窗口
分開然後再用 ":tag" 命令。Vim 有個縮寫命令可以

做到這些: :stag tagname使用下面的命令可以分割當前窗口並跳轉到光標下的標籤: CT
RL-W ]如果指定了計數參數,新窗口將包含指定的那

麼多行。多 個 標 記 文 件如果在多個目錄中都有文件,你可以在每一個目錄下創建一個
標籤文件。Vim 只能跳轉到那個目錄下的標籤。 通

過設定 'tags' 選項,你可以使用多個相關的標籤文件。 比如: :set tags=./tags,./.
./tags,./*/tags這會使 Vim 找到當前文件所在目錄

及其父目錄和所有子目錄下的標籤文件。 這已經是不少的標籤文件了,但也許仍不夠。比
如,當編輯 "~/proj/src" 目錄下的一個文件時,你

無法找到 "~/proj/sub/tags" 目錄下的標籤文件。對這種情況,Vim提供了一個查找整個
目錄樹下標籤文件的方法,比如: :set

tags=~/proj/**/tags單 個 標 記 文 件當 Vim 在多個地方查找標籤文件時,你會聽到硬
盤在格格作響。這樣會有點慢。在這種情況下,你最

好將這些時間花在生成一個大的標籤文件上。你可以要等一會兒。 這得藉助上面提到的 
"Exuberant ctags" 程序。它有一個選項可以搜索整

個目錄樹: cd ~/proj ctags -R .這樣做的好處是
"Exuberant ctags" 可以識別多種文件類型,它不僅適用於 C 和 C++程序,還適用於 Ei
ffel 甚至 Vim 腳本。請參考 ctags 文檔進行調整

所用參數。 現在你只需要告訴 Vim 你的標籤文件在何處: :set tags=~/proj/tags多 個
 匹 配當一個函數(或類中的方法)被定義多次,
":tags" 命令會跳轉到第一處。如果在當前文件中存在匹配,那它將會被首先使用。 你現
在可以跳轉到同一個標籤的其它匹配處: :tnext重

復執行這個命令可以找到更多的匹配。如果存在很多匹配,你可以選擇要跳轉到哪一個:

:tselect tagnameVim 會爲你展示一個選擇列表: # pri kind tag file 1 F f mch_ini
t os_amiga.c mch_init() 2 F f mch_init

os_mac.c mch_init() 3 F f mch_init os_msdos.c mch_init(void) 4 F f mch_init os
_riscos.c mch_init() Enter nr of choice (<CR>

to abort): 你現在可以輸入要跳轉到的匹配代號(在第一列)。其它列的信息可以讓你知
道匹配在何處被定義。可以用這些命令在各匹配的標

籤間移動: :tfirst 到第一個匹配 :[count]tprevious 向前 [count] 個匹配 :[count]
tnext 向後 [count] 個匹配 :tlast 到最後一個匹配

如果沒有指定,[count] 省缺爲一。
猜 測 標 籤 名命令行補全是避免輸入長標籤名的好辦法。只需輸入開始的一部分然後按
 <Tab>: :tag write_<Tab>你會得到第一個匹配。如

果這不是你想要的,重複輸入 <Tab> 直到你找到正確的匹配。 有時你只知道一個函數名
的一部分,或是你有很多以相同字符串開頭而結尾不

同的標記。這時你可以告訴 Vim 使用一個模式來查找標籤。 假設你要跳轉到一個包含 "
block" 的標籤。首先輸入: :tag /block現在再利用

命令行補全功能:輸入 <Tab>。Vim 會找到所有包含 "block" 的標籤並使用第一個匹配。
 標籤名前面的 "/" 告訴 Vim 這不是一個確定的標

簽名而是一個模式。你可以利用有關查找模式的所有特性。舉個列子,假設你要選擇所有
以 "write_" 開頭的標籤: :tselect /^write_"^"

指定標籤以 "write_" 開頭,否則在中間含有 "write_" 的標籤名也會被找到。類似地,
"___FCKpd___0quot; 指定標籤名結尾處的匹配。
標 籤 瀏 覽 器CTRL-] 可以讓你跳轉到光標所在標識符的定義處,因此你可以利用標識符
的列表來形成一個目錄。
這裏給出一個例子。 首先生成一個標識符列表(需要 Exuberant ctags): ctags --c-t
ypes=f -f functions *.c現在打開 Vim 並在一個垂

直分割窗口中編輯這個文件: vim :vsplit functions窗口中包含一個所有函數的列表。
其它的東西可以被忽略。用 ":setlocal ts=99" 命令

使其顯示得更清晰些。 在這個窗口中,定義一個 mapping: :nnoremap <buffer> <CR> 
0ye<C-W>w:tag <C-R>"<CR>移動光標至要跳轉到函數

的所在行,輸入 <Enter>。Vim 會在另一個窗口中跳轉到所選擇的函數定義處。相 關 雜
 項你可以設定 'ignorecase' 選項來忽略標籤名裏的

大小寫。'tagbsearch' 選項標明標籤文件是否經過排序。省缺是假定爲標籤文件已排序,
這樣會使查找更快,但如果文件沒有被排序是無法工

作的。'taglength' 選項可用來告訴 Vim 一個標籤的有效字符個數。當你使用 SNiFF+ 程
序時,你可以利用 Vim 的有關接口 |sniff| 。

SNiFF+ 是一個商業軟件。Cscope 是一個自由軟件。它不僅可以找到一個標識符被聲明的
地方,還可以找到標識符被使用的地方。 請參考

|cscope|。

---

*29.2* 預覽窗口當編輯含有函數調用的代碼時,你需要使用正確的調用參數。
要獲知所要傳遞的值,你可以查看這個函數是如何定義的。標籤機制對此十分適用。如果
定義可在另一個窗口內顯示那就更好了。對此我們可

以利用預覽窗口。 打開一個預覽窗口來顯示函數 "write_char": :ptag write_charVim
 會打開一個窗口,跳轉到 "write_char" 標籤。然後

它會回到原來的位置。這樣你可以繼續輸入而不必使用 CTRL-W 命令。 如果函數名出現在
文本中,你可以用下面的命令在預覽窗口中得到其定

義: CTRL-W }有一個腳本可以自動顯示光標處的標籤定義。請參考 |CursorHold-exampl
e| 。用下面的命令關閉預覽窗口: :pclose要在預覽

窗口中編輯一個指定的文件,用 ":pedit" 。這在編輯頭文件時很有用,比如: :pedit 
defs.h最後, "psearch" 可用來查找當前文件和任何

包含文件中的單詞並在預覽窗口中顯示匹配。這在使用沒有標籤文件的庫函數時十分有用
。例如: :psearch popen這會在預覽窗口中顯示含有

popen() 原型的 "stdio.h" 文件: FILE *popen __P((const char *, const char *));
 你可以用 'previewheight' 選項指定預覽窗口打開

時的高度。

---

*29.3* 在代碼間移動因爲程序代碼是結構化的,Vim 可以識別其中的有關項目。
一些特定的命令可用來完成相關的移動。 C 程序中經常包含類似下面的代碼: #ifdef U
SE_POPEN fd = popen("ls", "r") #else fd =

fopen("tmp", "w") #endif 有時會更長,也許還有套嵌。
將光標置於 "#ifdef" 處按 %。Vim 會跳轉到"#else"。繼續按 % 會跳轉到 "#endif"。再
次按下 % 又回到原來的 "#ifdef"。 當代碼套嵌時

,Vim 會找到相匹配的項目。這是檢查你是否忘記了一個 "#endif" 的好辦法。
當你在一個 "#ifdef" - "#endif" 塊內的某個位置,你可以用下面的命令回到開始處: 
[#如果你的位置不是在 "#if" 或 "#ifdef" 之後,

Vim 會鳴音。
用下面命令可以跳轉到下一個 "#else" 或 "#endif": ]#這兩個命令會跳過它所經過的 
"#if" - "#endif" 塊。例如: #if defined

(HAS_INC_H)
a = a + inc();
# ifdef USE_THEME
a += 3;
# endif
set_width(a);
如果光標在最後一行,"[#" 會移動到第一行。中間的 "#ifdef" - "#endif" 塊被跳過。
在 代 碼 塊 內 移 動C 代碼塊包含在 {} 中,有時

一個代碼會很長。要跳轉到外部代碼塊的開始處,用 "[["命令。用 "][" 找到結尾處。(
前提是 "{" 和 "}" 都在第一列。) "[{" 命令跳轉

到當前代碼塊的開始處。它會跳過同一級別的 {} 對。"]}" 跳轉到結尾。 一點概述: f
unction(int a) +-> { | if (a) | +-> { [[ | |

for (;;) --+ | | +-> { | | [{ | | foo(32); | --+ | | [{ | if (bar(a)) --+ | ]}
 | +-- | +-- break; | ]} | | | } <-+ | | ][ +--

foobar(a) | | } <-+ | } <-+當編寫 C++ 或 Java 代碼時,外部代碼塊是類,而下一級
的 {} 是方法。在類內部用"[m" 可以找到前一個方法

的開始。"]m" 會找到下一個方法的開始。另外,"[]" 向後移動到一個函數的結尾,"]]"
 向前移動到一個函數的結尾。函數的結尾指的是處在

第一列的 "}"。 int func1(void) { return 1; +---> } | [] | int func2(void) | +-
> { | [[ | if (flag) start +-- +-- return flag;

| ][ | return 2; | +-> } ]] | | int func3(void) +---> { return 3; }不要忘了你還
可以用 "%" 在匹配的 (), {} 和 [] 間移動。這在

它們相距很多行時仍然適用。在 括 號 內 移 動"[(" 和 "])" 命令"[}" 和 "]}" 類似,
只不過它們適用於 () 對而不是 {} 對。 [( <----

<------- if (a == b && (c == d || (e > f)) && x > y) -------> ----> ])在 注 釋
 間 移 動移動到一個註釋的開始用 "[/";向前移動

到註釋的結尾用 "]/"。這隻對 /* - */ 註釋有效。 +-> +-> /* | [/ | * A comment a
bout --+ [/ | +-- * wonderful life. | ]/ | */

<-+ | +-- foo = bar * 3; --+ | ]/ /* a short comment */ <-+

---

*29.4* 查找全局標識符你在編輯一個 C 程序,想要知道一個變量是被聲明爲 "int" 還是
 "unsigned"。
一個快速的方法是使用 "[I" 命令來查找。
假設光標在單詞 "column" 處。輸入: [IVim 會列出它所找出的匹配行,不僅在當前文件
內查找,還會在所有的包含文件中查找。結果如下

所示:
structs.h 1: 29 unsigned column; /* column number */ 相對使用標籤文件或預覽窗口
的好處是包含文件也被搜索。大多數情況下都能找

到正確的聲明。即使標籤文件已經過期或者你沒有爲包含文件建立標籤也不會影響結果。
 但是一些準備工作是必要的,否則 "[I" 就沒法工作

。首先,'include' 選項必須指定文件是如何被包含的。省缺值適用於 C 和 C++。對其它
的語言,你需要自己設定。定 位 包 含 文 件 Vim

會找到 'path' 選項指定路徑中的包含文件。如果缺少某個目錄,一些包含文件將不會被
找到。你可以用這個命令來查看: :checkpath它會列

出不能找到的包含文件,以及被找到的包含文件。一個輸出樣例:
--- Included files not found in path ---
<io.h> vim.h -->
<functions.h> <clib/exec_protos.h>
文件 "io.h" 被當前文件包含但無法找到。"vim.h" 可以找到,這樣 ":checkpath" 跟進
這個文件並檢查其中的包含文件。結果顯示無法找到

"vim.h" 包含的 "functions.h" 和"clib/exec_protos.h" 文件。
Note: Vim 不是一個編譯器。它無法識別 "#ifdef" 語句。這就是說所有的 "#include" 
語句都會被使用,即使它在 "#if NEVER" 之後。
給 'path' 選項增加一個目錄可以修正無法找到文件的錯誤。一個好得參考是 Makefile。
注意那些包括 "-I" 的條目,比如 "-

I/usr/local/X11"。
要增加這個目錄,用: :set path+=/usr/local/X11如果有很多的子目錄,你可以用 "*"
 通配符。
例如:
:set path+=/usr/*/include這會找到 "/usr/local/include" 以及 "/usr/X11/include"
 目錄下的文件。如果你的工程項目的包含文件都在

一個套嵌的目錄樹下,"**" 就非常有用。它會搜索所有的子目錄。例如: :set path+=/
projects/invent/**/include這會找到這些目錄下的

文件: /projects/invent/include /projects/invent/main/include /projects/invent
/main/os/include etc.還有其它的可能性。更多信息

,請查看 'path' 選項。
如果你想查看找到的包含文件,用這個命令: :checkpath!你會得到一個(很長)的包含
文件列表。爲使它更短些,Vim 會對已經找到的文件

顯示"(Already listed)" 而不再重新顯示一遍。跳 轉 到 匹 配"[I" 產生一個每項只有
一行文本的列表。如果你想要進一步的查看第一項,

你可以這個命令來跳轉: [<Tab>你也可以使用 "[ CTRL-I", 因爲 CTRL-I 和按 <Tab> 效
果一樣。"[I" 產生的列表在每行的開頭都有一個序

號。如果你要跳轉到第一項外的其它項,首先輸入序號: 3[<Tab>會跳轉到列表中的第三
項。記住你可以用 CTRL-O 跳回到原來的地方。相 關

命 令 [i 只列出第一項匹配 ]I 只列出光標下面的項目 ]i 只列出光標下面的第一項匹配
查 找 宏 定 義 標 識 符"[I" 命令查找任何標識符

。只查找 "#define" 定義的宏,用: [D同樣,這會在所有的包含文件中查找。 'define
' 選項指定 "[D" 所查找的預定義樣式。你需要改變

它值來適用於 C 或 C++ 以外的語言。 "[D" 相關命令: [d 只列出第一項匹配 ]D 只列
出光標下面的項目 ]d 只列出光標下面的第一項匹配

---

*29.5* 查找局部標識符"[I" 命令查找所有的包含文件。要在當前文件中查找並跳轉到光
標處單詞被首次使用的地方,用:
gD提示:Goto Definition。這個命令對查找局部(C 語言中的 "static") 聲明的變量或
函數很有用。例如(光標在 "counter" 處): +->

static int counter = 0; | | int get_counter(void) gD | { | ++counter; +-- retu
rn counter; }要進一步的縮小查找範圍,只在當前函

數內查找,用這個命令: gd這會回到當前函數的開始處尋找光標處單詞首次出現的地方。
實際上,它是向後找到一個在第一列 '{' 上面的空

行,然後再從那裏向前查找標識符。例如(光標位於 idx 上): int find_entry(char 
*name) { +-> int idx; | gd | for (idx = 0; idx

< table_len; ++idx) | if (strcmp(table[idx].name, name) == 0) +-- return idx; 
} 
發佈了5 篇原創文章 · 獲贊 7 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章