使用这样的配置:
nn <F9> :!g++ % -o %< -std=c++2a -Wall<CR>
nn <F10> :!./%<<CR>
然后用 F9 编译,F10 运行。
能用,但是太难用。
如果只使用 C++,那么上面的方法基本可以满足需求。但你也很有可能需要编写 Python, Rust 之类的东西,在这样配置便不妥了。
可以使用 autocmd
来依据语言选择编译/运行方式:
augroup Runner
autocmd!
autocmd BufRead,BufNewFile *.cpp
\ nn <buffer><F9> !:g++ % -o %< -std=c++2a -Wall<CR>
\ nn <buffer><F10> :!./%<<CR>
autocmd BufRead,BufNewFile *.py
\ nn <buffer><F10> :!python %<CR>
augroup END
或者你也可以用 ftplugin
来实现:
~/.vim/ftplugin/cpp.vim
:
nn <buffer><F9> :!g++ % -o %< -std=c++2a -Wall<CR>
nn <buffer><F10> :!./%<<CR>
~/.vim/ftplugin/python.vim
:
nn <buffer><F10> :!python %<CR>
你需要在 vimrc
中设置 filetype plugin on
才能让 vim 根据文件类型执行相应的命令。
上面的配置对于普通算法竞赛已经够用了,然而存在这样一个问题:如果代码 CE,则难以根据编译信息定位错误位置。我们可以考虑使用 vim 的 quickfix 功能加速对 CE 的处理。
首先确保你的 vim 有 quickfix 功能:has('quickfix')
。
然后大概是这个流程:
makeprg
,默认选项是 make
,你也可以改成 clang++
,g++
,rustc
之类的:make
执行 makeprg
中的命令,注意这个 make
是 vim 中的命令,输出将会自动输送到 quickfix 窗口。比如我现在有这样一份代码:
#include <iostream>
#include <vector>
int main()
{
int n;
std::cin >> n;
std::vector<long long> v(n);
for (auto &i : v) std::cin >> i;
long long ans = std::numeric_limits<long long>::max();
for (auto i : v) ans = std::min(ans, i);
cout << std::max(ans, 0) << endl;
}
这里为了演示 makeprg
都用法,我们先不使用默认的 make
。使用 set makeprg=g++\ %\ -o\ %<
以使用 g++
编译,可以使用 %
,#
字符代替文件名,注意空格需要转义。
然后 :make
以编译程序,再 :copen
打开 quickfix 窗口。vim 会自动解析出对应的行号列号。如图:
quickfix 窗口是特殊的 buffer,可以定位到高亮的行,回车来到对应位置。
quickfix 常见操作有:
:copen " 打开 quickfix 窗口
:cnext " 下一个定位位置
:cprev " 上一个定位位置
:cfirst " 首个定位位置
:clast " 末个定位位置
可以映射成快捷键以方便操作。
注意:如果你再更改程序时行号改变了,quickfix 不会自动更改行号。
分割线:以下的内容在实际比赛、考试中意义不大,你没有时间进行详尽的配置。
当你的编译命令复杂了,你也可以使用 Makefile 来管理你的编译命令(即 GNU Make)。这时,你的 makeprg
便不必配置了,使用默认值即可。
关于如何编写 Makefile,可以参考:
Make 不仅可以用于编译程序,也可以管理测试样例,对拍的脚本。下面就是一个可以自动测试样例的 Makefile:
CXXFLAGS = -std=c++2a -Wall
%-test: % %.in %.ans
cat $<.in | ./$< | tee $<.out
diff $<.out $<.ans
.PHONY: %-test
使用 make a-test
自动编译 a.cpp,并将 a.in 输入到 a 又输出到 a.out,再对比
a.out 和 a.ans。CXXFLAGS
是指定 Make 编译 C++ 代码时使用的参数。
以上全部都是同步编译的,在编译时会中断操作,十分影响体验。而 vim8 支持了异步操作,我们可以在后台运行比较费时的操作,而不打断编辑过程。
首先确保你的 vim 有 channel 和 jobs 特性。
下面是个异步运行 Make 的例子,ToQuickFix
表示将编译信息输出到 Quickfix 窗口,
AsyncMake
用于异步执行 Make。这是 vim9 的脚本,你也可以把它改写成老式 vim 脚本。
vim9script
var current_job = null_job
def ToQuickfix(channel: channel, msg: string): void
setqflist([], 'a', {"lines": split(msg, "\n")})
enddef
def AsyncMake(task: string): void
if current_job != null_job && job_status(current_job) == "run"
return
endif
setqflist([], "r")
setqflist([], "r", {"title": "make " .. task})
current_job = job_start("make " .. task, {"callback": "ToQuickfix"})
enddef
command! -nargs=* AsyncMake :call AsyncMake("<args>")
实际上你竞赛写不写得完题目跟编译是不是异步的一点关系都没有
rough 的代码高亮太垃圾了
推荐使用 ALE 异步检查文件语法。
直接在 vim 内置终端里头操作也是不错的选择。