强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

04 - 动作与文本对象

“Vim’s power comes from the composability of operators, motions, and text objects.”

4.1 动作(Motion)深入

4.1.1 动作的本质

动作(Motion)是 Vim 中移动光标的命令。它不仅用于浏览,还能与操作符组合形成操作。

" 动作可以独立使用(移动光标)
w       " 跳到下一词
b       " 跳到上一词

" 动作可以与操作符组合(操作范围)
dw      " 删除到下一词
yw      " 复制到下一词
cw      " 修改到下一词

4.1.2 动作分类总览

Motion(动作)
├── 字符级:h l
├── 查找级:f F t T ; ,
├── 搜索级:/ ? n N * #
├── 单词级:w W b B e E ge gE
├── 行级:  0 ^ $ g_ | f{c} t{c}
├── 段落级:( ) { }
├── 文件级:gg G H M L % [[ ]]
├── 标记级:m{a-z} '{a-z} `{a-z}
└── 跳转级:<C-o> <C-i> gd gD gf

4.1.3 单词级动作详解

word(小写)以非字母数字字符为分隔:

hello-world example.test
^     ^     ^       ^
|     |     |       |
word1 word2 word3  word4

WORD(大写)仅以空白字符为分隔:

hello-world example.test
^                   ^
|                   |
WORD1              WORD2
" 实际对比
let url = "https://example.com/path?q=1&a=2"

" 使用 w(按 word 移动)
" https://example.com/path?q=1&a=2
"  ^   ^      ^   ^    ^ ^ ^ ^ ^
" 每次跳过一个 word 片段

" 使用 W(按 WORD 移动)
" https://example.com/path?q=1&a=2
"  ^                               ^
" 一次跳过整个 URL

4.1.4 查找动作(Character Find)

f{char}     " 跳到当前行下一个 {char}
F{char}     " 跳到当前行上一个 {char}
t{char}     " 跳到当前行下一个 {char} 之前(till)
T{char}     " 跳到当前行上一个 {char} 之后
;           " 重复上次 f/F/t/T
,           " 反向重复

业务场景

# 假设光标在行首,要修改函数名
result = calculate_total_price(items, tax_rate)
#        ^
# 目标:修改 calculate_total_price

