162 lines
3.9 KiB
VimL
162 lines
3.9 KiB
VimL
if exists('g:autoloaded_tabby_job')
|
|
finish
|
|
endif
|
|
let g:autoloaded_tabby_job = 1
|
|
|
|
let s:vim = exists('*job_start')
|
|
let s:nvim = !s:vim && has('nvim') && exists('*jobstart')
|
|
|
|
function! tabby#job#Check()
|
|
return #{
|
|
\ ok: s:vim || s:nvim,
|
|
\ message: 'Tabby requires Vim 9.0+ with +job feature support, or NeoVim 0.6.0+.',
|
|
\}
|
|
endfunction
|
|
|
|
let s:nvim_job_map = {}
|
|
|
|
" Assume Json IO
|
|
" Options 'out_cb', 'err_cb', 'exit_cb' supported
|
|
" Return job id
|
|
function! tabby#job#Start(command, ...)
|
|
let options = get(a:, 1, {})
|
|
if s:vim
|
|
let opt = #{
|
|
\ in_mode: 'json',
|
|
\ out_mode: 'json',
|
|
\ }
|
|
if has_key(options, 'out_cb')
|
|
let opt.out_cb = options.out_cb
|
|
endif
|
|
if has_key(options, 'err_cb')
|
|
let opt.err_cb = options.err_cb
|
|
endif
|
|
if has_key(options, 'exit_cb')
|
|
let opt.exit_cb = options.exit_cb
|
|
endif
|
|
return job_start(a:command, opt)
|
|
endif
|
|
if s:nvim
|
|
let id = jobstart(a:command, #{
|
|
\ on_stdout: function('s:NvimHandleStdout'),
|
|
\ on_stderr: function('s:NvimHandleStderr'),
|
|
\ on_exit: function('s:NvimHandleExit'),
|
|
\})
|
|
let s:nvim_job_map[id] = #{
|
|
\ out_buffer: '',
|
|
\ requests: {},
|
|
\}
|
|
if has_key(options, 'out_cb')
|
|
let s:nvim_job_map[id].out_cb = options.out_cb
|
|
endif
|
|
if has_key(options, 'err_cb')
|
|
let s:nvim_job_map[id].err_cb = options.err_cb
|
|
endif
|
|
if has_key(options, 'exit_cb')
|
|
let s:nvim_job_map[id].exit_cb = options.exit_cb
|
|
endif
|
|
return id
|
|
endif
|
|
endfunction
|
|
|
|
function! tabby#job#Stop(job)
|
|
if s:vim
|
|
return job_stop(a:job)
|
|
endif
|
|
if s:nvim
|
|
let ret = jobstop(a:job)
|
|
call jobwait([a:job], 100)
|
|
if has_key(s:nvim_job_map, a:job)
|
|
unlet s:nvim_job_map[a:job]
|
|
endif
|
|
return ret
|
|
endif
|
|
endfunction
|
|
|
|
" Align to Vim's ch_sendexpr
|
|
" Options 'callback' supported
|
|
function! tabby#job#Send(job, data, ...)
|
|
let options = get(a:, 1, {})
|
|
let id = s:NextRequestId()
|
|
if s:vim
|
|
call ch_sendexpr(a:job, a:data, options)
|
|
endif
|
|
if s:nvim
|
|
let request = [id, a:data]
|
|
let s:nvim_job_map[a:job].requests[id] = {}
|
|
if has_key(options, 'callback')
|
|
let s:nvim_job_map[a:job].requests[id].callback = options.callback
|
|
endif
|
|
call chansend(a:job, json_encode(request) . "\n")
|
|
endif
|
|
return id
|
|
endfunction
|
|
|
|
let s:request_id = 0
|
|
function! s:NextRequestId()
|
|
let s:request_id += 1
|
|
return s:request_id
|
|
endfunction
|
|
|
|
function! s:NvimHandleStdout(job, data, event)
|
|
if !has_key(s:nvim_job_map, a:job)
|
|
return
|
|
endif
|
|
let buf = s:nvim_job_map[a:job].out_buffer
|
|
for data_line in a:data
|
|
let buf .= data_line
|
|
try
|
|
let decoded = json_decode(buf)
|
|
let buf = ''
|
|
catch
|
|
continue
|
|
endtry
|
|
call s:NvimHandleOutDecoded(a:job, decoded)
|
|
endfor
|
|
let s:nvim_job_map[a:job].out_buffer = buf
|
|
endfunction
|
|
|
|
function! s:NvimHandleOutDecoded(job, decoded)
|
|
if !has_key(s:nvim_job_map, a:job)
|
|
return
|
|
endif
|
|
if type(a:decoded) != v:t_list || len(a:decoded) < 1 || (type(a:decoded[0]) != v:t_number)
|
|
return
|
|
endif
|
|
let id = a:decoded[0]
|
|
if len(a:decoded) >= 2
|
|
let data = a:decoded[1]
|
|
else
|
|
let data = {}
|
|
endif
|
|
if (id > 0) && has_key(s:nvim_job_map[a:job].requests, id)
|
|
let request = s:nvim_job_map[a:job].requests[id]
|
|
if has_key(request, 'callback')
|
|
call request.callback(a:job, data)
|
|
endif
|
|
unlet s:nvim_job_map[a:job].requests[id]
|
|
else
|
|
if has_key(s:nvim_job_map[a:job], 'out_cb')
|
|
call s:nvim_job_map[a:job].out_cb(a:job, data)
|
|
endif
|
|
endif
|
|
endfunction
|
|
|
|
function! s:NvimHandleStderr(job, data, event)
|
|
if !has_key(s:nvim_job_map, a:job)
|
|
return
|
|
endif
|
|
if has_key(s:nvim_job_map[a:job], 'err_cb')
|
|
call s:nvim_job_map[a:job].err_cb(a:job, join(a:data, "\n"))
|
|
endif
|
|
endfunction
|
|
|
|
function! s:NvimHandleExit(job, status, event)
|
|
if !has_key(s:nvim_job_map, a:job)
|
|
return
|
|
endif
|
|
if has_key(s:nvim_job_map[a:job], 'exit_cb')
|
|
call s:nvim_job_map[a:job].exit_cb(a:job, a:status)
|
|
endif
|
|
endfunction
|