本文授權轉載自原作者, 未經許可請勿轉載
現實當中使用 Vim 來寫前端的人是少之又少,大多數人基本上都是使用 VSCode。但作為「編輯器之神」,不管使不使用 Vim 進行編碼,學習 Vim 的編輯模式都是有好處的。
本文會從最基本的使用和配置開始介紹作為前端工程師怎麼從零到一到開始使用 Vim。當然,我也不期望因為一篇文章而讓廣大的 VSCode 使用者轉用 Vim,是以最後會介紹如何在 VSCode 中使用 Vim 插件進行更高效的編碼。
基本使用
模式
與一般的編輯器最大的不同是,在 Vim 中有 4 種編輯模式,分别是:普通模式、插入模式、可視模式和指令行模式。使用 Vim 進行編輯就需要熟練的在各個模式之間進行切換。
普通模式
一般情況下每次進入編輯器的時候預設為普通模式,此時可以使用
h/j/k/l
來對光标進行移動。
普通模式下我們的輸入會被當作是一個指令,而指令是可以指定次數的。例如我們想要向下移動 10 行。我們可以在普通模式下連續按10次 j(類似于在普通編輯器中連續按 10 次向下鍵),除此之外我們也可以直接輸入 10j。
移動光标
在 Vim 中為了提高輸入效率而區分編輯模式,是以我們可以在盡量少的移動手指的情況下來進行光标的移動。以下是一些在普通模式下常用的用于移動光标的指令:
-
:分别代表着向左,下,上,右的方向移動h/j/k/l
-
:跳到行首/行尾^/$
-
:跳到下一個單詞頭/跳到上一個單詞頭w/b
-
:跳到下一個字元為 char 的位置/跳到上一個字元為 char 的位置f{char}/F{char}
h/j/k/l
等同于一般情況下的上下左右鍵,能夠在不移出鍵盤主區域的情況下移動光标。一種簡單的記憶方式是左右兩邊的
h/l
代表左右移動,而食指在鍵盤的預設位置
j
即為向下,反之
k
為向上。
如果你也是快捷鍵小能手的話,大機率也會使用
ctrl + a
或者
ctrl + e
來跳到行首或者行尾。在 Vim 的普通模式下我們可以使用
^/$
來進行這個操作,如果你熟悉正規表達式的話可以發現其實
^
就是表示行首的意思,而
$
是行尾的意思。
我們這個時候已經能夠上下左右移動光标和跳轉到行首行尾了。你可能會問,如果我隻想移動兩個單詞的位置的話該怎麼辦?這時候我們就可以使用
w/b
來移動到下一個單詞或者上一個單詞的單詞頭了。如上所提到的,在普通模式下指令是可以指定字數的,是以我們可以通過
2w
來移動兩個單詞的位置。
這時候又有了另外的一個疑惑,我們在移動光标的時候總不能還在腦子裡面算一下還有幾個單詞的位置吧?就算連續的按 w 來到達我們想要到的地方也有點蠢,是以在 Vim 中,我們還能夠使用
f{char}/F{char}
來向前/向後搜尋某個字元,然後跳過去。
是以,我們也可以通過
f{char}/F{char}
來操作光标跳轉到上圖的位置:
通過以上的各種跳轉方式可以滿足絕大多數跳轉的場景,熟練使用之後基本上就不要再通過滑鼠去移動光标了。
插入模式
插入模式其實大家都很熟悉,一般的編輯器預設的狀态就是 Vim 中的插入模式。在插入模式我們能夠進行插入字元、換行等操作。當然,在這個模式裡面也可以通過方向鍵移動光标,假如忽略其他的模式的話,完全可以把 Vim 當成普通的編輯器進行使用。但這樣的話就失去了學 Vim 的意義了,Vim 最值得學習的就是通過切換編輯模式來進行快速的移動/輸入/選擇。
在 Vim實用技巧[1] 中是這樣描述 Vim 中的普通模式的:
“
畫家在休息時不會把畫筆放在畫布上。對Vim而言也是這樣,普通模式就是Vim的自然放松狀态,其名字已經寓示了這一點。
“
誰說一定要切換到插入模式才行?我們可以重新調整已有代碼的格式,複制它們,移動其位置,或是删除它們。在普通模式中,我們有衆多的工具可以利用。
是以當我們使用 Vim 的時候,隻有想要輸入點什麼内容的時候才會進入插入模式。那麼我們如何從普通模式進入插入模式呢?
從普通模式進入插入模式有許多種方式:
-
:在光标的前面進行插入i
-
:在光标的後面進行插入a
-
:在光标所在行後面插入新一行o
變種指令
除此之外,我們還可以使用變種的
I/A/O
來使用不同的插入姿勢。
I
與
i
都是在前面進行插入,而不同的是
I
是在行首進行插入,操作有點類似與使用
^
将光标移動到行首之後在通過
i
進入插入模式。相似的
A
是在行尾進行輸入,約等于
$a
。
使用
o
在光标所在行的後面插入新一行進行插入,那麼如何在光标所在行的前面插入新一行呢?我們可以使用
O
來做類似
k
向上移一行然後
o
的操作。
簡單來說,可以這樣去記憶:
-
==I
^i
-
==A
$a
-
==O
ko
那麼如何在插入模式中切換到普通模式呢?答案是
Esc
或者
ctrl + [
。我們在任何模式當中都可以通過這兩種方式來切換回普通模式。是以一般的流程是普通模式中移動光标或者執行指令,然後在需要插入代碼的位置切換到插入模式進行編輯,編輯完成之後再切換回普通模式。就像是畫家思考完成之後拿起畫布畫,然後再放下畫筆繼續思考,以此往複。
如果你能夠練習到熟練的切換普通模式與插入模式的話,會發現在輸入效率上會有所提升。雖然這可能需要經曆一段陣痛期,一但形成肌肉記憶之後就可以不需要回憶那個指令是自己想要的操作了。這一點上跟從全拼輸入法切換到雙拼輸入法的時候的感覺類似。習慣了通過切換模式 + 指令的方式移動光标進行輸入後,移動滑鼠去點選的動作就會顯得非常的不自然。
可視模式
細心的你可能會發現,到目前為止我們隻提到了如何在普通模式下進入插入模式進行編輯操作。沒有提到如何在普通模式下面進行删除操作。
雖然你也可以在插入模式裡通過删除鍵進行删除,但此時隻能夠删除光标前的字元。顯然,我們總不能每次都切換到普通模式後移動光标,再進入插入模式進行删除操作。插入模式,最大的職責就是進行字元的插入。
是以,我們可以在普通模式中移動光标,然後通過
x
這個指令來删除對應的字元,并且通過
d
來删除指定範圍的内容。
以下是指令
d
的常用用法:
-
:删除目前光标所在的行dd
-
:删除目前光标所在的單詞diw
-
:從目前位置删除到某個字元前為止dt{char}
一般情況下我們會使用
dd
來删除一整行,但是真實的情況是我們可能不想一整行都删除,這時候你可以會想要進入插入模式使用滑鼠選中某一點要删除的内容然後按删除鍵。這有笨拙,我們有更友善的做法。
在普通模式裡面我們可以使用
v
進入可視模式,在可視模式中允許我們通過普通模式中移動光标的方式來選中某一段内容進行操作。使用的
v
指令是進入以字元為機關的可視模式,此外我們還有以行為機關的可視模式的指令
V
以及以列為機關的可視模式指令
ctrl + v
。這裡我們主要讨論 以字元為機關的可視模式
v
,另外可視模式的差別請自行了解。
剪切、複制與粘貼
當我們在普通模式中按
v
的時候,會把目前光标為主作為選區的起點,然後我們可以通過
h/j/k/l/w/b
等進行光标的移動,确定選區的終點。
在選擇了要操作的範圍之後我們就可以使用
d
指令來進行删除。使用
d
指令進行操作的時候實際上進行的是我們熟悉的「剪切」操作,我們可以通過另外的一個指令
p
在普通模式下進行粘貼操作。
與
d
指令類似的還有複制指令
y
,我們可以通過
yy
來複制一行内容。同樣的,也可以進入可視模式之後標明指定的内容進行複制,然後回到普通模式進行
p
粘貼操作。
文本對象
講到這裡就不得不說 Vim 非常有特色的文本對象(text object)了。文本對象能夠讓我們不移動光标的情況下來操作一定區域内的内容。
上面提到的
diw
删除目前光标所在的單詞的指令中就使用到了文本對象,我們可以把這一整個指令拆解為
d
+
iw
。這裡的
iw
即為文本對象,指的是目前單詞的意思。
我常用的其他文本對象:
-
:目前單詞以及空格aw
-
:括号内的内容i(
-
:括号以及括号内的内容a(
其中,
i(
和
a(
中的括号可以換成任何成對的符号,例如
i[
、
i{
、
i"
等,表示删除成對的符号範圍的内容。
既然
d
指令後面可以跟着文本對象,那麼同理
y
指令進行複制的時候也是可以跟着文本對象來指定複制的區域内容的。例如我們可以在普通模式下通過
yiw
來複制光标下的單詞:
類似的,我們還能夠快速的複制任何成對符号中的内容,這在複制代碼中的字元串時非常的有用。通過文本對象我們可以無需進入可視模式而進行一些簡單的操作。關于文本對象的内容非常的多,這裡由于篇幅原因就不詳細介紹了,有興趣的小夥伴可以自行去了解。
指令模式
在普通模式中我們輸入
:
會進入指令模式,在指令模式中我們可以使用與 shell 下的指令行類似的指令,比如我們退出 Vim 編輯器需要使用的
:qa
指令。
這裡隻介紹下我最常使用的指令:
-
:強制退出:q!
-
、:w
:保持目前檔案/儲存所有檔案:wa
-
:将字元串:s/old/new/g
替換為old
new
指令模式下支援非常多的指令[2],但一般來說我們不需要進入指令模式就可以完成我們的編輯操作了,并且把需要經常使用的指令模式下的指令映射到某一個快捷鍵當中來進行使用。
快捷鍵
例如我們可以把上面的字元串的指令映射到某一個快捷鍵上,在
~/.vimrc
檔案中添加如下内容:
然後在指令模式中重新載入我們的 vim 配置:
:source $MYVIMRC
。之後我們就可以通過
ctrl + f
這個快捷鍵來進入指令模式,并且自動的為你輸入
:s/
,我們隻需要在後面輸入對應的替換的正規表達式就可以了。
這裡的
nnoremap
表示的意思是普通模式下的非遞歸映射,此外我們還有
inoremap
,
vnoremap
等表示在不同模式下的非遞歸映射。
是以到底什麼是非遞歸映射(noremap)?這裡我們需要先介紹下遞歸映射,如果我們有如下的配置:
那麼就相對于是
map c b
,即快捷鍵的映射會被其他的映射所影響。而如果是非遞歸映射的話:
當我們按下 c 的時候會直接映射到 a 而不會繼續映射到 c。一般情況下我們使用
noremap
即可。對于
map
以及
noremap
的詳細的介紹可以檢視這篇文章:vim的幾種模式和按鍵映射[3]。
另外,在 Vim 中還有
Leader
鍵的概念,它有點像是我們按快捷鍵的時候的
ctrl
或者
cmd
。但不同的是我們不需要按住它。例如我們可以為普通模式下的某個插件的功能或者指令添加如下快捷鍵:
這樣我們就可以先按
Leader
鍵,然後在按
j
來映射到
2j
上。日常情況下我們會把安裝的插件按照自己喜歡的組合方式配置快捷鍵,這個時候就會經常使用到
Leader
鍵。
Leader
鍵在預設的情況下是
,
,即我們上面的設定的快捷鍵是
,j
映射到
2j
。此外我們可以通過如下配置将
Leader
鍵修改為其他的按鍵,我的習慣是把
Leader
鍵設定為空格。
喜歡使用 Vim 的其中一個原因其實也跟快捷鍵有關,在 Vim 中我們可以相對自由的設定自己喜歡的快捷鍵,而不會像其他編輯器一樣有諸多限制,并且容易跟現有的預設快捷鍵産生沖突。
宏
Vim 中提供了「宏」來友善進行一系列的操作,簡單來說就是在開始前開啟宏的錄制,然後進行一頓操作後停止宏的錄制。這樣會把我們的操作都儲存到寄存器中,執行宏的時候會從寄存器上取出來進行回放操作。
一般情況下我會通過
qq
來開啟宏錄制,把相關的操作錄制到名為
q
的寄存器上(第一個
q
表示開始宏的錄制,第二個
q
表示寄存器)。再按一次
q
将會停止宏的錄制。
例如我們要給 10 行的文字添加相同的字首和字尾,我們可以開始宏的錄制後進行以下操作:
I
、
prefix
、
Esc
、
A
、
suffix
、
Esc
、
j
對第一行進行操作,然後按
q
停止宏的錄制。最後我們通過
@q
來回放存放在寄存器 q 中的操作來對第二行生效。
那麼剩下的 8 行難道要按 8 次
@q
來進行回放嗎?顯然,宏跟指令一樣都适用在前面加執行次數的規則,是以我們可以通過
[email protected]
來完成剩下的工作:
這種通過錄制和回放宏來執行重複機械式的操作非常有用,我經常會使用宏來處理枚舉,JSON 或者對象的轉換上。
宏作為 Vim 中的意大利炮非常的強大,這裡隻做了最基本的時候介紹,關于宏還有非常多的使用技巧,有機會的話再寫另一篇文章進行介紹。
簡單配置
目前到這裡我們已經學會了如何使用 Vim 進行最基本的光标移動、輸入、删除和快捷鍵映射等。但是對于一個什麼配置都沒有的 Vim 編輯器來說實在是太簡陋了。是以我們需要對 Vim 進行簡單的配置。
預設情況下,我們可以在
~/.vimrc
中添加我們自己的個性化配置(如果不存在這個檔案需要自行建立)。
顯示相對行号
通過
set number
可以顯示目前光标所在行的行号,而
set relativenumber
将顯示相對光标所在行的行數,友善我們執行類似
10j
,
4dd
之類對行進行的操作。
縮進設定
在普通模式下,我們可以通過
>>
或者
<<
來調整縮進,有點類似與普通的編輯器中的
tab
與
shift + tab
。但每一次都按兩下
>
來進行縮進顯得非常的繁瑣,是以我們可以添加如下快捷鍵映射:
這樣我們就可以在普通模式下愉快的使用
>
和
<
縮進了!
說到縮進那麼就免不了提到用空格還是用 Tab 了。理想的情況下我是不希望我一直按空格的,但是我又不希望使用 Tab 來進行縮進,是以我會添加如下配置:
這裡的意思是我們使用 2 個空格來進行縮進,不管是在普通模式還是在插入模式中按
>
或者
Tab
進行縮進都使用空格。如果想了解 Vim 縮進設定推薦看這篇文章:Vim縮進有關的設定總結[4]
更好的光标跳轉
如果你和我一樣,覺得使用
^
或者
$
來跳轉到行首和行尾很别扭的話,可以像我一樣考慮添加相關的快捷鍵映射:
這裡額外的添加了兩條映射,目的是讓我們大寫的
H/J/K/L
更加符合直覺:我們可以通過
J
或者
K
來到達檔案的開頭和結尾,通過
H
和
L
來到達目前行的行首和行尾。簡單來說,它就是光标移動的放大版。
在 VS Code 中使用
按照一般的套路,這裡我們會接着讨論如何給 Vim 添加配置以及插件,使得 Vim 更加好用。但絕大多數的人在讀了這篇文章之後也不會有換編輯器的想法,是以我們這裡會聊聊如何在現有的編輯器中更好的使用 Vim 模式進行編輯,這裡我們主要介紹如何在 VS Code 中使用。
在 VS Code 中使用 Vim 模式進行編輯可以通過兩個插件來實作,分别是:
- VSCodeVim/Vim[5]
- asvetliakov/vscode\-neovim[6]
VSCodeVim/Vim
說到 VS Code 上的 Vim 插件就必須要提 VSCodeVim/Vim 了。該插件在 VS Code 中模拟了 Vim 中的模式切換以及基本的指令。但比較可惜的是我們不能複用前面所提到的 .vimrc 配置檔案,我們需要在
settings.json
裡通過 JSON 的方式來進行設定,添加快捷鍵等。
除此之外如果我們要通過快捷鍵來調用 VS Code 中的插件的話也是同樣的需要在
settings.json
進行配置。
作為 Vim 使用者的我是不喜歡這種方式的,我更加希望通過 .vimrc 來複用原先的配置,無縫的切換到 VS Code 中。而 VSCodeVim/Vim 需要重新寫配置,并且配置的過程過于複雜,是以我很快就放棄了這個插件。
但如果是作為 VS Code 使用者想在 VS Code 中慢慢開始使用 Vim 的編輯模式的話,不失為一個好的入門插件。
asvetliakov/vscode-neovim
由于 VSCodeVim/Vim 插件配置比較繁瑣,并且使用起來也稍微有點卡。我放棄 Vim 插件在 VS Code 中使用了一段時間,然後我發現了 vscode-neovim 這個插件。
vscode-neovim 插件內建了 neovim 與 VS Code,完美的滿足了我的需求,它能夠讀取現有的 Vim 配置并且使用起來非常的順滑。
隻需要在 Vim 的配置中通過
if !exists('g:vscode')
将不需要的 Vim 插件剔除就可以直接使用了。與 neovim 內建的好處就是我們既可以使用部分 Vim 插件又可以使用 VS Code 插件。當然,這也提高了門檻,該插件依賴 neovim 0.5.0+ 以上的版本。對于剛入門 Vim 的同學來說安裝的步驟過于複雜,這裡就不向 Vim 新手推薦了。
熟悉 neovim 的同學感興趣可以試試。或者檢視我在 vscode-neovim 中使用的 Vim 配置[7]。
最後
雖然本文已經非常的長了,但是依然對于 Vim 中的快速分屏與切換以及其他非常有用的功能或者技巧沒有進行介紹。這裡強烈的建議感興趣的小夥伴看 簡明Vim 練級攻略[8] 或者 Vim 實用技巧[9] 這本書來進一步的了解。
如果是面向 VS Code 使用者的話,本篇文章到這裡就結束了。原本是打算繼續寫 Vim 中相關的一些好用的插件推薦的,但考慮到閱讀本文的同學可能大部分對 Vim 比較陌生,是以就沒有繼續再寫。如果你感興趣的話歡迎留言,後面可以專門寫一篇。
最後,不管看完文章的你是開始使用 Vim 編輯模式還是重新審視目前的輸入習慣,希望大家都能夠有所收獲。
參考資料
[1]
Vim實用技巧: https://book.douban.com/subject/26967597/
[2]
支援非常多的指令: http://vimdoc.sourceforge.net/htmldoc/vimindex.html#ex-cmd-index
[3]
vim的幾種模式和按鍵映射: http://haoxiang.org/2011/09/vim-modes-and-mappin/
[4]
Vim縮進有關的設定總結: https://www.kawabangga.com/posts/2817
[5]
VSCodeVim/Vim: https://marketplace.visualstudio.com/items?itemName=vscodevim.vim
[6]
asvetliakov/vscode-neovim: https://marketplace.visualstudio.com/items?itemName=asvetliakov.vscode-neovim
[7]
使用的 Vim 配置: https://github.com/ahonn/dotfiles/tree/master/vim/vscode
[8]
簡明Vim 練級攻略: https://coolshell.cn/articles/5426.html
[9]
Vim 實用技巧: https://book.douban.com/subject/25869486/
[10]
Vim 實用技巧: https://book.douban.com/subject/25869486/
[11]
簡明Vim 練級攻略| | 酷殼- CoolShell: https://coolshell.cn/articles/5426.html
[12]
Vim Awesome: http://vimawesome.com/
[13]
Vim documentation: index: http://vimdoc.sourceforge.net/htmldoc/vimindex.html
[14]
Learn Vimscript the Hard Way: https://learnvimscriptthehardway.stevelosh.com/
[15]
vim的幾種模式和按鍵映射: http://haoxiang.org/2011/09/vim-modes-and-mappin/
[16]
Vim縮進有關的設定總結: https://www.kawabangga.com/posts/2817