mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 22:40:05 +08:00
203 lines
6.2 KiB
VimL
203 lines
6.2 KiB
VimL
let s:Guard = vital#gina#import('Vim.Guard')
|
|
let s:String = vital#gina#import('Data.String')
|
|
|
|
function! s:extend_content(content, data) abort
|
|
unlockvar 1 a:content
|
|
let a:content[-1] .= a:data[0]
|
|
call extend(a:content, a:data[1:])
|
|
lockvar 1 a:content
|
|
endfunction
|
|
|
|
|
|
" Default pipe -------------------------------------------------------------
|
|
function! gina#process#pipe#default() abort
|
|
let pipe = deepcopy(s:default_pipe)
|
|
return pipe
|
|
endfunction
|
|
|
|
function! s:_default_pipe_on_start() abort dict
|
|
call gina#process#register(self)
|
|
endfunction
|
|
|
|
function! s:_default_pipe_on_exit(exitval) abort dict
|
|
call gina#process#unregister(self)
|
|
endfunction
|
|
|
|
let s:default_pipe = {
|
|
\ 'on_start': function('s:_default_pipe_on_start'),
|
|
\ 'on_exit': function('s:_default_pipe_on_exit'),
|
|
\}
|
|
|
|
|
|
" Store pipe ---------------------------------------------------------------
|
|
function! gina#process#pipe#store() abort
|
|
let pipe = deepcopy(s:store_pipe)
|
|
let pipe.stdout = ['']
|
|
let pipe.stderr = ['']
|
|
let pipe.content = ['']
|
|
lockvar 1 pipe.stdout
|
|
lockvar 1 pipe.stderr
|
|
lockvar 1 pipe.content
|
|
return pipe
|
|
endfunction
|
|
|
|
function! s:_store_pipe_on_receive(event, data) abort dict
|
|
call map(a:data, 'v:val[-1:] ==# "\r" ? v:val[:-2] : v:val')
|
|
call s:extend_content(self[a:event], a:data)
|
|
call s:extend_content(self.content, a:data)
|
|
endfunction
|
|
|
|
function! s:_store_pipe_on_exit(exitval) abort dict
|
|
" Content may has an extra empty line (POSIX text) so remove it
|
|
if has_key(self, 'stdout') && empty(self.stdout[-1])
|
|
unlockvar 1 self.stdout
|
|
call remove(self.stdout, -1)
|
|
lockvar 1 self.stdout
|
|
endif
|
|
if has_key(self, 'stderr') && empty(self.stderr[-1])
|
|
unlockvar 1 self.stderr
|
|
call remove(self.stderr, -1)
|
|
lockvar 1 self.stderr
|
|
endif
|
|
if has_key(self, 'content') && empty(self.content[-1])
|
|
unlockvar 1 self.content
|
|
call remove(self.content, -1)
|
|
lockvar 1 self.content
|
|
endif
|
|
call call('s:_default_pipe_on_exit', [a:exitval], self)
|
|
endfunction
|
|
|
|
let s:store_pipe = {
|
|
\ 'on_start': function('s:_default_pipe_on_start'),
|
|
\ 'on_stdout': function('s:_store_pipe_on_receive', ['stdout']),
|
|
\ 'on_stderr': function('s:_store_pipe_on_receive', ['stderr']),
|
|
\ 'on_exit': function('s:_store_pipe_on_exit'),
|
|
\}
|
|
|
|
|
|
" Echo pipe ----------------------------------------------------------------
|
|
function! gina#process#pipe#echo() abort
|
|
let pipe = deepcopy(s:echo_pipe)
|
|
let pipe.stdout = ['']
|
|
let pipe.stderr = ['']
|
|
let pipe.content = ['']
|
|
lockvar 1 pipe.stdout
|
|
lockvar 1 pipe.stderr
|
|
lockvar 1 pipe.content
|
|
return pipe
|
|
endfunction
|
|
|
|
function! s:_echo_pipe_on_exit(exitval) abort dict
|
|
if len(self.content)
|
|
call gina#core#console#message(
|
|
\ s:String.remove_ansi_sequences(join(self.content, "\n")),
|
|
\)
|
|
endif
|
|
call call('s:_store_pipe_on_exit', [a:exitval], self)
|
|
endfunction
|
|
|
|
let s:echo_pipe = {
|
|
\ 'on_start': function('s:_default_pipe_on_start'),
|
|
\ 'on_stdout': function('s:_store_pipe_on_receive', ['stdout']),
|
|
\ 'on_stderr': function('s:_store_pipe_on_receive', ['stderr']),
|
|
\ 'on_exit': function('s:_echo_pipe_on_exit'),
|
|
\}
|
|
|
|
|
|
" Stream pipe --------------------------------------------------------------
|
|
function! gina#process#pipe#stream(...) abort
|
|
let pipe = deepcopy(s:stream_pipe)
|
|
let pipe.writer = gina#core#writer#new(a:0 ? a:1 : s:stream_pipe_writer)
|
|
let pipe.stderr = ['']
|
|
let pipe.content = ['']
|
|
lockvar 1 pipe.stderr
|
|
lockvar 1 pipe.content
|
|
return pipe
|
|
endfunction
|
|
|
|
function! s:_stream_pipe_on_start() abort dict
|
|
call call('s:_default_pipe_on_start', [], self)
|
|
let self.writer._job = self
|
|
call self.writer.start()
|
|
endfunction
|
|
|
|
function! s:_stream_pipe_on_receive(data) abort dict
|
|
call map(a:data, 'v:val[-1:] ==# "\r" ? v:val[:-2] : v:val')
|
|
call self.writer.write(a:data)
|
|
endfunction
|
|
|
|
function! s:_stream_pipe_on_exit(data) abort dict
|
|
call self.writer.stop()
|
|
call call('s:_echo_pipe_on_exit', [a:data], self)
|
|
endfunction
|
|
|
|
let s:stream_pipe = {
|
|
\ 'on_start': function('s:_stream_pipe_on_start'),
|
|
\ 'on_stdout': function('s:_stream_pipe_on_receive'),
|
|
\ 'on_stderr': function('s:_store_pipe_on_receive', ['stderr']),
|
|
\ 'on_exit': function('s:_stream_pipe_on_exit'),
|
|
\}
|
|
|
|
" Stream pipe writer -------------------------------------------------------
|
|
function! gina#process#pipe#stream_writer() abort
|
|
return deepcopy(s:stream_pipe_writer)
|
|
endfunction
|
|
|
|
function! s:_discard_winview() abort
|
|
augroup gina_process_pipe_stream_pipe_writer_internal
|
|
autocmd! * <buffer=abuf>
|
|
autocmd CursorMoved <buffer=abuf>
|
|
\ silent! unlet! b:gina_winview |
|
|
\ autocmd! gina_process_pipe_stream_pipe_writer_internal * <buffer=abuf>
|
|
augroup END
|
|
endfunction
|
|
|
|
function! s:_stream_pipe_writer_on_start() abort dict
|
|
let self._spinner = gina#core#spinner#start(self.bufnr)
|
|
call gina#process#register('writer:' . self.bufnr, 1)
|
|
call gina#core#emitter#emit('writer:started', self.bufnr)
|
|
" When user moves cursor, remove 'b:gina_winview' to prevent unwilling
|
|
" cursor change after completion
|
|
augroup gina_process_pipe_stream_pipe_writer_internal
|
|
execute printf('autocmd! * <buffer=%d>', self.bufnr)
|
|
execute printf(
|
|
\ 'autocmd CursorMoved <buffer=%d> call s:_discard_winview()',
|
|
\ self.bufnr
|
|
\)
|
|
augroup END
|
|
endfunction
|
|
|
|
function! s:_stream_pipe_writer_on_exit() abort dict
|
|
call self._job.stop()
|
|
call self._spinner.stop()
|
|
|
|
let focus = gina#core#buffer#focus(self.bufnr)
|
|
if empty(focus) || bufnr('%') != self.bufnr
|
|
call gina#core#emitter#emit('writer:stopped', self.bufnr)
|
|
call gina#process#unregister('writer:' . self.bufnr, 1)
|
|
return
|
|
endif
|
|
try
|
|
if exists('b:gina_winview')
|
|
silent! call winrestview(b:gina_winview)
|
|
endif
|
|
finally
|
|
call focus.restore()
|
|
call gina#core#emitter#emit('writer:stopped', self.bufnr)
|
|
call gina#process#unregister('writer:' . self.bufnr, 1)
|
|
endtry
|
|
endfunction
|
|
|
|
let s:stream_pipe_writer = {
|
|
\ 'on_start': function('s:_stream_pipe_writer_on_start'),
|
|
\ 'on_exit': function('s:_stream_pipe_writer_on_exit'),
|
|
\}
|
|
|
|
|
|
" Save winview on BufUnload while winsaveview() returns unwilling value
|
|
" on BufReadCmd
|
|
augroup gina_process_pipe_internal
|
|
autocmd! *
|
|
autocmd BufUnload gina://* let b:gina_winview = winsaveview()
|
|
augroup END
|