182 lines
4.7 KiB
VimL
182 lines
4.7 KiB
VimL
|
|
||
|
|
||
|
if has('pythonx')
|
||
|
let s:py = 'pythonx'
|
||
|
let s:pyeval = function('pyxeval')
|
||
|
elseif has('python3')
|
||
|
let s:py = 'python3'
|
||
|
let s:pyeval = function('py3eval')
|
||
|
else
|
||
|
let s:py = 'python'
|
||
|
let s:pyeval = function('pyeval')
|
||
|
endif
|
||
|
|
||
|
func! neovim_rpc#serveraddr()
|
||
|
if exists('g:_neovim_rpc_nvim_server')
|
||
|
return g:_neovim_rpc_nvim_server
|
||
|
endif
|
||
|
|
||
|
" must be utf-8
|
||
|
if &encoding !=? "utf-8"
|
||
|
throw '[vim-hug-neovim-rpc] requires `:set encoding=utf-8`'
|
||
|
endif
|
||
|
|
||
|
try
|
||
|
execute s:py . ' import neovim'
|
||
|
catch
|
||
|
call neovim_rpc#_error("failed executing: " . s:py . " import neovim")
|
||
|
call neovim_rpc#_error(v:exception)
|
||
|
throw '[vim-hug-neovim-rpc] requires `:' . s:py . ' import neovim` command to work'
|
||
|
endtry
|
||
|
|
||
|
execute s:py . ' import neovim_rpc_server'
|
||
|
let l:servers = s:pyeval('neovim_rpc_server.start()')
|
||
|
|
||
|
let g:_neovim_rpc_nvim_server = l:servers[0]
|
||
|
let g:_neovim_rpc_vim_server = l:servers[1]
|
||
|
|
||
|
let g:_neovim_rpc_main_channel = ch_open(g:_neovim_rpc_vim_server)
|
||
|
|
||
|
" close channel before vim exit
|
||
|
" au VimLeavePre * let s:leaving = 1 | execute s:py . ' neovim_rpc_server.stop()'
|
||
|
|
||
|
" identify myself
|
||
|
call ch_sendexpr(g:_neovim_rpc_main_channel,'neovim_rpc_setup')
|
||
|
|
||
|
return g:_neovim_rpc_nvim_server
|
||
|
endfunc
|
||
|
|
||
|
" elegant python function call wrapper
|
||
|
func! neovim_rpc#pyxcall(func,...)
|
||
|
execute s:py . ' import vim, json'
|
||
|
let g:neovim_rpc#_tmp_args = copy(a:000)
|
||
|
let l:ret = s:pyeval(a:func . '(*vim.vars["neovim_rpc#_tmp_args"])')
|
||
|
unlet g:neovim_rpc#_tmp_args
|
||
|
return l:ret
|
||
|
endfunc
|
||
|
|
||
|
" supported opt keys:
|
||
|
" - on_stdout
|
||
|
" - on_stderr
|
||
|
" - on_exit
|
||
|
" - detach
|
||
|
func! neovim_rpc#jobstart(cmd,...)
|
||
|
|
||
|
let l:opts = {}
|
||
|
if len(a:000)
|
||
|
let l:opts = a:1
|
||
|
endif
|
||
|
|
||
|
let l:real_opts = {'mode': 'raw'}
|
||
|
if has_key(l:opts,'detach') && l:opts['detach']
|
||
|
let l:real_opts['stoponexit'] = ''
|
||
|
endif
|
||
|
|
||
|
if has_key(l:opts,'on_stdout')
|
||
|
let l:real_opts['out_cb'] = function('neovim_rpc#_on_stdout')
|
||
|
endif
|
||
|
if has_key(l:opts,'on_stderr')
|
||
|
let l:real_opts['err_cb'] = function('neovim_rpc#_on_stderr')
|
||
|
endif
|
||
|
let l:real_opts['exit_cb'] = function('neovim_rpc#_on_exit')
|
||
|
|
||
|
let l:job = job_start(a:cmd, l:real_opts)
|
||
|
let l:jobid = ch_info(l:job)['id']
|
||
|
|
||
|
let g:_neovim_rpc_jobs[l:jobid] = {'cmd':a:cmd, 'opts': l:opts, 'job': l:job}
|
||
|
|
||
|
return l:jobid
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#jobstop(jobid)
|
||
|
let l:job = g:_neovim_rpc_jobs[a:jobid]['job']
|
||
|
return job_stop(l:job)
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#rpcnotify(channel,event,...)
|
||
|
call neovim_rpc#pyxcall('neovim_rpc_server.rpcnotify',a:channel,a:event,a:000)
|
||
|
endfunc
|
||
|
|
||
|
let s:rspid = 1
|
||
|
func! neovim_rpc#rpcrequest(channel, event, ...)
|
||
|
let s:rspid = s:rspid + 1
|
||
|
|
||
|
" a unique key for storing response
|
||
|
let rspid = '' . s:rspid
|
||
|
|
||
|
" neovim's rpcrequest doesn't have timeout
|
||
|
let opt = {'timeout': 24 * 60 * 60 * 1000}
|
||
|
let args = ['rpcrequest', a:channel, a:event, a:000, rspid]
|
||
|
call ch_evalexpr(g:_neovim_rpc_main_channel, args, opt)
|
||
|
|
||
|
let expr = 'json.dumps(neovim_rpc_server.responses.pop("' . rspid . '"))'
|
||
|
|
||
|
execute s:py ' import neovim_rpc_server, json'
|
||
|
let [err, result] = json_decode(s:pyeval(expr))
|
||
|
if err
|
||
|
if type(err) == type('')
|
||
|
throw err
|
||
|
endif
|
||
|
throw err[1]
|
||
|
endif
|
||
|
return result
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#_on_stdout(job,data)
|
||
|
let l:jobid = ch_info(a:job)['id']
|
||
|
let l:opts = g:_neovim_rpc_jobs[l:jobid]['opts']
|
||
|
" convert to neovim style function call
|
||
|
call call(l:opts['on_stdout'],[l:jobid,split(a:data,"\n",1),'stdout'],l:opts)
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#_on_stderr(job,data)
|
||
|
let l:jobid = ch_info(a:job)['id']
|
||
|
let l:opts = g:_neovim_rpc_jobs[l:jobid]['opts']
|
||
|
" convert to neovim style function call
|
||
|
call call(l:opts['on_stderr'],[l:jobid,split(a:data,"\n",1),'stderr'],l:opts)
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#_on_exit(job,status)
|
||
|
let l:jobid = ch_info(a:job)['id']
|
||
|
let l:opts = g:_neovim_rpc_jobs[l:jobid]['opts']
|
||
|
unlet g:_neovim_rpc_jobs[l:jobid]
|
||
|
if has_key(l:opts, 'on_exit')
|
||
|
" convert to neovim style function call
|
||
|
call call(l:opts['on_exit'],[l:jobid,a:status,'exit'],l:opts)
|
||
|
endif
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#_callback()
|
||
|
execute s:py . ' neovim_rpc_server.process_pending_requests()'
|
||
|
endfunc
|
||
|
|
||
|
let g:_neovim_rpc_main_channel = -1
|
||
|
let g:_neovim_rpc_jobs = {}
|
||
|
|
||
|
let s:leaving = 0
|
||
|
|
||
|
func! neovim_rpc#_error(msg)
|
||
|
if mode() == 'i'
|
||
|
" NOTE: side effect, sorry, but this is necessary
|
||
|
set nosmd
|
||
|
endif
|
||
|
echohl ErrorMsg
|
||
|
echom '[vim-hug-neovim-rpc] ' . a:msg
|
||
|
echohl None
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#_nvim_err_write(msg)
|
||
|
if mode() == 'i'
|
||
|
" NOTE: side effect, sorry, but this is necessary
|
||
|
set nosmd
|
||
|
endif
|
||
|
echohl ErrorMsg
|
||
|
let g:error = a:msg
|
||
|
echom a:msg
|
||
|
echohl None
|
||
|
endfunc
|
||
|
|
||
|
func! neovim_rpc#_nvim_out_write(msg)
|
||
|
echom a:msg
|
||
|
endfunc
|