04|编辑语法与文本对象
普通模式的高效来自一套小语法:
操作 + 范围例如,d 表示删除,w 表示移动到下一个词;二者组合成 dw,意思就是“删除到下一个词”。掌握这条规则后,许多快捷键都可以按含义组合,不必逐个死记。
这一章会写出 Task 数据模型,并重点练:
d、c、y三个操作;p粘贴与.重复;i/a文本对象;- 当前配置里
mini.ai提供的参数和函数调用对象。
1. 先输入一份故意留有两处问题的模型
在终端进入项目并打开文件:
cd ~/playground/pocket-tasks
nvim src/pocket_tasks/model.py
按 i 输入:
from dataclasses import dataclass
from datetime import datetime
@dataclass(slots=False)
class Task:
name: str
created_at: datetime
completed: bool = False
按 Esc 回普通模式。
这里故意写入了 slots=False 和 name,后面会通过编辑语法修改这两处内容。
输入时如果弹出自动补全菜单,可以继续打字缩小候选范围;用
Tab接受候选,Enter仍然只是正常换行。当然,这里完全手动输入也没问题。
2. 三个操作符
| 操作符 | 含义 | 完成后所处模式 |
|---|---|---|
d | 删除范围 | 普通模式 |
c | 删除范围,并立刻开始输入 | 插入模式 |
y | 复制范围,Vim 术语叫 yank | 普通模式 |
它们后面需要一个范围。上一章学过的移动键已经可以充当范围:
| 组合 | 逐键解释 | 效果 |
|---|---|---|
dw | d 删除,w 到下一词 | 删除到下一个词 |
d$ | d 删除,$ 到行尾 | 删除到行尾 |
cw | c 修改,w 到下一词 | 删除词尾范围并进入插入模式 |
yw | y 复制,w 到下一词 | 复制到下一个词 |
按下第一个操作符后,Neovim 会进入“等待范围”的状态。底部可能显示等待中的操作;补上范围后才真正执行。中途反悔就按 Esc。
双击形式:整行操作
| 按键 | 效果 |
|---|---|
dd | 删除当前整行 |
cc | 清掉当前行内容,保留合适的缩进并进入插入模式 |
yy | 复制当前整行 |
前面可加次数:2dd 删除两行,3yy 复制三行。
3. 练习删除、复制和粘贴
先搜索到最后一个字段:
/completed
Enter
复制一行再粘贴
- 按
yy:复制整行,画面暂时不变。 - 按
p:把整行粘贴到当前行下方。

- 按
u:撤销粘贴,恢复一行。

普通模式下:
p把字符内容放在光标后,把整行内容放在当前行下;P把字符内容放在光标前,把整行内容放在当前行上。
删除和修改的内容也会进入寄存器,所以 dd 后按 p,可以把那一行挪回来。
删除一行再恢复
- 保持光标在
completed行,按dd。 - 这一行消失。

- 按
u,这一行回来。

修改整行再恢复
- 按
cc,当前内容被清掉,光标进入插入模式。

- 先不输入,按
Esc。 - 按
u,原行恢复。

