You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
4.1 KiB
VimL
148 lines
4.1 KiB
VimL
6 years ago
|
" ___vital___
|
||
|
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||
|
" Do not mofidify the code nor insert new lines before '" ___vital___'
|
||
|
if v:version > 703 || v:version == 703 && has('patch1170')
|
||
|
function! vital#_tsuquyomi#ProcessManager#import() abort
|
||
|
return map({'read': '', '_vital_depends': '', 'touch': '', 'read_wait': '', 'writeln': '', 'write': '', 'kill': '', 'state': '', 'term': '', 'is_available': '', 'debug_processes': '', 'status': '', '_vital_loaded': ''}, 'function("s:" . v:key)')
|
||
|
endfunction
|
||
|
else
|
||
|
function! s:_SID() abort
|
||
|
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||
|
endfunction
|
||
|
execute join(['function! vital#_tsuquyomi#ProcessManager#import() abort', printf("return map({'read': '', '_vital_depends': '', 'touch': '', 'read_wait': '', 'writeln': '', 'write': '', 'kill': '', 'state': '', 'term': '', 'is_available': '', 'debug_processes': '', 'status': '', '_vital_loaded': ''}, \"function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||
|
delfunction s:_SID
|
||
|
endif
|
||
|
" ___vital___
|
||
|
let s:save_cpo = &cpo
|
||
|
set cpo&vim
|
||
|
|
||
|
let s:_processes = {}
|
||
|
|
||
|
function! s:_vital_loaded(V) abort
|
||
|
let s:V = a:V
|
||
|
let s:S = s:V.import('Data.String')
|
||
|
let s:P = s:V.import('Process')
|
||
|
endfunction
|
||
|
|
||
|
function! s:_vital_depends() abort
|
||
|
return ['Data.String', 'Process']
|
||
|
endfunction
|
||
|
|
||
|
function! s:is_available() abort
|
||
|
return s:P.has_vimproc()
|
||
|
endfunction
|
||
|
|
||
|
function! s:touch(name, cmd) abort
|
||
|
if has_key(s:_processes, a:name)
|
||
|
return 'existing'
|
||
|
else
|
||
|
let p = vimproc#popen3(a:cmd)
|
||
|
let s:_processes[a:name] = p
|
||
|
return 'new'
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:_stop(i, ...) abort
|
||
|
let p = s:_processes[a:i]
|
||
|
call p.kill(get(a:000, 0, 0) ? g:vimproc#SIGKILL : g:vimproc#SIGTERM)
|
||
|
" call p.waitpid()
|
||
|
unlet s:_processes[a:i]
|
||
|
if has_key(s:state, a:i)
|
||
|
unlet s:state[a:i]
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:term(i) abort
|
||
|
return s:_stop(a:i, 0)
|
||
|
endfunction
|
||
|
|
||
|
function! s:kill(i) abort
|
||
|
return s:_stop(a:i, 1)
|
||
|
endfunction
|
||
|
|
||
|
function! s:read(i, endpatterns) abort
|
||
|
return s:read_wait(a:i, 0.05, a:endpatterns)
|
||
|
endfunction
|
||
|
|
||
|
let s:state = {}
|
||
|
|
||
|
function! s:read_wait(i, wait, endpatterns) abort
|
||
|
if !has_key(s:_processes, a:i)
|
||
|
throw printf("vital: ProcessManager: doesn't know about %s", a:i)
|
||
|
endif
|
||
|
|
||
|
let p = s:_processes[a:i]
|
||
|
|
||
|
if s:status(a:i) ==# 'inactive'
|
||
|
let s:state[a:i] = 'inactive'
|
||
|
return [p.stdout.read(), p.stderr.read(), 'inactive']
|
||
|
endif
|
||
|
|
||
|
let out_memo = ''
|
||
|
let err_memo = ''
|
||
|
let lastchanged = reltime()
|
||
|
while 1
|
||
|
let [x, y] = [p.stdout.read(-1, 0), p.stderr.read(-1, 0)]
|
||
|
if x ==# '' && y ==# ''
|
||
|
if str2float(reltimestr(reltime(lastchanged))) > a:wait
|
||
|
let s:state[a:i] = 'reading'
|
||
|
return [out_memo, err_memo, 'timedout']
|
||
|
endif
|
||
|
else
|
||
|
let lastchanged = reltime()
|
||
|
let out_memo .= x
|
||
|
let err_memo .= y
|
||
|
for pattern in a:endpatterns
|
||
|
if out_memo =~ ("\\(^\\|\n\\)" . pattern)
|
||
|
let s:state[a:i] = 'idle'
|
||
|
return [s:S.substitute_last(out_memo, pattern, ''), err_memo, 'matched']
|
||
|
endif
|
||
|
endfor
|
||
|
endif
|
||
|
endwhile
|
||
|
endfunction
|
||
|
|
||
|
function! s:state(i) abort
|
||
|
return get(s:state, a:i, 'undefined')
|
||
|
endfunction
|
||
|
|
||
|
function! s:write(i, str) abort
|
||
|
if !has_key(s:_processes, a:i)
|
||
|
throw printf("vital: ProcessManager: doesn't know about %s", a:i)
|
||
|
endif
|
||
|
if s:status(a:i) ==# 'inactive'
|
||
|
return 'inactive'
|
||
|
endif
|
||
|
|
||
|
let p = s:_processes[a:i]
|
||
|
call p.stdin.write(a:str)
|
||
|
|
||
|
return 'active'
|
||
|
endfunction
|
||
|
|
||
|
function! s:writeln(i, str) abort
|
||
|
return s:write(a:i, a:str . "\n")
|
||
|
endfunction
|
||
|
|
||
|
function! s:status(i) abort
|
||
|
if !has_key(s:_processes, a:i)
|
||
|
throw printf("vital: ProcessManager: doesn't know about %s", a:i)
|
||
|
endif
|
||
|
let p = s:_processes[a:i]
|
||
|
" vimproc.kill isn't to stop but to ask for the current state.
|
||
|
" return p.kill(0) ? 'inactive' : 'active'
|
||
|
" ... checkpid() checks if the process is running AND does waitpid() in C,
|
||
|
" so it solves zombie processes.
|
||
|
return get(p.checkpid(), 0, '') ==# 'run'
|
||
|
\ ? 'active'
|
||
|
\ : 'inactive'
|
||
|
endfunction
|
||
|
|
||
|
function! s:debug_processes() abort
|
||
|
return s:_processes
|
||
|
endfunction
|
||
|
|
||
|
let &cpo = s:save_cpo
|
||
|
unlet s:save_cpo
|
||
|
" vim:set et ts=2 sts=2 sw=2 tw=0:
|