为 Vim 编辑器开发定制插件
簡介
盡管 Vim 的界面非常簡單,但它是所有風格的 UNIX? 中最流行的兩種編輯器之一。可以輕松地擴展它,從而滿足各種軟件開發和系統管理需求。Vim 甚至有自己的腳本語言,可以使用它編寫腳本并把腳本裝載到 Vim 中。也可以使用 Perl 或 Python 等外部腳本語言擴展編輯器的功能。這些腳本統稱為?Vim 插件。
定制插件能夠提供幫助的最常見的方面是編程語言的語法高亮顯示。Vim 在安裝時附帶對?C、C++、Perl 和 Tcl 的預定義語法支持(請查看?Vim_Installation_Folder/vim72/syntax),但是有時候需要對定制的或新的編程語言的支持,或者希望擴展插件以便實施組織特有的編碼標準。
同樣,從編輯器內編譯源代碼也是不錯的特性。可以為 Perl 或 Python 代碼創建用于從編輯器內編譯源代碼的定制插件,還可以把光標放在有錯誤的地方,這有助于節省大量開發時間。
本文討論為了高亮顯示定制編程語言的語法 Vim 必須提供什么。然后討論通過使用簡單的正則表達式實施編碼標準,再轉到 Vim 的 Perl 腳本編程。最后,講解如何從 Vim 內編譯源代碼。
注意:本文假設讀者基本了解 Vim、Perl、make?和正則表達式。我們將使用 Vim version 7.2 和 Perl version 5.8。
回頁首
語法高亮顯示
我們將使用 Vim 的內部腳本引擎高亮顯示您創建的定制語言的語法。清單 1?包含這種定制語言的一些關鍵字。
清單 1. 定制編程語言的關鍵字
foreach if then else elsif while repeat until disable integer unsigned signed byte always initialVim 使用以下格式把特定的單詞標識為關鍵字:syntax keyword <group name> <keyword list>。
因此,對于您的定制語言,使用?清單 2?中的偽代碼。
清單 2. 在 Vim 中定義關鍵字
syntax keyword group1 foreach if then else elsif while repeat until disable integer unsigned signed byte always initial接下來,把此文件保存在 $HOME 下,命名為?lang.vim。現在,用您定制的語言編寫一小段代碼(見?清單 3)。
清單 3. 用定制編程語言編寫的代碼
integer k=0; repeat (k < 3) beginprint “hello world” + k + “\n”;k = k + 1; end在 Vim 編輯器中,作為 :source $HOME/lang.vim 裝載 lang.vim。但是,有一個問題,什么變化也沒有。盡管指定了語法,但是沒有指定應該如何高亮顯示語法。清單 4?給出 lang.vim 文件的改進版。
清單 4. 支持語法高亮顯示的 lang.vim 改進版
syntax keyword type1 integer unsigned signed byte syntax keyword statement1 foreach if then else elsif while repeat until disable always initial highlight link type1 Type highlight link statement1 Statement重新裝載 lang.vim,清單 3?中代碼的語法現在高亮顯示(見?圖 1)。在圖 1 中,高亮顯示關鍵字?integer?和?repeat。
圖 1. 定制代碼中高亮顯示的語法
在?清單 4?中究竟做了什么?有兩個方面需要理解:
- 用戶通常希望程序中的語句(if-then-else、repeat?等)與數據類型(integer、byte?等)以不同的方式高亮顯示,這樣可讀性更好。因此,把語法劃分為組,每個組包含適當的內容:type1?組包含?integer、unsigned、signed?和?byte?關鍵字。
- Vim 已經預定義了?Type、Statement、Comment?和?Identifier?組以及相應的顏色方案。highlight?命令把?type1?與 Vim 的?Type?組關聯起來,這樣就會使用相同的顏色方案顯示?byte?等關鍵字。
回頁首
更多語法支持
您可能希望自己的語言是不區分大小寫的,所以?integer?和?INTEGER?都應該高亮顯示。還希望支持?// C++?風格的注釋。清單 5?給出修改后的 lang.vim 文件。
清單 5. 支持語法高亮顯示的 lang.vim 改進版
syntax case ignore syntax keyword type1 integer unsigned signed byte syntax keyword statement1 foreach if then else elsif while repeat until disable always initial syntax match comment1 /\/\/.*/ highlight link type1 Type highlight link statement1 Statement highlight link comment1 Commentsyntax case ignore?語句處理不區分大小寫。不能使用關鍵字處理注釋,所以需要一個正則表達式,然后把它與 Vim?Comment?組關聯起來。使用?syntax match <identifier> /<pattern>/?定義正則表達式。在兩個前向斜杠 (/) 之間,定義模式?\/\/.*,這表示從?//?開始直到行末的所有內容。因此,圖 2?所示的定制語言代碼會正確地高亮顯示。
圖 2. 對注釋和不區分大小寫的支持
回頁首
定制編碼標準支持
很容易通過擴展定制的插件處理組織特有的編碼標準。下面是一些典型的編碼規則:
- 代碼中不應該有制表符。
- 變量名長度不應該超過 14 個字符。
- 一行上的字符數不應該超過 80 個。
- 函數不能超過 100 行。
代碼中不應該有制表符
我們先來處理最簡單的規則,代碼中不應該有制表符。只需為?tab?定義標識符,然后把這個標識符與 Vim 預定義的?Error?標記關聯起來:
syntax match identifier1 “\t” highlight link identifier1 Error那么,如果代碼中有制表符,會發生什么情況?圖 3?給出?圖 2?中的代碼加上制表符之后的情況。
圖 3. Vim 用紅色高亮顯示制表符
在圖 3 中,用紅色高亮顯示?repeat?后面的制表符;這明確地警告用戶這里有錯誤。
變量名長度不應該超過 14 個字符
對變量名長度的支持需要進一步了解如何使用正則表達式進行語法匹配:
syntax match longword1 “\w\{14,}” highlight link longword1 Error在這里,\w?定義字符類?[0-9A-Za-z_]— 即允許任何數字、字母字符(大寫或小寫)或下劃線 (_)。后面是?\{14,},這意味著需要匹配最少 14 個連續的字符。因此,this_is_a_REAL_long_word1?會導致高亮顯示,因為標識符長度超過 14 個字符,而?this_is_ok_2?沒問題。圖 4?給出錯誤情況的顯示方式。
圖 4. 用紅色高亮顯示超過 14 個字符的變量名
在圖 4 中,用紅色高亮顯示變量?this_is_a_REAL_long_word1(再次采用 Vim 的默認顏色方案),這警告用戶這里有錯誤。
一行上的字符數不應該超過 80 個
一行上的字符數超過 80 個會導致混亂,讓閱讀更困難。再次使用?syntax match?為一個正則表達式定義標識符,然后把標識符與?Error?關聯起來。理解這個正則表達式應該不難:脫機符 (^) 表示行的開頭;美元符號 ($) 表示行的末尾;這兩者之間的內容超過 80 個字符就識別為錯誤匹配。注意,點號 (.) 表示匹配除換行符外的任何字符:
syntax match longline1 “^.\{80,}$” highlight link longline1 Error圖 5?給出一個由于超過 80 個字符高亮顯示的代碼行。
圖 5. 禁止行長度超過 80 個字符的規則
在圖 5 中,由于復雜的公式導致超過 80 個字符,所以 Vim 用紅色高亮顯示一整行。刪除一個字符,把行長度從 80 減少到 79,高亮顯示就會消失了。
函數不能超過 100 行
定制編碼標準的最后一條規則是函數的長度必須少于 100 行。清單 6?給出一個用定制編程語言編寫的函數。
清單 6. 用定制編程語言編寫的函數
function f (int k, int l) returns float beginf = k * l;for (int i=0; i<10; i++)beginf += sqrt(k) * sqrt(l);endreturn f + 2; endfunction與設計復雜的正則表達式或調用 Vim 預定義的內部函數相比,把整個函數傳遞給 Perl 以檢查行數可能更容易(而且肯定更快)。下一節討論這個主題。
回頁首
使用外部腳本語言創建 Vim 插件
Vim 很容易與 Perl、Python、Tcl 和 Ruby 腳本連接。盡管這里只涉及 Perl,但是與 Python、Tcl 和 Ruby 連接的方法是相似的。清單 7?給出一個 Vim 插件,如果任何函數的長度超過 100 行,它就會顯示錯誤消息。
清單 7. 使用 Perl 為 Vim 創建定制的插件
perl << EOF sub checksize {my $count = 0;my $startfunc = 0;my $filelen = scalar @_;while ($count < $filelen) {if ($_[$count] =~ /^function/) {$startfunc = $count;}elsif ($_[$count] =~ /endfunction/){if ($count - $startfunc > 100){Vim::Msg($_[$startfunc], "Error");}}++$count;} } EOFfunction! L1( )perl checksize($curbuf->Get(1..$curbuf->Count())) endfunction這些代碼都放在前面使用過的 lang.vim 文件中。下面是這個插件的一些注意事項:
回頁首
從 Vim 內編譯源代碼
可以從 Vim 編輯器內部編譯源代碼。這個特性(加上語法高亮顯示和定制代碼檢查)讓 Vim 更接近定制的集成開發環境 (IDE)。清單 8?給出一個包含若干錯誤的?C++?文件。
清單 8. 非常糟糕的 C++ 代碼
#include <iostream> using namespace stdlclass mytags { public:int getid(int id=0);void setid(int)protectd: list<int> tags;const list<int>::iterator tag_i; }在 Vim 腳本中添加?清單 9?所示的五行代碼,就可以在編輯器中執行編譯。
清單 9. 把 F3 鍵映射為在編輯器中執行編譯并顯示錯誤
function! build()make cl “list the errors endfunction map <F3> :call build()<CR>在 ESC 模式下按 F3 鍵即可編譯源代碼。build()?函數從 Vim 內部調用?make,然后調用?cl?以顯示錯誤。在 ESC 模式下輸入?:cfirst?跳到第一個錯誤;使用?:cn?跳到后續的錯誤;使用?:clast?跳到最后一個錯誤。注意,在默認情況下假設?Makefile?在與源代碼相同的文件夾中。盡管這么說,但這不是必需的,可以修改?清單 9?中的?build()?函數,讓它轉到?Makefile?所在的文件夾。另外,向?make?傳遞參數也很容易。清單 10?證明了這一點。
清單 10. 使用 make 編譯源代碼的 Vim 腳本改進版
function! build()cd /home/arpan/ibm/scripts “go to the folder where Makefile ismake CC=g++cd /home/sources “back to sourcescl “list the errors endfunction map <F3> :call build()<CR>現在,在編譯代碼時,清單 11?中的錯誤會在 Vim 中顯示。
清單 11. 在 Vim 環境內顯示編譯錯誤
#include <iostream> using namespace stdlclass mytags { public:int getid(int id=0);void setid(int)protectd: list<int> tags;const list<int>::iterator tag_i; }t.cpp:4: error: expected namespace-name before "class" t.cpp:4: error: `<type error>' is not a namespace t.cpp:4: error: expected `;' before "class" t.cpp:8: error: expected `;' before "protectd" t.cpp:10: error: ISO C++ forbids declaration of `list' with no type t.cpp:10: error: expected `;' before '<' token t.cpp:6: error: expected unqualified-id at end of input t.cpp:6: error: expected `,' or `;' at end of input Press ENTER or type command to continue回頁首
安裝語法文件
在 $HOME/.vim 下面創建名為?syntax?的文件夾,把定制的插件復制到其中。如果您的定制語言名為?ml2,那么把此文件命名為?ml2.vim。然后編輯 $HOME/.vimrc 并添加?syntax on?行。這樣就可以了:現在,每當在 Vim 中打開擴展名為?ml2?的文件時,會自動地高亮顯示語法。這種行為不包括顯式的函數調用;建議為子例程長度檢查等快速定制代碼檢查設置鍵映射。
回頁首
結束語
進行快速開發并不一定需要高級的 IDE,Vim 就能夠滿足需要。通過使用到 Ruby 和 Python 等語言的接口,甚至可能使用 Vim 連接 web。要想進一步研究這個主題,請參見?參考資料。
參考資料
學習
- Vim 文檔:查閱關于 Vim 編輯器的更多信息。
- Vim regular expressions:尋找對于 Vim 有用的正則表達式。
- Vim Table of Contents:Peruse Swaroop C H 的 Vim 目錄。
- 使用腳本編寫 Vim 編輯器,第 1 部分: 變量、值和表達式(Damian Conway,developerWorks,2009 年 5 月):了解 Vimscript 編程語言的基本組件。
總結
以上是生活随笔為你收集整理的为 Vim 编辑器开发定制插件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vi 技巧和诀窍:令人刮目相看的 10
- 下一篇: Hadoop 新 MapReduce 框