Skip to content

Latest commit

 

History

History
79 lines (50 loc) · 4.81 KB

tutorial.md

File metadata and controls

79 lines (50 loc) · 4.81 KB

Vim配置:用VimScript实现一键编译运行及样例测试

前言

发现我的编译方式不合适,是在陕西邀请赛(2017)的现场上。彼时的我启用Vim写ICPC相关代码已经接近一年,对Vim主要快捷键已经趋于熟悉。Vim强大的功能使得我在代码编写和修改的时候得心应手,然而在编辑以外的部分,情况却不是那么的美好。Vim是一个编辑器,为了编译其中代码,我每次都需要在Vim中键入

:!g++ % -Wall
:!./a.out

随后是手动输入测试样例。然而这样的方法过于愚蠢,大量的时间浪费在了样例的输入上(为了避免交题的时候未去除文件重定向,我队往往采用手输的方式)而且每次测试,我都需要重复敲击上述两个命令,这在赛场紧张十分容易出错,非常危险。

恰好,我从宽神知乎号上得知“一键编译运行”的存在,这令我耳目一新。经过一番摸索我发现,利用makeVimScript,我能完全自动化地完成编译运行任务,而代价仅仅是数十行的**.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

参考文档:

第二个是最重要的,对我的这个配置帮助很大。