vim實用技術

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

吳 詠煒 ([email protected]), 軟件架構師

本系列文章分三部分詳細闡述了 Vim 的使用技巧、插件、定製。第一部分主要是深入分析了 Vim 的使用。

0. Vim 簡介

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

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

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

  • 正常(normal)模式,缺省的編輯模式;下面如果不加特殊說明,提到的命令都直接在正常模式下輸入;任何其它模式中都可以通過鍵盤上的 Esc 鍵回到正常模式。
  • 命令(command)模式,用於執行較長、較複雜的命令;在正常模式下輸入“:”(一般命令)、“/”(正向搜索)或“?”(反向搜索)即可進入該模式;命令模式下的命令要輸入回車鍵(Enter)纔算完成。
  • 插入(insert)模式,輸入文本時使用;在正常模式下鍵入“i”(insert)或“a”(append)即可進入插入模式(也有另外一些命令,如“c”,也可以進入插入模式,但這些命令有其它的作用)。
  • 可視(visual)模式,用於選定文本塊;可以在正常模式下輸入“v”(小寫)來按字符選定,輸入“V”(大寫)來按行選定,或輸入“Ctrl-V”來按方塊選定。
  • 選擇(select)模式,與普通的 Windows 編輯器較爲接近的選擇文本塊的方式;在以可視模式和選擇模式之一選定文本塊之後,可以使用“Ctrl-G”切換到另一模式——該模式很少在 Linux 上使用,本文中就不再介紹了。

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

  • 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
    圖3 

需要設定的選項通常放在用戶的 Vim 資源配置文件中,即在 ~/.vimrc 文件中加入:

 

set encoding=utf-8set fileencoding=chineseset fileencodings=ucs-bom,utf-8,chineseset ambiwidth=double

 

如果想進一步瞭解這些選項的話,可以使用“: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 源代碼中的模式行:

 

/* vim: set tabstop=4 shiftwidth=4 expandtab: */

 

模式行有好幾種形式。本文只介紹上面的這種形式(其它形式類似,請自行參考“: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 中,如:

 

nmap <F2> :nohlsearch<CR>

 

以上命令表示,在正常模式下按 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),並輸入:

 

#include <stdio.h>int main(){    pri

 

最後一行不要回車,直接在“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,那我們可以使用:

 

