Skip to content

05|包围符与注释

这一章来认识两组很实用的操作:

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

所有练习都在 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 默认映射:

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

另外还有两组辅助操作:

前缀效果
s h短暂高亮匹配到的包围,默认约半秒
s f / s F跳到包围的右边 / 左边

如果 s 单独按会怎样

mini.surrounds 当成前缀,单独按 s 什么也不会做,这样就不容易误触。按下 s 以后,还得继续输入 adrhf 等后续按键。

如果你想用 Vim 传统的“替换当前字符并进入插入模式”,按 c l 就行:c 负责修改,l 给出一个字符的范围。

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

先输入 /title,按 Enter 找到字段名。

搜索并定位 title 字段
搜索并定位 title 字段

然后按 s a i w "

拆开来看:

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

结果应该是:

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

现在再搜索一次 /title,确保光标落在引号里面,然后按 s d "

s d 表示准备删除包围,最后的 " 指定双引号。完成后会恢复成:

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

包围操作同样支持点命令。以后要给好几个单词加引号,可以先做一次 s a i w ",再移到下一处按 .,把刚才的操作重放一遍。

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

再次搜索 /title,然后按 s a i w )

完成后会得到一对紧凑括号:

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

mini.surround 把开括号和闭括号分成了两种很实用的写法:

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

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

先看它认出了哪一对

把光标留在 title 上,按 s h )

匹配到的左右圆括号会短暂亮一下。s h 只负责显示范围,不会改文件;遇到一层套一层的括号时尤其好用。

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

圆括号换成方括号

s r ) ]

拆开来看:

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

结果应该是:

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

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

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

mini.surround 默认只处理光标所在的那对包围符。如果光标没在里面,它会提示找不到目标;把光标挪进去再试就行。

5. 注释来自 Neovim 0.12 本体

Neovim 0.12 已内置:

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

它会根据文件类型读取 commentstring。在 Python 文件里,它生成的是 # 注释;碰到 Treesitter 语言注入时,还能看光标落在哪儿,自动换成对应语言的注释格式。

切换多行注释时,规则是这样的:如果选区里的每个非空行都已经注释掉了,这次操作会统一取消注释;只要里面还混着普通代码,就会把整组选区一起注释掉。

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

单行

  1. 输入 /created_at,按 Enter
  2. g c c

这一行应该会变成类似这样:

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

再按一次 g c c,注释被移除。

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

用次数处理两行

  1. 输入 /title,按 Enter
  2. 2 g c c

titlecreated_at 两行会一起变成注释。

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

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

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

次数要放在动作前面。3 g c c 就是从当前行起处理三行,很适合临时关掉一小段连续代码。

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

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

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

要恢复:

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

完成后,这两行应该会恢复成普通代码。

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

如果注释范围没法用行数说清,可以先用 Vjk 把选区框出来,再按 g c

操作符版本

g c 也遵循上一章的“操作 + 范围”语法。按 g c j,意思就是切换当前行和下一行的注释。

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

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

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

范围一眼就能看清时,g c j 会比先进入可视模式更快。

8. 最终检查与保存

前面加过的包围和注释,现在都应该已经清理干净了。文件最后仍然是:

python
from dataclasses import dataclass
from datetime import datetime

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

如果还有包围符没清掉,把光标移到里面,用 s d 加对应符号删除;如果还有注释,就把光标放到那一行,按 g c c。也可以顺着撤销记录多按几次 u,一步步退回去。

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

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

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

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

再按一次 Enter 保存。

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

最后再用 F1wqaEnterEnter 退出。

本章肌肉记忆

目标按键
给当前词加双引号s a i w "
删除双引号s d "
加紧凑圆括号s a i w )
预览圆括号s h )
圆括号换方括号s r ) ]
切换当前行注释g c c
切换两行注释2 g c cg c j
选中整行并扩展V,然后 j / k
切换可视选区注释g c

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

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