天天看點

便利的開發編輯工具-vim

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指令也使用這些指令。