au BufEnter /home/my/proj1/* setlocal tags+=/home/my/proj1/tagsau BufEnter /home/my/proj2/* setlocal tags+=/home/my/proj2/tags

 

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(打開快速修訂窗口,在其中顯示所有錯誤,可在錯誤上雙擊鼠標或按回車鍵跳轉至該錯誤;示例參見圖 4)

     

    圖 4
    圖4 

  • :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 的第一句話的結果:

 

It was nearing midnight and the PrimeMinister was sitting alone in hisoffice, reading a long memo that wasslipping through his brain withoutleaving the slightest trace of meaningbehind.

 

輸入時我只使用了英文字母和空格,換行符都是 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

 

Vim 實用技術,第 2 部分: 常用插件

本系列第一部分介紹了一些基本的 Vim 使用技巧。掌握這些技巧可以很大地提高編輯效率,但是 Vim 的強大功能並不僅限於此。Vim 還可以通過“插件”來進行功能擴展。精確地說,是通過腳本來進行擴展,腳本類型有插件、語法加亮、配色方案、文件類型檢測等多種。大部分的腳本都是由 Vim 的用戶寫的,解決了用戶身邊的問題,使 Vim 變得更加有用。本章將介紹最常用的一些腳本,其中除了一個屬於“語法加亮”腳本外,其它都屬於“插件”類型。關於如何寫腳本的一些基礎知識將在下一部分進行一些介紹。

2.1. gzip(壓縮文件支持)

作者:Bram Moolenar

網站腳本編號:無(包含在 Vim 的標準發佈之中)

安裝說明:

功能說明:

該腳本使得 Vim 可以直接打開使用 gzip [1]、bzip2 [2] 和 compress [3] 壓縮的文件(要求存在相應的命令行工具)。後綴爲“.gz”、“.bz2”和“.Z”的文件會在打開時被動態解壓縮,並在寫操作時被自動重新壓縮。

打開壓縮文件時,屏幕上出現一個(不正確的)“[noeol]”的提示是正常的,不必進行理睬。

2.2. netrw(網絡文件支持)

作者:Charles E. Campbell, Jr.(綽號 Dr. Chip)

網站腳本編號:1075(Vim 的標準發佈之中可能包含一個較老的版本)

安裝說明:

Vim 6.4 的標準發佈帶的版本是 42,較老、功能不齊全,但無須安裝。建議:

1.在 Vim 網站上下載版本 62(更新的版本只能用於 Vim 7);
2.使用“tar xvfj netrw.tar.bz2 -C ~/.vim”解開;
3.在Vim中運行“:helptags ~/.vim/doc”安裝文檔。

功能說明:

支持直接讀寫網絡上的文件,支持的協議有 ftp、http、rsync、scp 等。比如,使用 FTP 協議以用戶名 adah 打開服務器 server 上 ~/temp 目錄下的 test.cpp 文件,可以直接在命令行上使用:

vim ftp://adah@server/temp/test.cpp

Vim會自動提示用戶輸入口令,然後打開文件。

更多的幫助內容請參考“:help netrw”。

2.3. engspchk(英文拼寫檢查)

作者:Charles E. Campbell, Jr.(綽號Dr. Chip)

網站腳本編號:195

安裝說明:
在 Vim 網站上下載最新版本(engspchk.tar.gz);
使用“tar xvfz engspchk.tar.gz -C ~/.vim”解開;
在Vim中運行“:helptags ~/.vim/doc”安裝文檔。
提示替換拼寫功能需要 agrep [4],可能需要另外下載安裝。

功能說明:
一個Vim專用的拼寫檢查器,其最主要的特點是:

  • 可以通過變量 spchkdialect 選擇英語變體(英國、美國、加拿大),對於找不到的詞、不常見的詞、不在當前英語變體中的詞以不同的方式加亮顯示;
  • 支持用戶詞典(保存在 .vim/CVIMSYN 目錄中)和項目詞典(保存在被檢查文件所在的目錄中);
  • 對於源代碼文件,只對註釋進行拼寫檢查,而不會對你的變量名稱胡亂提抗議;
  • 通過詞典文件可支持除英語以外的其它語言。

圖 5 中的窗口裏 engspchk 正在運行中。其中可以看到,紅色部分是插件所不能識別的單詞,黃色部分是當前英文變體(缺省是美國英語)中不正確的拼法,而青色部分是很少見的單詞。圖中運行的是包含圖形界面支持的 Vim,因而還可以看到一個名爲 DrChip 的菜單項(參見圖6),在其中可通過菜單選擇拼寫檢查相關的各項功能;同時還能看到快捷鍵:“\ec”開始拼寫檢查,“\ee”結束拼寫檢查,“\ea”選擇替換拼寫,等等。在文本模式的 Vim 中,我們一般就只使用這些快捷鍵了。


圖 5
圖 5 

 

圖 6
圖 6 

更多的幫助內容請參考“:help engspchk”。

2.4. calendar(日曆顯示)

作者:Yasuhiro Matsumoto

網站腳本編號:52

安裝說明:

在 Vim 網站上下載文件 calendar.vim,存到 ~/.vim/plugin 目錄中。

功能說明:

圖 6 的下半部分就是 calendar 的運行示例,是直接在正常模式下鍵入“\caL”顯示出來的。光標在該窗口中時,可使用左箭頭或上箭頭顯示前一個月,右箭頭或下箭頭顯示後一個月,“t”回到“今天”,“q”關閉日曆窗口。在有鼠標支持時,也可以使用鼠標在黃色字樣的“Prev”、“Today”、“Next”上雙擊達到類似的效果。

除使用“\caL”外,“\cal”也可以打開一個日曆窗口,但顯示位置是在 Vim 的左側而不是下方。另外,命令“:Calendar”效果和“\cal”相同,但其後可以跟參數:一個參數的話表示月份,兩個參數的話則分別表示年份和月份。“:CalendarH”與“:Calendar”類似,但日曆窗口的打開位置和“\caL”(而不是“\cal”)一樣,是在下方而不是左側。

2.5. project(文件的“項目”管理)

作者:Aric Blumer

網站腳本編號:69

安裝說明:

1.在 Vim 網站上下載最新版本(project-1.3.tar.gz);
2.使用“tar xvfz project-1.3.tar.gz -C ~/.vim”解開;
3.在 Vim 中運行“:helptags ~/.vim/doc”安裝文檔。

功能說明:

該插件可以把文件組織成一棵樹的形式,以便於查找和管理。使用命令“:Project”即可打開一個用戶的“項目文件”(~/.vimprojects)。項目文件採用普通的文本文件的形式,非常易於瀏覽和修改。圖 7 是一個示例。其中左邊窗口部分的就是一棵項目樹,完整內容如下:


圖 7
圖7 

 

 

CvsMenu="~/.vim" CD=. { plugin/cvsmenu.vim doc/cvsmenu.txt}Nvwa="~/nvwa_local" CD=. { doc=doc {  ChangeLog  README  webupdate.sh } nvwa=nvwa {  bool_array.cpp  debug_new.cpp  mem_pool_base.cpp  static_mem_pool.cpp  bool_array.h  class_level_lock.h  cont_ptr_utils.h  debug_new.h  fast_mutex.h  fixed_mem_pool.h  mem_pool_base.h  object_level_lock.h  pctimer.h  set_assign.h  static_assert.h  static_mem_pool.h }}

在這個項目文件中存在兩個項目:CvsMenu 和 Nvwa。引號中的內容表示路徑,“CD=.”則表示打開該項目中的文件時,當前目錄會更改到項目所在的目錄。項目下面可以再分子項目,如 Nvwa 項目下有 doc 和 nvwa 兩個子項目,沒有“CD=.”表示打開子項目裏的文件時不再更改當前目錄。

圖中並沒有顯示出完整的內容,因爲其中的內容可以摺疊(缺省打開項目文件時是完全摺疊起來的,即在上面的例子中,只能看到兩個項目的名字“CvsMenu”和“Nvwa”)。在非文件名行上使用鼠標雙擊或回車鍵可以進行展開或摺疊,在文件名行上使用鼠標雙擊或回車鍵則可以打開對應的文件。

更多的幫助內容請參考“:help project”。

2.6. taglist(源代碼結構瀏覽)

作者:Yegappan Lakshmanan

網站腳本編號:273

安裝說明:

1.確保機器上有一個可用的 Exuberant Ctags 的版本(可以執行命令“ctags”)

2.在 Vim 網站上下載 taglist(假設爲 taglist.zip);

3.使用“unzip taglist.zip -d ~/.vim”解開;

4.在 Vim 中運行“:helptags ~/.vim/doc”安裝文檔。

雖然 taglist 使用 ctags,但並不要求 tags 文件的存在。

功能說明:

使用命令“:Tlist”啓用/關閉 taglist,效果請先看一下圖 8。Taglist 的主要特性有:


圖 8
圖8 
  • 可以顯示宏(macro)、函數(function)、變量(variable)、類型定義(typedef)、類(class)、結構(struct)等多種內容信息;
  • 打開多個文件時,可以同時看到多個文件的結構信息;
  • 在左邊的 taglist 窗口顯示的名稱上雙擊鼠標或按回車鍵,右邊主窗口中會跳轉到相應的定義位置;
  • 右邊窗口中光標的位置改變,左邊的窗口也會在 4 秒內(缺省值,參見“:help 'updatetime'”)黃色加亮顯示相應的名稱;
  • 在啓用/關閉 taglist 時,插件能夠自動改變當前 Vim 窗口的大小(不管是文本模式的 Vim 還是圖形界面的 Vim),除非使用“:let Tlist_Inc_Winwidth=0”關閉這一功能(當使用這一功能導致兼容性問題時)。

更多的幫助內容請參考“:help taglist”。

2.7. cvsmenu(CVS集成)

作者:Thorsten Maerz/吳詠煒

網站腳本編號:1245

安裝說明:

1.在 Vim 網站上下載文件 cvsmenu.vim,存到 ~/.vim/plugin 目錄中;
2.啓動 gvim,在菜單中選擇“CVS-Settings-Install-Install updates”(文本模式的 Vim 可以使用快捷鍵“,cgii”),從網上(SourceForge)的 CVS 中安裝最新版本和幫助文檔(此步驟可選)。

功能說明:

在 Vim 中集成 CVS [24]版本管理功能。該插件最初由 Thorsten Maerz 編寫,在 2002 年以來沒有再得到維護。我在 2005 年初開始使用這個插件後,非常喜歡它,修正了其中存在的錯誤,並一直維護該插件。如果大家發現有 bug,報告給我就可以了。

主要功能可在圖 9 的菜單中看到:


圖 9
圖9 
  • 瞭解 CVS 環境的基本信息和 cvsmenu 中的變量設定(參見圖 10); 
    圖 10
    圖10 
  • 調整設定,安裝更新版本;
  • 插入 CVS 的可擴展關鍵字,如“$Date$”、“$Id$”;
  • 對目錄進行基本操作(cvs update 等);
  • 接受附加參數的基本操作(文件比較等);
  • 管理功能,如登錄;
  • 刪除類操作;
  • 打標籤;
  • 觀察(跟蹤)和編輯功能;
  • 將本地文件和 CVS 中的文件進行比較(以 Vim 的分左右兩列使用顏色加亮顯示修改、增加、刪除部分的比較方式;效果參見圖 11); 
    圖 11
    圖11 
  • 顯示文件每一行的更改人和更改時間(cvs annotate,參見圖 12); 
    圖 12
    圖12 
  • 顯示庫的訪問歷史(cvs history);
  • 顯示文件修訂日誌(cvs log;參見圖 13); 
    圖 13
    圖13 
  • 顯示文件狀態;
  • 顯示較短的文件狀態;
  • 根據本地信息顯示文件狀態(不訪問庫);
  • 簽出模塊(cvs checkout);
  • 查詢更新;
  • 更新,如有衝突會高亮顯示(cvs update);
  • 取消修改;
  • 添加當前文件到 CVS 中(cvs add);
  • 簽入當前文件(cvs commit);
  • 導入文件(cvs import);
  • 添加並簽入當前文件。

根據實際使用的需要,除了修訂錯誤之外,我加入了一些編碼相關的支持。拿一個最實際的情況,如果使用“set encoding=utf-8”,但源代碼中仍使用了 GBK 編碼的中文字符,那麼,必須在 .vimrc 中加入一行“let g:CVScvsoutputencoding='gbk'”才能保證“cvs annotate”操作的結果是正確的。

Thorsten 把該插件的易用性設計得相當好。舉例來說,在作文件比較時,按 Tab 可跳轉到下一個不同處,左側的比較窗口中按一下“q”即可關閉該窗口。更多的幫助內容請參考“:help cvsmenu”。

2.8. doxygen(文檔註釋語法加亮)

作者:Michael Geddes

網站腳本編號:5

安裝說明:

1.在 Vim 網站上下載最新版本(doxygen.zip);
2.使用“unzip doxygen.zip”解開;
3.執行“cp -p doxygen.vim ~/.vim/syntax”和“cp -p doxygen.txt ~/.vim/doc”複製文件到 Vim 目錄下;
4.在 Vim 中運行“:helptags ~/.vim/doc”安裝文檔。
5.如果 ~/.vim/after/syntax 目錄不存在,使用“mkdir -p ~/.vim/after/syntax”創建該目錄;
6.進入 ~/.vim/after/syntax 目錄,使用下面三行創建語法文件之間的關聯,使得在 C、C++ 和Java 文件中可以識別文檔註釋:


ln -s http://www.cnblogs.com/syntax/doxygen.vim c.vimln -s http://www.cnblogs.com/syntax/doxygen.vim cpp.vimln -s http://www.cnblogs.com/syntax/doxygen.vim java.vim"

6.可選地,看一下我的個人編程網頁 [6] 下有沒有對 doxygen.vim 的更新(裏面包含有作者尚未併入到標準發佈中去的我的更改——好奇的話,你可以在 doxygen.vim 文件中數一下,看一看 Wu Yongwei 的名字出現了幾次:-))。

功能說明:

如果你用過文檔註釋,相信我不需要多說,看一下圖 14你就知道這個腳本的功能了。如果你沒有用過文檔註釋,強烈建議你到 Doxygen [7] 的網站上看一下,瞭解一下這個非常有用的工具。作爲示例,可在 http://nvwa.sourceforge.net/doc/debug__new_8cpp.html#a17 看一下圖中的代碼使用 Doxygen 自動生成的 HTML 網頁。


圖 14
圖14 

2.9. matrix(!)

作者:Don Yang

網站腳本編號:1189

安裝說明:

在 Vim 網站上下載文件 matrix.vim,存到 ~/.vim/plugin 目錄中即可。

功能說明:

是的,說的就是電影 Matrix!Vim 的腳本並不是都幹“正經事”的。想看一下電影裏那些酷酷的字符在 Vim 的窗口裏翻滾嗎?發一個命令“:Matrix”即可(按任意鍵退出)。效果見圖 15。


圖 15
圖15 

 

 



回頁首

 

 

參考資料

[1]The gzip home page: http://www.gzip.org/

[2]bzip2: http://www.bzip.org/

[3]Compress for UNIX: http://www.answers.com/compress#Wikipedia

[4]agrep: http://www.answers.com/agrep

[5]CVS-Concurrent Versions System: http://www.nongnu.org/cvs/

[6]Wu Yongwei's Programming Page: http://wyw.dcweb.cn/

[7]Doxygen: http://www.stack.nl/~dimitri/doxygen/

 

Vim 實用技術,第 3 部分: 定製 Vim

簡介: 本系列前面兩部分講的都是如何使用現有的 Vim 系統,本部分則會通過實例來講如何定製 Vim 的行爲。良好的定製可以讓使用 Vim 變得更爲得心應手;同時,在掌握了基本的定製之後,也許你就會想進一步寫一些自己的 Vim 腳本,從而真正地成爲一個 Vim 專家。

3.1. Vim 腳本基礎

在 .vimrc 文件中,和在第二章提到的插件和語法文件中,使用的語言就是 Vim 腳本語言。這種腳本語言語法有點像 BASIC,表達式有點像 C,還是比較容易理解的。本章中並不打算對其作很系統的介紹(要完整了解的話,請參見“:help usr_41.txt”),而只是介紹一些基本知識,特別是,瞭解定製 .vimrc 所需要的基本知識。

Vim 腳本相當於可直接在命令模式下執行的命令,只是不需要輸入前面的冒號(如果用了冒號也不會出錯)。因此,像設置選項、創建鍵盤映射這樣的命令是直接可用的。當然,作爲一種腳本語言,除了普通鍵盤上會輸入的命令外,我們還需要一些更復雜的功能,特別是:變量,表達式,條件和循環語句,函數。

3.1.1. 變量

Vim 中使用如下的語法對變量進行賦值(創建變量):

let 變量名 = 數值

變量類型有兩種,整數和字符串,在第一次賦值之前都不能使用。變量名除了可使用常規的字母、下劃線和數字外,還可以使用幾種特殊的前綴:

  • “b:”——只對當前緩衝區(buffer)有效的變量;
  • “w:”——只對當前編輯窗口(window)有效的變量。
  • “g:”——全局變量(在函數中訪問全局變量必須使用該前綴,不加前綴的話則認爲是函數內的局部變量);
  • “s:”——變量名只在當前腳本中有效;
  • “a:”——函數的參數;
  • “v:”——Vim 內部預定義的特殊變量(參見“:help vim-variable”)。

下面三個前綴用來訪問特殊的數值,由於行爲和變量較爲相似(可以讀取和修改),也放在這兒一起講:

  • “$”——訪問環境變量;
  • “&”——訪問 Vim 選項;
  • “@”——訪問寄存器。

當變量不再使用時,可以使用“unlet 變量名”刪除變量。

3.1.2. 表達式

和 C 非常類似,可以使用變量和常量,可以使用括號,可以調用函數(“函數名(...)”),支持加法(“+”)、減法(“-”)、乘法(“*”)、除法(“/”)和取模(“%”),支持邏輯操作(“&&”、“||”和“!”),支持三元條件表達式(“a ? b : c”)。字符串操作方面當然比 C 要強,可以使用“.”進行字符串拼接;可使用“==”、“<=”等進行字符串大小比較,可使用“=~”和“!~”進行正則表達式匹配,而且可以在比較操作符後面添加“#”或“?”來強制進行大小寫敏感或不敏感的比較(缺省受 Vim 選項 ignorecase 影響)。顯示一個表達式的結果,可以使用“:echo 表達式”顯示到狀態欄上,或者在插入模式下使用“Ctrl-R=表達式”插入到緩衝區的文本中。

和其它很多在 Unix 下成長起來的語言一樣,Vim 的字符串常量有雙引號和單引號兩種方式。使用單引號的話,單引號間的任何字符都是字符串的一部分,其中不能再包含單引號。使用雙引號的話,則可以使用“\”產生換碼序列(具體可參考“:help expr-quote”),如“\n”代表換行符,“\"”代表雙引號,“\\”代表反斜槓本身,等等。

需要注意的話,雙引號除了可以表示字符串常量外,還可以表示註釋。行首的“"”,以及表達式中出現的成單的“"”,都表示“"”後面的部分全部是註釋。

3.1.3. 條件和循環語句

條件語句形式如下:


if 表達式  語句endif


if 表達式  語句else  語句endif


if 表達式  語句elseif 表達式  語句endif

循環語句形式如下:


while 表達式  語句endwhile

條件和循環語句都可以嵌套。這些比較簡單,就不多加說明了。

3.1.4. 函數

在表達式中使用函數時,就跟 C 裏面的方式類似,直接使用函數名加括號,括號裏寫上參數(可選)。在不需要返回值的情況下調用函數時,稍稍有些不同,要使用“call”命令,後面跟函數名和括號(括號裏面寫上可能有的參數)。

定義函數使用下面的語法:


function 函數名稱(參數列表)  語句endfunction

如果已有同名函數存在,Vim 會報錯,除非在“function”後面加上一個“!”。

如果參數中不包含“...”,那麼參數的數量是固定的,函數的調用者必須提供跟定義同樣多的參數(在函數定義中使用參數名之前加上“a:”進行訪問)。如果參數中包含“...”,那麼參數的數量不固定,除了可以使用參數名稱訪問傳遞過來的參數外,還可以使用“a:0”知道額外傳遞的參數數量,使用“a:1”、“a:2”等訪問這些額外傳遞的參數。

要在函數的中間返回,或者要返回數值的話,可以使用“return”語句。

Vim 內部定義了一百多個函數,詳細列表請參見“:help function-list”。

3.2. 我的 .vimrc

作爲一個 Vim 腳本的一個具體示例,我將講解一下最實用的情況,我的 .vimrc 文件。文件 .vimrc.html (請下載到本地打開) 是我的 .vimrc 文件通過以下步驟生成的 HTML 文件:

1.在 Vim 中打開 .vimrc 文件;

2.執行命令“:colorscheme koehler”(缺省配色可能在瀏覽器中效果不佳)

3.執行命令“:%!nl -w4 -s' '”(1.11 節)

4.執行命令“:TOhtml”(1.13 節)

5.執行命令“:w”

可以把瀏覽器中的文本內容粘貼到 Vim 中,然後使用下面這個替換命令“:%s/^ \+[0-9]\+ //”刪除前面的行號,來恢復出最初的 .vimrc 文件。

下面逐行進行講解,幷包含理解其內容所需的資料的鏈接。建議大家直接閱讀 .vimrc 文件的內容,並在有疑問時查閱下面的解釋。

第 1 行:註釋(3.1.2 節末段),其中包含一個模式行(1.4 節和 1.5 節)。

第 2 行:首先判斷系統是否具有“自動命令”(autocmd)的支持,有的話才執行第3到第六行的內容(1.1 節、“:help has”和“:help feature-list”)。

第 3 行:純註釋(後面我將跳過註釋行不再說明)。

第 4 行:清除所有的自動命令(“:help autocmd-remove”),以方便調試,可以使用“source ~/.vimrc”查看一些修改後的效果(“:help source”)。

第 6 行:對於後綴爲“.asm”的文件,認爲其是微軟的 Macro Assembler 格式(“:help masm-syntax”)。

第 7 行:與第 2 行的 if 語句配對。

第 8-10 行:當使用了圖形界面時(“:help feature-list”),確保所有的文件類型會在菜單“語法”(“Syntax”)下出現,而不是出現一個菜單項“Show filetypes in menu”。缺省行爲可以讓 Vim 啓動得更快一點點。

第 11-13 行:當使用了圖形界面,並且環境變量 LANG 中不含“.”(即沒有規定編碼)時,把 Vim 的內部編碼設爲 UTF-8。

第 14 行:不需要保持和 vi 非常兼容(“:help 'compatible'”)。

第 15 行:執行 Vim 缺省提供的 .vimrc 文件的示例,包含了打開語法加亮顯示等最常用的功能。

第 16 行:打開自動縮進(1.4 節)。

第 17 行:缺省不產生備份文件(“:help 'backup'”)。

第 18 行:在輸入括號時光標會短暫地跳到與之相匹配的括號處,不影響輸入(“:help 'showmatch'”)。

第 19 行:正確地處理中文字符的折行和拼接(1.12 節)。

第 20 行:可自動識別的文件類型爲帶 BOM 字符的 Unicode 文件、UTF-8 編碼的文件和 GBK 編碼的文件。

第 21 行:設置狀態行,使其能額外顯示文件的編碼信息,如圖 2 中的“gbk”和“big5”(“:help 'statusline'”)。


圖 2
圖2 

第 22-24 行:如果該 Vim 支持鼠標,則啓用鼠標支持(1.3 節)。

第 25-29 行:判斷 Vim 是否包含多字節語言支持(multi_byte 特性),並且版本號(“:help v:version”)大於 6.1(包含 ambiwidth 選項)。

第 26-28 行:如果 Vim 的語言(“:help v:lang”;受環境變量 LANG 影響)是中文(zh)、日文(ja)或韓文(ko)的話,將模糊寬度的 Unicode 字符的寬度(ambiwidth選項,1.2 節)設爲雙寬度(double)。

第 31-36 行:改變上、下方向鍵行爲方式:通常情況下這些鍵的作用範圍是邏輯行,所以如果行很長的話光標的移動可能會不太方便;這些鍵盤映射把這些鍵的作用範圍改成屏幕行(“help gk”),還爲習慣使用“j”、“k”的人增加了映射“Ctrl-j”和“Ctrl-k”作用於屏幕行。前面四個映射使用的命令是“noremap”,作用於正常模式、可視模式和命令執行時;後面兩個映射使用的命令是“inoremap”,僅作用於插入模式,其中使用“Ctrl-O”臨時執行一個普通模式的命令(“:help i_CTRL-O”)。

第 38-41 行:在 Vim 中的插入模式中可以使用“Ctrl-R =”計算整數表達式的數值,但 Vim 本身沒有計算浮點表達式的能力。這四個映射提供了浮點表達式的計算能力:使用“\ma”(假設 Leader 字符爲缺省的“\”,參見“:help <Leader>”)可將計算的結果放到下一行上(待計算的表達式爲當前行或在可視模式選中的內容),使用“\mr”則用計算的結果替換待計算的表達式(同樣爲當前行或在可視模式選中的內容)。這些映射假設有一個命令“calcu”可用來計算一個表達式的內容。該命令可用下面的 shell 腳本簡單實現:


#! /bin/shecho "$*" | sed -e $'s/\r$//' -e 's/sin *(/s(/g' -e 's/cos *(/c(/g' -e 's/atan *         (/a(/g' -e 's/log *(/l(/g' -e 's/exp *(/e(/g' | bc -l

該腳本把表達式轉換成 bc [1] 能接受的形式(把“sin(x)”轉換成“s(x)”,等等),並通過標準輸出送到 bc 的標準輸入。

該映射較爲複雜,此處不詳加解釋了——其中心思想都是選取待計算的表達式,放到無名寄存器中,然後使用“Ctrl-R"”粘貼到命令行上,使用 calcu 進行計算,再把結果粘貼回正在編輯的緩衝區中;最後一個最複雜,因爲爲了替換原先的表達式,還需要記住原先被選中的內容的起始和結束位置,你可能希望看一下“:help gv”、“:help v_o”、“:help m”、“:help `”,並複習節 1.11。可以注意一下,在映射中使用了“<silent>”(“:help map-<silent>”),這會防止命令行上回顯執行的內容。

第 43-44 行:允許用戶使用 F2 來取消搜索/替換的加亮顯示。此處一個映射用於正常模式(nmap),一個用於插入模式(imap)。上面已經提過一次,“Ctrl-O”可以在插入模式中執行一個正常模式的命令。

第 46-47 行:這兩個映射用於 taglist 插件,使用 F9 直接打開(或關閉)taglist 的窗口。

第 49-50 行:方便快速修訂窗口(1.10 節)的使用,可使用 F11(和 F12)查看下一個(上一個)錯誤(或 grep 項等)。

第 52-65 行:一些適用於文本模式運行的 Vim 的設定;詳見下面的具體說明。

第 54-56 行:將變量 Tlist_Inc_Winwidth 的值設爲 0,防止 taglist 插件改變終端窗口的大小(有些情況下會引起系統不穩定)。使用“has('eval')”是讓該語句僅在功能較爲完整、至少支持表達式的 Vim 版本中運行。

第 58-64 行:在系統支持 wildmenu 特性(“:help 'wildmenu'”)啓用文本模式的菜單。

第 59 行:打開 wildmenu 選項,啓動具有菜單項提示的命令行自動完成。

第 60 行:確保字符序列“<C-Z>”被理解爲 Ctrl-Z 而不是分開的五個字符(“:help 'cpoptions'”)。

第 61 行:設置使用 Ctrl-Z 激活自動完成提示。

第 62-63 行:把正常模式和插入模式下的 F10 映射成執行菜單項,並自動提示菜單內容。注意缺省菜單仍不會自動載入,我使用該特性的主要目的是在文本模式的 Vim 中使用 CVS 菜單。圖 16 是按 F10 鍵後再按 Tab 鍵的結果。


圖 16
圖16 

第 66-161 行:使用自動命令(autocmd)特性的設置。使用“has”來防止該部分內容在不支持自動命令的 Vim 版本中運行。

第 67-129 行:定義了若干個下面的自動命令會用到的函數,具體在下面的自動命令中講。請注意在每個“function”之後都用了一個“!”(“:help E122”):這也是爲了方便調試,讓“source ~/.vimrc”能正確運行而不會報告函數已定義的錯誤。

第 131-133 行:只要沒有將環境變量 VIM_HATE_SPACE_ERRORS 的值設爲零,則把變量 c_space_errors 的值設爲 1——效果是在 C/C++ 代碼中“不正確”的空白字符(行尾的空白字符和緊接在製表符之前的空格字符)將會被高亮顯示。圖 17所示的代碼中,第 3 行的行尾多了兩個空格,第 5 行的第一個製表符之前多了個空格。Vim 提示#935 裏有一些額外的說明。同時請參看對第 160 行的說明。


圖 17
圖 17 

第 135 行:使用的英文拼寫變體爲加拿大風格,即:使用拼寫“abridgement”(而不是“abridgment”)、“colour”(而不是“color”)、“realize”(而不是“realise”)、“theatre”(而不是“theater”)等,比較符合中國人一般的英語教科書中的拼寫方式,也比較適合於寫“國際”英語。

第 138 行:使用鍵盤映射“\a”來查看光標下字符的屬性,主要用於調試 Vim 的語法文件。圖 18顯示了光標下的字符所屬的語法“組”爲 vimOption,使用配色方案中的 PreProc(預處理符號)項,前景色爲紫色(RGB:#a020f0)。有興趣可查看 Vim 腳本#383 的具體內容。


圖 18
圖18 

第 140 行:在函數找不到時(“:help FuncUndefined”),自動在運行環境(Linux 下一般爲 ~/.vim)的 autoload 目錄下讀入與函數名同名的 .vim 文件。這是腳本#383 的建議安裝方式(SyntaxAttr.vim 文件放在 autoload 目錄下,僅在執行時載入)。

第 142 行:設置適用於 C/C++ 文件的選項(1.4 節)。

第 143 行:把補丁文件的縮進和製表符寬度設定設成和 C/C++ 文件相同(1.4 節)。

第 144 行:取消 Vim 對 HTML 標記自動產生的縮進,但打開自動縮進選項(1.4 節)。

第 145 行:對於變更日誌類型的文件,設置行寬爲 76 個字符(1.12 節)。

第 147 行:當文件後綴爲“.gb”時,認爲這是一個 GBK 編碼的文件,在讀入文件之前(“:help BufReadPre”)調用函數 SetFileEncodings 把原先的 fileencodings 選項的內容保存在本緩衝區的一個變量中(3.1.1 節),然後把 fileencodings 設成 gbk,即只嘗試對文件內容作爲 GBK 字符序列來解釋。

第 148 行:類似於上面把“.big5”後綴的文件當作 Big5 編碼的文件,在讀入文件之前把 fileencodings 設成 big5,只嘗試對文件內容作爲 Big5 字符序列來解釋。

第 149 行:類似於上面把“.nfo”後綴的文件當作 CP437 編碼(即英文 DOS 的 OEM 字符集編碼)的文件。效果可參看圖 19。


圖 19
圖19 

第 150 行:在讀入 .gb、.big5 或 .nfo 文件之後(“:help BufReadPost”),調用函數 RestoreFileEncodings 恢復保存起來的 fileencodings 原數值。

第 151 行:對於 .txt 後綴的文件,在顯示文件時(“:help BufWinEnter”,確保在模式行被執行之後)調用函數 CheckFileEncoding 檢查文件是否已修改並且 fileencoding 設有數值。條件滿足的話說明該文件在模式行中修改了 fileencoding,因而使用該編碼(“:help ++enc”)重新強制(“!”)讀入該文件以保證文件被正確解碼。Vim 提示#911 裏有一些額外的說明。

第 153 行:在遇到 HTML 文件時,如果 Vim 判斷出的編碼類型和 HTML 代碼中使用“<meta http-equiv="Content-Type" content="text/html; charset=編碼">”規定的編碼不一致,將使用網頁中規定的編碼重新讀入該文件。函數 ConvertHtmlEncoding 會把一些網頁中使用的編碼名稱轉換成 Vim 能夠正確處理的編碼名稱;函數 DetectHtmlEncoding 在判斷文件類型確實是 HTML 之後,會記下當前的光標位置,並搜索上面這樣的 HTML 代碼行,找出字符集編碼後,在編碼不等於當前文件編碼(fileencoding)時且當前文件編碼爲空或等於系統判斷出的文件編碼時,使用該編碼強制重新讀入文件,忽略任何錯誤(“silent!”)。該自動命令寫成是可嵌套執行的(“:help autocmd-nested”),目的是保證語法高亮顯示有效,且上次打開文件的光標位置能夠正確保持。Vim 提示#1074 裏有一些額外的說明。

第 155-156 行:確保把 /usr/include/c++ 和 /usr/include/g++-3 目錄下的所有文件都當成 C++ 類型的文件,不管 Vim 原先認定這些文件類型是什麼(“:help BufEnter”)。C++ 的很多標準頭文件(如“algorithm”)沒有文件後綴,缺省情況下不會被 Vim 當作 C++ 文件。

第 158 行:第 142 行把 C/C++ 文件的製表符寬度設成了 4(個人設置),但系統的源代碼一般使用 GNU 編碼規範,製表符寬度爲 8。該行設置所有 /usr 目錄下的文件都使用 GNU 編碼規範(1.4 節)。

第 160 行:在寫文件之前(“:help BufWritePre”),調用函數 RemoveTrailingSpace:只要沒有將環境變量 VIM_HATE_SPACE_ERRORS 的值設爲零,則對於文件類型爲 C、C++、Vim 腳本類型的文件,自動悄悄清除所有的行尾空白字符;“normal m`”記憶當前的光標位置,“normal ``”恢復記憶下來的光標位置。

至此爲此,我已經介紹了 Vim 的基本知識、很多實用技巧和一些最常用的 Vim 插件,並通過定製 .vimrc 文件介紹了腳本的基本知識。如果有需要進一步深入學習 Vim 或是想提什麼關於 Vim 的特定問題的話,不妨參加從 Vim 的網站上參加 Vim 的郵件討論列表,應該會獲益良多。而作者也希望本文至此也已經完成了引導讀者學習、瞭解 Vim 的高級特性的任務。

參考資料

[1]bc: http://www.answers.com/bc%20(Unix)

關於作者

吳詠煒,目前從事與開源相關的軟件架構工作,可通過 [email protected] 和他聯繫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章