VIM 的自定义命令可以通过 command
命令来定义,比如:
command! -nargs=* -complete=custom,helloworld#complete HelloWorld call helloworld#test()
紧接 command
命令其后的 !
表示强制定义该命令,即使前面已经定义过了同样名称的命令,也将其覆盖掉。 -nargs=*
表示,该命令可接受任意个数的参数, 包括 0 个。-nargs
的取值有以下几种情况:
参数 | 定义 |
---|---|
-nargs=0 |
不接受任何参数(默认) |
-nagrs=1 |
只接受一个参数 |
-nargs=* |
可接收任意个数参数 |
-nargs=? |
可接受 1 个或者 0 个参数 |
-nargs=+ |
至少提供一个参数 |
-complete=custom,helloworld#complete
表示,改命令的补全方式采用的是自定义函数 helloworld#complete
。-complete
可以接受的参数包括如下内容:
参数 | 描述 |
---|---|
-complete=augroup |
autocmd 组名 |
-complete=buffer |
buffer 名称 |
-complete=behave |
:behave 命令子选项 |
-complete=color |
颜色主题 |
-complete=command |
Ex 命令及参数 |
-complete=compiler |
编译器 |
-complete=cscope |
:cscope 命令子选项 |
-complete=dir |
文件夹名称 |
-complete=environment |
环境变量名称 |
-complete=event |
自动命令的事件名称 |
-complete=expression |
VIM 表达式 |
-complete=file |
文件及文件夹名称 |
-complete=file_in_path |
path 选项里的文件及文件夹名称 |
-complete=filetype |
文件类型 |
-complete=function |
函数名称 |
-complete=help |
帮助命令子选项 |
-complete=highlight |
高亮组名称 |
-complete=history |
:history 子选项 |
-complete=locale |
locale 名称(相当于命令locale -a 的输出) |
-complete=mapping |
快捷键名称 |
-complete=menu |
目录 |
-complete=messages |
:messages 命令子选项 |
-complete=option |
VIM 选项名称 |
-complete=packadd |
可选的插件名称补全 |
-complete=shellcmd |
shell 命令补全 |
-complete=sign |
:sign 命令补全 |
-complete=syntax |
语法文件名称补全 |
-complete=syntime |
:syntime 命令补全 |
-complete=tag |
tags |
-complete=tag_listfiles |
tags, file names are shown when CTRL-D is hit |
-complete=user |
user names |
-complete=var |
user variables |
-complete=custom,{func} |
custom completion, defined via {func} |
-complete=customlist,{func} |
custom completion, defined via {func} |
这里主要解释一些自定义的补全函数,从上面的表格可以看出,有两种定义自定义命令补全函数的方式。 -complete=custom,{func}
和 -complete=customlist,{func}
。这两种区别在与函数的返回值, 前者要求是一个 string
而后者要求补全函数的返回值是 list
. 自定义命令补全函数接受三个参数。
:function {func}(ArgLead, CmdLine, CursorPos)
我们以实际的例子来解释这三个参数的含义,比如在命令行是如下内容时,|
表示光标位置,我按下了 `` 键调用了补全函数,那么传递给补全函数的三个参数分别是:
:HelloWorld hello|
参数名 | 描述 |
---|---|
ArgLead |
当前需要补全的部分,通常是光标前的字符串,上面的例子中是指hello |
CmdLine |
指的是整个命令行内的内容,此时是HelloWorld hello |
CursorPos |
指的当前光标所在的位置,此时是 16, 即为len('HelloWorld hello') |
下面,我们来看下定义的函数具体内容:
function! helloworld#complete(ArgLead, CmdLine, CursorPos) abort
return join(['hellolily', 'hellojeky', 'hellofoo', 'world']
\ "\n")
endfunction
在上面的函数里,返回的实际上是一个有四行的字符串,VIM 会自动根据 ArgLead
来筛选出可以用来补全的选项,并展示在状态栏上。 此时,四行里最后一个 world
因为开头不匹配 ArgLead
所以不会被展示在状态栏上,因此补全效果只有三个可选项。
-complete=customlist,{func}
这一参数所对应的补全函数,也是接受相同的三个参数,但该函数返回的是一个 list。下面,我们来测试这个函数:
function! helloworld#complete(ArgLead, CmdLine, CursorPos) abort
return ['hellolily', 'hellojeky', 'hellofoo', 'world']
endfunction
区别很明显,customlist
补全时不会自动根据 ArgLead
进行筛选,并且直接补全整个返回的 list,即使列表中有一个 world
完全与 ArgLead(hello)
不同, 也会将其直接覆盖。因此,当使用 customlist
时,需要在函数内根据 ArgLead
进行筛选,将函数该为如下,就可以得到相同效果了:
function! helloworld#complete(ArgLead, CmdLine, CursorPos) abort
return filter(['hellolily', 'hellojeky', 'hellofoo', 'world'], 'v:val =~ "^" . a:ArgLead')
endfunction
-bang
参数:在定义 VIM 自定义命令时,可以通过 -bang
参数来申明这个命令接受感叹号。比如 :q
与 :q!
。 下面是一个实例:
fu! s:hello(bang)
if a:bang
echom "带有叹号"
else
echom "不带有叹号"
endif
endf
command! -bang Hello call s:hello(<bang>0)
在上面的实例里,函数的参数写法为 0
, 当执行:Hello!
时,传递给 s:hello
这一函数的参数是 !0
即为 1
,因此,此时看到打印了”带有叹号“。
其实除了写成 0
, 还可以写 1
, 甚至是 `` + 一个全局变量。比如:
let g:hello = 0
fu! s:hello(bang)
if a:bang
echom "带有叹号"
else
echom "不带有叹号"
endif
endf
command! -bang Hello call s:hello(<bang>g:hello)