# 方法:用 f 跳到 ( 然后回退
f(b    # 跳到 ( ,再跳到上一个词首
ciw    # 修改这个词

4.1.5 搜索跳转

/pattern     " 向前搜索
?pattern     " 向后搜索
n            " 下一个匹配
N            " 上一个匹配
*            " 搜索光标下的单词(向前)
#            " 搜索光标下的单词(向后)
g*           " 搜索部分匹配(不加词边界)
g#           " 搜索部分匹配(向后)

4.1.6 标记(Mark)

标记让你在文件中设置"书签":

m{a-z}      " 在文件内设置标记(小写标记,仅当前文件有效)
m{A-Z}      " 在文件间设置标记(大写标记,全局有效)
'{mark}     " 跳到标记所在行的首个非空字符
`{mark}     " 跳到标记的精确位置(行和列)

" 常用标记
ma          " 在当前位置设置标记 a
'a          " 跳到标记 a 所在行
`a          " 跳到标记 a 的精确位置

" 自动标记
'.          " 跳到上次修改的位置
'"          " 跳到上次退出时的光标位置
'[          " 跳到上次修改/粘贴区域的开始
']          " 跳到上次修改/粘贴区域的末尾
''          " 跳到上次跳转前的位置

业务场景

" 在函数头部标记,编辑函数尾部后跳回
ma          " 标记函数头部
}           " 跳到段落末尾
...编辑...
`a          " 精确跳回标记位置

4.2 文本对象(Text Object)

4.2.1 什么是文本对象

文本对象是 Vim 对结构化文本的抽象。它们是 操作符 + i/a + 对象 的组合:

[操作符] [i(内部) | a(含界定符)] [对象类型]

  i = inner(内部,不含界定符)
  a = a / around(含界定符)

4.2.2 文本对象一览表

对象i(内部)a(含界定符)
w单词单词 + 空格
WWORDWORD + 空格
s句子句子 + 空格
p段落段落 + 空行
"双引号内含双引号
'单引号内含单引号
`反引号内含反引号
( / )小括号内含小括号
b等同 i(等同 a(
{ / }花括号内含花括号
B等同 i{等同 a{
[ / ]方括号内含方括号
< / >尖括号内含尖括号
tXML 标签内含 XML 标签

4.2.3 i vs a 的区别

示例文本: (hello world)

ci(  →  修改后: ()           " 括号内被替换为空
ca(  →  修改后:              " 括号和内容一起被替换

示例文本: "hello world"

ci"  →  修改后: ""           " 引号内被替换
ca"  →  修改后:              " 引号和内容一起被替换

4.2.4 文本对象实战

场景一:修改函数参数

// 原始代码
const result = processData(input, options, callback);
//                        ^ 光标在此

// 修改第二个参数
f,       " 跳到第一个逗号
w        " 移到下一个词
ciw      " 修改这个单词
config   " 输入新名称

场景二:修改引号内容

message = "Hello, World!"
#              ^ 光标在此

ci"      # 修改引号内内容
Goodbye, Vim!  # 输入新内容

场景三:删除整个函数调用

alert("This is a message");
//           ^ 光标在此

da(      " 删除整个括号及其内容含括号

场景四:修改 HTML 标签

<div class="container">
    <p>Hello World</p>
</div>
#        ^ 光标在 p 标签内的文本上

cit      # 修改标签内内容
<span>New Content</span>

场景五:复制整个段落

yip     " 复制当前段落(inner paragraph)
yap     " 复制当前段落 + 空行(a paragraph)

4.3 组合的艺术

4.3.1 操作符 + 动作

operator  +  motion  =  操作
   d      +    w     =  删除一个单词
   c      +    $     =  修改到行尾
   y      +    ip    =  复制段落
   >      +    }     =  缩进到段落末尾
   =      +    G     =  自动缩进到文件末尾

4.3.2 操作符 + 文本对象

operator  +  text-object  =  操作
   d      +     i(        =  删除括号内容
   c      +     a"        =  修改引号及内容
   y      +     iw        =  复制单词
   gU     +     it        =  标签内转大写
   =      +     i{        =  花括号内自动缩进

4.3.3 计数 + 操作符 + 动作/文本对象

count  +  operator  +  motion/text-object  =  操作
  2    +     d      +      aw              =  删除 2 个词(含空格)
  3    +     c      +      w               =  修改 3 个词
  2    +     >      +      ap              =  缩进 2 个段落

4.3.4 常用组合速查表

组合操作
diw删除光标所在的单词
daw删除单词(含空格)
ciw修改光标所在的单词
ci"修改双引号内内容
ci(修改小括号内内容
ci{修改花括号内内容
dit修改 XML 标签内内容
da(删除括号及其内容
yi"复制引号内内容
>i{缩进花括号内内容
=ip自动缩进段落
gUiw单词转大写
gu$到行尾转小写
g~ip段落内大小写翻转
!ipsort对段落内容排序

4.4 搜索模式进阶

4.4.1 搜索选项

/pattern/e      " 光标停在匹配末尾
/pattern/b      " 光标停在匹配开头
/pattern/+2     " 光标停在匹配下方 2 行
/pattern/-1     " 光标停在匹配上方 1 行

4.4.2 搜索历史

/               " 然后按 ↑/浏览历史
:history /      " 查看搜索历史
q/              " 打开搜索历史窗口(可编辑)

4.4.3 增量搜索技巧

" 设置增量搜索
set incsearch
set hlsearch

" 搜索时使用 \v(very magic)模式避免转义
/\vfunction\s+\w+     " 等同于标准正则
/function\s\+\w\+     " 需要转义特殊字符

" 搜索光标下的单词
*     " 向前搜索单词(精确匹配)
g*    " 向前搜索部分匹配
#     " 向后搜索单词(精确匹配)
g#    " 向后搜索部分匹配

4.5 跳转列表与变更列表

4.5.1 跳转列表(Jump List)

:jumps          " 查看跳转列表
<C-o>           " 后退(较旧的跳转)
<C-i>           " 前进(较新的跳转)

注意jk 等逐行移动不算跳转。只有长距离移动才算跳转(如 ggG、搜索、标记跳转等)。

4.5.2 变更列表(Change List)

:changes        " 查看变更列表
g;              " 跳到较旧的变更位置
g,              " 跳到较新的变更位置
'.              " 跳到上次修改的行
`.              " 跳到上次修改的精确位置

业务场景

" 在大文件中修改了多处代码,想快速跳回修改点
g;      " 跳到上一个修改位置
g;      " 再跳到更早的修改位置
g,      " 跳回较新的修改位置

4.6 实战练习

练习一:函数参数重命名

# 原始代码(光标在第一行 def 处)
def calculate(user_name, order_list, discount_rate):
    total = sum(order_list)
    result = total * (1 - discount_rate)
    return format_result(user_name, result)

# 任务:将 user_name 改为 customer_name
# 步骤:
/customer_name<CR>    " 跳到第一个 user_name
ciwcustomer_name<Esc> " 修改为 customer_name
n.                    " 下一个匹配并重复修改
n.                    " 继续下一个

练习二:括号内内容操作

// 原始
const data = parseJSON(getResponse(url, headers));

// 光标在 getResponse 内的某个位置
// 任务:修改 getResponse 的参数
f(a         " 跳到 ( 后开始插入
params, timeout  " 输入新参数

练习三:快速导航长行

" 一个很长的 JSON 行
{"name":"John","age":30,"city":"New York","country":"USA"}

" 快速跳到 city 字段
fc      " 跳到 c
;       " 继续找下一个 c
;       " 直到目标 city 的 c

4.7 业务场景

场景推荐组合
重命名变量*ciw新名称<Esc>n.n.
修改函数参数f,ciw新名称
删除引号内内容di"da"
修改 HTML 标签内容cit新内容
复制整个函数体]yVa{y
大写 SQL 关键字gUiw

4.8 总结

分类核心命令
单词移动w b e W B E
行内查找f F t T ; ,
搜索/ ? n N * #
文本对象iw aw i" a" i( a( it at ip ap
标记m{a-z} 'm \m`
跳转历史<C-o> <C-i> g; g,

下一步第 05 章 - 编辑命令 → 掌握修改(change)、宏(macro)、寄存器(register)、撤销(undo)等核心编辑功能。


扩展阅读