概述
Vim从8.0版本开始支持异步IO,通过job来开始执行另一个进程,通过channel来进行进程通信。
只要Vim的版本高于8.0,并且在编译时有+channel
和+job
的feature,就可以通过使用Vim的异步支持来让插件或脚本拥有更好的体验,比如异步编译使Vim在编译时不在阻塞、异步语法高亮来时Vim获得更快的速度等。
使用
has('channel')
has('job')
来判断Vim是否有相关支持。
我有一个在Vim中翻译单词的插件,但在网络不好的情况下翻译会阻塞正常的浏览,本文是我希望插件可以进行异步翻译而进行的学习笔记,只简单记录了job的工作方式,更多详细内容请在Vim中使用:help channel
查看。
job的工作方式
job可以理解为Linux中的进程,通过:
job_start(command, {options})
可以在这个一个进程(job)中执行command,job_start返回job对象,使用
let channel = job_getchannel(job)
可以获得channel用于进程(job)之间通信,但我的目的只是异步执行翻译的job,用不到在job之间通信,所以不再讨论。
command是要执行的外部命令,如果要获取命令的执行结果或状态,可以使用options设置回调函数来完成。
处理任务输出
捕获每次输出
如果command产生输出,可以使用out_cb
定义回调函数处理输出:
func! Handler(channel, msg)
" deal with msg
endfunc
let job = job_start(command, {'out_cb': 'Handler'})
cb表示callback
或者可以使用ch_read(job)
或者cd_readraw(job)
读取job产生的输出。
捕获结束输出
如果不想获取处理任务的中间输出,可以使用close_cb
定义回调函数获取结束job的输出:
func! CloseHandler(channel)
while ch_status(a:channel, {'part': 'out'}) == 'buffered'
echomsg ch_read(a:channel)
endwhile
endfunc
let job = job_start(command, {'close_cb': 'CloseHandler'})
处理任务的错误输出
out_cb
指定的回调函数不会接收标准错误输出,可以使用err_cb
指定的回调函处理错误输出:
let job = job_start(command, {'out_cb': 'Handler',
\ 'err_cb': 'ErrHandler'})
callback
指定的回调函数既可以接收错误输出,也可以接收普通输出。
let job = job_start(command, {"callback": "MyHandler"})
控制job
得到job状态:
job_status(job)
停止job:
job_stop(job)
示例
如果我们有一个耗时3s的外部程序要执行,程序执行之后输出日期,如果使用过去的方法,将其映射到<F3>
键(这里使用sleep 3s模拟该耗时程序):
nnoremap <F3> :!/bin/bash -c 'sleep 3s; date'<CR>
点击<F3>
后Vim将有3s处于阻塞状态,无法进行任何操作。
接下来使用异步来处理这个程序:
" 回调函数
func! Handler(channel, msg)
echo a:msg
endfunc
" 执行job
func! GetDate()
call job_start(['/bin/bash', '-c', 'sleep 3s; date'], {'callback': 'Handler'})
endfunc
nnoremap <F3> :call GetDate()<cr>
此时再点击<F3>
,Vim将不会阻塞,可以继续进行操作,并在3s后输出日期。
- older
- Newer