首页 » 软件优化 » 学会偷懒——首席软件工程师教你开发小妙招(输入命令修改插入模式)

学会偷懒——首席软件工程师教你开发小妙招(输入命令修改插入模式)

落叶飘零 2024-07-24 00:15:22 0

扫一扫用手机浏览

文章目录 [+]

随着云服务的发展,越来越多的开发工作在Linux下进行,Vim的使用已成为一项必备技能。
本文针对有一些Vim使用经验,但使用不多的开发人员,通过一些实例介绍如何在Vim中进行重复操作。
如果你已经能在工作学习中熟练使用Vim,对Vim宏的使用已经有一定的了解,请直接跳转至第4部分开始阅读。

1. 重复输入命令

Vim中的 . 命令用于重复操作。
我们先看一下Vim帮助手册中对 . 命令的描述:

. Repeat last change, with count replaced with [count]. Also repeat a yank command, when the 'y' flag is included in 'cpoptions'. Does not repeat a command-line command.

学会偷懒——首席软件工程师教你开发小妙招(输入命令修改插入模式) 软件优化
(图片来自网络侵删)

可以看到 . 命令的作用就是一个,“重复上次修改”。
我们先需要了解一下什么可以称为一次修改。
例如,当使用 x 命令删除一个字符后,“删除一个字符” 就是一次修改,再使用 . 命令就会重复这个删除操作。
再如,使用 p 命令粘贴一段文本,那个这个粘贴就是一次修改,再使用 . 就会重复进行粘贴。
特别要注意的是,每次从普通模式到插入模式,输入文字后再回到普通模式,算是一次修改,不论中间输入了多少文字。

实例1

删除多个单词

One Two unwanted wrong words Three Four

首先把光标移动到unwanted的词首。
我们可以输入 3dw 删除后面的3个单词,也可以用 dw.. 删除一个单词,然后重复两次。
区别在于,第一个命令是一次修改,而后面的操作是三次修改。
如果使用 u 命令来撤销操作的话,后面的命令可以分次撤销,而且不用数单词数,即使多按了一两次 . 按键,也不是什么问题,只要按 u 命令撤销就是了。

实例 2

在每一行代码后面加一个逗号

ONE = 1TWO = 2THREE = 3FOUR = 4

在第一行输入 A 在行尾插入,输入需要的逗号,然后按<esc>退回到普通模式。
在其他行使用 . 命令就可以重复在行尾插入逗号的操作。
这里 A 相当于输入 $a ,移动到行尾并进入到插入模式,不同之处在于,如果使用 $a ,就变成了一次移动加一次修改,就不能直接使用 . 命令来重复操作了,因为 . 命令只会“重复上一次修改”。
Vim还有其它一些和 A 类似的“移动并进入插入模式”的命令。

2. Vim宏

当需要执行的操作比较复杂时,我们把操作录制成一个宏来,然后通过播放这个宏完成重复。
在普通模式下,按 q 命令加宏名称开始录制宏,再次按 q 键结束录制,然后就可以通过 @ 键播放录制的宏来进行重复操作。

实例1

曾经我们有类似这样的代码:

char string1 = "Not enough energy.";char string2 = "We are under attack!";...char string9 = "Nuclear launch detected.";

从C++11开始这些代码就会产生一个警告,提示不能从字面量转换到char 指针。
于是我们考虑把它们替换成更加现代化的C++风格:

std::string string1 {"Not enough energy."};std::string string2 {"We are under attack!"};...std::string string9 {"Nuclear launch detected."};

由于字符串数量较多,我们希望只对 string1 做一次修改,然后在其他行通过重复动作自动完成所有的更改。
这可以通过录制下面这样一个宏来完成。

在 string1 所在行输入 qa 开始录制宏到寄存器 a 。
输入 0dwx 删除 char 。
输入 i 命令进入编辑模式,输入 std::string␣ ,输入 <ESC> 返回普通模式。
输入 f= ,输入 caw{ 把 = 替换为 { 。
输入 $i} 在分号前插入 } 。
输入 j 切换到下一行。
输入 q 结束宏的录制。

现在我们处于 string2 这一行。
输入 @a 即可完成对改行的修改,在输入多次 . 命令完成所有行的修改。
或者输入 8@a 直接完成所有修改。

这里由于我们在宏的结尾处输入了 j 命令跳到下一行,所以直接重复操作就可以完成所有行的修改。
如果一个宏只有针对一行的操作而没有切换到下一行,我们可以在选择模式下选中需要修改的行,然后执行普通模式下的 @a 命令,那么就会对每一行执行操作,也可以直接完成对所有行的修改。

:'<,'>norm! @a

实例 4

我们使用GTest编写单元测试代码,经常需要对一些成员函数做mock。
也就是把如下一些函数:

virtual int GetValue(int proj, int user);virtual bool IsGood(bool lie);virtual bool IsBad(void);HRESULT DoSomething(int proj, int user, bool flag);HRESULT DoSomethingElse(int user, bool flag);

