读工具书之《Vim实用技巧》

2 阅读10分钟

敲代码时,有一个困扰我很久的问题,终于在最近的一次搜索中找到答案。这问题发生在Vim普通模式下:

# 1. 选中并复制一个单词A
vey
# 2. 搜索单词bbbbb
/bbbbb<CR>
# 3. 用单词A覆盖掉第一个单词bbbbb
<Esc>vep
# 4.继续覆盖下一个bbbbb
n.

问题出在第4步,n.在此处没有反应,单词bbbbb并不变成A。我网上冲浪好多次,都没找到答案,直到某天在Stack Overflow上看到这样的一句:

In 2023, you can use P instead of p, which will allow you to keep pasting the "yanked" selection.(粘贴时可以使用大写的P代替小写的p,这样复制的内容就不会变化啦。)

由此,我找到这问题的处理方式。

于此同时,我在其它回答中看到registry关键字:p操作会默认将被覆盖的内容复制下来,可以通过使用不同的寄存器来存储要粘贴的内容。我对Vim的寄存器一点不了解,导致这句话看不太懂,于是内心又突发奇想:“Vim是不是其实也有相关书籍的,不然找一本来看看?”

我找到《Vim实用技巧》然后看完了它,整个的阅读过程,是在不停发出“帅!”“赞啊!”之类感叹中度过的。作者于书中分享的那些操作方式,巧妙实用又有迹可循。

我初次接触Vim,是15年刚换到跟萌哥一个组时。萌哥对我敲Lua代码的方式(在Visual Studio中装一个BabyLua插件)感到好奇,经过一番讨论之后我发现:“萌哥敲代码的手法可太熟练了。”

见贤思齐,从那以后我敲代码,也都用Vim。(前两年,改成在VS Code中用Vim,为这切换,我还专门理了一篇小博客。)

正像使用Git一样,熟悉基本操作之后,这些年来,我使用Vim的方式是没有大的变化的,直到想要优化复制粘贴方式的今天。

正像阅读《Pro Git》一样,读完《Vim实用技巧》,我对Vim也新增许多认知、多出许多未来会常用的指令。

本篇读书笔记,便是这些认知与指令的整理。未来的我,将基于此,持续完善自己的编辑能力。(作者使用Vim写成本书,由此,未来的公众号写作,如果是电脑上操作,我将也用Vim。)

一、一些概念性认知

1、Vim是什么?

Vim是一种文本编辑方式,使用Vim编辑,我们可以保证手不离开键盘,快速做出自己想要的修改。熟悉Vim之后,我们敲代码时,会有一种行云流水之感,脑子怎样想,手便怎么做;手是绝不会拖脑子后腿的。

Vi是Visual单词的缩写,而Vim则是Vi improved(Vi增强版)的缩写。

2、Vim的操作机理是怎样的?

操作符与动作命令的结合形成了一种语法。这种语法的第一条规则很简单,即一个操作由一个操作符,后面跟一个动作命令组成。学习新的动作命令及操作符,就像是在学习Vim的词汇一样。如果掌握了这一简单的语法规则,在词汇量增长时,就能表达更多的想法。

假如我们已经知道如何用 daw 删除一个单词,然后又学到 gU 命令(参见 :h gU)。它也是个操作符,所以我们可以用 gUaw 把当前单词转换成大写形式。如果我们的词汇进一步扩充,学会了作用于段落的 ap 动作命令,就会发现我们可以进行两个新的操作:用 dap 删除整个段落,或者用 gUap 把整段文字转换为大写。

Vim的语法只有一条额外规则,即当一个操作符命令被连续调用两次时,它会作用于当前行。所以 dd 删除当前行,而 >> 缩进当前行。gU 命令是一种特殊情况,我们既可以用 gUgU ,也可以用简化版的 gUU 来使它作用于当前行。

执行、重复、回退,是Vim的编辑哲学。我们的终极形态,是完成一次“语法”执行之后,剩下的重复修改,只用.

3、寄存器

此前的我,从没有了解过Vim的寄存器概念,或者说尝试了解过,但没有了解明白。

图片

寄存器示例

其实Vim的寄存器概念很简单,它就是一个容器而已,它存储的,是我们复制的内容或一些类似文件名的固定配置。

Vim拥有很多个寄存器,每一个寄存器有自己的单独名字。如上图,在Vim普通模式下,按:后输入reg便能查看当前拥有值的所有寄存器。

