在传统的单线程模式下,运行外部命令时,将中断用户当前的编辑操作,并等待命令完成才可以返回vim。
自8.0版本起,包含+channel和+job特性的Vim将可以支持异步操作。Vim使用作业(job)来启动进程,并利用通道(channel)和其他进程通信。
利用异步支持,可以在后台进行复杂耗时的操作(比如使用外部grep工具查找文本),不必等待外部命令结束即可返回Vim,而不中断前台的正常编辑。在外部命令结束运行时,可以通过回调函数来处理输出结果。
例如使用:!ls
外部命令,将在屏幕底部列示目录内容,并等待用户按回车键以返回常规模式,此时用户无法进行其它操作:
使用job_start()函数,可以异步执行命令,其格式为:
job_start({command} [, {options}])
其中:command,用于指定需要运行的外部系统命令;options,是包含多个键值的字典选项,用于配置和控制作业的行为。
使用以下命令,可以启动作业以执行外部命令,并立刻返回常规模式,不影响用户的后续操作:
:call job_start('ls')
作业采用管道(pipe)将外部命令与vim联接起来,并与标准输入(stdin)、标准输出(stdout)和标准错误(stderr)输出进行交互。
在使用job_start()函数启动作业时,可以注册一个或多个回调函数来处理特定的信息。如果希望静默执行命令,而不关心输出信息,那么也可以不注册任何回调函数。
使用"callback"选项,可以同时捕获标准输出与标准错误输出;也可以分别使用"out_cb"或"err_cb"选项,来单独捕获标准输出或标准错误输出。
首先定义用于捕获输出的回调函数:
func! MyHandler (channel, msg)
echomsg a:msg
endfunc
通过"callback"选项,指定回调函数来处理stdout和stderr的内容:
let job = job_start ('ls', {"callback": "MyHandler"})
通过"out_cb"选项,指定回调函数来处理stdout的内容:
let job = job_start ('ls', {"out_cb": "MyHandler"})
通过"err_cb"选项,指定回调函数来处理stderr的内容:
let job = job_start ('ls', {"err_cb": "ErrHandler"})
在以上回调函数中使用了:echomsg
命令,因此随后可以使用:message
命令来查看信息历史,以确认命令执行结果:
使用"in_io"、"out_io"或"err_io"选项,可以将作业管道重定向到文件或缓冲区。
使用以下命令,可以将标准输出重定向至指定缓冲区:
:let job = job_start('ls', {'out_io': 'buffer', 'out_name': 'mybuffer'})
使用以下命令,则可以打开缓冲区查看输出信息:
:sbuf mybuffer
请注意,首行包含了“Reading from channel output...”的说明文字:
使用以下任一命令,均可以将标准输出重定向至指定文件:
:let job = job_start('ls -al', {'out_io': 'file', 'out_name': '/tmp/file.txt'})
:call job_start(["/bin/sh", "-c", "ls -al > /tmp/file.txt"])
?使用以下命令,可以查看作业选项的帮助信息:
:help job-options
使用job_status()函数,可以返回指定作业的状态:
:echo job_status(job)
状态 | 描述 |
---|---|
run | 作业运行中 |
fail | 作业无法启动 |
dead | 作业启动后结束或被终止 |
使用job_info()函数,则可返回指定作业的详细信息:
:echo job_info(job)
函数将返回包含详细信息的字典:
键 | 描述 |
---|---|
status | job_status()返回值 |
cmd | 启动作业的命令行参数列表 |
stoponexit | Vim结束时给作业发信号(缺省是 "term") |
channel | job_getchannel()返回值 |
process | 进程ID |
tty_in | 终端输入名,如果没有则为空 |
tty_out | 终端输出名,如果没有则为空 |
exitval | "status" 为 "dead" 时才有效 |
exit_cb | 退出时调用的函数 |
termsig | 终止程序的信号(仅用于Unix) 仅当"status"为"dead"时才有意义 |
tty_type | 使用的虚拟控制台类型(仅用于MS-Windows) 可选值是"winpty"或"conpty" |
使用job_stop()函数,可以停止指定的作业:
:call job_stop(job)
实例1:启动Apache HTTP Server服务
:let job = job_start('apachectl start')
使用以下命令载入首页内容,以确认服务启动成功:
:silent r ! curl localhost
实例2:在位置列表中显示命令输出
function! s:on_find(chan, msg)
lgetexpr split(a:msg, '')
endfunction
call job_start('find . -print0', {
\ 'out_mode': 'raw',
\ 'callback': function('<SID>on_find')
\ })
使用以下命令,执行包含以上命令的脚本:
:so %
使用以下命令,将在位置列表(location list)中显示外部find命令输出的文件列表:
:lopen
?使用以下命令,可以查看关于作业的帮助信息:
:help job
job_start() | 启动作业 |
job_status() | 显示作业状态 |
job_info() | 显示作业的详细信息 |
job_stop() | 停止作业 |