Add neovim job/terminal APIs
This commit is contained in:
parent
18627b9244
commit
29c26996fb
5 changed files with 237 additions and 2 deletions
163
autoload/vimspector/internal/neojob.vim
Normal file
163
autoload/vimspector/internal/neojob.vim
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
" vimspector - A multi-language debugging system for Vim
|
||||||
|
" Copyright 2018 Ben Jackson
|
||||||
|
"
|
||||||
|
" Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
" you may not use this file except in compliance with the License.
|
||||||
|
" You may obtain a copy of the License at
|
||||||
|
"
|
||||||
|
" http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
"
|
||||||
|
" Unless required by applicable law or agreed to in writing, software
|
||||||
|
" distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
" See the License for the specific language governing permissions and
|
||||||
|
" limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let s:save_cpo = &cpoptions
|
||||||
|
set cpoptions&vim
|
||||||
|
" }}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function! s:_OnEvent( chan_id, data, event ) abort
|
||||||
|
" In neovim, the data argument is a list.
|
||||||
|
if a:event ==# 'stdout'
|
||||||
|
py3 _vimspector_session.OnChannelData( '\n'.join( vim.eval( 'a:data' ) ) )
|
||||||
|
elseif a:event ==# 'stderr'
|
||||||
|
py3 _vimspector_session.OnServerStderr( '\n'.join( vim.eval( 'a:data' ) ) )
|
||||||
|
elseif a:event ==# 'exit'
|
||||||
|
echom 'Channel exit with status ' . a:data
|
||||||
|
redraw
|
||||||
|
unlet s:job
|
||||||
|
py3 _vimspector_session.OnServerExit( vim.eval( 'a:data' ) )
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neojob#StartDebugSession( config ) abort
|
||||||
|
if exists( 's:job' )
|
||||||
|
echom 'Not starging: Job is already running'
|
||||||
|
redraw
|
||||||
|
return v:false
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:job = jobstart( a:config[ 'command' ],
|
||||||
|
\ {
|
||||||
|
\ 'on_stdout': funcref( 's:_OnEvent' ),
|
||||||
|
\ 'on_stderr': funcref( 's:_OnEvent' ),
|
||||||
|
\ 'on_exit': funcref( 's:_OnEvent' ),
|
||||||
|
\ 'cwd': a:config[ 'cwd' ],
|
||||||
|
\ }
|
||||||
|
\ )
|
||||||
|
|
||||||
|
" FIXME: Missing in neovim 0.4. But in master:
|
||||||
|
" \ 'env': a:config[ 'env' ],
|
||||||
|
"
|
||||||
|
|
||||||
|
" FIXME: error handling ?
|
||||||
|
return v:true
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:JobIsRunning( job ) abort
|
||||||
|
return jobwait( [ s:job ], 0 )[ 0 ] == -1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neojob#Send( msg ) abort
|
||||||
|
if ! exists( 's:job' )
|
||||||
|
echom "Can't send message: Job was not initialised correctly"
|
||||||
|
redraw
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !s:JobIsRunning( s:job )
|
||||||
|
echom "Can't send message: Job is not running"
|
||||||
|
redraw
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
call chansend( s:job, a:msg )
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neojob#StopDebugSession() abort
|
||||||
|
if !exists( 's:job' )
|
||||||
|
echom "Not stopping session: Job doesn't exist"
|
||||||
|
redraw
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if s:JobIsRunning( s:job )
|
||||||
|
echom 'Terminating job'
|
||||||
|
redraw
|
||||||
|
call jobstop( s:job )
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neojob#Reset() abort
|
||||||
|
call vimspector#internal#neojob#StopDebugSession()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:_OnCommandEvent( category, id, data, event ) abort
|
||||||
|
if a:data == ['']
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if a:event ==# 'stdout'
|
||||||
|
let buffer = s:commands[ a:category ][ a:id ].stdout
|
||||||
|
elseif a:event ==# 'stderr'
|
||||||
|
let buffer = s:commands[ a:category ][ a:id ].stderr
|
||||||
|
endif
|
||||||
|
|
||||||
|
let last_line_list = getbufline( buffer, '$' )
|
||||||
|
if len( last_line_list ) == 0
|
||||||
|
let last_line = ''
|
||||||
|
else
|
||||||
|
let last_line = last_line_list[ 0 ]
|
||||||
|
endif
|
||||||
|
|
||||||
|
call setbufline( buffer, '$', last_line . a:data[ 0 ] )
|
||||||
|
call appendbufline( buffer, '$', a:data[ 1: ] )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:commands = {}
|
||||||
|
|
||||||
|
function! vimspector#internal#neojob#StartCommandWithLog( cmd, category ) abort
|
||||||
|
if ! has_key( s:commands, a:category )
|
||||||
|
let s:commands[ a:category ] = {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
let stdout_buf = bufnr( '_vimspector_log_' . a:category . '_out', 1 )
|
||||||
|
let stderr_buf = bufnr( '_vimspector_log_' . a:category . '_err', 1 )
|
||||||
|
|
||||||
|
let id = jobstart(a:cmd,
|
||||||
|
\ {
|
||||||
|
\ 'on_stdout': funcref( 's:_OnCommandEvent',
|
||||||
|
\ [ a:category ] ),
|
||||||
|
\ 'on_stderr': funcref( 's:_OnCommandEvent',
|
||||||
|
\ [ a:category ] )
|
||||||
|
\ } )
|
||||||
|
|
||||||
|
let s:commands[ a:category ][ id ] = {
|
||||||
|
\ 'stdout': stdout_buf,
|
||||||
|
\ 'stderr': stderr_buf
|
||||||
|
\ }
|
||||||
|
|
||||||
|
return [ stdout_buf, stderr_buf ]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neojob#CleanUpCommand( category ) abort
|
||||||
|
if ! has_key( s:commands, a:category )
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
for id in keys( s:commands[ a:category ] )
|
||||||
|
call jobstop( id )
|
||||||
|
call jobwait( id )
|
||||||
|
endfor
|
||||||
|
unlet! s:commands[ a:category ]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let &cpoptions=s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
|
" }}}
|
||||||
67
autoload/vimspector/internal/neoterm.vim
Normal file
67
autoload/vimspector/internal/neoterm.vim
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
" vimspector - A multi-language debugging system for Vim
|
||||||
|
" Copyright 2018 Ben Jackson
|
||||||
|
"
|
||||||
|
" Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
" you may not use this file except in compliance with the License.
|
||||||
|
" You may obtain a copy of the License at
|
||||||
|
"
|
||||||
|
" http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
"
|
||||||
|
" Unless required by applicable law or agreed to in writing, software
|
||||||
|
" distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
" See the License for the specific language governing permissions and
|
||||||
|
" limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let s:save_cpo = &cpoptions
|
||||||
|
set cpoptions&vim
|
||||||
|
" }}}
|
||||||
|
|
||||||
|
" Ids are unique throughtout the life of neovim, but obviously buffer numbers
|
||||||
|
" aren't
|
||||||
|
"
|
||||||
|
" FIXME: Tidy this map when buffers are closed ?
|
||||||
|
let s:buffer_to_id = {}
|
||||||
|
|
||||||
|
function! vimspector#internal#neoterm#Start( cmd, opts ) abort
|
||||||
|
if ! get( a:opts, 'curwin', 0 )
|
||||||
|
if get( a:opts, 'vertical', 0 )
|
||||||
|
vsplit
|
||||||
|
else
|
||||||
|
split
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" FIXME: 'env' doesn't work
|
||||||
|
let id = termopen( a:cmd, { 'cwd': a:opts[ 'cwd' ] } )
|
||||||
|
let bufnr = bufnr()
|
||||||
|
let s:buffer_to_id[ bufnr ] = id
|
||||||
|
return bufnr
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:JobIsRunning( job ) abort
|
||||||
|
return jobwait( [ a:job ], 0 )[ 0 ] == -1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neoterm#IsFinished( bufno ) abort
|
||||||
|
if !has_key( s:buffer_to_id, a:bufno )
|
||||||
|
return v:true
|
||||||
|
endif
|
||||||
|
|
||||||
|
return !s:JobIsRunning( s:buffer_to_id[ a:bufno ] )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neoterm#GetPID( bufno ) abort
|
||||||
|
if !has_key( s:buffer_to_id, a:bufno )
|
||||||
|
return -1
|
||||||
|
endif
|
||||||
|
|
||||||
|
return jobpid( s:buffer_to_id[ a:bufno ] )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let &cpoptions=s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
|
" }}}
|
||||||
|
|
@ -19,8 +19,13 @@ let s:save_cpo = &cpoptions
|
||||||
set cpoptions&vim
|
set cpoptions&vim
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
let s:is_neovim = has( 'nvim' )
|
||||||
|
|
||||||
function! vimspector#internal#state#Reset() abort
|
function! vimspector#internal#state#Reset() abort
|
||||||
let prefix = ''
|
let prefix = ''
|
||||||
|
if s:is_neovim
|
||||||
|
let prefix='neo'
|
||||||
|
endif
|
||||||
py3 << EOF
|
py3 << EOF
|
||||||
from vimspector import debug_session
|
from vimspector import debug_session
|
||||||
_vimspector_session = debug_session.DebugSession( vim.eval( 'prefix' ) )
|
_vimspector_session = debug_session.DebugSession( vim.eval( 'prefix' ) )
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ class OutputView( object ):
|
||||||
vim.command( 'bdelete! {0}'.format( tab_buffer.buf.number ) )
|
vim.command( 'bdelete! {0}'.format( tab_buffer.buf.number ) )
|
||||||
except vim.error as e:
|
except vim.error as e:
|
||||||
# FIXME: For now just ignore the "no buffers were deleted" error
|
# FIXME: For now just ignore the "no buffers were deleted" error
|
||||||
if 'E516' not in e:
|
if 'E516' not in str( e ):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
self._buffers = {}
|
self._buffers = {}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ def SetUpHiddenBuffer( buf, name ):
|
||||||
def SetUpPromptBuffer( buf, name, prompt, callback, hidden=False ):
|
def SetUpPromptBuffer( buf, name, prompt, callback, hidden=False ):
|
||||||
# This feature is _super_ new, so only enable when available
|
# This feature is _super_ new, so only enable when available
|
||||||
if not int( vim.eval( "exists( '*prompt_setprompt' )" ) ):
|
if not int( vim.eval( "exists( '*prompt_setprompt' )" ) ):
|
||||||
return SetUpScratchBuffer( buf, name )
|
return SetUpHiddenBuffer( buf, name )
|
||||||
|
|
||||||
buf.options[ 'buftype' ] = 'prompt'
|
buf.options[ 'buftype' ] = 'prompt'
|
||||||
buf.options[ 'swapfile' ] = False
|
buf.options[ 'swapfile' ] = False
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue