Vim 實用技術,第 1 部分: 實用技巧

發表於2013-03-29

來源:吳詠煒@developerworks

0. Vim 簡介

作為開源世界最重要的編輯器之一(另一個是 Emacs),Vim 以其強大的功能和可定製能力被眾多開發者所喜愛。不過,也許就是因為 Vim 的功能太強大了,要真正用好 Vim 並不容易。本文作者在多年的實際使用中逐漸掌握了一些實用技術,在此介紹給大家。——本文並不企圖對 Vim 作全面而系統的介紹,但也絕非零星地點到即止;而是希望通過介紹一些重要特性和提供相關參考資訊,引起大家的興趣,去深入挖掘其能力,真正把這一強大的工 具用好。

下面首先對 Vim 做一下最基本的介紹,並給出一些參考資訊,以方便對 Vim 不熟悉的讀者也能夠理解並自己查閱進一步資訊。

與大部分其它編輯器不同,進入 Vim 後,預設狀態下鍵入的字元並不會插入到所編輯的檔案之中。Vim 的模式(mode,可以簡單地理解為“狀態”)概念非常重要。需要知道,Vim 有以下幾個模式:

●正常(normal)模式,預設的編輯模式;下面如果不加特殊說明,提到的命令都直接在正常模式下輸入;任何其它模式中都可以通過鍵盤上的 Esc 鍵回到正常模式。

●命令(command)模式,用於執行較長、較複雜的命令;在正常模式下輸入“:”(一般命令)、“/”(正向搜尋)或“?”(反向搜尋)即可進入該模式;命令模式下的命令要輸入Enter鍵(Enter)才算完成。

●插入(insert)模式,輸入文字時使用;在正常模式下鍵入“i”(insert)或“a”(append)即可進入插入模式(也有另外一些命令,如“c”,也可以進入插入模式,但這些命令有其它的作用)。

●可視(visual)模式,用於選定文字塊;可以在正常模式下輸入“v”(小寫)來按字元選定,輸入“V”(大寫)來按行選定,或輸入“Ctrl-V”來按方塊選定。

●選擇(select)模式,與普通的 Windows 編輯器較為接近的選擇文字塊的方式;在以可視模式和選擇模式之一選定文字塊之後,可以使用“Ctrl-G”切換到另一模式——該模式很少在 Linux 上使用,本文中就不再介紹了。

Vim 帶有完整的幫助文件。在當前的 Vim 6.4 的標準釋出中,有一百多章、近六十萬英文詞的幫助檔案,進入 Vim 後輸入“:help”(命令模式中輸入的命令要敲Enter鍵才結束輸入,下面不再說明這一點)即可訪問。本文在介紹特性時,對文件中已經說明得很詳細的內容只 會提綱挈領地加以簡短說明和提供應用範例,並提供訪問相應的 Vim 文件的命令。

一般的釋出版中還常常帶有一個簡單的 30 分鐘的 Vim 教程,新手在作業系統的命令列上輸入“vimtutor”命令即可開始學習。除上面的簡單說明外,本文並不介紹最基本的 Vim 命令,Vim 的新手應該先通過教程熟悉一下 Vim,再繼續往下閱讀。

建議所有的 Vim 使用者經常訪問 Vim 的主站點 [1]。上面除了基本的釋出、安裝、下載等資訊外,最有用的內容是使用者可以上傳自己寫的 Vim 指令碼(script)和撰寫自己認為有用的提示(tip),供其他 Vim 使用者使用。在寫這一段的時候,Vim 站點上已有一千三百多個指令碼,提示數剛好超過了一千。對於序號為 nn 的指令碼,直接訪問的 URL 是 http://www.vim.org/scripts/script.php?script_id=nn;對於序號為 nn 的提示,直接訪問的 URL 是 http://www.vim.org/tips/tip.php?tip_id=nn。

不另加說明的話,本文討論的內容適用於 Vim 版本 6(即從 6.0 到 6.4)。建議認真的 Vim 使用者升級到 Vim 6.4,最好是自己編譯升級所有的補丁包。相關資訊網站上都有,此處不再贅述。

1. 實用技巧

1.1 安裝

如果從 Linux 釋出版直接安裝 Vim,需要注意的一點是,預設情況下系統並不一定為你安裝了一個完整的 Vim。比如,在 Red Hat(以及後來的 Fedora Core)的釋出版中,Vim 被拆成了四個包:vim-common(公用部分),vim-minimal(最小安裝),vim-enhanced(除 X Window 支援外的完整安裝),和 vim-X11(X Window 圖形介面支援)。最小安裝不能完整展示 Vim 的優點,通常只是作為 vi 的替代品出現,缺少很多重要的特性如多位元組語言支援、滑鼠支援和指令碼支援。如果裝了 X Window 的話,圖形介面的 gvim 也比文字模式的 vim 具有更多的特性。建議大家儘可能安裝完全的 Vim。

如果願意稍稍費一點功夫,自己編譯 Vim 的話,可以更好地定製 Vim。——附帶的另一個好處是,你如果發現什麼錯誤的話,你就可以自己動手來修復這個錯誤,或至少找到錯誤所在的位置,讓 Bram(Vim 的作者)可以更快地解決問題。圖 1 是在 Vim 中執行“:version”的結果的一部分,可以看到 Vim 有很多不同的特性(feature)可在編譯時開啟或關閉。如果自己編譯的話,就可以選擇開啟需要的功能,關閉不需要的功能,來獲得一個既功能強大、又小 巧快速的 Vim 定製版本。

圖 1

Vim 實用技術,第 1 部分: 實用技巧

1.2 中文支援

Vim 支援世界上的主要語言,當然也包括中文。如果你用 Vim 編輯中文,而中文不能正確顯示,那有兩種可能性:一是使用的 Vim 不完整,不含多位元組語言支援(multi_byte 特性);二是某個配置出了問題。

說到多語言支援,最基本的概念有兩個:一是檔案的語言編碼,而是環境的內部編碼。在較老的作業系統中,不管 Linux 還是 Windows,這兩個編碼都是一樣的,也就意味著,一次只能處理一種編碼的檔案:要麼只能處理西文編碼(Latin1,即 ISO-8859-1 [5]),要麼只能處理中文編碼(GB2312 [2])。而在新的作業系統中,這兩者可以是不一樣的。在 Linux 上,常見的情況是環境的內部編碼使用 UTF-8 [6],而 UTF-8 可以同任何一種語言編碼作無損轉換,這就保證了系統的多語言處理能力。Vim 這方面秉承了 Unix/Linux 的傳統,在內部編碼使 UTF-8 的時候,可以同時處理不同意語言編碼的檔案。

以下列出了和語言編碼的相關的設定:

●環境變數 LANG(使用的語言);

●環境變數 LC_CTYPE(使用的內部編碼);

●Vim 選項 encoding(Vim 的內部編碼);

●Vim 選項 termencoding(Vim 在與螢幕/鍵盤互動時使用的編碼);

●Vim 選項 fileencoding(Vim 當前編輯的檔案在儲存時的編碼);

●Vim 選項 fileencodings(Vim 開啟檔案時的嘗試使用的編碼);

●Vim 選項 ambiwidth(對“不明寬度”字元的處理方式;Vim 6.1.455 後引入)。

如果你的環境只需要處理簡體中文的話,那麼,最簡單的方式就是所有的設定全部使用簡體中文。只需要:設定 LANG=zh_CN.GB2312,不設定 LC_CTYPE(預設跟 LANG 一樣),不設定與編碼相關的 Vim 選項(預設由 LANG 和 LC_CTYPE 決定),也無需設定 Vim 選項 ambiwidth。也就是說,我們把語言設定為中國(CN)使用的中文(zh),編碼為 GB2312(注意:Vim 內部並不識別國標 GB18030 [3],所以此處只能設 GB2312;參看下面關於 UTF-8 的討論)。

不過,如果按照目前 Linux 下的慣例,內部編碼一律使用 UTF-8 的話,會有一些額外的好處,其中之一就是在這種情況下 Vim 支援同時編輯多種不同編碼的檔案,如簡體中文和繁體中文(參見圖 2);另外,此時 Vim 也可以通過編碼轉換支援 GBK [4] 和 GB18030了。這樣,眾多關於語言編碼的 Vim 選項就有了用武之地了。下面進一步說明一下這些選項和推薦設定(如果適用的話):

圖 2

Vim 實用技術,第 1 部分: 實用技巧

●encoding=utf-8:不管檔案的編碼如何,不管如何顯示和輸入,Vim 內部使用的編碼是 UTF-8;這是國際化支援的基礎。

●termencoding:取決於實際的終端或 X Window 的設定。舉例來說,如果選擇語言簡體中文登入到 X Window,或者正在使用 CXTERM [10] 的話,那麼該選項應被設為 GB2312;如果使用預設的語言(LANG=en_US.UTF-8)登入到 X Window,或者使用 PuTTY [11] 遠端訪問 Linux 機器、並且設定裡的字元編碼(配置中 Window-Translation)設為 UTF-8 的話,該選項就應該設為 utf-8。從 Windows 下使用 PuTTY 遠端連線 Linux 的請特別注意,測試表明,僅在使用 UTF-8 的情況下,PuTTY 才能可靠地支援中文的顯示和輸入(顯示字型必須設成中文字型)。

●fileencoding:檔案載入時,該選項被置為 Vim 認定的檔案編碼,因此,儲存時檔案的編碼不會改變。此處和下面 fileencodings 可使用的編碼為 libiconv 支援的所有幾百種編碼(如果編譯時包含了 iconv 特性的話),與中文相關的有 gb2312、gbk、gb18030、hz-gb-2312、iso-2022-cn、big5、cp936、cp950 等。如果建立新檔案,你又不希望使用 UTF-8 作為檔案編碼時,那麼,你可能需要手工設定該選項,如“:set fileencoding=gb2312”。需要注意的一點是,使用“set”來設定該選項的話會改變以後新建檔案的預設編碼,而使用 “setlocal”的話則隻影響當前檔案(參考“:help setlocal”)。

●fileencodings=ucs-bom,utf-8,chinese:Vim 會首先判斷檔案的開頭是否是一個 Unicode [7] 的 BOM(byte order mark)字元 [8],是的話則把檔案的其餘內容解釋成相應的 Unicode 序列;否的話再試圖把檔案內容解釋成 UTF-8 的序列;再失敗的話,則把檔案解釋為簡體中文(chinese 是一個跨平臺的簡體中文字符集的別名,Linux 下相當於 gb2312 和 euc-cn;此處也可以根據需要以 gb2312、gbk 或 gb18030 等編碼替代)。需要注意的是,該順序不能顛倒,並且在後面再新增其它編碼如 big5、latin1 也是沒有意義的,因為 Vim 不能識別 8 位元編碼中的錯誤,因此這些編碼後列的編碼永遠不會被用到。

●ambiwidth=double:把所有的“不明寬度”字元 [9]——指的是在 Unicode 字符集中某些同時在東西方語言中使用的字元,如省略號、破折號、書名號和全形引號,在西方文字中通常字元寬度等同於普通 ASCII 字元,而在東方文字中通常字元寬度等同於兩倍的普通 ASCII 字元,因而其寬度“不明”——的寬度置為雙倍字元寬度(中文字元寬度)。此數值只在 encoding 設為 utf-8 或某一 Unicode 編碼時才有效。需要額外注意的是,如果你通過終端使用 Vim 的話,需要令終端也將這些字元顯示為雙寬度。比如,XTERM [12] 的情況下應該使用選項“-cjk”,即使用命令“uxterm -cjk”來啟動使用雙寬度顯示這些字元的 Unicode X 終端;使用 PuTTY 遠端連線的話則應在配置的 Window-Translation 中選中“Treat CJK ambiguous characters as wide”(參見圖 3)。

圖 3

Vim 實用技術,第 1 部分: 實用技巧

需要設定的選項通常放在使用者的 Vim 資源配置檔案中,即在 ~/.vimrc 檔案中加入:

如果想進一步瞭解這些選項的話,可以使用“:help ‘選項’”檢視幫助文件中的相關(英文)資訊。幫助中也可以查到這些選項(以及命令)的縮寫:本文中為方便理解,除一些極少有人使用完整拼寫的命令如 “:e(dit)”、“:s(ubstitute)”等之外,一般使用完整拼寫而不說明或使用縮寫。關於配置檔案 .vimrc,可以使用“:help .vimrc”檢視相關資訊。

在使用內部編碼 UTF-8 的情況下,如需編輯 fileencodings 之外(其不能自動識別)的檔案,則可以使用以下命令:“:e ++enc=編碼 檔名”。詳情可參考“:help ++enc”。

1.3. 滑鼠支援

不管是文字介面還是圖形介面的 Vim,都支援滑鼠。不過,在文字介面中,滑鼠支援預設沒有被啟用;這就意味著,在終端上使用滑鼠,所有的功能仍和沒有使用 Vim 時相同,並不受 Vim 影響。要啟用文字介面中的滑鼠支援也很容易,只需要執行一句“:set mouse=a”即可。

啟用了滑鼠支援之後,Vim 主要支援的滑鼠操作有:

●單擊移動游標到點選的位置;

●在幫助的關鍵字上雙擊顯示該關鍵字相關的幫助資訊;

●在普通文字上雙擊選中點選位置的單詞;

●拖動滑鼠選中文字;

●使用滑鼠滾輪滾動當前緩衝區中的文字;

●多視窗編輯時可以拖動視窗分欄的位置。

進一步的資訊可參看“:help ‘mouse’”、“:help mouse-using”和“:help scroll-mouse-wheel”。

特別需要值得一提的是,在遠端訪問 Linux 系統時也是可以使用滑鼠的。如果使用 X Window 系統,自然不必說;而使用 SSH 遠端連線時,大部分 Linux 下的終端客戶程式,如 XTERM、GNOME-Terminal [13]、較新版本的 Konsole [14],以及 Windows 下的 PuTTY,支援滑鼠的使用:你只需簡單地啟動 Vim、執行一句“:set mouse=a”就可以了(當然,也可以把上面的語句去掉起始的冒號放到 .vimrc 檔案中)。

1.4. 空格、製表符和縮排

對於編寫程式碼,縮排是最基本的概念之一。至於縮排是使用空格還是製表符(Tab),或者縮排是否正好使用一個製表符來表示,很多程式設計師,特別是 Windows 開發出身的程式設計師,很容易混淆。幸好,Vim 對於這些概念有非常完整的支援,足以應付各種複雜的情況。以下是相關的主要 Vim 選項:

●shiftwidth(縮排的空格數);

●tabstop(製表符的寬度);

●expandtab(是否在縮排和遇到 Tab 鍵時使用空格替代;使用 noexpandtab 取消設定);

●softtabstop(軟製表符寬度,設定為非零數值後使用 Tab 鍵和 Backspace 時游標移動的格數等於該數值,但實際插入的字元仍受 tabstop 和 expandtab 控制);

●autoindent(自動縮排,即每行的縮排值與上一行相等;使用 noautoindent 取消設定);

●cindent(使用 C 語言的縮排方式,根據特殊字元如“{”、“}”、“:”和語句是否結束等資訊自動調整縮排;在編輯 C/C++ 等型別檔案時會自動設定;使用 nocindent 取消設定);

●cinoptions(C 語言縮排的具體方式,請參考“:help cinoptions-values”);

●paste(貼上模式,會取消所有上述選項的影響來保證後面的操作——通常是從剪貼簿貼上程式碼——保持原有程式碼的風格;使用 nopaste 取消設定)。

下面給出一些常用的組合:

●shiftwidth=4 tabstop=4:很多 Windows 出身的程式設計師會習慣這樣的設定,讓縮排等於製表符寬度。

●shiftwidth=4 tabstop=8:很多 Unix 程式設計師的設定,仍使用較常用的 4 格縮排,但製表符寬度為標準的 8。

●cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 shiftwidth=2 tabstop=8:標準的 GNU 編碼風格的設定,對 Vim 預設的 C 縮排風格作了很多微調,比如,if 語句下的“{”、“}”要在“if”後縮排兩格,但函式定義部分“{”、“}”仍和函式名一行對齊。開源軟體經常使用該種縮排風格。

在編輯程式碼時一個很有用的命令是調整程式碼縮排,可以很方便地增加(或減少)若干級縮排,並自動根據選項設定使用正確的空格或製表符。只需要使用 “V”選中你要調整的程式碼行,然後鍵入“<”(或“>”)即可增加(或減少)一級縮排;在鍵入“<”(或“>”)之前鍵入數字則 可以指定增加(或減少)的縮排級數。

我們要討論的最後一個相關的命令是“:retab”。在設定了 expandtab 選項時,該選項會把所有的製表符轉換成空格。在沒有設定 expandtab 選項時,使用“:retab!”可把空白字元轉換成製表符(可能誤轉換,慎用),使用“:retab n”可以把 tabstop 重置為 n,並轉換含製表符的連續空白字元為適當的製表符和空格的組合以保證含製表符的行看起來沒有任何變化。詳細資訊請參看“:help :retab”。

1.5. 模式行(modeline)

沒人願意每次都手工輸入一大堆的 Tab 和縮排設定。可是,放在 .vimrc 檔案中似乎也不是個好主意:如果我編輯的程式碼不止一種風格呢?——考慮一下,如果你參加開源軟體專案,你能保證你參加的所有專案,還有你公司裡的軟體項 目,程式碼風格都一樣嗎?——Vim 是我用過的第一個支援在檔案中記錄程式碼風格設定的編輯器。這個特性在 Vim 中叫做模式行,實際上,它所做的是在開啟檔案時根據檔案中的 Vim 指令設定相關的 Vim 選項。下面就是一個嵌在 C 原始碼中的模式行:

模式行有好幾種形式。本文只介紹上面的這種形式(其它形式類似,請自行參考“:help modeline”):行首的“/*”和尾部的“*/”告訴 C 編譯器這是一行註釋,不是程式碼的一部分;而 Vim 可通過後面的“vim:”識別出模式行的開始(必須出現在行首或前面有一個空白字元);後面則是“set”和空格間隔開的一串 Vim 選項;“:”表示模式行結束。

這種方式非常簡單,功能也非常強大。另外請注意,出於安全的考慮,模式行中的選項隻影響當前檔案(“:help modeline-local”),也不能做任何設定選項以外的工作。

1.6. 暫存器

通常的編輯器有一個剪貼簿,以儲存複製和剪下的內容。Vim 中的類似概念叫做暫存器(register)。除了有一個無名暫存器外,Vim 還有一大堆有名的暫存器,可以通過“””(參見“:help “”)或“Ctrl-R”(參見“:help i_CTRL-R”和“:help c_CTRL-R”)加暫存器名(字母、數字和某些特殊字元,參見“:help registers”;“無名”暫存器的名字是“””)來訪問。比如,你先使用“”ayy”複製了一行,然後使用“dd”刪掉了一行,然後移動游標到要復 制到的位置,就可以使用“”aP”把先前複製的內容貼上上去了。手工編輯是有名暫存器的作用還不是很大,但當你想讓 Vim 通過類似於巨集的方式自動完成工作時,有名暫存器就變成不可缺少的重要功能了。下面我們還會用到。

在使用 X Window 系統時,有兩個特殊的暫存器是需要注意一下的:“”*”訪問的暫存器是 X 的主選擇區域(primary selection),“”+”訪問的暫存器是 X 的剪貼簿(clipboard)。如果你要在 Vim 和其它的 X 應用程式之間複製文字內容,你可以試一下這兩個暫存器。

還有一個很特殊的“暫存器”:“=”。在插入模式或命令模式中,鍵入“Ctrl-R=”,Vim 會提示你輸入一個表示式,普通的整數運算在此完全有效。如果想要進行浮點運算,請參見第 3.2 節中的技巧。

1.7. 搜尋、替換和正規表示式

大家應該都已經知道 Vim 裡使用“/模式”(或“?模式”)進行搜尋,使用“:s/模式/字串/標誌”進行替換,其中的“模式”是一個正規表示式。關於正規表示式,不熟悉的話可 以邊用邊學,本節也不打算對 Vim 的正規表示式作完整的闡述(那可能可以專門寫一本小冊子了),而只拋磚引玉式地給出一些有用的例子加以說明,以及一些實用技巧。

先說一點點搜尋。搜尋裡最最有用的一個快捷方式是“*”(向下完整匹配游標下的單詞)。把游標移動到你要搜尋的詞(變數名、函式名等)上,比如 “test”,然後按“*”,Vim 將自動產生一個對“\<test\>”(參見“:help /\<”和“:help /\>”)的搜尋,也就是說,搜尋完整的單詞“test”。不要小看這個技巧,它經常可以大幅度地提高搜尋的速度。事實上,這是 Vim 網站上公佈的第 1 號技巧,也是被評價最高的技巧。相似的技巧還有“#”(向上完整匹配游標下的單詞)、“g*”(向下部分匹配游標下的單詞)等,請自行檢視(“:help #”等)。

Vim 在搜尋和替換時會對匹配成功的文字進行加亮,在已經完成搜尋和替換任務後,這種加亮有時反而會妨礙顯示。Vim 專門提供一個命令取消這種加亮(直到使用者再一次使用搜尋或替換命令):“:nohlsearch”。建議使用者建立一個鍵盤對映(key mapping)加入到 .vimrc 中,如:

以上命令表示,在正常模式下按 F2 鍵相當於輸入“:nohlsearch”後面跟一個回車,即取消搜尋加亮顯示。

再看幾個搜尋替換的實用例子。

●去掉所有的行尾空格:“:%s/\s\+$//”。“%”表示在整個檔案範圍內進行替換,“\s”表示空白字元(空格和製表符),“\+”對 前面的字元匹配一次或多次(越多越好),“$”匹配行尾(使用“\$”表示單純的“$”字元);被替換的內容為空;由於一行最多隻需替換一次,不需要特殊 標誌。這個還是比較簡單的。

●去掉所有的空白行:“:%s/\(\s*\n\)\+/\r/”。這回多了“\(???\)”、“\n”、“\r”和“*”。“*”代表對前 面的字元(此處為“\s”)匹配零次或多次(越多越好;使用“\*”表示單純的“*”字元),“\n”代表換行符,“\r”代表回車符,“\(??? \)”對錶達式進行分組,使其被視作一個不可分割的整體。因此,這個表示式的完整意義是,把連續的換行符(包含換行符前面可能有的連續空白字元)替換成為 一個單個的換行符。唯一很特殊的地方是,在模式中使用的是“\n”,而被替換的內容中卻不能使用“\n”,而只能使用“\r”。原因是歷史造成的,詳情如 果有興趣的話可以檢視“:help NL-used-for-Nul”。

●去掉所有的“//”註釋:“:%s!\s*//.*!!”。首先可以注意到,這兒分隔符改用了“!”,原因是在模式或字串部分使用了“/” 字元,不換用其他分隔符的話就得在每次使用“/”字元本身時寫成“\/”,上面的命令得寫成“:%s/\s*\/\/.*//”,可讀性較低。命令本身倒 是相當簡單,用過正規表示式的人估計都知道“.”匹配表示除換行符之外的任何字元吧。

●去掉所有的“/* */”註釋:“:%s!\s*/\*\_.\{-}\*/\s*! !g”。這個略有點複雜了,用到了幾個不太常用的 Vim 正規表示式特性。“\_.”匹配包含換行在內的所有字元;“\{-}”表示前一個字元可出現零次或多次,但在整個正規表示式可以匹配成功的前提下,匹配的 字元數越少越好;標誌“g”表示一行裡可以匹配和替換多次。替換的結果是個空格的目的是保證像“int/* space not necessary around comments */main()”這樣的表示式在替換之後仍然是合法的。

希望上面的這些簡單的例子能夠引起你使用 Vim 的正規表示式高效完成任務的興趣。進一步的資訊可參考“:help regexp”。

1.8. 自動完成和路徑設定

Vim 支援單詞的自動完成。比如,你前面使用了一個很長的變數名,叫 aLongVariable,下面你在輸入時,就不用完整鍵入了。很可能,你只需要鍵入“aL”,然後按下“Ctrl-P”(向前搜尋可匹配的單詞並完 成)就可以得到完整的變數名(沒有得到想要的結果的話,多按幾下“Ctrl-P”;或者前面多輸入幾個字元,如“aLongV”)。類似的命令還有 “Ctrl-N”(向後搜尋可匹配的單詞並完成)、“Ctrl-X Ctrl-L”(搜尋可匹配的行並完成)、“Ctrl-X Ctrl-F”(搜尋可匹配的檔名並完成)等,具體可參看“:help ins-completion”。

如果你並不熟悉這些功能,但也並不覺得這有什麼稀奇的話,下面這個例子可能會讓你覺得吃驚。請嘗試開啟一個空白的 C 檔案(vim test.c),並輸入:

最後一行不要回車,直接在“pri”後面輸入“Ctrl-P”,你將看到“printf”出現。是的,雖然檔案裡沒有“printf”,但 Vim 知道到哪裡去尋找它!在作關鍵字匹配完成時,如果當前檔案和其它開啟的檔案中沒有想要的結果,Vim 會自動到“#include”的檔案中進行進一步的搜尋(為什麼是“#include”呢?請查閱“:help ‘include’”),搜尋的目錄則由選項 path 決定,其預設值在 Unix(含 Linux)下為“.,/usr/include,,”,代表搜尋的目錄依次是檔案所在目錄、/usr/include 和當前目錄。根據實際情況,你可能需要在 .vimrc 檔案中設定該選項,加入專案相關的包含目錄,注意一般要保留最後的“,,”,除非你不需要在當前目錄下搜尋。

設定了合適的 path 後,另外帶來的一個便利就是可以使用“gf”命令方便地跳轉到游標下的檔名所代表的檔案中。在上面的例子中,把游標移到“stdio.h”的任一字元 上,鍵入“gf”,則 Vim 會自動開啟 /usr/include/stdio.h 檔案。使用“Ctrl-O”(參見“:help CTRL-O”)可返回到原先的檔案中。

1.9. 檔案跳轉和 Tags

大家一般都知道,在 Vim 的幫助視窗中的關鍵字上雙擊滑鼠或者鍵入“Ctrl-]”即可跳轉至該關鍵字相關的幫助主題。不過,“跳轉至匹配的關鍵字”這一功能並不僅僅侷限於幫助文 件。只要有合適的 tags 檔案(參見“:help tags-file-format”),我們同樣可以在原始碼中使用這個方便的功能,跳轉到與關鍵字匹配的“標記”處(通常是原始碼中某一函式、型別、變 量或巨集的定義位置)。

要產生 tags 檔案,通常我們使用 Exuberant Ctags [15]。一般的 Linux 釋出版中均帶有這一工具。Ctags 帶有的選項數量極多,此處我們僅簡單介紹如何在一個典型的多檔案、多層目錄的專案中使用其基本功能:我們只需在專案的根目錄處鍵入“ctags -R .”,Ctags 即可自動在檔案中查詢、識別支援的檔案格式、生成 tags 檔案。目前 Exuberant Ctags 支援多達 33 種程式語言 [16],包括了 Linux 下常用的 C、C++、Java、Perl、PHP 等。有了 tags 檔案,以下的 Vim 命令就可以方便使用了(進一步的資訊可參考“:help tags-and-searches”):

●:tag 關鍵字(跳轉到與“關鍵字”匹配的標記處)

●:tselect [關鍵字](顯示與“關鍵字”匹配的標記列表,輸入數字跳轉到指定的標記)

●:tjump [關鍵字](類似於“:tselect”,但當匹配項只有一個時直接跳轉至標記處而不再顯示列表)

●:tn(跳轉到下一個匹配的標記處)

●:tp(跳轉到上一個匹配的標記處)

●Ctrl-](跳轉到與游標下的關鍵字匹配的標記處;除“關鍵字”直接從游標位置自動獲得外,功能與“:tags”相同

●g](與“Ctrl-]”功能類似,但使用的命令是“:tselect”)

●g Ctrl-](與“Ctrl-]”功能類似,但使用的命令是“:tjump”)

●Ctrl-T(跳轉回上次使用以上命令跳轉前的位置)

當我們在專案的根目錄下工作時,上面這些命令工作得很好。但如果我們進到多層目錄的裡層再執行 Vim 開啟檔案時,這些命令的執行結果通常就變成了錯誤資訊“E433: No tags file”。這是因為預設 Vim 只在檔案所在目錄和當前目錄下尋找 tags 檔案,而我們前面只在專案的根目錄下生成了 tags 檔案,Vim 無法找到該檔案。解決方法有好幾種,我認為一般較簡單的做法是對每個專案都在 .vimrc 檔案中增加一個路徑相關設定。假設我們有兩個專案,位置分別是 /home/my/proj1 和 /home/my/proj2,那我們可以使用:

Vim 選項 tags 用於控制檢查的 tags 檔案,預設值為“./tags,tags”,即前面所說的檔案所在目錄下和當前目錄下的 tags 檔案。上面兩行自動命令告訴 Vim,在開啟專案目錄下的檔案時,tags 選項中的內容要增加專案的 tags 檔案的路徑。進一步資訊可參看“:help ‘tags’”。

1.10. Make 和 grep

Make [17] 和grep [18] 應當算是 Unix 世界裡無人不曉的基本工具了吧。很自然的,Vim 對它們有著特殊的支援。該支援主要通過訪問一個特殊的快速修訂視窗(quickfix window)來實現。直接在 Vim 的命令模式裡輸入相應的 make 或 grep 命令(如“:grep foo *.c”)即可將命令的執行結果放入該視窗,同時根據返回的結果跳轉到第一個錯誤(make 的情況;在使用 grep 時是匹配成功之處)。以下是常用的“快速修訂”命令:

●:cn(顯示下一個錯誤)

●:cp(顯示上一個錯誤)

●cl(列出所有的錯誤及其編號)

●:cc(跳轉到指定編號的錯誤)

●:copen(開啟快速修訂視窗,在其中顯示所有錯誤,可在錯誤上雙擊滑鼠或按Enter鍵跳轉至該錯誤;示例參見圖 4)

圖 4

Vim 實用技術,第 1 部分: 實用技巧

●:cclose(關閉快速修訂視窗)

Vim 的這個特性也可以與 make 和 grep 以外的程式一起工作(事實上,在 Windows XP 上,“:grep”命令一般調起的是“findstr /n”)。具體呼叫那個程式由選項 makeprg(Linux 下預設為“make”)和 grepprg(Linux 下預設為“grep -n $* /dev/null”)控制,而如何解析返回的內容則由選項 errorformat 和 grepformat 控制。鑑於在 Unix/Linux 下一般不需更改這些選項的內容,此處不再詳述。

1.11. 執行外部命令

在“:make”這樣的命令中,Vim 會自動呼叫外部的程式。使用者當然也可以自己執行外部的程式:估計很多的人都已經知道了用“:!命令”可以在 Vim 中執行一個外部命令。不過,估計大部分人都不知道,還有其它一些命令可以執行外部命令,並且,即使“:!”命令裡面也有一些技巧可以使用。

最正規的執行外部命令的方法,如前所述,就是“:!”。比如,我們想要顯示當前目錄下的所有檔案,就可以直接執行:“:!ls”。Vim 會在一個終端視窗中進行檔案列表,然後提示我們按鍵返回 Vim 中。事實上,這種方式對於“cp”、“rm”這樣基本不需要輸出的命令比較實用,而對於“ls”這樣關注於輸出的命令並不太適用。

如果想把外部命令執行的結果插入到當前編輯的緩衝區中,可以考慮使用“:r!”。比如,我們使用“:r!ls”,就可以把“ls”命令的執行結果插入到緩衝區中游標所在行下面。在使用巨集時,這可能會特別有用。

Vim 的“:!”命令還有一個特別強大的技巧可以使用。拿一個實際例子,我們需要對在一個檔案的每一行之前插入一個編號,該怎麼做呢?——用 Vim 的巨集或者指令碼可以完成這一工作,但這不是最高效、最靈活的工作方式。Linux 下一般帶有的 GNU 的 nl,可以用非常靈活的方式來完成這一任務——要對所有的非空行進行編號,只需要“:%!nl”;要對包含空行的所有行進行編號?OK,“:%!nl -ba”。

