這是 Neovim 從零開始系列的第二篇。整個系列共 12 篇文章,將帶你從完全不懂 Vim,到能用 Neovim 打造一個完整的現代化開發環境。

為什麼 Vim 像一門語言?

上一篇我們提到 Vim 的操作就像一門語言。這不是比喻——它真的是一套設計精良的文法系統。

大多數編輯器的快捷鍵是「一個組合做一件事」:Ctrl+D 選取下一個相同的詞、Ctrl+Shift+K 刪除整行。每個操作都是獨立的,你需要一個一個背。

Vim 不一樣。它的操作遵循一個簡單的文法:

Operator + Motion = Action
(動詞)   (名詞)  (動作)

學會 5 個動詞和 10 個名詞,你就有了 50 種操作。這就是 Vim 的 乘法效應

動詞(Operators)

Operator 定義了你想「做什麼」。以下是最常用的動詞:

Operator 功能 記憶法
d 刪除(delete) delete
c 修改(change)——刪除並進入 Insert mode change
y 複製(yank) yank(Vim 用 yank 而非 copy)
v 選取(visual select) visual
> 向右縮排 箭頭方向
< 向左縮排 箭頭方向
= 自動排版 等號=對齊
gu 轉小寫 go uppercase 的反向
gU 轉大寫 go Uppercase

其中 dcy 是你每天都會用到的三個核心動詞。

d vs c 的差別

這兩個很容易搞混,但它們的差別很關鍵:

  • d(delete):刪除文字後留在 Normal mode
  • c(change):刪除文字後進入 Insert mode,讓你直接打新的內容
原始文字:const name = "hello"

 ci"  →  const name = "|"     (游標在引號內,Insert mode)
 di"  →  const name = ""      (引號內被清空,Normal mode)

簡單記法:d 是「我要移除」,c 是「我要替換成別的」。

名詞:Motions

Motion 定義了「作用範圍到哪裡」。它們描述從游標目前位置到目標位置的移動。

字元級移動

Motion 功能
h 左一個字元
l 右一個字元
j 下一行
k 上一行

單字級移動

Motion 功能 說明
w 下一個單字開頭 word
b 上一個單字開頭 back
e 目前單字的結尾 end
W 下一個大單字開頭 以空白分隔
B 上一個大單字開頭 以空白分隔
E 目前大單字的結尾 以空白分隔

小寫 w/b/e 以標點符號為分界(hello-world 是兩個 word),大寫 W/B/E 只以空白為分界(hello-world 是一個 WORD)。

行級移動

Motion 功能
0 移到行首(第 0 個字元)
^ 移到行首第一個非空白字元
$ 移到行尾

搜尋移動

Motion 功能
f{char} 移到本行下一個 {char}
t{char} 移到本行下一個 {char} 的前一格
F{char} 反向搜尋 {char}
T{char} 反向移到 {char} 的後一格

名詞:Text Objects

Text Objects 是 Vim 最精華的設計之一。它們描述的不是「從這裡移動到那裡」,而是「一個完整的文字單位」。

語法格式

i + 符號 = inner(內部,不含邊界)
a + 符號 = a/around(包含邊界)

常用 Text Objects

