跳过正文
  1. Posts/

Vim 学习笔记 Day 004:文本对象,把“操作范围”从移动升级成结构

·3773 字·8 分钟
📖 阅读 --
DogDu
作者
DogDu
工作结束或者累了, 要不休息一会, 看会动漫吧 ~
目录
Vim 14 天 - 这篇文章属于一个选集。
§ 4: 本文

今日主题
#

  • 主主题:文本对象
  • 副主题:把编辑范围从“到哪里”升级成“改哪一块”

学习目标
#

  • 解决“已经会 operator + motion,但范围边界还是找得很累”的问题。
  • 明确文本对象不是单纯移动,而是把“词、引号内、括号内、方括号内”当成稳定结构来操作。
  • 建立最常用的对象直觉:
    • iw / aw
    • i" / a"
    • i( / a(
    • i[ / a[
  • 为后面的搜索替换、可视模式、代码编辑闭环做准备。

前置回顾
#

  • Day 003 已经建立了一个关键句式:
    • operator 决定做什么
    • motion 决定做到哪里
  • 但真实编辑里还会遇到一个更常见的问题:
    • 我不是只想“删到某处”
    • 我是想“改这个词里边”
    • 或者“改引号里面那段”
    • 或者“删括号里的参数”
  • 这时如果还只靠 we$ 来拼范围,会逐渐觉得边界不够贴结构。
  • Day 004 的作用,就是把操作范围继续从“路径”推进成“对象”。
  • 当前本地环境已确认:
    • Vim 9.2
    • Neovim 0.12.0

典型场景
#

这一篇要解决的是真实编辑里很常见的几个高频动作:

  • 改一个词,但不想自己判断该不该包含周围空格。
  • 改引号里的内容,但不想把引号一起删掉。
  • 删掉函数调用里的参数,但保留括号本身。
  • 复制一整个带引号的字符串或一整个括号块。

如果 Day 003 解决的是“我能对一个范围做事”,那 Day 004 解决的就是“我能更自然地说出这个范围是什么”。

最小命令集
#

今天只保留最高频、最适合立刻形成手感的一层。

核心前提
#

  • 文本对象通常只能:
    • 在 Visual 模式中使用
    • 或接在 operator 后面使用

词对象
#

  • iw
    • inner word,词内部
  • aw
    • a word,一个词,常连同周围空白一起考虑

引号对象
#

  • i"
    • 双引号内部
  • a"
    • 包含双引号本身
  • i'
    • 单引号内部
  • a'
    • 包含单引号本身

括号与方括号对象
#

  • i(
    • 圆括号内部
  • a(
    • 包含圆括号本身
  • i[
    • 方括号内部
  • a[
    • 包含方括号本身

最常用组合
#

  • ciw
    • 改当前词内部
  • daw
    • 删除一个词对象
  • ci"
    • 改双引号内部内容,保留引号
  • da"
    • 删除带双引号的一整个字符串
  • ci(
    • 改圆括号内部内容,保留括号
  • da(
    • 删除包含圆括号的一整个块
  • yi[
    • 复制方括号内部内容

它是怎么用的
#

核心心法:文本对象不是“怎么走过去”,而是“当前这块是什么”
#

Day 003 里,你更像是在说:

  • 删到词尾
  • 改到行尾
  • 复制到某个位置

Day 004 里,你开始换一种说法:

  • 改这个词
  • 改这个引号里的内容
  • 删这个括号块

这两者不是互相替代,而是层次不同:

  • motion 更像路径
  • text object 更像结构

真实编辑里,一旦目标本身是清晰结构,文本对象通常会比普通 motion 更顺手。

ia 的区别:先记“内部”和“包含外壳”
#

今天最重要的区分就是:

  • i
    • inner,倾向于只取内部
  • a
    • a,倾向于把对象外壳也算进去

例如:

  • ci"
    • 改双引号里面的内容,但保留 "
  • da"
    • 把带引号的整段一起删掉
  • ci(
    • 改括号里面的内容,但保留 ()
  • da(
    • 括号连同里面内容一起删掉

这组直觉一旦建立,后面很多对象都能类推。

iwaw:先用它解决“改词”和“删词”
#

词对象是今天最该先练顺的一组。

它很适合解决:

  • 改变量名
  • 改普通英文单词
  • 删除一个多余词

最值得先形成肌肉记忆的是:

  • ciw
    • 改当前词
  • daw
    • 删除一个词对象

本地帮助里对 awiw 的区分非常明确:

  • aw 会把前后空白一起纳入考虑
  • iw 更偏向对象内部

所以在真实效果上,经常会感觉:

  • ciw 更适合“把词换掉”
  • daw 更适合“把这个词连带空位一起处理掉”

引号对象:最适合“保留外壳,只改内容”
#

比如你有这一段:

TXT 代码 · 共 1 行
name = "old value"

如果你的真实目标是把 "old value" 改成 "new value",最自然的动作往往不是自己找边界,而是:

  • ci"

它的优势是:

  • 不用自己判断从哪里删到哪里
  • 不会误删外层引号
  • 很贴合“改字符串内容”这个真实动作

而如果你是想把整个字符串,包括引号都删掉,才更像:

  • da"

括号对象:最适合参数、调用、数组元素这一类结构
#

比如:

TXT 代码 · 共 1 行
print(user_name, user_email)

如果你只想改参数列表,保留调用壳子,通常会优先想到:

  • ci(

结果会变成:

TXT 代码 · 共 1 行
print(|)

然后你直接输入新参数即可。

如果你是想把整个括号块删掉,才会更像:

  • da(

这也是为什么文本对象一进入代码场景,价值会突然变大。

常见操作套路
#

套路 1:改词,优先试 ciw
#

低效做法:

  1. wb 到词附近
  2. 进插入模式
  3. 手动删
  4. 重打

更稳的方式:

  1. 光标落在目标词内部任意位置
  2. ciw
  3. 直接输入新词
  4. Esc

套路 2:改字符串内容,优先试 ci"ci'
#

场景非常高频:

  • 改配置值
  • 改 JSON / Lua / Python 里的字符串
  • 改 Markdown 链接标题的一部分

如果目标是改内容不改引号,先想:

  • ci"
  • ci'

套路 3:改参数列表,优先试 ci(
#

场景包括:

  • 改函数参数
  • 改调用参数
  • 改括号包住的一整段表达式

如果目标是保留括号本身,只换里面内容,先想:

  • ci(

套路 4:删整个对象时,再用 a
#

一个很实用的判断是:

  • 我是要保留壳子,还是连壳子一起处理?

通常:

  • 保留结构,用 i
  • 连结构一起处理,用 a

例如:

  • 保留引号:ci"
  • 删除整段带引号文本:da"
  • 保留括号:ci(
  • 删除整个括号块:da(

环境差异:vim / nvim / LazyVim
#

文本对象是 Vim / Neovim 的共同底层能力
#

本地 Vim 9.2motion.txtobject-motions 章节里明确说明:

  • 这组命令只能在 Visual 模式或 operator 之后使用
  • a 系列包含对象及其相关空白或外壳
  • i 系列偏向对象内部

同样的对象说明也保留在本地 Neovim 0.12.0 的运行时文档里。

所以今天讲的不是某个插件增强,而是 Vim 系编辑器原生语法的一部分。

到了 LazyVim,文本对象会直接接到代码编辑工作流上
#

LazyVim 会让你更快:

  • 找文件
  • 跳符号
  • 看诊断
  • 用 LSP

但一旦光标已经落到代码里,像下面这种动作仍然是底层主力:

  • 改字符串内容
  • 改函数参数
  • 删一对括号里的表达式

也就是说,文本对象不是和现代工作流分离的老知识,反而是现代工作流真正落到编辑动作时最值钱的那层。

今日练习(5-10 分钟)
#

练习材料
#

新建一个临时文件,写入下面内容:

TXT 代码 · 共 4 行
title = "old title"
tags = ["vim", "notes", "draft"]
call(user_name, user_email)
this sentence needs a better word

练习任务
#

  1. vimnvim 打开这个文件。
  2. 在第一行把引号里的 old title 改成 new title,使用 ci"
  3. 在第二行复制方括号里的内容,使用 yi[
  4. 在第三行把括号里的参数改成 account_id,使用 ci(
  5. 在第四行把 better 改成 clearer,优先使用 ciw
  6. 再额外试一次:
    • daw
    • da"
    • da(
  7. 每做完一步都回看自己是在操作“结构对象”,而不是手工数边界。

完成标准
#

  • 能清楚说出 ia 的差别。
  • 能在词、引号、括号三个场景里各做出一个顺手动作。
  • 能说出为什么 ci"ci(ciw 比手工删改更贴真实场景。

今日问题与讨论
#

我的问题
#

问题 1:文本对象和 Day 003 的 operator + motion 是什么关系?
#

  • 简答:
    • 文本对象可以看作一种更贴结构的范围描述方式。
  • 场景:
    • 你已经会写 d$cw,但遇到“引号里面”“括号里面”这种结构时,普通 motion 不够自然。
  • 依据:
    • 本地 motion.txt 把 text object 放在 motions 体系里,并明确说明它们可在 operator 后使用。
  • 当前结论:
    • 文本对象不是替代 Day 003,而是把 Day 003 的范围表达升级成结构表达。
  • 是否需要后续回看:

问题 2:iwaw 到底先记哪个?
#

  • 简答:
    • 两个都要记,但上手时通常先把 ciwdaw 练顺。
  • 场景:
    • 改一个词,和删掉一个词,往往对是否带空白的期待不同。
  • 依据:
    • 本地帮助里 aw 包含前后空白,iw 更偏向内部。
  • 当前结论:
    • 改词先多想 ciw,删词时多试 daw,手感会更稳定。
  • 是否需要后续回看:

问题 3:为什么 ci"da" 需要分开记?
#

  • 简答:
    • 因为一个是在保留结构,一个是在删除整个结构。
  • 场景:
    • 改字符串内容时通常不想把引号破坏掉;删掉整段字符串时则可能希望连引号一起处理。
  • 依据:
    • i / a 的帮助定义就是“inner”与“a object”的差别。
  • 当前结论:
    • 先问自己要不要保留外壳,再决定用 i 还是 a
  • 是否需要后续回看:

外部高价值问题
#

问题 1:为什么 Day 4 主线只讲词、引号、括号,没有把更多对象一起铺开?
#

  • 问题:
    • Learn-Vim 的 text objects 看起来比这里更多,为什么主线没有一次全讲?
  • 简答:
    • 不是因为 Learn-Vim 没讲,而是因为主线刻意只保留最常用的一层,避免 Day 4 变成对象清单。
  • 场景:
    • 你今天最常碰到的是改词、改字符串、改参数列表;而句子、段落、HTML tag 对象虽然有用,但没有前面几组高频。
  • 依据:
    • 本地 motion.txt 的 text objects 说明。
    • D:\program\Learn-Vim\ch04_vim_grammar.md
  • 当前结论:
    • Day 4 的主线选择是“高频优先”,不是“资料里没有所以跳过”。
  • 是否需要后续回看:

常见误区或易混点
#

  • 误区 1:文本对象只是 Visual 模式技巧
    • 不是。它们和 operator 组合时才最能体现价值。
  • 误区 2:ia 只是两个记法,没有本质区别
    • 区别很关键,一个偏内部,一个偏包含外壳。
  • 误区 3:文本对象只适合代码,不适合普通文本
    • 不是。iw / aw 在普通文本里同样高频。
  • 误区 4:只要会 ciw 就等于会文本对象
    • ciw 只是入口,真正的提升来自把“词、引号、括号”都当成对象。
  • 误区 5:文本对象会替代普通 motion
    • 不会。motion 和 text object 是互补关系。

扩展内容
#

  • aW / iW
    • 按更粗粒度的 WORD 工作,适合处理带符号的整段非空白文本。
  • as / is
    • 句子对象,适合纯文本场景,但不是今天主线重点。
  • ap / ip
    • 段落对象,在写长文时有价值。
  • at / it
    • HTML / XML tag 对象,处理标签内容时很顺手。
  • a< / i<
    • 角括号对象,和 tag 对象相关但心智略有区别。
  • a` / i`
    • 反引号对象,在 Markdown 或 shell 片段里会用到。
  • ab / ib
    • a( / i( 的别名写法,可后续再收。
  • a] / i]
    • 今天已点到,但更复杂的嵌套与转义边界可以后续再补。

今日小结
#

Day 004 最重要的变化是:

  • 你不再只是对“移动路径”做操作
  • 你开始对“文本结构对象”做操作

一旦这件事建立起来,很多以前要自己找边界的动作,就会自然变成:

  • ciw
  • ci"
  • ci(

这正是 Vim 编辑手感开始明显上台阶的地方。

明日衔接
#

下一步建议进入:

  • Day 005:搜索 / 替换 / 可视模式

重点会开始解决:

  • 怎样更快找到目标
  • 怎样批量改
  • 怎样在视觉选择和结构选择之间切换

复习题
#

  1. 为什么说文本对象是在把“范围”升级成“结构”?
  2. ia 的核心区别是什么?
  3. ciwci"ci( 分别最适合什么场景?
  4. 为什么改字符串内容时,ci" 常常比手工删改更顺?
  5. 文本对象和普通 motion 是替代关系,还是互补关系?
Vim 14 天 - 这篇文章属于一个选集。
§ 4: 本文