Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Async wrapper #4

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions autoload/minpac/impl.vim
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ endfunction

function! s:job_err_cb(name, channel, message) abort
echohl WarningMsg
echom a:name . ': ' . a:message
echom a:name . ': ' . join(a:message, "\n")
echohl None
endfunction

Expand All @@ -89,11 +89,13 @@ function! s:start_job(cmds, name, seq) abort
else
let l:cmds = a:cmds
endif
let l:job = job_start(l:cmds, {
\ 'exit_cb': function('s:job_exit_cb', [a:name, a:seq]),
\ 'in_io': 'null', 'out_io': 'null',
\ 'err_cb': function('s:job_err_cb', [a:name])})
if job_status(l:job) ==# 'fail'
let l:job = minpac#job#start(l:cmds, {
\ 'on_stderr': function('s:job_err_cb'),
\ 'on_exit': function('s:job_exit_cb', [a:name]),
\ })
if l:job > 0
" It worked!
else
echohl ErrorMsg
echom 'Fail to execute: ' . a:cmds[0]
echohl None
Expand Down
180 changes: 180 additions & 0 deletions autoload/minpac/job.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
" Author: Prabir Shrestha <mail at prabir dot me>
" License: The MIT License
" Website: https://github.com/prabirshrestha/async.vim

let s:save_cpo = &cpo
set cpo&vim

let s:jobidseq = 0
let s:jobs = {} " { job, opts, type: 'vimjob|nvimjob'}
let s:job_type_nvimjob = 'nvimjob'
let s:job_type_vimjob = 'vimjob'
let s:job_error_unsupported_job_type = -2 " unsupported job type

function! s:job_supported_types() abort
let l:supported_types = []
if has('nvim')
let l:supported_types += [s:job_type_nvimjob]
endif
if !has('nvim') && has('job') && has('channel') && has('lambda')
let l:supported_types += [s:job_type_vimjob]
endif
return l:supported_types
endfunction

function! s:job_supports_type(type) abort
return index(s:job_supported_types(), a:type) >= 0
endfunction

function! s:out_cb(job, data, jobid, opts) abort
if has_key(a:opts, 'on_stdout')
call a:opts.on_stdout(a:jobid, split(a:data, "\n", 1), 'stdout')
endif
endfunction

function! s:err_cb(job, data, jobid, opts) abort
if has_key(a:opts, 'on_stderr')
call a:opts.on_stderr(a:jobid, split(a:data, "\n", 1), 'stderr')
endif
endfunction

function! s:exit_cb(job, status, jobid, opts) abort
if has_key(a:opts, 'on_exit')
call a:opts.on_exit(a:jobid, a:status, 'exit')
endif
if has_key(s:jobs, a:jobid)
call remove(s:jobs, a:jobid)
endif
endfunction

function! s:on_stdout(jobid, data, event) abort
if has_key(s:jobs, a:jobid)
let l:jobinfo = s:jobs[a:jobid]
if has_key(l:jobinfo.opts, 'on_stdout')
call l:jobinfo.opts.on_stdout(a:jobid, a:data, a:event)
endif
endif
endfunction

function! s:on_stderr(jobid, data, event) abort
if has_key(s:jobs, a:jobid)
let l:jobinfo = s:jobs[a:jobid]
if has_key(l:jobinfo.opts, 'on_stderr')
call l:jobinfo.opts.on_stderr(a:jobid, a:data, a:event)
endif
endif
endfunction

function! s:on_exit(jobid, status, event) abort
if has_key(s:jobs, a:jobid)
let l:jobinfo = s:jobs[a:jobid]
if has_key(l:jobinfo.opts, 'on_exit')
call l:jobinfo.opts.on_exit(a:jobid, a:status, a:event)
endif
endif
endfunction

function! s:job_start(cmd, opts) abort
let l:jobtypes = s:job_supported_types()
let l:jobtype = ''

if has_key(a:opts, 'type')
if type(a:opts.type, v:t_string)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i fixed the bug on upstream async.vim. You would want to sync this with latest master.

if !s:job_supports_type(a:opts.type)
return s:job_error_unsupported_job_type
endif
let l:jobtype = a:opts.type
else
let l:jobtypes = a:opts.type
endif
endif

if empty(l:jobtype)
" find the best jobtype
for l:jobtype2 in l:jobtypes
if s:job_supports_type(l:jobtype2)
let l:jobtype = l:jobtype2
endif
endfor
endif

if l:jobtype == ''
return s:job_error_unsupported_job_type
endif

if l:jobtype == s:job_type_nvimjob
let l:job = jobstart(a:cmd, {
\ 'on_stdout': function('s:on_stdout'),
\ 'on_stderr': function('s:on_stderr'),
\ 'on_exit': function('s:on_exit'),
\})
if l:job <= 0
return l:job
endif
let l:jobid = l:job " nvimjobid and internal jobid is same
let s:jobs[l:jobid] = {
\ 'type': s:job_type_nvimjob,
\ 'opts': a:opts,
\ }
let s:jobs[l:jobid].job = l:job
elseif l:jobtype == s:job_type_vimjob
let s:jobidseq = s:jobidseq + 1
let l:jobid = s:jobidseq
let l:job = job_start(a:cmd, {
\ 'out_cb': {job,data->s:out_cb(job, data, l:jobid, a:opts)},
\ 'err_cb': {job,data->s:err_cb(job, data, l:jobid, a:opts)},
\ 'exit_cb': {job,data->s:exit_cb(job, data, l:jobid, a:opts)},
\ 'mode': 'raw',
\})
if job_status(l:job) != 'run'
return -1
endif
let s:jobs[l:jobid] = {
\ 'type': s:job_type_vimjob,
\ 'opts': a:opts,
\ 'job': l:job,
\ 'channel': job_getchannel(l:job)
\ }
else
return s:job_error_unsupported_job_type
endif

return l:jobid
endfunction

function! s:job_stop(jobid) abort
if has_key(s:jobs, a:jobid)
let l:jobinfo = s:jobs[a:jobid]
if l:jobinfo.type == s:job_type_nvimjob
call jobstop(a:jobid)
elseif l:jobinfo.type == s:job_type_vimjob
call job_stop(s:jobs[a:jobid].job)
endif
if has_key(s:jobs, a:jobid)
call remove(s:jobs, a:jobid)
endif
endif
endfunction

function! s:job_send(jobid, data) abort
let l:jobinfo = s:jobs[a:jobid]
if l:jobinfo.type == s:job_type_nvimjob
call jobsend(a:jobid, a:data)
elseif l:jobinfo.type == s:job_type_vimjob
call ch_sendraw(l:jobinfo.channel, a:data)
endif
endfunction

" public apis {{{
function! minpac#job#start(cmd, opts) abort
return s:job_start(a:cmd, a:opts)
endfunction

function! minpac#job#stop(jobid) abort
call s:job_stop(a:jobid)
endfunction

function! minpac#job#send(jobid, data) abort
call s:job_send(a:jobid, a:data)
endfunction
" }}}