Asynchronous Vim
In my last post I explored using Python and nccurses
to asynchronously render
streamed content from curl
. Upon a re-think of my strategy, I wondered why I
even needed Python at all. In modern versions of Vim, I knew that asynchronous
abilities were available, but I had no idea how to use it at all. After quite a
bit of experimentation and reading the docs, this is what I learned:
Jobs
The job_start
command can execute a shell command and intercept the results
with callbacks. You can even create partial functions and use them as callbacks!
" job_demo.vim
function! OutCb(bufchannel, msg) abort
call append('$', a:msg)
endfunction
function! ExitCb(foo, job, status) abort
call append('$', "Status: ".a:status)
call append("$", a:foo)
endfunction
let cmd = ['/bin/bash', '-c', 'for i in 1 2 3; do echo $i; sleep 1; done']
let callbacks = {'out_cb': function("OutCb"), 'exit_cb': function("ExitCb", [456])}
let job_id = job_start(cmd, callbacks)
Write this script to as buffer and running :w job_demo.vim | so %
will append the script with
1
2
3
Status: 0
456
as the job progresses. With this working example, I was able to understand :h job
much more!
Timers
Sometimes you just need a function to call every N seconds or so.
" timer_demo.vim
let g:counter = 0
function! MyFunc(msg, timer_id) abort
if g:counter > 3
return
endif
let g:counter += 1
call append("$",a:msg)
let n_msecs = 1000
call timer_start(n_msecs, function('MyFunc', [1000 * n_msecs]))
endfunction
let timer_id = timer_start(1000, function('MyFunc', ["timer go!"]))
This appends the text
timer go!
1000
2000
3000
As the timer executes. Check out :h timer
for more info.
And both these methods don’t block other actions in Vim! You can keep editing or processing text in another buffer without interruption.