vimproc を使用して非同期で外部コマンドを実行し、後から結果を取得する

殆ど quickrun.vim の写経なんですが、自分でも書いてみました。

[ソース]

set updatetime=100


augroup vimproc-async-receive-test
augroup END


" コマンド終了時に呼ばれる関数
function! s:finish(result)
    echom "finish"
    echo a:result
endfunction

function! s:receive_vimproc_result()
    if !has_key(s:, "vimproc")
        return
    endif

    let vimproc = s:vimproc

    try
        if !vimproc.stdout.eof
            let s:result .= vimproc.stdout.read()
        endif

        if !vimproc.stderr.eof
            let s:result .= vimproc.stderr.read()
        endif

        if !(vimproc.stdout.eof && vimproc.stderr.eof)
            return 0
        endif
    catch
        echom v:throwpoint
    endtry

    " 終了時に呼ぶ
    call s:finish(s:result)
    
    augroup vimproc-async-receive-test
        autocmd!
    augroup END

    call vimproc.stdout.close()
    call vimproc.stderr.close()
    call vimproc.waitpid()
    unlet s:vimproc
    unlet s:result
endfunction


function! s:system_async(cmd)
    let cmd = a:cmd
    let vimproc = vimproc#pgroup_open(cmd)
    call vimproc.stdin.close()
    
    let s:vimproc = vimproc
    let s:result = ""
    
    augroup vimproc-async-receive-test
        execute "autocmd! CursorHold,CursorHoldI * call"
\               "s:receive_vimproc_result()"
    augroup END
endfunction

call s:system_async("ruby -e \"sleep 3; puts 'homu'; puts 'mado'\"")

s:system_async に渡したコマンドを非同期で実行し、処理が終わったら s:finish を呼ぶような感じです。
上記のコードでは :source すると3秒後に "homu" と "mado" が出力されます。
もうちょっと複雑なイメージがあったんですが、実際に書いてみるとそうでもなかったですね。
おもしろい。


差し当っての問題としては更新のタイミングは updatetime に依存してしまうことですかね…。
プラグイン側で非同期処理を行う場合、updatetime を気軽に変更することが出来ないのがつらぽよ…。