设置vim代码编辑器的一键编译运行功能

对于计算生物学研究者来说,Vim编辑器是一个不可缺少的工具。特别是在Linux服务器上,由于缺乏必要的图形界面,代码编写工作需要借助终端完成,此时vim的重要性就体现出来了。

vim的下载安装不再赘述,vim的入门教程网上也都有(也可以通过 vimtutor 指令进入交互式vim学习教程)。此处介绍一点高级知识:为vim代码编辑器添加一键编译运行的功能。

具体来说,就是在vim编辑器内,按下键盘上的F5按键直接编译代码,按F6按键直接运行代码。添加这一功能可以方便程序的调试,省去了退出程序再运行代码的麻烦。

一个例子:

vim compiler

我们在编辑helloworld.py这个python文件。此时直接按下F6按钮,这个python文件就会直接执行,并输出对应的结果:

vim result

如何才能实现这一效果呢?

(一) vim script介绍

Vimscript是Vim编辑器自带的脚本语言,也被称为Vim脚本。它是一种动态命令式语言,具备大多数常见的语言特性,如变量、表达式、控制结构、内置函数和用户定义函数等。

Vimscript主要用于编 写Vim的配置文件和插件,用户可以通过编写Vim脚本来定制Vim的行为和功能,使其更加符合个人的使用习惯和需求。

我们将通过编写vim script函数,实现上述一键执行的功能

要想了解更多vim script的相关知识,可以参考vim的官方教程:

以及各种中文教程:

(二)vimrc文件

有多种方法可以执行vim script的脚本,但是如果能让vim在每次启动时自动执行脚本,从而开启一键执行的函数,则会方便很多。包含vim程序初始化命令的文件称为“ vimrc”文件,我们可以将自定义的函数放在这里以实现自动加载。

vimrc文件的位置根据操作系统的不同而略有差异,但基本都是固定的。下面是官方文档给出的vimrc文件位置:

Operating system vimrc file path
Linux和macOS $HOME/.vimrc
MS-DOS和Windows $HOME/_vimrc$VIM/_vimrc

其中,$HOME代表用户目录:

  • 在Linux上一般是/home/<username>/
  • 在macOS上一般是/Users/<username>/
  • 在Windows上一般是C:\Users\<username>\
    <username>代表用户名)

有时候,vimrc文件可能预先并不存在,我们可以在上述位置新建一个同名的文本文件作为vimrc文件。

(三)编写自动执行代码的函数

下面直接给出vimscript代码。这些代码直接粘贴到vimrc文件中,即可实现我们想要的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
func! CompileGcc()
exec "w"
let compilecmd="!gcc "
let compileflag="-o %< "
if search("mpi\.h") != 0
let compilecmd = "!mpicc "
endif
if search("glut\.h") != 0
let compileflag .= " -lglut -lGLU -lGL "
endif
if search("cv\.h") != 0
let compileflag .= " -lcv -lhighgui -lcvaux "
endif
if search("omp\.h") != 0
let compileflag .= " -fopenmp "
endif
if search("math\.h") != 0
let compileflag .= " -lm "
endif
exec compilecmd." % ".compileflag
endfunc
func! CompileGpp()
exec "w"
let compilecmd="!g++ "
let compileflag="-o %< "
if search("mpi\.h") != 0
let compilecmd = "!mpic++ "
endif
if search("glut\.h") != 0
let compileflag .= " -lglut -lGLU -lGL "
endif
if search("cv\.h") != 0
let compileflag .= " -lcv -lhighgui -lcvaux "
endif
if search("omp\.h") != 0
let compileflag .= " -fopenmp "
endif
if search("math\.h") != 0
let compileflag .= " -lm "
endif
exec compilecmd." % ".compileflag
endfunc

func! RunPython()
exec "!python %"
endfunc
func! CompileJava()
exec "!javac %"
endfunc

func! RunRscript()
exec "!Rscript %"
endfunc

func! RunBash()
exec "!bash %"
endfunc


