- Published on
Vim 編輯基礎:輸入、刪除和複製貼上

Vim 系列文章
- Vim 生存指南:模式與移動
- Vim 編輯基礎:輸入、刪除和複製貼上 (本篇)
- Vim 選取模式:三種 Visual Mode
- Vim 語法系統:動詞 + 量詞 + 名詞
- Vim 搜尋技巧:快速定位與取代
- Vim 效率倍增:重複與自動化
- Vim 客製化:設定與 IDE 整合
上一篇我們學會了在 Vim 中移動。但光會移動還不夠,今天要學的是編輯:怎麼輸入文字、怎麼刪除、怎麼複製貼上
先搞懂 Vim 的游標
在一般編輯器裡,游標是一條細線,停在字元之間
h e l l o
^ ← 游標在 h 和 e 之間
但 Vim 不一樣。在 Normal Mode 中,游標是一個方塊,停在字元上面
h e l l o
^(游標「在」e 上面)
這個設計是有原因的:Vim 的很多指令是「對游標所在的字元做操作」。例如 x 會刪除游標下的字元,r 會取代游標下的字元
理解這點很重要,因為等下學 i 和 a 時,你會發現它們的差別就在於:
i在游標所在字元的前面插入a在游標所在字元的後面插入
進入 Insert Mode 的方式
在第一篇我們提到 Vim 有不同的模式,其中 Insert Mode 是用來輸入文字的。要怎麼進入 Insert Mode?有很多種方式,每種都有它的用途
基本方式
| 指令 | 動作 | 記憶 |
|---|---|---|
i | 在游標前插入 | insert |
a | 在游標後插入 | append |
I | 在行首(非空白)插入 | 大寫 = 行 |
A | 在行尾插入 | 大寫 = 行 |
o | 在下方新增一行 | open line below |
O | 在上方新增一行 | 大寫 = 上方 |
i vs a
hello
^(游標在 l 上)
按 i 後輸入 X
結果:heXllo ← 在游標「前」插入
按 a 後輸入 X
結果:helXlo ← 在游標「後」插入
I vs A
I 和 A 是 i 和 a 的「整行版」
hello world
^(游標在 w 上)
按 I
hello world
^ ← 跳到第一個非空白字元,會在 h 前面,進入 Insert Mode
按 A
hello world
^ ← 跳到行尾,會在 d 後面,進入 Insert Mode
換句話說:
I=^+i(跳到行首非空白 + 插入)A=$+a(跳到行尾 + 插入)
A 超常用,因為「在行尾加東西」是很常見的需求
o vs O
1 current line
^(在 l 上)
按 o:在「下方」開新行
1 current line
2
^(游標在第 2 行對齊 c 的位置)
按 O:在「上方」開新行
1
^(游標在第 1 行對齊 c 的位置)
2 current line
刪除 (Delete)
刪除操作完成後,你還是留在 Normal Mode,不會進入 Insert Mode。如果你想「刪掉然後馬上打新的字」,請看下面的「修改 (Change)」
基本刪除
| 指令 | 動作 | 說明 |
|---|---|---|
x | 刪除游標下的字元 | 像 Del 鍵 |
X | 刪除游標前的字元 | 像 Backspace |
dd | 刪除整行 | d 重複兩次 = 整行 |
D | 刪除到行尾 | 同 d$ |
dd 刪除整行後,游標在哪?
刪除整行後,游標會移到下一行的第一個非空白字元
下一行有縮排
1 function foo() {
2 var a = 1
^(游標在第 2 行的 v)
3 return 2
4 }
按 dd 刪除整行
1 function foo() {
2 return 2
^ ← 游標在下一行的第一個非空白字元(r)
3 }
下一行沒有縮排
1 function foo() {
2 return 1
^(游標在第 2 行的 r)
3 }
按 dd 刪除整行
1 function foo() {
2 }
^ ← 游標在下一行的第一個非空白字元(})
修改 (Change)
c 的作用是:刪除 + 進入 Insert Mode
可以想成:c = d + i
| 指令 | 動作 |
|---|---|
cc | 修改整行 |
C | 修改到行尾(同 c$) |
s | 刪除一個字元並進入 Insert(同 cl) |
S | 刪除整行並進入 Insert(同 cc) |
cc / S 修改整行後,游標在哪?
cc 和 S 的效果一樣,都是刪除整行內容然後進入 Insert Mode
重點:縮排會保留
1 function foo() {
2 return 1
^(游標在第 2 行的 r)
3 }
按 cc 或 S
1 function foo() {
2
^(游標會停在原本 r 的位置)
3 }
這個設計很貼心,因為你通常想保留縮排。對比 dd + O(刪除整行再往上開新行),cc 省事多了
沒有縮排的情況
1 function foo() {
2 return 1 ← 這行沒有縮排
^(游標在第 2 行的 r)
3 }
按 cc 或 S
1 function foo() {
2 ← 整行清空,游標在行首
^(游標會停在原本 r 的位置)
3 }
取代單一字元:r
r 可以取代游標下的字元,不需要進入 Insert Mode
原文:hello warld
游標: ^(游標在 a 上)
按 ro(r 後按 o)
結果:hello world ← a 被取代成 o,仍在 Normal Mode
超適合用來修正 typo
Undo / Redo
| 指令 | 動作 |
|---|---|
u | Undo(復原) |
Ctrl + r | Redo(重做) |
注意:Vim 的 undo 是以「一次 Insert Mode」為單位。如果你一直在 Insert Mode 中打字,按一次 u 會把全部都復原
複製貼上 (Yank & Paste)
在 Vim 中,複製叫做 yank(不是 copy),但概念是一樣的
複製 (Yank)
| 指令 | 動作 |
|---|---|
yy | 複製整行 |
Y | 複製整行(同 yy) |
貼上 (Paste)
| 指令 | 動作 |
|---|---|
p | 貼在游標後面 |
P | 貼在游標前面 |
p vs P 的差異
1 first line
^(游標在 f 上)
2 second line
yy(複製第 1 行),然後
按 p
1 first line
2 first line ← 貼在「下一行」
^(游標在新貼上那行的 f 上)
3 second line
按 P
1 first line ← 貼在「上一行」
^(游標在新貼上那行的 f 上)
2 first line
3 second line
小技巧:複製整行時,p 貼在下一行,P 貼在上一行,游標都會停在新貼上那行的第一個非空白字元
剪下在哪裡?
Vim 沒有獨立的「剪下」指令。因為 d 刪除的內容會自動存起來,所以 d 就等於剪下
hello world
^
按 dd(刪除 hello world 一整行)
按 p
hello world ← 剛刪掉的被貼回來了
所以在 Vim 中
- 剪下一行 =
dd - 剪下到行尾 =
D
連續貼上的陷阱
這是新手一定會踩到的坑
假設你想把某行複製到好幾個地方
1. yy 複製一行
2. 移動到目標位置,按 p 貼上
3. 移動到另一個位置,中間順手 dd 刪了一行
4. 按 p ,結果貼出來的是剛刪的那行!
為什麼? 因為 Vim 的 d 和 y 都會存到同一個地方(預設寄存器)。後面的操作會覆蓋前面的
解法一:先貼再刪
調整操作順序,先把要貼的都貼完,再做刪除
解法二:用指定寄存器
"ayy → 複製到 a 寄存器
"ap → 從 a 寄存器貼上
這樣不管中間做什麼操作,a 寄存器的內容都不會被覆蓋
寄存器是進階主題,後續文章會詳細介紹。現在只要知道有這個解法就好
其他實用操作
合併行:J
J 可以把下一行接到當前行後面
1 first line
2 second line
在第一行任何位置按 J
1 first line second line
大小寫轉換
| 按鍵 | 動作 |
|---|---|
~ | 切換游標下字元的大小寫 |
gUU | 整行轉大寫 |
guu | 整行轉小寫 |
hello world
^
按 ~ → Hello world(h 變 H,游標移到下一個字元)
連按 ~~~~~ → HELLO world
縮排
| 按鍵 | 動作 |
|---|---|
>> | 當前行增加縮排 |
<< | 當前行減少縮排 |
function hello() {
console.log("hi"); ← 游標在這行
}
按 >>
function hello() {
console.log("hi"); ← 增加一層縮排
}
可以搭配數字使用:3>> 會把當前行和下面兩行一起增加縮排
本篇重點整理
進入 Insert
i/a → 游標前/後
I/A → 行首/行尾
o/O → 下方/上方新行
刪除
x → 刪一個字元
dd → 刪整行
D → 刪到行尾
修改
c = d + 進入 Insert Mode
cc/C/s/S
r → 取代單一字元(不進 Insert)
複製貼上
yy → 複製整行
p/P → 貼在後/前
d 就是剪下(刪除的內容會自動存起來)
大小寫
~ → 切換大小寫
gUU/guu → 整行轉大寫/小寫
縮排
>> → 增加縮排
<< → 減少縮排