发现我的编译方式不合适,是在陕西邀请赛(2017)的现场上。彼时的我启用Vim写ICPC相关代码已经接近一年,对Vim主要快捷键已经趋于熟悉。Vim强大的功能使得我在代码编写和修改的时候得心应手,然而在编辑以外的部分,情况却不是那么的美好。Vim是一个编辑器,为了编译其中代码,我每次都需要在Vim中键入
:!g++ % -Wall
:!./a.out
随后是手动输入测试样例。然而这样的方法过于愚蠢,大量的时间浪费在了样例的输入上(为了避免交题的时候未去除文件重定向,我队往往采用手输的方式)而且每次测试,我都需要重复敲击上述两个命令,这在赛场紧张十分容易出错,非常危险。
恰好,我从宽神知乎号上得知“一键编译运行”的存在,这令我耳目一新。经过一番摸索我发现,利用make和VimScript,我能完全自动化地完成编译运行任务,而代价仅仅是数十行的**.vimrc**配置。更惊喜的是,vimrc的配置提供了一个安全、自动化的,对代码黑箱的样例测试与方便的利用print log的debug方式。我不用再在手动编译、控制台输入样例而浪费宝贵的时间,也再也不必因为时间紧迫慌神而在上述过程出错了。
本vimrc完全面向ACM-ICPC刷题及竞赛现场环境的场景。因此,我对该配置文件作出了如下要求:
- 要简单,易读。赛场上需要花时间把配置文件从纸质文档上抄到电脑上,因此内容一定要在不牺牲逻辑性和可读性的情况下短!短!短!
- 要灵活。按下F9,该编译编译,编译成功运行程序从文件读样例,编译失败要能方便debug,跑完样例要能既把输出显示在当前屏幕上又能继续改代码。把99.9%的时间放在想代码、写代码、读代码、改代码的工作上面去。
- 要人性化。编译出来一堆错误,不能单靠肉眼慢慢定位,要能直接显示;编译前自动保存,避免新代码、老运行的情况出现;要能方便条件编译print调试,免得交题前疯狂删调试print代码。
本vimrc具有以下功能:
- quickfix快速修改语法错误
- 利用VimScript中的函数自动保存,自动编译,并在编译成功后运行及测试样例
- 利用Vim的window工具,分屏显示程序代码、输入、输出的内容
- 关键字自动转化(如pub扩写为push_back)
- 其他内容,包括缩进格式、输入模式、界面设置等
首先我们抛弃愚蠢的:!g++ % -Wall
,改用如下配置完成编译工作:
:set makeprg=g++\ %\ -o%<\ -Wall\ -std=c++14\ -DLOCAL\ -g
通过这行配置,我们能直接通过:make
而不是:!g++ % -o%< -Wall -g -DLOCAL
来完成单文件的编译了(代码中的%是vim中的寄存器,表示文件名)。这样做的好处是通过Vim的make组件,我们能使用quickfix对照编译器的报错与源代码进行Debug工作。(默认情况下make指向shell中的make命令,即!make,但我们将其设置成了单文件的编译命令)
之后,通过VimScript的函数,我们使用上述的命令,完成从保存文件、编译源代码、到运行程序测试样例、显示样例的一系列功能。 自动编译运行的函数列表如下:
Run()
Cmp()
Test()
使用时只需输入
:call Cmp()
就可以完成编译运行了,当然我们可以更进一步,把这个命令映射到一个键位上,例如,我想每次按下F9就能调用这个函数,在vimrc中加入如下键位映射:
nnoremap <F9> :call CompileRun()<CR> "句末的<CR>表示Enter键
inoremap <F9> <Esc>:call CompileRun()<CR> "插入模式中的键位映射
值得注意一点,Cmp()中有个小技巧,那就是通过
let v:statusmsg = ''
silent make
if empty(v:statusmsg)
...
来判断编译是否成功,这个只保证了在Terminal模式下有效,对于gVim到底是否可行是个未知数。
最后,来看看编译参数。编译命令相当于:
g++ % -o{filename} -Wall -std=c++14 -DLOCAL -g "filename为当前文件名
-Wall使所有warning输出, -g保证编译器不对代码做任何优化,只有这样才能调用gdb进行调试, -DLOCAL给print调试提供了一个方式,可以在C\C++代码中键入
#ifdef LOCAL
//print somethint
#endif
进行调试,这样既能在本机上看到调试信息,又能交题后不产生额外输出。END
第二个是最重要的,对我的这个配置帮助很大。