Wiki LogoWiki - The Power of Many

W01: 语义化语法构造 (The Atomic Foundation)

抛弃记忆按键, 建立『动词 + 范围 + 名词』的语义化逻辑体系, 深度掌握 Vim 内核语法.

1. 通往心流的"原子语法"

Vim 的操作本质上是一门编辑语言. 所有的按键都不是孤立的, 而是遵循以下公式:

[count] + Operator (动词) + Motion/Text-Object (动作/名词)

d       2       w
│       │       └── 名词: 单词
│       └────────── 数量: 2
└────────────────── 动词: 删除
= 删除 2 个单词

1.1 核心动词 (Operators)

动词助记功能
yYank复制到寄存器
dDelete删除 (内容进入寄存器)
cChange删除并进入插入模式
> / <Indent缩进/反缩进
=Format自动格式化缩进
g~Toggle切换大小写
gu / gULower/Upper强制小写/大写
!Filter通过外部命令过滤

双击动词作用于整行:

  • dd - 删除整行
  • yy - 复制整行
  • cc - 修改整行
  • >> - 缩进整行

1.2 名词: 运动 (Motions) vs 对象 (Text-Objects)

Motions (运动): 描述从当前位置到目标的移动:

Motion描述
w / W下一个词首 (word/WORD)
e / E当前词尾
b / B上一个词首
0 / ^ / $行首/首个非空/行尾
gg / G文件首/尾
f{c} / F{c}向前/后查找字符
t{c} / T{c}到字符前一格
%匹配括号跳转
{ / }上/下一段落
/pattern搜索跳转

Text-Objects (文本对象): 描述结构化文本块:

    i = inside (内部, 不含边界)
    a = around (周围, 含边界)
