.
你没看错,就是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,拯救像我一样还在屎里挣扎的人~~~~