150 lines
3.9 KiB
VimL
150 lines
3.9 KiB
VimL
|
if get(s:, 'loaded', 0)
|
||
|
finish
|
||
|
endif
|
||
|
let s:loaded = 1
|
||
|
|
||
|
let s:id = 1
|
||
|
let s:reg = {}
|
||
|
let s:leaving = 0
|
||
|
|
||
|
augroup yarp
|
||
|
autocmd!
|
||
|
" this one is which you're most likely to use?
|
||
|
autocmd VimLeavePre * let s:leaving = 1
|
||
|
augroup end
|
||
|
|
||
|
if has('nvim')
|
||
|
let s:rpcrequest = 'rpcrequest'
|
||
|
let s:rpcnotify = 'rpcnotify'
|
||
|
let s:jobstart = 'jobstart'
|
||
|
fun! s:_serveraddr()
|
||
|
return v:servername
|
||
|
endfunc
|
||
|
let s:serveraddr = function('s:_serveraddr')
|
||
|
else
|
||
|
let s:rpcrequest = get(g:, 'yarp_rpcrequest', 'neovim_rpc#rpcrequest')
|
||
|
let s:rpcnotify = get(g:, 'yarp_rpcnotify', 'neovim_rpc#rpcnotify')
|
||
|
let s:jobstart = get(g:, 'yarp_jobstart', 'neovim_rpc#jobstart')
|
||
|
let s:serveraddr = get(g:, 'yarp_serveraddr', 'neovim_rpc#serveraddr')
|
||
|
endif
|
||
|
|
||
|
func! yarp#core#new()
|
||
|
let s:id = s:id + 1
|
||
|
|
||
|
let rp = {}
|
||
|
|
||
|
let rp.jobstart = function('yarp#core#jobstart')
|
||
|
func rp.error(msg) dict
|
||
|
call yarp#core#error(self.module, a:msg)
|
||
|
endfunc
|
||
|
let rp.call = function('yarp#core#request')
|
||
|
let rp.request = function('yarp#core#request')
|
||
|
let rp.notify = function('yarp#core#notify')
|
||
|
let rp.wait_channel = function('yarp#core#wait_channel')
|
||
|
let rp.id = s:id
|
||
|
let rp.job_is_dead = 0
|
||
|
let s:reg[rp.id] = rp
|
||
|
|
||
|
" reserved for user
|
||
|
let rp.extra = {}
|
||
|
return rp
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#on_stderr(chan_id, data, event) dict
|
||
|
let mod = self.self
|
||
|
call mod.error(filter(a:data, 'len(v:val)'))
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#on_exit(chan_id, data, event) dict
|
||
|
let mod = self.self
|
||
|
let mod.job_is_dead = 1
|
||
|
if v:dying == 0 && s:leaving == 0
|
||
|
call mod.error("Job is dead. cmd=" . string(mod.cmd))
|
||
|
endif
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#channel_started(id, channel)
|
||
|
let s:reg[a:id].channel = a:channel
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#request(method, ...) dict
|
||
|
call self.wait_channel()
|
||
|
return call(s:rpcrequest, [self.channel, a:method] + a:000)
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#notify(method, ...) dict
|
||
|
call self.wait_channel()
|
||
|
call call(s:rpcnotify, [self.channel, a:method] + a:000)
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#wait_channel() dict
|
||
|
if has_key(self, 'channel')
|
||
|
return
|
||
|
endif
|
||
|
if ! has_key(self, 'job')
|
||
|
call self.jobstart()
|
||
|
endif
|
||
|
if get(self, 'job', -1) == -1
|
||
|
throw '[yarp] [' . self.module . '] job is not running'
|
||
|
endif
|
||
|
let cnt = 5000 / 20
|
||
|
while ! has_key(self, 'channel')
|
||
|
if self.job_is_dead
|
||
|
throw '[yarp] [' . self.module .
|
||
|
\ '] job is dead. failed establishing channel for ' .
|
||
|
\ string(self.cmd)
|
||
|
endif
|
||
|
if cnt <= 0
|
||
|
throw '[yarp] [' . self.module . '] timeout establishing channel for ' . string(self.cmd)
|
||
|
endif
|
||
|
let cnt = cnt - 1
|
||
|
silent sleep 20m
|
||
|
endwhile
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#jobstart() dict
|
||
|
if ! has_key(self, 'cmd')
|
||
|
call self.init()
|
||
|
if ! has_key(self, 'cmd')
|
||
|
call self.error("cmd of the job is not set")
|
||
|
return
|
||
|
endif
|
||
|
endif
|
||
|
if has_key(self, 'job')
|
||
|
return
|
||
|
endif
|
||
|
let opts = {'on_stderr': function('yarp#core#on_stderr'),
|
||
|
\ 'on_exit': function('yarp#core#on_exit'),
|
||
|
\ 'self': self}
|
||
|
try
|
||
|
let self.job = call(s:jobstart, [self.cmd, opts])
|
||
|
if self.job == -1
|
||
|
call self.error('Failed starting job: ' . string(self.cmd))
|
||
|
endif
|
||
|
catch
|
||
|
let self.job = -1
|
||
|
call self.error(['Failed starting job: ' . string(self.cmd), v:exception])
|
||
|
endtry
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#serveraddr()
|
||
|
return call (s:serveraddr, [])
|
||
|
endfunc
|
||
|
|
||
|
func! yarp#core#error(mod, msg)
|
||
|
if mode() == 'i'
|
||
|
" NOTE: side effect, sorry, but this is necessary
|
||
|
set nosmd
|
||
|
endif
|
||
|
if type(a:msg) == type("")
|
||
|
let lines = split(a:msg, "\n", 1)
|
||
|
else
|
||
|
let lines = a:msg
|
||
|
endif
|
||
|
echoh ErrorMsg
|
||
|
for line in lines
|
||
|
echom '[' . a:mod . '@yarp] ' . line
|
||
|
endfor
|
||
|
echoh None
|
||
|
endfunc
|