func! CompileCode()
exec "w"
if &filetype == "cpp"
exec "call CompileGpp()"
elseif &filetype == "c"
exec "call CompileGcc()"
elseif &filetype == "python"
exec "call RunPython()"
elseif &filetype == "sh"
exec "call RunBash()"
elseif &filetype == "r"
exec "call RunRscript()"
elseif &filetype == "java"
exec "call CompileJava()"
endif
endfunc

func! RunResult()
exec "w"
if search("mpi\.h") != 0
exec "!mpirun -np 4 ./%<"
elseif &filetype == "cpp"
exec "! ./%<"
elseif &filetype == "c"
exec "! ./%<"
elseif &filetype == "python"
exec "call RunPython()"
elseif &filetype == "sh"
exec "call RunBash()"
elseif &filetype == "r"
exec "call RunRscript()"
elseif &filetype == "java"
exec "!java %<"
endif
endfunc

map <F5> :call CompileCode()<CR>
imap <F5> <ESC>:call CompileCode()<CR>
vmap <F5> <ESC>:call CompileCode()<CR>
map <F6> :call RunResult()<CR>

(四)一些知识点和补充说明

1、按键绑定

参考:

上述代码最后四行的目的是完成按键绑定,map、imap、vmap是在vim的不同模式下绑定按键的意思。其中,map是一般模式下的按键绑定;imap是插入模式下的按键绑定;vmap是可视模式下的按键绑定。

按键绑定的格式如下:

1
map <键盘上按下的键> <要实现的组合键>

例如,map <F5> :call CompileCode()<CR> 的意思是,将 <F5> 按键绑定到下面的这一系列组合键:向vim命令行中输入指令:call CompileCode(),然后按下回车(就是执行CompileCode()这个函数)。

同样的,

imap <F5> <ESC>:call CompileCode()<CR> 的意思是,在插入模式下,将<F5>按键绑定到下面的这一系列组合键:先按ESC键(退出插入模式),然后执行CompileCode()函数。

2、函数

不论是CompileCode()还是RunResult(),
本质都是一样的,所以我们挑一个讲。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func! CompileCode()
exec "w"
if &filetype == "cpp"
exec "call CompileGpp()"
elseif &filetype == "c"
exec "call CompileGcc()"
elseif &filetype == "python"
exec "call RunPython()"
elseif &filetype == "sh"
exec "call RunBash()"
elseif &filetype == "r"
exec "call RunRscript()"
elseif &filetype == "java"
exec "call CompileJava()"
endif
endfunc

首先,exec "w" 就是保存当前文件的意思。先保存文件,然后运行,保证所有修改都能被存下来。

然后根据filetype选择不同的执行函数。

filetype是vim中的一个运行时变量,用于标明当前文件的文件类型,详情可以参考 https://vimdoc.sourceforge.net/htmldoc/usr_43.html

在vim安装目录的filetype.vim文件中预定义了所有可被vim识别的文件类型。要想知道一个文件在vim中被定义为何种类型的话,可以使用vim打开该文件,然后在命令模式下输入指令

1
:set filetype

然后就可以得到文件类型

3、执行文件

主要讲一点东西:

1
exec "!python %"

1
exec "!java %<"

的区别

首先,exec是vimscript里面执行指令的函数,如果指令以英文感叹号”!”开头,则表明这是个shell指令。
( 参考 https://vimdoc.sourceforge.net/htmldoc/usr_21.html#21.2

所以,上面这两行脚本都是执行shell指令的意思,一个是执行python,一个是执行java。

python和java后面跟着的百分比符号 % 则代表当前文件的文件名,不过也有所区别。% 代表文件名,包含文件后缀;而 %< 则仅仅有文件名,不包含文件后缀(如.java或.exe)。这种区分是有用的。例如,在执行java程序时,编译后的java字节码文件一般以<classname>.class命名,但要执行字节码中的程序,使用的指令是java <classname>(没有.class后缀)。去除文件后缀可以方便的实现文件的运行。