这三次实验结束后,模型仍应有三个字段。
4. 文本对象:选择内部或连同边界
用移动键指定范围时,往往需要先找准边界。文本对象则可以直接描述一个完整单位,例如单词、引号中的内容、括号中的内容或函数参数。
基本结构是:
操作 + i/a + 对象i:inside,只取里面;a:around,把包围符或相邻空白也包括在内。
最常用的对象
| 对象 | i 版本 | a 版本 |
|---|---|---|
| 单词 word | iw 取词本身 | aw 通常连相邻空白一起取 |
| 双引号 | i" 取引号里的内容 | a" 连双引号一起取 |
| 圆括号 | i( 或 i) 取括号内部 | a( 或 a) 连括号一起取 |
| 任意常见括号 | ib | ab,mini.ai 会在 ()、[]、{} 中找平衡的一对 |
由此可以读出:
ciw:修改当前词;di":删除双引号里的内容,留下引号;da":连内容和双引号一起删除;yi(:复制圆括号里面的内容。
先选中,再决定
v 进入字符可视模式。它也能和文本对象组合:
- 光标放进任意单词;
- 按
viw; - 当前单词被高亮选中;

- 按
Esc取消选择。
遇到不熟悉的文本对象时,可以先用 v 预览选区,确认范围后再改用 c、d 或 y。
5. 用 ciw 修正字段名
输入:
/name
Enter
ciw
title
按 Esc 完成本次修改。
逐键发生了这些事:
/name找到name;c准备修改;iw指定当前单词内部;name被清掉,并进入插入模式;- 输入
title; Esc完成本次修改。
字段变化如下:
- name: str
+ title: str
ciw 是日常编辑中最常用的组合之一。只要光标位于单词内部,具体停在哪个字母上都没有关系。
把文字复制到系统剪贴板
普通的 y 主要把内容放进 Neovim 寄存器。如果需要在浏览器、终端或聊天窗口之间复制文字,可以在操作前指定 "+ 寄存器:
- 输入
/title,按Enter。 - 按
viw选中title。

- 按
"+y,把选中文字复制到系统剪贴板。 - 按
o,输入# clipboard:后跟一个空格,按Esc。 - 按
"+p,系统剪贴板里的title会粘到注释末尾。

- 按
dd删除这行临时注释。

" 表示“接下来指定寄存器”,+ 代表系统剪贴板,最后的 y / p 才是复制 / 粘贴动作。若系统缺少剪贴板后端,Neovim 会报 provider 错误;当前系统已有 wl-copy,这组按键可以直接使用。
6. mini.ai 的特色对象:参数 a
当前配置启用了 mini.ai 默认映射。它在常规文本对象上增加了几种很实用的目标:
| 对象字母 | 代表什么 | 示例 |
|---|---|---|
a | 函数调用中的一个 argument | cia 修改当前参数内部 |
f | 整个 function call | vaf 选中函数名与括号 |
q | 最近的一对单引号、双引号或反引号 | ciq 修改任一种引号内部 |
t | HTML/XML 标签 | vit 选中标签内容 |
这里的字母会根据语法位置解释。cia 可以拆成:
c + i + a
改 内部 当前参数现在修复装饰器参数:
/slots
Enter
cia
slots=True
按 Esc 完成本次修改。
预期结果:
@dataclass(slots=True)
mini.ai 识别了 dataclass(...) 中的参数 slots=False,cia 会选择整个参数内容供你修改。若要同时包含参数旁边的分隔空白或逗号,可以使用 around 版本 caa。
看看函数调用对象
- 再搜索
/slots。 - 按
vaf。 - 预期高亮
dataclass(slots=True)这一整个函数调用,行首的@不在选择中。

- 按
Esc取消。
mini.ai 默认会优先查找光标所在的对象。如果当前位置没有匹配对象,它会在前后 50 行内寻找下一处。因此不确定范围时,可以先用 v 预览选区。
7. 点命令 .:重放上一次修改
普通模式下的 . 会重复上一次文本修改,其中也包括当时输入的文字;移动和搜索本身不会被重复。
做一个可撤销实验:
- 输入
/created_at,按Enter。 - 按
ciw,输入created,按Esc。

- 输入
/completed,按Enter。 - 按
.。

预期结果:
- 第一次修改把
created_at变成created; .在新位置重放ciw加输入created,把completed也变成created。
现在按一次 u,先恢复 completed。

再按一次 u,恢复 created_at。

常见的用法是先完成一次可重复的修改,再移动到下一处按 .。后面批量处理同类代码时还会继续用到这种方法。
8. 保存最终模型
确认文件为:
from dataclasses import dataclass
from datetime import datetime
@dataclass(slots=True)
class Task:
title: str
created_at: datetime
completed: bool = False
按 F1,输入 write。

第一次按 Enter 后,命令行中会出现 :write。

再按一次 Enter 执行保存。

按 Space e 打开 Explorer,可以同时检查文件位置和最终内容。

如果左侧符号栏出现诊断标记,可以先等 basedpyright 完成分析;本章最终代码在 Python 3.11 下应当保持干净。
本章肌肉记忆
| 目标 | 按键 |
|---|---|
| 删除 / 修改 / 复制范围 | d / c / y + 范围 |
| 删除 / 修改 / 复制整行 | dd / cc / yy |
| 粘贴到后面 / 前面 | p / P |
| 当前词内部 | iw |
| 连词与邻近空白 | aw |
| 修改当前词 | ciw |
修改 mini.ai 参数 | cia |
| 选中整个函数调用 | vaf |
| 重复上次修改 | . |
| 复制到 / 粘贴自系统剪贴板 | "+y / "+p |