Skip to content

05|包围符与注释

这一章介绍两组很实用的操作:

  • mini.surround 用来处理引号、括号、标签等成对符号;
  • Neovim 0.12 内置的 gc / gcc 用来处理注释。

所有练习都在 model.py 上完成,结束时文件内容会恢复到上一章的最终版本,不会保留临时修改。

1. 打开训练文件

bash
cd ~/playground/pocket-tasks
nvim src/pocket_tasks/model.py

先确认内容为:

python
from dataclasses import dataclass
from datetime import datetime

@dataclass(slots=True)
class Task:
    title: str
    created_at: datetime
    completed: bool = False
打开干净的 model.py 作为训练起点
打开干净的 model.py 作为训练起点

如果内容有差异,请先按上一章的最终结果修正,再用 F1writeEnterEnter 保存当前正确版本。

2. mini.surround 的三个核心操作

当前配置使用 mini.surround 默认映射:

前缀含义后面还要输入什么
saadd,添加包围目标范围,再输入新的包围符
sddelete,删除包围要删除的包围符类型
srreplace,替换包围旧包围符类型,再输入新包围符

另外还有两组辅助操作:

前缀效果
sh短暂高亮匹配到的包围,默认约半秒
sf / sF跳到包围的右边 / 左边

如果 s 单独按会怎样

mini.surrounds 用作前缀,并将单独的 s 映射为空操作,避免误触。按下 s 后,需要继续输入 adrhf 等后续按键。

若你想使用 Vim 传统的“替换当前一个字符并进入插入模式”,按 cl 即可:c 修改,l 给出一个字符的范围。

3. 第一轮:添加和删除引号

先找到字段名:

text
/title
Enter
搜索并定位 title 字段
搜索并定位 title 字段

然后按:

text
saiw"

逐段解释:

  1. sa:准备添加包围;
  2. iw:目标是当前单词内部,也就是 title
  3. ":使用双引号作为新的包围符。

预期结果:

python
    "title": str
给 title 添加双引号
给 title 添加双引号

现在搜索 /title 让光标确保在引号里面,再按:

text
sd"

sd 准备删除包围,最后的 " 指定双引号。预期恢复为:

python
    title: str
删除 title 两侧的双引号
删除 title 两侧的双引号

包围操作也支持点命令。以后需要给多处单词加引号时,可以先完成一次 saiw",移动到下一处后按 . 重复操作。

4. 第二轮:括号、预览与替换

再次搜索 /title,然后按:

text
saiw)

预期结果是紧凑括号:

python
    (title): str
给 title 添加紧凑圆括号
给 title 添加紧凑圆括号

mini.surround 对开括号和闭括号安排了很实用的区别:

最后输入生成结果
)(text)
(( text )
][text]
[[ text ]
}{text}
{{ text }

想要代码常见的紧凑形式,就输入闭括号。

先看它认出了哪一对

把光标留在 title 上,按:

text
sh)

匹配到的左右圆括号会短暂高亮。sh 只显示范围,不会修改文件;遇到多层嵌套括号时尤其有用。

用 sh 预览当前圆括号范围
用 sh 预览当前圆括号范围

圆括号换成方括号

按:

text
sr)]

逐键解释:

  1. sr:准备替换包围符;
  2. ):寻找紧凑圆括号;
  3. ]:换成紧凑方括号。

预期结果:

python
    [title]: str
把圆括号替换为方括号
把圆括号替换为方括号

最后搜索 /title,按 sd] 删除方括号,恢复 title: str

删除方括号并恢复 title
删除方括号并恢复 title

mini.surround 默认只处理光标所在的那对包围符。如果光标不在符号内部,它会提示找不到目标;把光标移进去再试即可。

5. 注释来自 Neovim 0.12 本体

Neovim 0.12 已内置:

按键效果
gcc切换当前行注释
数字 gcc从当前行开始切换指定行数,例如 2gcc
gc + 移动切换该移动范围覆盖的行,例如 gcj
可视选择后 gc切换选中行的注释

它会根据文件类型读取 commentstring。在 Python 文件中会生成 # 注释;遇到 Treesitter 语言注入时,还能根据光标位置选用对应语言的注释格式。

切换多行时有一条规则:选区内每个非空行都已经是注释,操作会统一取消;只要其中还有普通代码,操作就会把整组选区注释起来。

6. 第三轮:gcc 切换单行与多行

单行

  1. 输入 /created_at,按 Enter
  2. gcc

预期这一行变成类似:

python
    # created_at: datetime
用 gcc 注释 created_at
用 gcc 注释 created_at

再按一次 gcc,注释被移除。

再次 gcc 取消 created_at 注释
再次 gcc 取消 created_at 注释

用次数处理两行

  1. 输入 /title,按 Enter
  2. 2gcc

titlecreated_at 两行会一起变成注释。

用 2gcc 注释连续两行
用 2gcc 注释连续两行

保持光标不动,再按 2gcc,两行一起恢复。

再次 2gcc 恢复连续两行
再次 2gcc 恢复连续两行

次数放在动作前面。3gcc 就是从当前行开始处理三行,适合暂时关闭一小段连续代码。

7. 第四轮:可视选择后注释

V 会按整行进入可视模式。结合 jgc

  1. 输入 /title,按 Enter
  2. V,当前整行高亮。
  3. j,选择扩展到下一行。
用 Vj 选中两整行
用 Vj 选中两整行
  1. gc,两行一起注释。
用 gc 注释可视选区
用 gc 注释可视选区

要恢复:

  1. 再次输入 /title,按 Enter;搜索可以命中注释里的文字。
  2. Vjgc

预期两行恢复成普通代码。

再次选择并恢复两行代码
再次选择并恢复两行代码

当注释范围不方便用行数表示时,可以先用 Vjk 明确选区,再按 gc 执行。

操作符版本

gc 也遵循上一章的“操作 + 范围”语法:

text
gcj

表示切换当前行和下一行的注释。

用 gcj 注释当前行和下一行
用 gcj 注释当前行和下一行

再执行一次相同组合即可恢复。

再次 gcj 恢复两行
再次 gcj 恢复两行

范围很清楚时,gcj 比先进入可视模式更快。

8. 最终检查与保存

所有包围和注释都应已经清理。文件最终仍为:

python
from dataclasses import dataclass
from datetime import datetime

@dataclass(slots=True)
class Task:
    title: str
    created_at: datetime
    completed: bool = False
重新启用诊断后的干净最终模型
重新启用诊断后的干净最终模型

如果还有包围符没有清理,把光标移到里面,用 sd 加对应符号删除;如果仍有注释,把光标放在相应行按 gcc。也可以用 u 沿撤销记录逐步恢复。

确认干净后,按 F1,输入 write

在命令选择器中查找 write
在命令选择器中查找 write

按第一次 Enter,让命令行形成 :write

确认即将执行 write 命令
确认即将执行 write 命令

再按一次 Enter 保存。

保存后的干净 model.py
保存后的干净 model.py

最后再用 F1wqaEnterEnter 退出。

本章肌肉记忆

目标按键
给当前词加双引号saiw"
删除双引号sd"
加紧凑圆括号saiw)
预览圆括号sh)
圆括号换方括号sr)]
切换当前行注释gcc
切换两行注释2gccgcj
选中整行并扩展V,然后 j / k
切换可视选区注释gc

上一章:编辑语法与文本对象 · 下一章:搜索与 Quickfix

本文档采用 知识共享 署名-相同方式共享 4.0 协议 进行许可。