0. 序言
程式設計人員花費最長時間的開發工具可能就是編輯器了,一個非常友善、高效的編輯器對開發人員來說是非常有效的。在unix/linux下,甚至windows下,vim都可以說是個非常優秀的編輯器。雖然許多朋友開發過程中都在使用vim,但通常隻使用了vim非常有限的功能,沒有接觸到vim的很多非常符合開發人員需求的功能。下面就從開發人員的角度出發,介紹開發過程經常使用到的功能。讀完本文,您會發現vim原來是如此強大的內建開發環境。
Vim是基于GPL的開源項目,是對vi的提升版本,而vi是unix環境下最通用的編輯器。不過由于vim的強大的功能,許多最新釋出的linux版本中已經把vim作為預設vi編輯器了。如果您的系統中沒有安裝vim,可以從vim.sourceforge.net上下載下傳合适的版本。閑話少提,下面從基本編輯指令、通用編輯指令、開發常用指令等方面介紹vim。本文以介紹功能為主,使用細節多嘗試一下就明白了。以下讨論基于vim 6.2。
1.基本編輯指令
本節簡單分類基本的vim編輯指令,隻給出簡單的功能說明,作為使用vim的指令速查,較長的描述請檢視vim的線上幫助。Vim下輸入:h <指令>即可。下面的指令是在常态模式下(就是任何狀态下多按幾次ESC鍵後到達的狀态,為了避免概念模糊,這裡對這些狀态不進行描述)輸入的字元序列。
指令
含義
移動
h
j
k
l
左下上右(和方向鍵相同含義)
H
M
L
同一頁(螢幕)内的第一行、中間行、
最後一行
ctrl+f
ctrl+b
下一頁
上一頁
ctrl+d
ctrl+u
下半頁
上半頁
b
w
e
前一個單詞首
後一個單詞首
後一個單詞尾
^
$
行首
行首的非空字元
行尾
輸入
a
A
目前字元後輸入
行尾輸入
i
I
目前字元前輸入
行前輸入
o
O
目前行下插入新行輸入
目前行上插入新行輸入
:r [filename]
目前行下插入檔案[filename]的内容
改變
d[範圍]
删除範圍内的文字,如:dw(删除到詞尾)d$(删除到行尾)
c[範圍]
改變,删除指定範圍後直接進入編輯狀态
~[範圍]
改變目前字元或者範圍内的大小寫
J
連接配接目前行和下一行
r[char]
替換字元,使用随後輸入的字元替換目前字元
R
進入替換模式,輸入的字元替換文本的文字
y[範圍]
拷貝範圍内的文字
p
粘貼到目前字元後
x
删除目前字元
.
重複最後一條改變文本内容的指令
查找
f[char]
F[char]
行内向後查找字元[char]
行内向前查找字元[char]
t[char]
T[char]
行内向後查找字元[char]前
行内向前查找字元[char]前
/[string]
?[string]
向下查找[string]
向上查找[string]
查找後使用n繼續查找,使用N向相反方向繼續查找
*
#
向下查找光标目前單詞
向上查找光标目前單詞
n
N
重複最後一次/ ? 指令
相反方向重複最後一次/ ? 指令
其他
:e filename
關閉目前檔案,編輯檔案
:w filename
寫入檔案中
ctrl+g
:g
顯示檔案資訊
:help [cmd]
檢視vim的指令cmd的幫助資訊
:u
undo一個改變
:red
重做undo的改變
U
undo目前行所有的改變
注:
[範圍] 是界定上個動作的範圍,vim裡面稱為motion。上面的改變類指令都屬于motion指令,意思是指移動了光标位置。
到行第一個字元
到行第一個非空字元
到行最後一個字元
[n]k
[n]j
向上幾行
向下幾行
[n]w
删除n個單詞
上面的分類是個人為便于記憶進行分類,沒有特定标準或已有規則。
2. 通用指令
2.1. 搜尋
搜尋應該說是開發過程中非常常用的指令。最常見的搜尋指令是/ 和? ,後面加需搜尋的詞句或者正規表達式(簡單的介紹見下面一小結)。然後使用n 或者N 找下一個或者上一個搜尋結果。
開發過程中最可能的情況是看到一個詞希望能夠找到它,這時候* (向下搜尋目前詞)和#(向上搜尋目前詞)指令就非常友善。如果想搜尋包含目前詞的詞都可以可以使用g* 或者g# 指令。
找到變量的定義,可以使用gd(目前詞的局部變量定義)和gD(目前詞的全局變量定義)指令,這兩個指令不一定非常準确,但有時候還是比較有用的。
目前詞的宏定義,可以使用[_ctrl-d 找到目前詞第一個出現在#define 後的位置。而[d 顯示目前檔案和包含檔案中目前詞的第一個宏定義,[D 列出所有的宏定義。] 開始的指令是從目前位置開始搜尋。
在目前檔案和包含頭檔案中進行搜尋,搜尋宏定義可以使用上面說的指令,函數、變量等的聲明、引用的搜尋,可以使用[i (從檔案頭開始搜尋包含目前詞的位置)指令,[I 列出所有的行。] 開始的指令是從目前位置開始搜尋。Vim的指令還是比較有一緻性的。跳到出現的位置則使用[_ctrl-i (從第一行開始),或者]_ctrl_i (從目前位置開始)。
多檔案的搜尋可以通過外部指令:grep 來實作,預設情況和使用grep指令非常類似,查找出來的清單,可以使用Quickfix類指令來在清單中循環通路,通過此類指令也可以在多個grep指令清單中進行跳轉,此類指令初始為編譯出錯時設計的,在3.4節介紹相關指令時較長的描述。
替換指令格式比較長,但有時候又非常有用,必須了解它每一個細節才能保障靈活使用。指令格式如下:
:[range]s[ubstitute]/{pattern}/{string}/[&][c][e][g][p][r][i][I] [count]
這個指令的含義就是在range的範圍内,查找pattern定義的模式替換為string。
Range的定義可以參考:help range,通常可以指定行數,标記,甚至指定一個搜尋也可以,例如:
3,.+1 從3行到目前行的後一行
‘t,$-2 從标記t到文章尾後兩行
% 全部文章,相當于.,$
.,/{pattern}/ 從目前行到下一個比對pattern的行
pattern和上面介紹的搜尋模式一樣可以是一個字元串或者是正規表達式。
String通常可以是字元串,其他特殊内容可以參考:help sub-replace-special 。
最後的标記的含義如下:
& 保持上個替換指令的标記
c 每次替換進行确認
g 對每行所有比對的模式進行替換,預設一行隻替換一次
i 忽略大小寫
I 不忽略大小寫
2.2. 正規表達式
使用正規表達式極大的增強了搜尋、替換的描述能力,但這也增加了學習的難度。這裡把開發過程中可能使用的标記簡單的羅列一下,然後舉幾個例子,大家應該可以舉一反三,大緻知道如何使用了。比對模式的學習可以參考:help pattern 。
ordinary atom
\_^
比對行首,必須在pattern開始
任何地方比對行首
\_$
比對行尾,必須在pattern最後
任何地方比對行尾
\_.
比對任意字元,不能在行尾
任意地方比對字元
\<
\>
詞首
詞尾
multi items
0或多個
\+
1或多個
\?
0或1個
\{n,m}
n到m個,盡量比對多數個
\{-n,m}
n到m個,盡量比對少數個
character classes
\s
\S
空白字元<space> <TAB>
非空白字元
\d
\D
數字
非數字
\x
\X
十六進制數字
非十六進制數字
\a
\A
字母a-zA-Z
\w
\W
詞字元包括字母、數字和下劃線
\h
\H
首字元包括字母和下劃線
\e
\t
\r
\b
\n
<ESC>
<TAB>
<CR>
<BS>
<NewLine>
\c
\C
忽略大小寫
比對大小寫
這樣c語言的标志符就可以使用 \<\h\w* 來比對;
\<ca\w*5 比對以ca為詞開始中間包含5的任意詞;
2.3. 多視窗
開發過程中有時候需要打開多個檔案或者看一個檔案的不同部分,這種情況就是多視窗的功用做在。
打開一個新視窗使用 :split [filename] 指令,加檔案名打開的視窗編輯此檔案,否則編輯目前檔案。
關閉目前視窗使用 :q 即可。
Ctrl-w j 下一個視窗
Ctrl-w k 上一個視窗
ctrl-w = 所有視窗等高、寬
ctrl-w + 增加目前視窗高度
ctrl-w – 減少目前視窗高度
不同的檔案在記憶體中的資料是一個buffer,一個buffer可以有1個或多個window,甚至沒有window。在多個檔案間跳轉(後面介紹)時,通常檔案所在buffer仍然在記憶體。可以使用 :buffers 列出目前記憶體中所有buffer。
使用:bn (下一個buffer)和 :bp (上一個buffer)在buffer間循環。
2.4. 可視模式
圖形界面使用太多了,可能覺得使用指令界定範圍不直覺,可視模式則允許可視的選擇一塊文本,然後輸入相關指令對其進行操作。其使用過程是移動到塊開始字元,輸入指令進入可視模式;使用各種移動指令移動到塊尾;輸入相關指令對此塊内容進行操作。
v 進入字元選擇可視模式
V 進入行選擇可視模式
Ctrl-v 進入塊選擇可視模式
2.5. 标記(mark)
對某行做一個标記有時候是非常有用的功能。以後可以友善的移動到此行,在motion中也可以引用這個位置。
設定标記使用 m{a-zA-Z} 設定一個标記,名字是後面跟的字元,一個檔案内可以定義a-z共26個标記,檔案間可以定義一個A-Z共26個标記。
移動到标記行,使用‘[char] 或者 `[char] 指令移動到[char]對應的标記。
2.6. 檔案恢複
敲半天的東西不能因為斷電丢失了。Vim預設輸入200個字元或者空閑4秒就自動儲存在.swp檔案中。
通常的恢複步驟是,移動到檔案所在目錄下;使用vim –r [filename] 恢複filename檔案,如果編輯的檔案沒有儲存使用 vim –r “” 即可;把恢複的檔案另存為另一個檔案,使用diff程式(可以使用vimdiff)檢視是否正确恢複。如果不記得檔案名,使用 vim –r 列出所有交換檔案。
3. 開發常用指令
3.1. tag
有tag後能夠非常友善的在多個源代碼檔案中進行跳轉,這個特性非常友善浏覽、閱讀代碼。
C/C++源程式可以使用 ctags -R *.c *.cpp 産生tag檔案,ctag已經包含在最新的vim釋出版本中。有了tag檔案,就可以友善的跳轉了。
使用vim –t [tagname] 啟動vim可以直接打開相應的檔案,并定位到tagname的位置。在vim裡使用指令 :tag [tagname] 可以跳轉到tagname的定義,tagname可以使用正規表達式來進行模糊比對。
使用ctrl-] 可以直接跳動到目前詞的定義,如果目前詞不是tag,使用右邊的第一個tagname。這個跳動過程組成tag堆棧,沿堆棧跳回的指令是 ctrl-t ,沿堆棧上下移動的指令是 :tn (老的項),:tp (新的項)。列出tag堆棧使用 :tags 。
3.2. 預覽視窗
調用函數時,通常非常需要檢視函數的參數,使用tag技術和預覽視窗可以友善的實作這個功能。
指令 :ptag [tagname] 在預覽視窗顯示跳轉到tagname定義。目前詞作為tagname,可以直接輸入 ctrl-w } ,在預覽視窗檢視目前詞的定義。
關閉預覽視窗使用 :pclose 指令。
在預覽視窗打開一個檔案,使用 :pedit [filename] 指令。在目前檔案和包含檔案中搜尋某個詞,并顯示到預覽視窗中,可以使用 :psearch [name]。通常使用這個指令搜尋函數原型。
3.2. 移動
vim預設非常好的支援多種縮進方式。調整縮進可以使用 < (向左縮進)或者 >(向右縮進),前面可以加範圍,或者後面加motion。
使用 ={motion} 指令對一塊文字進行自動縮進。
找到對應的{}、[]、(),有時候比較麻煩,使用 % 指令可以非常友善找到對應的符号,除了上面的幾組符号,還可以是 /* */ 或者 #if #ifdef #else #elif #endif 等。
代碼塊通常是由{}包括的,在各個代碼塊之間移動是非常友善的。[{ 移動到光标所在塊首,]} 移動到所在塊尾。使用指令 [[ 跳轉到最外層的{,]] 跳轉到最外層的},最外層通常是C/C++程式的函數邊界。第二層的{使用 [m 指令,第二層的}使用 ]m 指令,通常java程式第二層才是函數的邊界。
在檔案内或者檔案間跳轉,有時候需要傳回上次光标所在位置。可以使用ctrl-o 指令跳轉到以前的位置,ctrl-i 指令跳轉到新的位置。使用指令 :jumps 列出所有跳轉清單。這些跳轉指令包括跳轉到标記、跳轉到tag、搜尋、替換、%、多于一行或一列的移動等。
3.3. 幫助
編寫程式時,經常需要使用 man [section] funcname 來檢視某個系統函數的幫助,在vim中使用 [section] K 指令直接檢視目前詞的manpage。
如果确實需要執行shell指令,可以在不離開vim環境和目前終端的情況下,使用 :!<cmd> 來執行一個shell指令,要獲得一個shell,可以使用 :shell 。
3.4. 編譯
說vim可以是內建開發環境,就是它可以友善的實作編輯-編譯-編輯的循環。如果你的程式有makefile,使用 :make 指令來進行編譯,而且更友善的是vim可以識别編譯輸出的錯誤,并定位到相應的位置。指令 :cc [num] 顯示第num個完整的錯誤消息。
在錯誤清單中移動,可以使用 :cn (下一個錯誤)和 :cp (上一個錯誤)。列出整個錯誤清單使用指令 :clist 。
Vim儲存多個錯誤清單,老的錯誤清單使用 :colder ,新的錯誤清單使用 :cnewer 。
這些指令被稱為QuickFix指令,上面介紹的grep指令也使用這些指令。