对象内部 (i)周围 (a)
单词iwaw
WORDiWaW
句子isas
段落ipap
圆括号i(iba(ab
方括号i[a[
花括号i{iBa{aB
尖括号i<a<
双引号i"a"
单引号i'a'
反引号i`a`
XML Tagitat

2. 深度解密: 精准移动的逻辑

2.1 单词跳跃的差异

echo "node.js:v20.0.1" | grep -E "pattern"
     └──┬──┘ └─┬─┘ └─┬─┘
        w      w     w     ← word (标点分隔)
     └────────────────┬──────────────────┘
                WORD (空格分隔)
  • w/e: 以标点符号和空格为边界
  • W/E: 仅以空白符为边界

实战: 对于 config.yaml:prod, 按 W 一键跨越, 而 w 需要多次.

2.2 行内搜索的艺术

f{char}  ──→  跳转到 char
F{char}  ←──  反向跳转
t{char}  ──→  跳转到 char 前一格
T{char}  ←──  反向跳转到 char 后一格

;        重复上次 f/t
,        反向重复

常见用法:

ct)      " 修改到 ) 之前的内容
df,      " 删除到逗号 (含逗号)
yt|      " 复制到竖线之前

2.3 精确跳转技巧

" 跳转到上次编辑位置
`.       " 上次修改的位置
''       " 上次跳转前的位置

" 段落跳转
{        " 上一个空行
}        " 下一个空行

" 括号匹配
%        " 跳转到匹配的括号

3. 语法组合实战

理解了语法, 你可以像写英语一样操作文本:

3.1 日常高频操作

操作语义效果
ciwChange Inside Word修改当前单词
ci"Change Inside Quotes修改引号内内容
ci(Change Inside Parens修改括号内内容
da{Delete Around Braces删除花括号块 (含括号)
yapYank Around Paragraph复制整个段落
>ipIndent Inside Paragraph缩进当前段落
gUiwUppercase Inside Word当前单词转大写
=i{Format Inside Braces格式化花括号内代码

3.2 编程场景实战

# 光标在 hello 上
message = "hello, world"
#          ^^^^^
ciw"bye"     → message = "bye, world"

# 修改函数参数
def process(name, age, city):
#                 ^^^
ci,new_param → def process(name, new_param, city):

# 删除整个函数调用
result = calculate_value(a, b, c)
#        ^
daw              → result = (a, b, c)
da(              → result = calculate_value

# 修改 HTML 标签内容
<div class="container">Content</div>
#                       ^^^^^^^
cit"New Content"<div class="container">New Content</div>

3.3 搜索即动作

" 删除到搜索匹配
d/ERROR<CR>      " 删除到 ERROR 出现处

" 复制多个匹配
y3/pattern       " 复制到第 3 个 pattern 出现处

" 修改到搜索匹配
c/}<CR>          " 修改到下一个 } 出现处

4. 重复的力量: 点号命令 (.)

. 命令是 Vim 中最高效的单键功能, 它会重复你的上一个修改操作.

4.1 什么是"修改"?

Vim 定义的"一次修改"是指从进入插入模式返回普通模式之间的所有按键, 或者是一个简单的删除/修改/缩进指令.

  • x, dd, >>, p 都是一次修改.
  • ihello<Esc> 是一次修改.
  • 光标移动 (h, j, k, l, w, f) 符号不是修改, 它们是运动.

4.2 构造可重复的原子修改

大师的习惯是: 一个 Motion 定位 + 一个 Operator 执行修改.

# 初始
var_a = 1
var_b = 2
var_c = 3

# 目标: 在每个变量后添加 _suffix

错误做法: 进入插入模式, 逐行手动修改. 大师做法:

  1. 0f=i_suffix<Esc> (定位到首个 =, 插入后缀並退出)
  2. j. (跳到下一行, 重复修改)
  3. j. (跳到下一行, 重复修改)

4.3 "点号先知" (Dot Oracle) 策略

这种策略的核心是:一键移动, 一键修改.

/pattern<CR>     " 1. 查找目标
cwNewText<Esc>   " 2. 修改第一个
n                " 3. 跳到下一个 (移动)
.                " 4. 决定是否修改 (重复/跳过)
n                " 5. 跳到下一个
.                " 6. 修改

优势: 它像是一个微型的宏, 但比宏更灵活. 它赋予了你在每一个匹配项面前决策的权利: "改, 还是不改?"

4.4 为什么 . 命令如此重要?

它强迫你以语义化的方式思考. 如果你发现 . 命令没法按你预想的工作, 通常是因为你的上一个修改包含了太多的移动指令, 或者是你没有正确使用 Operator + Motion 的组合.


5. 模式深度理解

5.1 Vim 的模式架构

                    ┌─────────────┐
                    │ Normal Mode │ (命令模式, 默认)
                    └──────┬──────┘
           ┌───────────────┼───────────────┐
           ▼               ▼               ▼
    ┌────────────┐  ┌────────────┐  ┌────────────┐
    │Insert Mode │  │Visual Mode │  │Command Mode│
    │   (i,a,o)  │  │  (v,V,^V)  │  │    (:)     │
    └────────────┘  └────────────┘  └────────────┘
           │               │               │
           └───────────────┴───────────────┘
                         <Esc>

5.2 进入插入模式的方式

按键效果
i在光标前插入
I在行首插入
a在光标后插入
A在行尾插入
o在下方新建行并插入
O在上方新建行并插入
s删除当前字符并插入
S删除整行并插入 (同 cc)
C删除到行尾并插入

5.3 可视模式详解

v        " 字符可视模式
V        " 行可视模式
<C-v>    " 块可视模式 (多光标编辑)

" 可视模式下的操作
o        " 切换选择的另一端
gv       " 重新选择上次的选区

6. 本周深度任务清单

6.1 配置优化

" ~/.vimrc 或 ~/.config/nvim/init.vim

" 消除无效按键
nnoremap <Left>  <Nop>
nnoremap <Right> <Nop>
nnoremap <Up>    <Nop>
nnoremap <Down>  <Nop>

" Escape 映射 (减少手指移动)
inoremap jk <Esc>
inoremap jj <Esc>

" 相对行号 (便于 d5j 等操作)
set relativenumber
set number

" 搜索优化
set hlsearch       " 高亮搜索
set incsearch      " 增量搜索
set ignorecase     " 忽略大小写
set smartcase      " 智能大小写

" 缩进设置
set tabstop=4
set shiftwidth=4
set expandtab
set autoindent

6.2 练习任务

  1. 语法练习: 打开 JSON/YAML 文件, 使用 ci", ci{, da[ 练习结构化编辑.
  2. 行内跳转: 练习 f, t, ;, , 在长行中快速定位.
  3. 段落操作: 在 Markdown 文件中使用 dap, yap, >ip 操作段落.
  4. 文档探索: 阅读 :help motion.txt:help text-objects.

6.3 进阶挑战

查找 gn 指令的用法 (:help gn). 它可以操作上一个搜索匹配项, 是批量修改的利器:

/pattern<CR>     " 搜索 pattern
cgn              " 修改匹配项
.                " 重复修改下一个匹配项

7. 思考题

  1. dawdiw 有什么区别? 什么场景用哪个?
  2. 为什么 cwce 的行为相同, 但 dwde 不同?
  3. 如何用一条命令删除函数的所有参数 (含括号)?
  4. ft 各适合什么场景?
  5. 为什么要禁用方向键?

理解了"指令即语言", 你的手速将不再受限于生物极限, 而是取决于你构思修改逻辑的速度.

On this page