Text Object 範圍 範例文字 i 選取 a 選取
w 單字 hello world hello hello
" 雙引號 "hello" hello "hello"
' 單引號 'hello' hello 'hello'
` 反引號 `hello` hello `hello`
() 小括號 (a, b) a, b (a, b)
[] 中括號 [1, 2] 1, 2 [1, 2]
{} 大括號 { x: 1 } x: 1 { x: 1 }
t HTML tag <p>hi</p> hi <p>hi</p>
p 段落 一整個段落 段落本身 段落 + 前後空行
s 句子 一個句子 句子本身 句子 + 後方空白

inner vs around 的實際差異

理解 ia 的差別非常重要:

// 游標在 hello 上
const greeting = "hello world"

di"  →  const greeting = ""         // 刪除引號「內」的文字
da"    const greeting =            // 連引號一起刪除
ci"  →  const greeting = "|"        // 清空引號內容並開始輸入

經驗法則

  • 想要替換內容時用 i(保留容器)
  • 想要整個移除時用 a(連容器一起刪)

組合起來

現在我們把動詞和名詞組合在一起,你會發現 Vim 的威力:

經典組合表

組合 意思 場景
dw 刪除到下一個單字 刪除一個詞
d$D 刪除到行尾 清除行尾多餘內容
dd 刪除整行 operator 重複=作用整行
ciw 修改整個單字 重新命名變數
ci" 修改引號內容 修改字串
ci( 修改括號內容 修改函數參數
ya{ 複製整個大括號區塊(含括號) 複製程式碼區塊
yiw 複製整個單字 複製變數名稱
dit 刪除 HTML tag 內容 清空 tag
>i{ 縮排大括號內的程式碼 調整縮排
vap 選取整個段落 選取後進一步操作

數字修飾

你還可以加入數字來重複操作:

[數字] + 動詞 + 名詞
組合 意思
3dw 刪除 3 個單字
2dd 刪除 2 行
5j 往下移動 5 行
3yy 複製 3 行

實戰範例

讓我們用實際的程式碼來練習:

範例 1:修改函數參數

// 游標在 name 上
function greet(name, age) {
  • 要把 name 改成 userName:按 ciw,輸入 userName
  • 要刪除所有參數:按 di(
  • 要複製所有參數:按 yi(

範例 2:處理字串

# 游標在字串內任意位置
message = "Hello, World!"
  • 改字串內容:ci" → 輸入新內容
  • 刪除整個字串(含引號):da"
  • 複製字串內容:yi"

範例 3:操作程式碼區塊

// 游標在大括號內任意位置
if (condition) {
    doSomething()
    doAnother()
}
  • 刪除括號內所有程式碼:di{
  • 縮排括號內程式碼:>i{
  • 選取括號內程式碼:vi{

特殊的 Operator 技巧

重複 Operator = 作用整行

把 operator 按兩次,就是對整行操作:

組合 意思
dd 刪除整行
cc 修改整行
yy 複製整行
>> 縮排整行
== 自動排版整行

大寫 = 到行尾

部分 operator 的大寫版本等同於「到行尾」:

組合 等同於 意思
D d$ 刪除到行尾
C c$ 修改到行尾
Y yy 複製整行(注意:不是 y$

練習建議

第一天:核心三動詞

只專注 dcy 加上 wb$ 的組合:

dw  cw  yw
db  cb  yb
d$  c$  y$
dd  cc  yy

第二天:加入 Text Objects

開始使用 ia 系列:

diw  ciw  yiw
di"  ci"  yi"
di(  ci(  yi(
di{  ci{  yi{

第三天:搜尋組合

加入 ft 搭配操作:

df,    刪除到逗號(含逗號)
dt)    刪除到右括號前
ct"    修改到引號前

持續練習

每天刻意用一兩個新組合。不需要一次全背,自然就會記住常用的。

小結

Vim 的組合系統是它最核心的設計,也是它和其他編輯器最大的差異。理解了這個「語言」,後面的所有功能都是在這個基礎上延伸。

本篇重點

  • Operator + Motion/TextObject = Action
  • 核心動詞:d(刪除)、c(修改)、y(複製)
  • i = inner(不含邊界),a = around(含邊界)
  • 數字可以重複操作
  • Operator 重複兩次 = 作用於整行

下一篇,我們會深入學習所有重要的移動指令——讓你在程式碼中飛速穿梭。


Neovim 系列文章導航

基礎篇

  1. 為什麼我想離開 VSCode?
  2. Vim 的語言——動詞、名詞、組合技(本篇)
  3. 移動的藝術
  4. 編輯效率加倍

設定篇 5. 安裝 Neovim 與 init.lua 6. Plugin 管理 lazy.nvim 7. 程式碼智能 LSP + 補全 8. 語法高亮與檔案導航

進階篇 9. Git 整合工作流 10. Terminal 與 Claude Code 整合 11. 打造快捷鍵系統 12. 從 VSCode 完全畢業