.
你没看错,就是Normal模式下的.
键,它可以重复上一次的编辑命令
比如,有一个函数:
int foo(char *s, int len) {
char *p = s;
for (char *e = s+len; p < e; p++)
/* do something */ ;
return len / 2;
}
你可以:
- 将光标放在第一个len上,按
*
键高亮选择所有的len单词,并跳到下一个len上 - 按
N
键返回到第一个len上,按ciwn
将第一个len改成n - 按
n
调到第二个len上,按.
- 按
n
调到第三个len上,按.
norm命令
norm命令可以让你在Ex命令行上执行Normal模式的命令,比如在编辑Markdown时想在每一行前面都加上*
来让普通文本行变成无序列表,可以先用V选中这些行,然后按:norm I*
并回车即可
宏
Vim的命令丰富,组合使用可以使文本编辑更加高效,配合宏这种自动化的工具,可以实现更强大的功能
举一个小栗子,假如有很多宏定义的常量
#define CONST_A 1
#define CONST_B 2
#define CONST_C 3
#define CONST_D 4
#define CONST_E 5
现在想替换成const的形式
const int CONST_A = 1;
const int CONST_B = 2;
const int CONST_C = 3;
const int CONST_D = 4;
const int CONST_E = 5;
我需要录制这样的一个宏:
- 按
qa
键开始录制宏,将宏存到a寄存器里 - 按
0
键将光标移到行首,按ce
删除#define并进入插入模式,输入const int
并按ESC回到Normal模式 - 按
ee
来到变量名的最后一个字母,按a
进入模式,输入=
,按ESC回到Normal模式 - 按
A
将光标移动到最后并进入插入模式,输入;
并按ESC回到Normal模式 - 按
j
将光标移到下一行,按q
结束宏录制
录完这个宏之后,就可以按@a
执行了,这样没执行一次宏就会把当前行替换成const的形式并自动将光标移到下一行,我需要按四次@a
(或者@@
,@@
是指执行上一次执行的宏)来完成这个编辑任务
不过按四次还是很麻烦的,于是体现Vim灵活的特性出现了,你可以通过按4@a
一次替换完所有要编辑的行
假如你要替换的不止是5行,而是100行,你可以在第一行录完宏之后,在第二行只需按一次99@a
,100行就全部替换完成了,爽不爽?六不六?有一种快感有木有!!
:s命令
:s是Vim执行正则表达式替换的命令
还是刚才那个例子,我按V4j
选中这5行,然后执行:s/#define(.*)(d+)$/const int1= 2
便可完成相同的动作
理论上讲,用:s命令完成是比用宏快的,但是思考构造正则表达式也是需要一定的时间的,有时候需要根据具体情况选择使用那种方式
实现上面的编辑任务还用一个办法:假如你对Normal模式的命令足够熟悉并且记忆力足够好,你可以使用:norm
命令完成
寄存器
Vim中很多东西都是通过寄存器来传递的,比如你复制剪切一段文本、访问系统的剪贴板,就连刚才录制的宏也是将你的按键序列保存在寄存器里的,使用:reg a
命令可以查看我们刚才录制的宏
:reg a
--- 寄存器 ---
"a 0deiconst int^[wwi= ^[j
其中^[
是ESC键产生的按键序列
常用的特殊寄存器还有
:
存放的是上一次执行的Ex命令的内容+
这个寄存器和系统剪贴板相关联,比如按"+yy
可以复制一行到剪贴板,"+p
可以将剪贴板的文本粘贴到Vim/
存放的是上次用/命令搜索的内容"
存放的是上一次剪切的文本=
这个寄存器比较特殊,使用它Vim会让你输入一个表达式,它返回表达式的结果
使用:reg
命令查看所有的寄存器的内容
在插入模式下或者Ex命令模式下,使用<c-r>
键+寄存器名 可以输入寄存器里的内容
举一个例子,如果想使用:s命令替换一个很长的单词而又不想手动输入它,可以先在Normal模式下将他复制下来,他会存到"
寄存器里,然后使用<c-r>"
就可以输入了
最后说几句
Vim提供的功能还是很强大的,不过Vim的脚本真的是像坨屎一样臭,导致除了像我这么懒的人之外没大有人愿意去研究它
不过Vim的正则还是很强大的,虽然它和现有的任何标准都不太一样,不过正则这东西,你学会了一种再去学其他的就会触类旁通,简单多了
期待neovim的lua runtime,拯救像我一样还在屎里挣扎的人~~~~