稍作一點解釋。當使用可視模式選中文字行後然後鍵入“:!”(命令列上將出現“:'<,’>!”,表示命令的範圍是選定的文字),或者 使用“:%!”(表示命令的範圍是整個緩衝區中的文字),Vim 在執行後面的命令時,將把命令範圍裡的文字行作為後面執行的命令標準輸入,並用命令執行後的標準輸出替換當前緩衝區中的這些文字行。這就是上面的命令列的 工作原理。

1.12. 定寬文字排版

在傳統的 Unix 環境下,文字檔案的定義是具有一定長度限制的文字行的組合 [19]。雖然 Vim 本身對行的長度沒有任何實際的限制,但有一些工具有這樣的限制。為了最大程度的相容性,也為了在顯示、列印等處理上比較方便,一般推薦在郵件和原始碼中一 般不要超出 72 列(最多不超出 80 列)。Vim 在處理定寬的文字方面具有特殊的支援能力。下面是一個在 Vim 中把行寬(使用選項 textwidth)設為 40 後輸入 Harry Potter and the Half-Blood Prince 的第一句話的結果:

輸入時我只使用了英文字母和空格,換行符都是 Vim 自動插入的。如果在某一行加入或刪除了一些字元後行不就不齊了嗎,該如何處理?很簡單,把游標移到要重新格式化的文字開頭,使用“gq”命令後面跟一個光 標移動命令確定重新格式化的範圍。比如“gq}”(格式化一段),“gq5j”(格式化 5 行),“gqG”(格式化至檔案末尾)。

除了選項 textwidth 外,選項 formatoptions 確定了跟文字格式化有關的基本選項,常用的數值有:

●t:根據 textwidth 自動折行;

●c:在(程式原始碼中的)註釋中自動折行,插入合適的註釋起始字元;

●r:插入模式下在註釋中鍵入回車時,插入合適的註釋起始字元;

●q:允許使用“gq”命令對註釋進行格式化;

●n:識別編號列表,編號行的下一行的縮排由數字後的空白決定(與“2”衝突,需要“autoindent”);

●2:使用一段的第二行的縮排來格式化文字;

●l:在當前行長度超過 textwidth 時,不自動重新格式化;

●m:在多位元組字元處可以折行,對中文特別有效(否則只在空白字元處折行);

●M:在拼接兩行時(重新格式化,或者是手工使用“J”命令),如果前一行的結尾或後一行的開頭是多位元組字元,則不插入空格,非常適合中文

上面提到的註釋,可以是 C/C++ 中的“//”和“/*”,也可以是郵件中引用原文使用的“>”等字元(具體由 comments 選項控制;參見“:help ‘comments’”)。Vim 在遇到這些字元時,能夠相當智慧地進行處理,足以完成日常編輯原始碼和郵件的需要。在使用一些處理純文字不夠強大的郵件客戶端時,我通常使用 Vim 編輯郵件(特別是英文郵件),然後把結果貼回到郵件編輯視窗中進行傳送。

Vim 中 formatoptions 的預設值是“tcq”,一般我會在 .vimrc 檔案中加入一行“set formatoptions+=mM”來確保 Vim 能在中文字元之間折行而不要求空格的存在,並且在大部分情況下可以正確地處理中文重新格式化。

1.13. 其它小技巧

也許你會覺得這些很有用:

●%(跳轉到與之匹配的括號處)

●.(重複上次的修改命令)

●`.(跳轉到最近修改過的位置)

●ZQ(無條件退出

●ZZ(存檔退出)

●ga(顯示游標下的字元在當前使用的 encoding 下的內碼)

●guw(游標下的單詞變為小寫)

●gUw(游標下的單詞變為大寫)

●:TOhtml(根據 Vim 的語法加亮的方式生成 HTML 程式碼;在圖形介面中也可以使用選單“Syntax—Convert to HTML”達到同樣效果)

無聊的時候,還可以試試(呵呵!):

●:help!

●:help 42

●:help holy-grail

參考資料

[1] Vim Online: http://www.vim.org/

[2] 中國國家標準GB2312-1980;參考網頁: http://www.answers.com/GB2312

[3] 中國國家標準GB18030-2000;參考網頁: http://www.answers.com/GB18030

[4] 國標編碼擴充套件;參考網頁: http://gollum.easycp.de/gollum/gollum.php?wl=zh&q=gbk

[5] ISO/IEC 8859-1: http://www.answers.com/ISO_8859-1

[6] UTF-8: http://www.answers.com/UTF-8#Wikipedia

[7] Unicode Home Page: http://www.unicode.org/

[8] FAQ-UTF & BOM: http://www.unicode.org/faq/utf_bom.html#22

[9] East Asian Width: http://www.unicode.org/reports/tr11/

[10] CXTERM’s Unofficial Homepage: http://cxterm.sourceforge.net/

[11] PuTTY: A Free Telnet/SSH Client: http://www.chiark.greenend.org.uk/~sgtatham/putty/

[12] XTERM-Terminal Emulator for the X Window System: http://dickey.his.com/xterm/

[13] GNOME Terminal: http://www.gnomefiles.org/app.php?soft_id=113

[14] Konsole Homepage: http://konsole.kde.org/

[15] Exuberant Ctags: http://ctags.sourceforge.net/

[16] Languages Supported by Exuberant Ctags: http://ctags.sourceforge.net/languages.html

[17] make: http://www.answers.com/make#Wikipedia

[18] grep: http://www.answers.com/grep

[19] Text File: IEEE Std 1003.1, 2004 Edition, Section 3.392, http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html

相關文章