下面是两个简单使用示例(注意:字符"是必须的):

# 复制当前单词到寄存器a
"ayw
# 将寄存器a中的值粘贴出来
"ap
# 将当前单词复制到剪切板
"+yw
# 一个只读的寄存器,保存当前文件名
"%

4、宏

图片

正录制宏的提示

宏概念,与寄存器一样,都是以前了解过但不知道具体如何使用的,我甚至常常疑惑:上图中的那个提示到底是什么意思呢?

宏和.一样,都是为了方便的重复操作,以下是一个具体示例:

1. 开始宏的录制,将指令存到寄存器a中
qa
# 2. 在行前插入var关键字
Ivar <Esc>
# 3. 在行末插入一个;符号
A;<Esc>
# 4. 结束宏的录制
q5. 在下一行执行宏当中的内容,可太帅了啊!这会在下一行的行首行末分别加上var和;
j@a

与宏相关的指令,还有下方两条:

# 查看寄存器a中的指令内容
:reg a
# 在选中的区间内回放宏q(帅必须再加一)
:'<,'>normal @q

宏的具体指令内容存放在寄存器中,所以是可以直接将其内容复制进当前正编辑文件,编辑该条宏之后再将其复制进寄存器然后再执行宏的。

此处再加上一点自己的小想法:关于宏关于各种指令的详细阐述,建议大家看原书,我这里只记录自己不太熟悉但会常用的指令。正像书中所说:

就像黑白棋游戏一样,学会Vim的宏只需一分钟,但要穷其一生才能精通。不过从新手到高手,每个人都能从该功能中获益匪浅,因为它让我们的工作易于自动化。

二、那些将常使用但不太熟悉的操作

1、普通指令

# 选中上次选中
gv
# 行末插入,代替$a。少输入一个字符也算进步
A
# delete a word,从前面从后面都可以删
daw
# 对数字执行加和减操作,也太太太太帅了吧!
<c-a><c-x>
# 反转从当前光标到单词结束内字符的大小写
g~w
# 行内搜索,,逗号往前挪,;分号往后挪
f
# 放在某个字符上,可以查看这个字符的编码
ga
# 可视模式选择时,可以用o重新调整开头,用O调整结尾
v
# 大写的v,选中整行
V
# 进入Vim历史命令记录窗口
q:
# Ctrl+w是控制窗口的前置键,后面跟上jkhl(已经成为程序性记忆,手指知道但脑子不知道)是向对应方向切换窗口=将所有窗口等分,_最大化窗口高度,|最大化窗口宽度

# 前面加g,是在屏幕行中操作,如果一行文本太长,在屏幕中可能会显示两行,这两行,就是屏幕行
gj/gk
# 移动到第一个实际行的第一个非空白字符
^
# 按照字串移动
B/E/W
# 将文本选中并复制到系统剪切板("+是系统寄存器)
ve"+y

# 选中大括号内部的内容(大括号可以换成"、小括号、尖括号等等)
vi}
# 选中大括号内部的内容并且包含大括号
va}
# 如上,将大括号内部内容删掉并开始输入新的内容(d和y是一样的,太强大了)
ci}
# 如上,选中xml标签内的文本
vit
# 标记当前位置,第二个m可以是a到z。
mm
# 跳转到标记位置(当前文件内)
`m
# 标记当前位置,第二个M可以是A到Z
mM
# 跳转到标记位置(多个文件间跳转)
`M
# 在当前文件的修改位置列表中来回跳转
g;和g,
# 从上次插入的地方继续插入
gi
# 文件名跳转(VS Code中还是老实用F12吧),g代表“当前一整行范围”
gf
# 搜索的时候,加上\V,可以搜到真正的.号
/\V.
# 搜索时候,加上\v,并在单词左右加上小于大于号,可以只匹配到完整单词
/\v<the><CR

2、插入模式

# 加上寄存器名字则是粘贴
ctrl-r"

3、命令行模式

# %代表整个文件,normal代表执行普通模式下指令 A;代表在行末插入一个分号(帅啊!但vscode vim未实现)
:%normal A;
# 选中某区域后直接按:,命令行中会多出:'<,'>表示一个区间,之后再输入normal A;,则在选中部分每行末尾都加上;了
# 缓冲区(打开的文件)列表正向移动
:bn
# 缓冲区列表逆向移动(我一般用:b1,切换到具体某个更多一点)
:bp
# 删掉某个缓冲区
:bdelete n
# 在命令行模式下运行shell命令
:! ls
# 只显示当前正活动的窗口
:only
# 打开文件管理器,并显示当前工作目录
:e.
# 打开文件管理器,并显示活动缓冲区所在的目录
:E
# 打开循环查找
:set wrapscan
# 关闭循环查找(记在此处是为了告诉自己,设置bool值,可以直接在选项前加no)
:set nowrapscan
# 顺序查找test
/test
# 逆序查找test
?test
# 统计当前匹配到的个数(映射快捷键,gc似乎是没有使用的;但vscode中默认有数量,好像又不太有必要哦)
:%s///gn
# 在查找test后再跳转到匹配单词的最末处,这种情况下,可以很方便的n.出单词的完善,这个情况我遇见过很多次,此处很有用
/test/e
# 接上条,如果匹配之初忘记跳末尾,可以用这个换成末尾(帅!)
//e

上面查找是否加e有些难以理解,此处配一张图:

图片

匹配到单词的末尾

三、小结

阅读本书时,我经历一个小小的情绪变迁。

刚开始学着使用Vim时,我超级超级佩服萌哥(现在当然依然佩服着)的熟练,到自己跟着本书学习之后,再体验一次之前已经有过的认知:其实这世界上的技能,都是可以花时间去了解去熟悉然后学会接着熟练的,一切都在于是否愿意去花时间学习。难怪萌哥会说:“没什么的啦,你学一学也就会了。”

练无止境,且持续熟练着,“不加思考就能用Vim完成很多操作”是我的目标。

最后,我当然要再安利一次:“程序员们,不然花两周时间试试看Vim?那种手不用离开键盘的敲代码体验,真不错的。待操作稍微熟练些再看《Vim实用技巧》,它会帮助我们完善关于Vim的认知,它让我们理解某个操作为什么会有效。”