【vim】常用總結
簡介
什麼是vim?
Linux下兩大編輯神器之一 vim
- Linux/Unix下使用最多的編輯器
- vi的改進版
- 可能是最難上手的編輯器之一
為什麼要學習vim?
都21世紀了,為什麼還需要學習vim?
- 只要你用伺服器,vim就是個必備技能
- 後端和運維工程師必須掌握的編輯器,不然伺服器上操作很尷尬
- 可以純鍵盤編輯,提升編輯效率
初識vim
據說Stackoverflow幫助過上百萬開發者退出過vim!
- 輸入
vim
命令進入vim - 進去之後似乎沒法輸入東西,起始默認進去是normal模式
- 使用
:q
可以退出vim
開始編輯
進入編輯模式就可以像其他編輯器一樣編輯了
- 使用
i
(insert)進入編輯模式,開始輸入文字 i
表示(insert),a
(append),o
(open a line below)- 使用Esc可以退出編輯模式,又回到normal模式。
-
使用
:wq
保存退出w(write),q(quit)
insert -> normal:使用Esc
normal -> insert:(小寫是操作字元,大寫是操作行)
-
i
:(insert)表示進入insert編輯模式後,在當前字元的前面插入insert
-
a
:(append)表示進入insert編輯模式後,在當前字元後附加插入append
-
o
:(open a line below)表示進入insert編輯模式後,在當前行下新啟一行插入append
-
I
:(insert before line)表示在當前行的最前面插入insert before line
-
A
:(append after line)表示在當前行的最後附加插入append after line
-
O
:(append a line above)表示在當前行上新啟一行插入append a line above
保存:
-
:w
:(write)寫入,保存write
-
:q
:(quit)退出quit
-
:wq
:(write and quit)保存並退出write and quit
vim,為什麼你有這麼多模式
怪異的vim模式
vim和其他很多編輯器的區別在於多種模式
- 進入vim默認是normal(普通)模式?為什麼不是編輯模式呢?
- 使用
a
(append)、i
(insert)等進入編輯模式 - 還有cmd命令模式和
v
(visual)可視化模式
為什麼進入vim不能插入-normal模式
奇怪的是,為什麼vim進入之後不像其他編輯器一樣直接插入?
-
進入Vim默認是normal(普通)模式。使用
Esc
從插入回到普通模式 -
普通模式下可以進行各種命令操作和移動
-
大部分情況下你是在瀏覽而不是編輯,所以Vim默認是normal
Insert(插入)模式
插入模式下Vim可以直接編輯,和其他編輯器一樣
-
使用
i
(insert) 、a
(append) 、o
(open a line below)進入插入模式 -
使用Esc退出插入模式到normal模式
Command(命令)模式
Normal模式下輸入:
之後執行命令,比如保存退出:wq
一氣呵成
- 顧名思義,執行Vim命令,比如保存
:w
,退出:q
- 比如分屏:
:vs
(vertical split),:sp
(split) -
比如使用:
:% s/foo/bar/g
全局替換%:表示本文件全部文本
g:表示全局替換
Visual(可視)模式
Visual模式一般用來塊狀選擇文本(類比使用Alt+滑鼠拖動)
- Normal模式下使用
v
進入visual選擇 - 使用
V
選擇行 - 使用
ctrl+v
進行方塊選擇
vim編輯小技巧
如何快速糾錯(insert模式下)
程式碼就像人生,總是經常出錯,需要我們快速修正
- 進入Vim之後首先使用a/i/o之一進入插入模式
ctrl+h
刪除上一個字元,ctrl+w
刪除上一個單詞,ctrl+u
刪除當前行
快速切換insert和normal模式
很多鍵盤的鍵位設置, Esc
按起來不方便,不方便切換到normal
- 使用
Ctrl+c
代替Esc
(但是可能會中斷某些插件)或者ctrl+[
gi
快速跳轉到你最後一次編輯的地方並進入插入模式- 在配置章節我們會講解如何映射方便的快捷鍵來替代Esc
vim快速移動大法
反人類的hjkl
眾所周知,vim normal模式使用了反人類的hjkl來移動
- 據說編輯器作者在編寫vim的時候鍵盤還沒流行上下左右按鍵
h
(左) ,j
(下) ,k
(上) ,l
(右) ,移動也不會讓手指脫離主鍵盤區- 相信我,逼著自己使用hjkl一段時間之後,你會體會到它非常有效率
使用hjkl
只需要幾天的適應,你就可以熟練使用hjkl來移動
在單詞之間「飛舞」(normal模式下)
在單詞之間移動是我們瀏覽操作中最常使用的命令
w/W
移到下一個word/WORD開頭。e/E
下一個word/WORD尾b/B
回到上一個word/WORD開頭,可以理解為backword- word指的是以非空白符分割的單詞, WORD以空白符分割的單詞
行間搜索移動
同一行快速移動的方式其實是搜索一個字元並且移動到該字元
-
使用
f{char}
可以移動到char字元上,t{char}
移動到char的前一個字元f:(find)
t:(until)可以配合刪除使用,如
dt)
從當前字元開始刪除直到)。 - 如果第一次沒搜到,可以用分號(
;
)/逗號(,
)繼續搜該行下一個/上一個 -
大寫的
F{char}
表示反過來搜前面的字元
vim水平移動
如何快速移動到一行的行首或者行尾呢?
-
0
移動到行首第一個字元,^
移動到第一個非空白字元^:在正則表達式中,表示行的開頭
-
$
移動到行尾,g_
移動到行尾非空白字元$:在正則表達式中,表示行的結尾
-
記住常用的0和$就可以滿足日常需求了
Vim垂直移動
我們還可以在句子(sentence)和段落(paragraph)間移動(不常用)
- 使用括弧
()
在句子間移動,你可以用:help (
來查看幫助 - 使用
{}
在段落之間移動 - 插件章節我們會講如何用easy-motion插件移動,這些命令就都不用記憶啦
Vim頁面移動
翻頁命令太多, 2/8定律,記住常見的就能滿足需求
gg/G
移動到文件開頭和結尾,你可以使用ctrl+o
快速返回nG
移動到文件第n行,可以配合命令使用,如dnG
表示刪除到第n行H/M/L
跳轉到螢幕的開頭(Head),中間(Middle)和結尾(Lower)Ctrl+u
,ctrl+f
上下翻頁(upword/forward)。zz
把螢幕置為中間
什麼是vim的text object
Text Object(文本對象)
如果你學過主流的程式語言,一定知道面向對象編程
- Vim里文本也有對象的概念,比如一個單詞,一段句子,一個段落
- 很多其他編輯器經常只能操作單個字元來修改文本,比較低效
- 通過操作文本對象來修改要比只操作單個字元高效
文本對象操作方式
之前我們已經使用過文本對象了,回憶下dw
(刪除一個單詞)
[number] <command> [text object]
- 或者
<command> [number] [text object]
- number表示次數,command是命令,
d
(delete),c
(change),y
(yank) -
text object是要操作的文本對象
比如單詞
w
(word),句子s
(sentence),段落p
(paragraph),標籤t
(tag)
通過示例來學習
iw
表示inner word,如果鍵入viw
命令,那麼首先v
將進入選擇模式,然後iw
將選中當前單詞。aw
表示around word,它不但會選中當前單詞,還會包含當前單詞之後的空格。
以下實例中的[]表示作用範圍:
-
iw
This is a [test] sentence. -
aw
This is a [test ]sentence. -
iw
This is a […test…] sentence. -
aw
This is a […test… ]sentence. -
is
…sentence. [This is a sentence.] This… -
as
…sentence. [This is a sentence. ]This…
End of previous paragraph. -
ip
[This is a paragraph. It has two sentences.]
The next.
End of previous paragraph. -
ap
[This is a paragraph. It has two sentences.
]The next. -
ip
<xml>[hello world]</xml> -
ap
[<xml>hello world</xml>] -
i(
ori)
1*([2+3]) -
a(
ora)
1*[(2+3)] -
i<
ori>
The <[tag]> -
a<
ori>
The [<tag>] -
i{
ori}
some {[code block]} -
a{
ora}
some [{code block}] -
i[
ori]
some [[code block]] -
a[
ora]
some [[code block]] -
i"
The “[best]” -
a"
The [“best”] -
i'
The ‘[best]’ -
a'
The [‘best’]
vim快速增刪改查
數字+命令
表示多次執行命令,如 2dw
或者 命令+數字+對象
,如 d2w
Vim增加字元
增加字元就是進入插入模式,開始敲鍵盤吧
- 進入插入模式編輯文本
- 使用a/i/o進入插入模式
- 還記得A/I/O是什麼作用么?
Vim快速刪除
如何快速刪除一個字元或者單詞呢 ?
- Vim在normal模式下使用
x
快速刪除一個字元 -
使用
d
(delete)配合文本對象快速刪除一個單詞daw
(delete around word)dw
:默認為daw -
d
和x
都可以搭配數字來執行多次
Vim快速修改
相比刪除,更常用修改,一般是刪除之後改成我們期望的文本
- normal 模式下,常用有三個,
r
(replace),c
(change),s
(substitute) - 使用
r
可以替換一個字元。 - 使用
s
替換並進入插入模式 - 使用
c
配合文本對象,我們可以快速進行修改整個文本對象。如ci"
、ciw
Vim查詢
查詢單詞也是一個常用操作
- 使用
/
或者?
進行前向或者反向搜索 -
使用
n/N
跳轉到下一個或者上一個匹配next
-
使用
*
或者#
進行當前單詞的前向和後向匹配*:在正則表達式中表示出現0次或多次。
vim如何搜索替換
Vim替換命令
substitute命令允許我們查找並且替換掉文本,並且支援正則式
:[range]s(substitute)/{pattern}/{string}/[flags]
- range:表示範圍。比如:
10,20
表示10-20行,%
表示本文件中所有的行。 - pattern:是要替換的模式,正則表達式
- string:是替換後文本
注意:此命令不僅能用來替換,還能用來刪除!如 刪除所有星號*,命令為
:%s/\*//g
替換範圍range
你可以在命令之前設置一個範圍。以下是一些方法:
m, n
:表示範圍為從第 m 行到第 n 行-
1,
:表示範圍為從第 1 行到當前行注意:第一行的行號是已知的,行號為 1;而最後一行的行號是未知的,所以我們只用給最後一行分配一個符號代表即可。
除了數字之外,還可以使用這些符號作為範圍:
.
:表示當前行,可以省略。如.,3
表示當前行到第 3 行。$
:表示文件中的最後一行。如3,$
表示第 3 行到最後一行。+n
:表示當前行的後 n 行。3,+1
或者3,.+1
,.
可以用或不用,表示第 3 行到當前行後的 1 行。-
%
:表示本文件中所有的行。在 Vim 中,
%
通常表示整個文件。
示例:
:1,5g/console/d
匹配第 1 行和第 5 行之間的字元串”console”並刪除它們。:,5g/console/d
如果逗號之前沒有地址,則從當前行開始。它在當前行和行 5 之間尋找字元串”console”並刪除它們。:3,g/console/d
如果逗號後沒有地址,則以當前行結束。它尋找第 3 行和當前行之間的字元串”console”並刪除它們。:3g/console/d
如果僅傳遞一個沒有逗號的地址,則它只執行第 3 行的命令。它查看第 3 行,如果字元串”console”,它將刪除它。
替換模式pattern
請參照正則表達式
替換標誌位flag
Flags有幾個常用的標誌
- 默認為空,表示僅替換一行上的第一個匹配項
-
g
(global) 表示改變一行上的每個符合條件的匹配項,全局範圍內執行global
-
c
(confirm)表示確認 ,可以確認或者拒絕修改confirm
-
n
(number)報告匹配到的次數而不替換,可以用來查詢匹配次數number
& Reuse the flags from the previous substitute command. Must be passed as the first flag.
g Replace all matches in the line.
c Ask for substitution confirmation.
e Prevent error message from displaying when substitution fails.
i Perform case insensitive substitution
I Perform case sensitive substitution
There are more flags that I do not list above. To read about all the flags, check out .:h s_flags
Vim如何對匹配行執行命令
global命令實際上是分成兩步執行:首先掃描[range]
指定範圍內的所有行,給匹配{pattern}
的行打上標記;然後依次對打有標記的行執行{command}
命令,如果被標記的行在對之前匹配行的命令操作中被刪除、移動或合併,則其標記自動消失,而不對該行執行{command}命令。{command}
可以是一個ex命令,也可以是用|
分隔的多個ex命令,這樣我們就可以對被標記行,或從標記行定址到的行進行多種不同的操作。
全局命令執行步驟:
- 掃描
[range]
指定範圍內的所有行,給匹配{pattern}
的行打上標記; - 依次對打有標記的行執行
{command}
命令,如果被標記的行在對之前匹配行的命令操作中被刪除、移動或合併,則其標記自動消失,而不對該行執行{command}命令。
全局命令(The Global Command)
Vim 的全局命令用於同時在多行上運行命令行命令。
特別注意:全局命令是對匹配的行,來進行行操作,操作對象是整個行,而不僅僅是匹配的那一部分字元。
全局命令具有以下語法:
:[range]g(global)/{pattern}/{command}
該模式匹配包含該模式的所有行,類似於 substitute 命令中的模式。該命令可以是任何命令行命令。
全局命令的工作方式是對匹配pattern
的每一行執行command
命令。
反向全局命令
要在不匹配的行上運行全局命令,可以運行:
-
:[range]g(global)!/{pattern}/{command}
-
或
:v/{pattern}/{command}
通過示例來學習
如果你有下列表達式:
const one = 1;
console.log("one: ", one);
const two = 2;
console.log("two: ", two);
const three = 3;
console.log("three: ", three);
要刪除所有包含「控制台」的行,您可以運行::g/console/d
結果:
const one = 1;
const two = 2;
const three = 3;
如果使用反向全局命令,則它將刪除所有不包含「console」的行
vim如何編輯命令(如 粘貼一個命令)
問題速成解決方式
怎樣在vim的命令行中拷貝,粘貼?
在vim的普通模式下,輸入:
進入命令行模式,我們可以在螢幕下方輸入我們想讓vim執行的命令。
有時候,我們需要在命令行中執行拷貝粘貼,例如 我們想要查找替換正文中的特殊字元,但我們又不知道怎麼在命令行中輸入這個特殊字元。
查找還好說,不一定非要在命令行中輸入這個特殊字元,只要把游標放在這個特殊字元上,按*
向下查找,按#
向上查找。
但是如果我們要替換這個特殊字元,就必須在命令行中輸入它了,但是又不知道怎麼輸入這個特殊字元,怎麼辦?
答案是拷貝粘貼,先在正文中複製這個字元,然後粘貼在命令行中。
可是怎麼在命令行中實現粘貼呢?別急,介紹一個好東西:命令行窗口。
在正常模式下,輸入q:
,就打開了命令行窗口。
命令行窗口中都是我們輸入過的命令,在這個窗口中我們可以像編輯正文一樣編輯新的命令,或修改舊的命令。
因為像編輯普通緩衝區一樣,自然可以拷貝粘貼了。
編輯完之後,在想要執行的命令上按回車,就ok了。
命令執行後,命令行窗口也自動關閉了。
命令行窗口
「歷史記錄」窗口顯示以前使用的命令行命令的列表,但是不能從「歷史記錄」窗口執行該命令。若要在瀏覽時執行命令,請使用命令行窗口。有三個不同的命令行窗口:
q: Command-line window
q/ Forward search window
q? Backward search window
q(quick,快速的):
q:
:命令行命令編輯,可以看到所有使用過的命令的歷史記錄q/
:向前搜索命令編輯,可以看到所有使用過的向前搜索命令的歷史記錄q?
:向後搜索命令編輯,可以看到所有使用過的向後搜索命令的歷史記錄
運行 q:
以啟動命令行命令的命令行窗口。Vim 將在螢幕底部啟動一個新窗口。您可以使用 Up 或 Ctrl-p 鍵向上遍歷,使用 Down 或 Ctrl-n 鍵向下遍歷。如果按下回車,Vim 將執行該命令。若要退出命令行窗口,請按 Ctrl-c、 Ctrl-w c 或鍵入: quit。
類似地,要啟動用於搜索的命令行窗口,可以運行向前搜索的 q/
和向後搜索的 q?
。
vim複製粘貼與暫存器的使用
Vim Normal模式複製粘貼
初學者會感覺Vim複製粘貼比較奇怪,先從normal模式學習
- normal模式下複製粘貼分別使用
y
(yank)和p
(put) ,剪貼d
(delete)和p
(put) - 我們可以使用
v
(visual)命令選中所要複製的地方,然後使用p
粘貼 - 配合文本對象:比如使用
yiw
複製一個單詞,yy
複製一行
Vim里的剪貼(Cut)複製(copy)粘貼(paste)
分別是delete/yank/put
Insert模式下的複製粘貼
很多人會使用滑鼠進行選中,然後使用ctrl+v
或者cmd+v
粘貼
- 這個和其他的文本編輯器差不多,但是粘貼程式碼有個坑
-
很多人在vimrc中設置了autoindent ,粘貼Python程式碼縮進錯亂
這個時候需要使用:set paste
和:set nopaste
解決 -
Ctrl-r {register}
:可以粘貼暫存器{register}中的內容。系統剪貼板暫存器為
"+
什麼是Vim的暫存器?
你有沒有好奇? Vim在normal模式下複製/剪貼的內容去了哪?
- Vim里操作的是暫存器而不是系統剪貼板,這和其他編輯器不同
- 默認我們使用
d
刪除或者y
複製的內容都放到了「無名暫存器」 - 用
x
刪除一個字元放到無名暫存器,然後p
粘貼,可以調換倆字元
深入暫存器(register)
Vim不使用單一剪貼板進行剪貼、複製與粘貼,而是多組暫存器
- 通過
"{register}
前綴可以指定暫存器,不指定默認用無名暫存器 - 比如使用
"ayiw
複製一個單詞到暫存器a中,"bdd
刪除當前行到
暫存器b中 - Vim中
""
表示無名暫存器,預設使用。""p
其實就等同p
其他常見暫存器
除了有名暫存器a-z, Vim中還有一些其他常見暫存器
- 複製專用暫存器
"0
:使用y
複製文本同時會被拷到複製暫存器0 - 系統剪貼板
"+
:可以在複製前加上"+
複製到系統剪貼板 - 其他一些暫存器比如
"%
:當前文件名,".
:上次插入的文本
:set clipboard=unnamed
:可以讓你直接複製粘貼系統剪貼板內容
強大的vim宏(macro)
從需求說起
從一個需求說起,給多行url鏈接加上雙引號,你會怎麼做呢?
什麼是Vim宏(macro)
很多使用Vim很久的Vimer都沒用過宏
- 宏可以看成是一系列命令的集合
- 我們可以使用宏「錄製」一系列操作,然後用於「回放」
- 宏可以非常方便地把一系列命令用在多行文本上
如何使用宏
宏的使用分為錄製和回放,是不是有種拍電影的感覺
-
Vim使用
q{register}
來錄製,同時也是q
結束錄製quick
- 使用
q{register}
選擇要保存的暫存器,把錄製的命令保存其中 - 使用
q
結束錄製 -
使用
@{register}
回放暫存器中保存的一系列命令
用宏解決剛才的問題
現在你知道宏怎麼用了,如何解決剛才的問題呢?
- 先給一行加上雙引號,然後再回放到其他所有行
- 我們先使用
q{register}
開始錄製,給一行加上雙引號,之後使用q
退出 -
在剩下的所有行中回放錄製的宏(使用可視模式選中,然後使用宏)
需要使用v可視模式選擇所有url,再使用
:normal
在命令模式下使用normal模式下的命令。
不使用宏解決剛才的問題
可以通過可視模式選擇所有url
可以使用:normal
,在命令模式使用normal模式的命令
:normal I"
:normal A"
vim補全大法
什麼是補全?
只要手速快,補全什麼的都是浮雲
- 補全是根據當前環境上下文由編輯器「猜」你想輸入的東西
- 比如補全一個單詞、文件名,或者程式碼中的函數名、變數名等
- Vim中提供了多種補全功能,還可以由插件拓展功能實現程式碼補全
vim中常用的補全
Vim中有很多種補全的方式
命令 | 補全類型 |
---|---|
<C-n> |
普通關鍵字 |
<C-x><C-n> |
當前緩衝區關鍵字 |
<C-x><C-i> |
包含文件關鍵字 |
<C-x><C-]> |
標籤文件關鍵字 |
<C-x><C-k> |
字典查找 |
<C-x><C-l> |
整行補全 |
<C-x><C-f> |
文件名補全 |
<C-x><C-o> |
全能(Omni)補全 |
常見的三種補全類型
記不住不用擔心,根據筆者經驗,最常用的就三種
- 使用
ctrl+n和ctrl+p
補全單詞 - 使用
ctrl+x和ctrl+f
補全文件名 - 使用
ctrl+x和ctrl+o
補全程式碼,需要開啟文件類型檢查,安裝插件
vim多文件操作
Buffer Window Tab
我們先來介紹幾個多文件操作相關的概念
- Buffer是指打開的一個文件的記憶體緩衝區
- 窗口是Buffer可視化的分割區域
- Tab可以組織窗口為一個工作區
Buffer
Buffer-什麼是緩衝區?
- Vim 打開一個文件後會載入文件內容到緩衝區
- 之後的修改都是針對記憶體中的緩衝區,並不會直接保存到文件
- 直到我們執行
:w
(write)的時候才會把修改內容寫入到文件里
Buffer切換
那如何在buffer之間切換呢?
- 使用
:ls
會列舉當前緩衝區,然後使用:b n
跳轉到第n個緩衝區 :bpre
、:bnext
、:bfirst
、:blast
- 或者用
:b buffer_name
加上tab
補全來跳轉
Window窗口
窗口是可視化的分割區域
- 一個緩衝區可以分割成多個窗口,每個窗口也可以打開不同緩衝區
<Ctrl+w>s
水平分割,<Ctrl+w>v
垂直分割。或者:sp
和:vs
- 每個窗口可以繼續被無限分 割(看你螢幕是否夠大)
分割窗口示例
窗口分割效果
如何切換窗口
切換窗口的命令都是使用Ctrl+w
(window)作為前綴
命令 | 用途 |
---|---|
<C-w>w |
在窗口間循環切換 |
<C-w>h |
切換到左邊的窗口 |
<C-w>j |
切換到下邊的窗口 |
<C-w>k |
切換到上邊的窗口 |
<C-w>l |
切換到右邊的窗口 |
如何重排窗口?
重排窗口可以改變窗口的大小:h window-resize查看文檔
命令 | 用途 |
---|---|
<C-w>= |
使所有窗口等寬、等高 |
<C-w>_ |
最大化活動窗口的高度 |
<C-w>| |
最大化活動窗口的寬度 |
[N]<C-w>_ |
把活動窗口的高度設為[N]行 |
[N]<C-w>| |
把活動窗口的寬度設為[N]列 |
Tab(標籤頁)將窗口分組
Tab是可以容納-系列窗口的容器(:h tabpage)
- Vim的Tab和其他編輯器不太一樣,可以想像成Linux的虛擬桌面
- 比如一個Tab全用來編輯Python文件, 一個Tab全是HTML文件
- 相比窗口, Tab一般用的比較少, Tab太多管理起來也比較麻煩
Tab(標籤頁)操作
Tab使用不多,簡單了解一下常用操作就好
命令 | 用途 |
---|---|
:tabe[edit] {filename} |
在新標籤頁中打開{filename} |
<C-w>T |
把當前窗口移到一個新標籤頁 |
:tabc [close] |
關閉當前標籤頁及其中的所有窗口 |
:tabo [only] |
只保留活動標籤頁,關閉所有其他標籤頁 |
Tab(標籤頁)切換操作
如何切換不同的標籤頁,一般建立兩個就好,太多不好操作
Ex命令 | 普通模式命令 | 用途 |
---|---|---|
:tabn[next] {N} |
{N}gt |
切換到編號為{N} 的標籤頁 |
:tabn[next] |
gt |
切換到下一標籤頁 |
:tabp[previous] |
gT |
切換到上一標籤頁 |