变成下面这样的代码:

MOCK_METHOD2(GetValue, int (int proj, int user));MOCK_METHOD1(IsGood, bool (bool lie));MOCK_METHOD0(IsBad, bool (void));MOCK_METHOD3(DoSomething, HRESULT (int proj, int user, bool flag));MOCK_METHOD2(DoSomethingElse, HRESULT (int user, bool flag));

我们可以录制一个宏来完成操作。
和前一个例子相比,这个例子要复杂一些,原因在于 MOCK_METHOD 一系列名称需要知道参数个数。

简单起见,我们通过检查函数定义中的 , 的个数来确定参数数量,比如有一个,则说明有两个参数。
这里要注意的是,没有 , 可能有两种情况,一种是函数有一个参数,还有可能函数没有参数,这个需要通过检查参数表是不是 void 来确定。
基于这样的想法,可以通过下面的代码获取函数参数:

if getline(".") =~ "\([ \t][:a-zA-Z_].\)" \ && getline(".") !~ "\([ \t]void[ \t]\)" echo count(getline("."), ",") + 1else echo count(getline("."), ",")endif

我们可以把结果保存到寄存器里,在后面需要的时候插入寄存器里的内容。
这里选择寄存器 o 。

:let @o=execute('if getline(".") =~ "\([ \t][:a-zA-Z_].\)" && getline(".") !~ "\([ \t]void[ \t]\)" | echo count(getline("."), ",") + 1 | else | echo count(getline("."), ",") | endif')

查看一下寄存器 o 的内容:

:reg oType Name Content c "o ^J2

这不是我们想要的内容,多了一个 ^J (LineFeed)。
需要用下面的命令把这个多余的符号删掉。

:let @o=substitute(strtrans(@o),'\^@','','g')

再查看一下,现在OK了:

:reg oType Name Content c "o 2

知道怎么获取参数之后就可以开始录制我们需要的宏了。

在第一行输入 qm 开始录制宏到寄存器 m 。
输入 :s/^[ \t]\(virtual\)[ \t]//g 删除行首的 virtual ,如果有的话。
输入前面说的 :let @o=execute(...) 和 :let @o=substitute(...) 两个命令,把当前函数的参数个数保存到寄存器 o 。
输入 I 进入插入模式,光标停留在行首,输入 MOCK_METHOD 。
输入 =@o 在插入模式下插入参数数量。
输入 (<esc> ,并输入 ldw 剪切返回类型到无名寄存器。
输入 f( ,按 i 进入插入模式输入 ,<space><esc> 返回,然后输入 p 把返回类型粘贴在参数表前面。
输入 $i)<esc> 在分号前增加一个 ) 。
输入 j 切换到下一行。
输入 q 结束宏的录制。

各个步骤的结果如下:

序号

输入

结果

1

qm

开始录制宏

2

:s/^[ \t]\(virtual\)[ \t]//g

int GetValue(int proj, int user);

3

:let @o=execute(...):let @o=substitute(...)

@o == 2

4

IMOCK_METHOD

MOCK_METHODint GetValue(int proj, int user);

5

=@o

MOCK_METHOD2int GetValue(int proj, int user);

6

(ldw

MOCK_METHOD2(GetValue(int proj, int user);

7

f(i,p

MOCK_METHOD2(GetValue, int (int proj, int user);

8

$i)

MOCK_METHOD2(GetValue, int (int proj, int user));

9

jq

移动光标到下一行,结束录制

录制结束后,输入 4@m 即可完成对下面4行的修改。

3. Tips

在普通模式停留

避免长时间停留在插入模式,在任何需要暂停输入的情况下,就回到普通模式。
进出一次插入模式就形成一次修改,经常返回普通模式,也减小了每一次修改的粒度,而使用 u 命令撤销的操作就是一次修改,所以当长时间在插入模式下输入后如果输入错误想撤销时,会一次性把进入插入模式后的所有输入都撤销,一大片都没了,这可能并不是用户想要的结果。

配置

当重复操作应用在大量的行上时,可能会遇到性能问题,这主要是因为对每一行操作之后Vim会进行重绘。
通过下面的配置可以提高性能。

set lazyredraw4. 感谢

感谢阅读本文。

Happy Vimming!

点个关注可以了解更多微策略最新动态,行业资讯,计算机技术以及程序员日常

标签:

相关文章

中国IT分销市场,现状、挑战与未来展望

随着我国经济的快速发展,信息技术产业已成为我国国民经济的重要组成部分。IT分销作为产业链中的重要环节,对于推动我国信息技术产业的发...

软件优化 2024-12-30 阅读0 评论0

SM语言,探索数字时代下的沟通艺术

随着互联网的普及,数字时代下的沟通方式发生了翻天覆地的变化。在这个信息爆炸的时代,人们渴望更加高效、便捷的沟通方式。而SM语言作为...

软件优化 2024-12-30 阅读1 评论0