vim-logo.gif 在vim裡面除了我們在講刪除時所講的那些以外,事實上還有很多都是跟游標移動有關的指令。不過今天我們講的內容和 ctags 這個小傢伙比較有關。

簡單地說, ctags 主要是用來幫助程式寫作用的。怎麼說呢?如果你現在正在接手一套大程式,但事實上你需要維護的只是這大程式裡的某一條執行程序,你當然不會想說我要把這整個程式都看懂才要來做維護的工作,等到你看懂可能公司也準備請你走路了。所以這個時候 ctags 就可能幫上你的忙。它會把程式中函數(function)以及變數(variable)的定義區紀錄下來。比方說你現在看到目前在追的執行程序中呼叫了一個 line_extraction_algo(…) ,如果你想知道這個函數在幹什麼你會怎麼做?以前也許你就會用 grep 或是搜尋字串的方式看看這個東西在哪個檔案裡面,說不定還要一個個看到底哪個才是定義的地方。現在在 windows 或是一些整合性環境(IDE)大概都會提供在上面按兩下之後就會跳到函數或是變數的宣告區裡面。但是現有的IDE環境大概都沒有提供像 vim 那樣有很多好用的功能,這些等我們講到取代的時候大家就會逐漸發現 vim 的好。

以前我在使用 ctags 的時候本來是很簡單地用 ctags *.c *.h 這樣就好了,不過在 windows 下的話,可能預設的不太一樣,我會建議你可能要把 ctags 的說明看一下(我不確定日後會不會針對 ctags 的使用寫一個小短篇)再來使用。

當你用 ctags 對那一大堆程式「梳理」過後,在目錄下會出現一個 tags 的檔案,內容長得會像這樣: (我不打算去解釋裡面為什麼這樣寫,因為這超過對 vim 的說明範圍了。)

ctags tags file sample

讓我們再回到剛剛的例子裡面,假如現在你已經有了 ctags 幫你做出來的 tags 了,而你看到一個函數叫做 line_extraction_algo(…) ,你要怎麼樣才能方便看到這個函數在幹什麼呢?很簡單,你就把游標移到 line_extraction_algo(…) 的上面,然後在指令模式下按一下 <Ctrl+]>, vim 就會跳到 line_extraction_algo(…) 的定義區上,方便你看到這個函數的內容。這個功能對變數也一樣有效。

(由於這個函數可能在別的檔案裡面,所以在跳過去之前有時候 vim 會要求你先對目前的檔案作寫入的動作,這是因為你可能對目前的檔案作修改但是還沒有寫入。)

不過或許你會說,那假如現在臨時想到有個 function ,比方說是 curve_extraction_algo(…)想要改一下,那 ctags 或是 vim 能幫我這個忙嗎?當然!你可以在指令模式下輸入:

:tag curve_extraction_algo

不過有時候可能很多變數名字取得都一樣,在這個時候就會有多個選擇,所以指令的輸入也會改變:

:tn

或是:

:tp

分別用來表示下一個(Next, :tn)和前一個(Previous, :tp)。

那你又要問了,我跳過去了,那我怎麼跳回來?你按 <Ctrl-T> 就會回來了。你可以在 vim 用 :h tags 得到更詳細的資訊。

其實在 vim 裡面如果你對什麼按鍵或是對什麼功能不瞭解,你都可以用 :h 按鍵 或是用 :h 功能名字來看到詳細資料,比方說像剛剛你想要確定一下 <Ctrl-T> 的功用是什麼,你就可以打:

:h ctrl-T

在這裡順便補充一下,如果當你看 vim 的 help ,也就是你用 :h 查詢一些東西的時候,有些地方會變成青色的或是以「 | |」夾起來的地方,你就可以用 <Ctrl-]>和 <Ctrl-T>跳來跳去,方便你閱讀 vim 的 help。

如果你還記得我們談 vim 的刪除行為那篇的話,應該就還會記得「%」這個符號可以幫你找到每個括號的相對應括號在什麼地方。這個按鍵功能相信對於寫程式的人來說也是相當有用的。

提到寫程式,我不知道諸位的習慣如何。在我接受的訓練裡面,通常會說你一個功能或者是說一個小 task 不要寫超過 24 行。這個原因只是因為電腦的 terminal 預設大多是 24 行。如果你寫的不超過 24 行這樣就可以一個螢幕就看到在寫什麼了。不過有時候一路追 code 的時候,游標可能移到太下方了,你又想要看到底下東西,卻又不想用 <Ctrl-F>(跳下一頁)而改變游標的位置怎麼辦?所謂山不轉路轉,路不轉我轉。你可以用小寫「zz」就可以把螢幕的中間變成游標現在所在位置,所以「zz」不會改變游標所在位置。我個人是不常用這個功能,只是講出來也許有人會需要。

(在vim裡面 <Ctrl-F> 是跳下一頁跳上一頁則是用 <Ctrl-B>)

看了上面這些功能你可能又會問了,我用 :tag 和 <Ctrl-T>、<Ctrl-]>都只用對有名字的東西來跳,如果我只是在寫個程式,偏偏這個 task 寫得很長,為了程式好看,又把變數通通放在一開始的地方,那我要改的時候不就是經常一直上下移動?其實這有幾個方法可以完成這個目標。

我先講最不直覺的方法,那就是你去記變數區或是說你會想要經常修改的地方的行數。然後在指令模式下用:

:行數

來跳到你指定的行數上。這個,真的是不太直覺。不過當你配合一些編譯器( compiler)使用的時候,就很有用了。因為 compiler 通常會告訴你哪一行有錯,那這個功能就可以拿來用。

另一個方法是如果你只是在兩個地方互相跳來跳去,比方說變數區和你現在正在寫作的區域,你可以用:「`」連按兩次來跳到上一次寫的地方,不過有時候你也不太可能會只是在兩個地方互相跳來跳去,大多的情況你可能是好幾個地方跳來跳去。那「`」連按兩次的功能就有那麼一點不太好用。

所以這時候就要引進 mark 的功能了。 mark 在 vim 裡面是幫你 mark 現在所在的位置。那使用上也非常簡單,就是在指令模式下,把游標移到你想定位的地方打:

m (其後跟上任何的大小寫英文字母)

注意這個地方就不是用「:」開頭了,而是直接打「 m」這樣就可以了。

那你要用的時候,比方說我把變數區用 mv 來代表,那我現在工作的區域用 mm,另一個同步需要修改的地方是 ma 。我就可以在指令模式下打「`v」就會跳到變數區,同理,當我打「`m」的時候就會跳到正在修改的地方,再打「`a」則會跳到另一個需要修改的地方。如果配合「`」連按兩次就可以回到上一次跳到的地方,組合在一起這就非常方便了。

如果你懶得每次要從編輯模式切進指令模式才能跳到想要修改的地方,之後又要再切換到編輯模式的話,你可以在編輯模式下按 <Ctrl-o>(英文字母 o不是數字零),這就會進入指令模式,然後一旦你執行完一個指令,就會自動跳到編輯模式。配合起來會稍微省一點力,不過我自己已經在模式之間切換慣了,就比較少用這個方式。

而關於 mark 更詳細的資料可以用 :h mark 看到。

現在你已經有了游標移動的這些功能,對於一個編輯器來說,我們所介紹的基礎功能已經差不多了。下一次開始,我們會開始深入 vim 的使用。下一篇預告:vim 取代指令的使用。有了這個功能,你就可以應付更多更複雜的事情。你還在猶豫要不要用 vim 嗎?趕緊裝一個 vim 來用用看吧!

Updated 2005-08-30: 已按ASKA君所言補正過。感謝 ASKA 君。