commit
4318e567f2
18 changed files with 760 additions and 193 deletions
|
|
@ -96,6 +96,11 @@ function! vimspector#AddWatchPrompt( expr ) abort
|
||||||
call vimspector#AddWatch( a:expr )
|
call vimspector#AddWatch( a:expr )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#Evaluate( expr ) abort
|
||||||
|
py3 _vimspector_session.ShowOutput( 'Console' )
|
||||||
|
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) )
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! vimspector#EvaluateConsole( expr ) abort
|
function! vimspector#EvaluateConsole( expr ) abort
|
||||||
stopinsert
|
stopinsert
|
||||||
setlocal nomodified
|
setlocal nomodified
|
||||||
|
|
@ -110,6 +115,18 @@ function! vimspector#ListBreakpoints() abort
|
||||||
py3 _vimspector_session.ListBreakpoints()
|
py3 _vimspector_session.ListBreakpoints()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort
|
||||||
|
let buffers = py3eval( '_vimspector_session.GetOutputBuffers()' )
|
||||||
|
return join( buffers, "\n" )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort
|
||||||
|
return join( py3eval( '_vimspector_session.GetCompletionsSync( '
|
||||||
|
\.' vim.eval( "a:CmdLine" ),'
|
||||||
|
\.' int( vim.eval( "a:CursorPos" ) ) )' ),
|
||||||
|
\ "\n" )
|
||||||
|
endfunction
|
||||||
|
|
||||||
" Boilerplate {{{
|
" Boilerplate {{{
|
||||||
let &cpoptions=s:save_cpo
|
let &cpoptions=s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,6 @@ _vimspector_session.OnChannelData( vim.eval( 'a:data' ) )
|
||||||
EOF
|
EOF
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_OnServerError( channel, data ) abort
|
|
||||||
echom 'Channel received error: ' . a:data
|
|
||||||
redraw
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:_OnClose( channel ) abort
|
function! s:_OnClose( channel ) abort
|
||||||
echom 'Channel closed'
|
echom 'Channel closed'
|
||||||
redraw
|
redraw
|
||||||
|
|
@ -37,22 +32,11 @@ function! s:_OnClose( channel ) abort
|
||||||
py3 _vimspector_session.OnServerExit( 0 )
|
py3 _vimspector_session.OnServerExit( 0 )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_Send( msg ) abort
|
|
||||||
call ch_sendraw( s:ch, a:msg )
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! vimspector#internal#channel#Timeout( id ) abort
|
|
||||||
py3 << EOF
|
|
||||||
_vimspector_session.OnRequestTimeout( vim.eval( 'a:id' ) )
|
|
||||||
EOF
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! vimspector#internal#channel#StartDebugSession( config ) abort
|
function! vimspector#internal#channel#StartDebugSession( config ) abort
|
||||||
|
|
||||||
if exists( 's:ch' )
|
if exists( 's:ch' )
|
||||||
echo 'Channel is already running'
|
echo 'Channel is already running'
|
||||||
return v:none
|
return v:false
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let l:addr = 'localhost:' . a:config[ 'port' ]
|
let l:addr = 'localhost:' . a:config[ 'port' ]
|
||||||
|
|
@ -70,10 +54,21 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
|
||||||
if ch_status( s:ch ) !=# 'open'
|
if ch_status( s:ch ) !=# 'open'
|
||||||
echom 'Unable to connect to debug adapter'
|
echom 'Unable to connect to debug adapter'
|
||||||
redraw
|
redraw
|
||||||
return v:none
|
return v:false
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return funcref( 's:_Send' )
|
return v:true
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#channel#Send( msg ) abort
|
||||||
|
call ch_sendraw( s:ch, a:msg )
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#channel#Timeout( id ) abort
|
||||||
|
py3 << EOF
|
||||||
|
_vimspector_session.OnRequestTimeout( vim.eval( 'a:id' ) )
|
||||||
|
EOF
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#internal#channel#StopDebugSession() abort
|
function! vimspector#internal#channel#StopDebugSession() abort
|
||||||
|
|
@ -97,15 +92,6 @@ function! vimspector#internal#channel#Reset() abort
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#internal#channel#ForceRead() abort
|
|
||||||
if exists( 's:ch' )
|
|
||||||
let data = ch_readraw( s:ch, { 'timeout': 1000 } )
|
|
||||||
if data !=# ''
|
|
||||||
call s:_OnServerData( s:ch, data )
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Boilerplate {{{
|
" Boilerplate {{{
|
||||||
let &cpoptions=s:save_cpo
|
let &cpoptions=s:save_cpo
|
||||||
unlet s:save_cpo
|
unlet s:save_cpo
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ endfunction
|
||||||
function! s:_OnExit( channel, status ) abort
|
function! s:_OnExit( channel, status ) abort
|
||||||
echom 'Channel exit with status ' . a:status
|
echom 'Channel exit with status ' . a:status
|
||||||
redraw
|
redraw
|
||||||
unlet s:job
|
unlet s:job
|
||||||
py3 _vimspector_session.OnServerExit( vim.eval( 'a:status' ) )
|
py3 _vimspector_session.OnServerExit( vim.eval( 'a:status' ) )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
@ -39,35 +39,11 @@ function! s:_OnClose( channel ) abort
|
||||||
redraw
|
redraw
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_Send( msg ) abort
|
|
||||||
if ! exists( 's:job' )
|
|
||||||
echom "Can't send message: Job was not initialised correctly"
|
|
||||||
redraw
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
if job_status( s:job ) !=# 'run'
|
|
||||||
echom "Can't send message: Job is not running"
|
|
||||||
redraw
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let ch = job_getchannel( s:job )
|
|
||||||
if ch ==# 'channel fail'
|
|
||||||
echom 'Channel was closed unexpectedly!'
|
|
||||||
redraw
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
call ch_sendraw( ch, a:msg )
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! vimspector#internal#job#StartDebugSession( config ) abort
|
function! vimspector#internal#job#StartDebugSession( config ) abort
|
||||||
if exists( 's:job' )
|
if exists( 's:job' )
|
||||||
echom 'Not starging: Job is already running'
|
echom 'Not starging: Job is already running'
|
||||||
redraw
|
redraw
|
||||||
return v:none
|
return v:false
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let s:job = job_start( a:config[ 'command' ],
|
let s:job = job_start( a:config[ 'command' ],
|
||||||
|
|
@ -91,10 +67,34 @@ function! vimspector#internal#job#StartDebugSession( config ) abort
|
||||||
if job_status( s:job ) !=# 'run'
|
if job_status( s:job ) !=# 'run'
|
||||||
echom 'Unable to start job, status is: ' . job_status( s:job )
|
echom 'Unable to start job, status is: ' . job_status( s:job )
|
||||||
redraw
|
redraw
|
||||||
return v:none
|
return v:false
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return funcref( 's:_Send' )
|
return v:true
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#job#Send( msg ) abort
|
||||||
|
if ! exists( 's:job' )
|
||||||
|
echom "Can't send message: Job was not initialised correctly"
|
||||||
|
redraw
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if job_status( s:job ) !=# 'run'
|
||||||
|
echom "Can't send message: Job is not running"
|
||||||
|
redraw
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
let ch = job_getchannel( s:job )
|
||||||
|
if ch ==# 'channel fail'
|
||||||
|
echom 'Channel was closed unexpectedly!'
|
||||||
|
redraw
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
call ch_sendraw( ch, a:msg )
|
||||||
|
return 1
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#internal#job#StopDebugSession() abort
|
function! vimspector#internal#job#StopDebugSession() abort
|
||||||
|
|
@ -115,15 +115,6 @@ function! vimspector#internal#job#Reset() abort
|
||||||
call vimspector#internal#job#StopDebugSession()
|
call vimspector#internal#job#StopDebugSession()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#internal#job#ForceRead() abort
|
|
||||||
if exists( 's:job' )
|
|
||||||
let data = ch_readraw( job_getchannel( s:job ), { 'timeout': 1000 } )
|
|
||||||
if data !=# ''
|
|
||||||
call s:_OnServerData( job_getchannel( s:job ), data )
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort
|
function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort
|
||||||
if ! exists( 's:commands' )
|
if ! exists( 's:commands' )
|
||||||
let s:commands = {}
|
let s:commands = {}
|
||||||
|
|
@ -136,7 +127,7 @@ function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort
|
||||||
let l:index = len( s:commands[ a:category ] )
|
let l:index = len( s:commands[ a:category ] )
|
||||||
|
|
||||||
call add( s:commands[ a:category ], job_start(
|
call add( s:commands[ a:category ], job_start(
|
||||||
\ a:cmd,
|
\ a:cmd,
|
||||||
\ {
|
\ {
|
||||||
\ 'out_io': 'buffer',
|
\ 'out_io': 'buffer',
|
||||||
\ 'in_io': 'null',
|
\ 'in_io': 'null',
|
||||||
|
|
|
||||||
85
autoload/vimspector/internal/neochannel.vim
Normal file
85
autoload/vimspector/internal/neochannel.vim
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
" vimspector - A multi-language debugging system for Vim
|
||||||
|
" Copyright 2020 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
|
||||||
|
if a:data == ['']
|
||||||
|
echom 'Channel closed'
|
||||||
|
redraw
|
||||||
|
unlet s:ch
|
||||||
|
py3 _vimspector_session.OnServerExit( 0 )
|
||||||
|
else
|
||||||
|
py3 _vimspector_session.OnChannelData( '\n'.join( vim.eval( 'a:data' ) ) )
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neochannel#StartDebugSession( config ) abort
|
||||||
|
if exists( 's:ch' )
|
||||||
|
echom 'Not starging: Channel is already running'
|
||||||
|
redraw
|
||||||
|
return v:false
|
||||||
|
endif
|
||||||
|
|
||||||
|
let addr = 'localhost:' . a:config[ 'port' ]
|
||||||
|
|
||||||
|
let s:ch = sockconnect( 'tcp', addr, { 'on_data': funcref( 's:_OnEvent' ) } )
|
||||||
|
if s:ch <= 0
|
||||||
|
unlet s:ch
|
||||||
|
return v:false
|
||||||
|
endif
|
||||||
|
|
||||||
|
return v:true
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neochannel#Send( msg ) abort
|
||||||
|
if ! exists( 's:ch' )
|
||||||
|
echom "Can't send message: Channel was not initialised correctly"
|
||||||
|
redraw
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
call chansend( s:ch, a:msg )
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neochannel#StopDebugSession() abort
|
||||||
|
if !exists( 's:ch' )
|
||||||
|
echom "Not stopping session: Channel doesn't exist"
|
||||||
|
redraw
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
call chanclose( s:ch )
|
||||||
|
" It doesn't look like we get a callback after chanclos. Who knows if we will
|
||||||
|
" subsequently receive data callbacks.
|
||||||
|
call s:_OnEvent( s:ch, [ '' ], 'data' )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#neochannel#Reset() abort
|
||||||
|
call vimspector#internal#neochannel#StopDebugSession()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let &cpoptions=s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
|
" }}}
|
||||||
|
|
||||||
212
autoload/vimspector/internal/neojob.vim
Normal file
212
autoload/vimspector/internal/neojob.vim
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
" vimspector - A multi-language debugging system for Vim
|
||||||
|
" Copyright 2020 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
|
||||||
|
" This causes terminal spam in neovim due to
|
||||||
|
" https://github.com/neovim/neovim/issues/11725
|
||||||
|
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' ],
|
||||||
|
\ 'env': a:config[ 'env' ],
|
||||||
|
\ }
|
||||||
|
\ )
|
||||||
|
|
||||||
|
" FIXME: env might not work: Missing in neovim 0.4. But in master:
|
||||||
|
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' )
|
||||||
|
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
|
||||||
|
|
||||||
|
try
|
||||||
|
call bufload( buffer )
|
||||||
|
catch /E325/
|
||||||
|
" Ignore E325/ATTENTION
|
||||||
|
endtry
|
||||||
|
|
||||||
|
|
||||||
|
let numlines = py3eval( "len( vim.buffers[ int( vim.eval( 'buffer' ) ) ] )" )
|
||||||
|
let last_line = getbufline( buffer, '$' )[ 0 ]
|
||||||
|
|
||||||
|
call s:MakeBufferWritable( buffer )
|
||||||
|
try
|
||||||
|
if numlines == 1 && last_line ==# ''
|
||||||
|
call setbufline( buffer, 1, a:data[ 0 ] )
|
||||||
|
else
|
||||||
|
call setbufline( buffer, '$', last_line . a:data[ 0 ] )
|
||||||
|
endif
|
||||||
|
|
||||||
|
call appendbufline( buffer, '$', a:data[ 1: ] )
|
||||||
|
finally
|
||||||
|
call s:MakeBufferReadOnly( buffer )
|
||||||
|
call setbufvar( buffer, '&modified', 0 )
|
||||||
|
endtry
|
||||||
|
|
||||||
|
" if the buffer is visible, scroll it
|
||||||
|
let w = bufwinnr( buffer )
|
||||||
|
if w > 0
|
||||||
|
let cw = winnr()
|
||||||
|
try
|
||||||
|
execute w . 'wincmd w'
|
||||||
|
normal! Gz.
|
||||||
|
finally
|
||||||
|
execute cw . 'wincmd w'
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SetUpHiddenBuffer( buffer ) abort
|
||||||
|
call setbufvar( a:buffer, '&hidden', 1 )
|
||||||
|
call setbufvar( a:buffer, '&bufhidden', 'hide' )
|
||||||
|
call setbufvar( a:buffer, '&wrap', 0 )
|
||||||
|
call setbufvar( a:buffer, '&swapfile', 0 )
|
||||||
|
call s:MakeBufferReadOnly( a:buffer )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:MakeBufferReadOnly( buffer ) abort
|
||||||
|
call setbufvar( a:buffer, '&modifiable', 0 )
|
||||||
|
call setbufvar( a:buffer, '&readonly', 1 )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:MakeBufferWritable( buffer ) abort
|
||||||
|
call setbufvar( a:buffer, '&readonly', 0 )
|
||||||
|
call setbufvar( a:buffer, '&modifiable', 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', v:true )
|
||||||
|
let stderr_buf = bufnr( '_vimspector_log_' . a:category . '_err', v:true )
|
||||||
|
|
||||||
|
" FIXME: This largely duplicates the same stuff in the python layer, but we
|
||||||
|
" don't want to potentially mess up Vim behaviour where the job output is
|
||||||
|
" attached to a buffer set up by Vim. So we sort o mimic that here.
|
||||||
|
call s:SetUpHiddenBuffer( stdout_buf )
|
||||||
|
call s:SetUpHiddenBuffer( stderr_buf )
|
||||||
|
|
||||||
|
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,10 +19,16 @@ 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 = ''
|
||||||
|
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()
|
_vimspector_session = debug_session.DebugSession( vim.eval( 'prefix' ) )
|
||||||
EOF
|
EOF
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
|
||||||
37
autoload/vimspector/internal/term.vim
Normal file
37
autoload/vimspector/internal/term.vim
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
" 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! vimspector#internal#term#Start( cmd, opts ) abort
|
||||||
|
return term_start( a:cmd, a:opts )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#term#IsFinished( bufno ) abort
|
||||||
|
return index( split( term_getstatus( a:bufno ), ',' ), 'finished' ) >= 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#internal#term#GetPID( bufno ) abort
|
||||||
|
return job_info( term_getjob( a:bufno ) ).process
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Boilerplate {{{
|
||||||
|
let &cpoptions=s:save_cpo
|
||||||
|
unlet s:save_cpo
|
||||||
|
" }}}
|
||||||
|
|
@ -26,6 +26,7 @@ if exists( 'g:loaded_vimpector' )
|
||||||
call s:restore_cpo()
|
call s:restore_cpo()
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
"}}}
|
||||||
|
|
||||||
" TODO:
|
" TODO:
|
||||||
" - Check Vim version (for jobs)
|
" - Check Vim version (for jobs)
|
||||||
|
|
@ -36,28 +37,54 @@ let g:loaded_vimpector = 1
|
||||||
|
|
||||||
let s:mappings = get( g:, 'vimspector_enable_mappings', '' )
|
let s:mappings = get( g:, 'vimspector_enable_mappings', '' )
|
||||||
|
|
||||||
|
nnoremap <Plug>VimspectorContinue :<c-u>call vimspector#Continue()<CR>
|
||||||
|
nnoremap <Plug>VimspectorStop :<c-u>call vimspector#Stop()<CR>
|
||||||
|
nnoremap <Plug>VimspectorRestart :<c-u>call vimspector#Restart()<CR>
|
||||||
|
nnoremap <Plug>VimspectorPause :<c-u>call vimspector#Pause()<CR>
|
||||||
|
nnoremap <Plug>VimspectorToggleBreakpoint
|
||||||
|
\ :<c-u>call vimspector#ToggleBreakpoint()<CR>
|
||||||
|
nnoremap <Plug>VimspectorAddFunctionBreakpoint
|
||||||
|
\ :<c-u>call vimspector#AddFunctionBreakpoint( expand( '<cexpr>' ) )<CR>
|
||||||
|
nnoremap <Plug>VimspectorStepOver :<c-u>call vimspector#StepOver()<CR>
|
||||||
|
nnoremap <Plug>VimspectorStepInto :<c-u>call vimspector#StepInto()<CR>
|
||||||
|
nnoremap <Plug>VimspectorStepOut :<c-u>call vimspector#StepOut()<CR>
|
||||||
|
|
||||||
if s:mappings ==# 'VISUAL_STUDIO'
|
if s:mappings ==# 'VISUAL_STUDIO'
|
||||||
nnoremap <F5> :call vimspector#Continue()<CR>
|
nmap <F5> <Plug>VimspectorContinue
|
||||||
nnoremap <S-F5> :call vimspector#Stop()<CR>
|
nmap <S-F5> <Plug>VimspectorStop
|
||||||
nnoremap <C-S-F5> :call vimspector#Restart()<CR>
|
nmap <C-S-F5> <Plug>VimspectorRestart
|
||||||
nnoremap <F6> :call vimspector#Pause()<CR>
|
nmap <F6> <Plug>VimspectorPause
|
||||||
nnoremap <F9> :call vimspector#ToggleBreakpoint()<CR>
|
nmap <F9> <Plug>VimspectorToggleBreakpoint
|
||||||
nnoremap <S-F9> :call vimspector#AddFunctionBreakpoint( expand( '<cexpr>' ) )<CR>
|
nmap <S-F9> <Plug>VimspectorAddFunctionBreakpoint
|
||||||
nnoremap <F10> :call vimspector#StepOver()<CR>
|
nmap <F10> <Plug>VimspectorStepOver
|
||||||
nnoremap <F11> :call vimspector#StepInto()<CR>
|
nmap <F11> <Plug>VimspectorStepInto
|
||||||
nnoremap <S-F11> :call vimspector#StepOut()<CR>
|
nmap <S-F11> <Plug>VimspectorStepOut
|
||||||
elseif s:mappings ==# 'HUMAN'
|
elseif s:mappings ==# 'HUMAN'
|
||||||
nnoremap <F5> :call vimspector#Continue()<CR>
|
nmap <F5> <Plug>VimspectorContinue
|
||||||
nnoremap <F3> :call vimspector#Stop()<CR>
|
nmap <F3> <Plug>VimspectorStop
|
||||||
nnoremap <F4> :call vimspector#Restart()<CR>
|
nmap <F4> <Plug>VimspectorRestart
|
||||||
nnoremap <F6> :call vimspector#Pause()<CR>
|
nmap <F6> <Plug>VimspectorPause
|
||||||
nnoremap <F9> :call vimspector#ToggleBreakpoint()<CR>
|
nmap <F9> <Plug>VimspectorToggleBreakpoint
|
||||||
nnoremap <F8> :call vimspector#AddFunctionBreakpoint( expand( '<cexpr>' ) )<CR>
|
nmap <F8> <Plug>VimspectorAddFunctionBreakpoint
|
||||||
nnoremap <F10> :call vimspector#StepOver()<CR>
|
nmap <F10> <Plug>VimspectorStepOver
|
||||||
nnoremap <F11> :call vimspector#StepInto()<CR>
|
nmap <F11> <Plug>VimspectorStepInto
|
||||||
nnoremap <F12> :call vimspector#StepOut()<CR>
|
nmap <F12> <Plug>VimspectorStepOut
|
||||||
endif
|
endif
|
||||||
"}}}
|
|
||||||
|
|
||||||
|
command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr
|
||||||
|
\ VimspectorWatch
|
||||||
|
\ call vimspector#AddWatch( <f-args> )
|
||||||
|
command! -bar -nargs=1 -complete=custom,vimspector#CompleteOutput
|
||||||
|
\ VimspectorShowOutput
|
||||||
|
\ call vimspector#ShowOutput( <f-args> )
|
||||||
|
command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr
|
||||||
|
\ VimspectorEval
|
||||||
|
\ call vimspector#Evaluate( <f-args> )
|
||||||
|
command! -bar
|
||||||
|
\ VimspectorReset
|
||||||
|
\ call vimspector#Reset()
|
||||||
|
|
||||||
|
" boilerplate {{{
|
||||||
call s:restore_cpo()
|
call s:restore_cpo()
|
||||||
|
" }}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ from vimspector import utils
|
||||||
|
|
||||||
|
|
||||||
class CodeView( object ):
|
class CodeView( object ):
|
||||||
def __init__( self, window ):
|
def __init__( self, window, api_prefix ):
|
||||||
self._window = window
|
self._window = window
|
||||||
|
self._api_prefix = api_prefix
|
||||||
|
|
||||||
self._terminal_window = None
|
self._terminal_window = None
|
||||||
self._terminal_buffer_number = None
|
self._terminal_buffer_number = None
|
||||||
|
|
@ -214,8 +215,9 @@ class CodeView( object ):
|
||||||
if self._terminal_window is not None:
|
if self._terminal_window is not None:
|
||||||
assert self._terminal_buffer_number
|
assert self._terminal_buffer_number
|
||||||
if ( self._terminal_window.buffer.number == self._terminal_buffer_number
|
if ( self._terminal_window.buffer.number == self._terminal_buffer_number
|
||||||
and 'finished' in vim.eval( 'term_getstatus( {} )'.format(
|
and int( utils.Call( 'vimspector#internal#{}term#IsFinished'.format(
|
||||||
self._terminal_buffer_number ) ) ):
|
self._api_prefix ),
|
||||||
|
self._terminal_buffer_number ) ) ):
|
||||||
window_for_start = self._terminal_window
|
window_for_start = self._terminal_window
|
||||||
options[ 'curwin' ] = 1
|
options[ 'curwin' ] = 1
|
||||||
|
|
||||||
|
|
@ -224,13 +226,11 @@ class CodeView( object ):
|
||||||
with utils.TemporaryVimOptions( { 'splitright': True,
|
with utils.TemporaryVimOptions( { 'splitright': True,
|
||||||
'equalalways': False } ):
|
'equalalways': False } ):
|
||||||
with utils.LetCurrentWindow( window_for_start ):
|
with utils.LetCurrentWindow( window_for_start ):
|
||||||
# TODO/FIXME: Do something about closing this when we reset ?
|
buffer_number = int(
|
||||||
vim_cmd = 'term_start( {}, {} )'.format( json.dumps( args ),
|
utils.Call(
|
||||||
json.dumps( options ) )
|
'vimspector#internal#{}term#Start'.format( self._api_prefix ),
|
||||||
|
args,
|
||||||
self._logger.debug( 'Start terminal: {}'.format( vim_cmd ) )
|
options ) )
|
||||||
|
|
||||||
buffer_number = int( vim.eval( vim_cmd ) )
|
|
||||||
terminal_window = vim.current.window
|
terminal_window = vim.current.window
|
||||||
|
|
||||||
if buffer_number is None or buffer_number <= 0:
|
if buffer_number is None or buffer_number <= 0:
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,33 @@ class DebugAdapterConnection( object ):
|
||||||
if not self._SendMessage( msg ):
|
if not self._SendMessage( msg ):
|
||||||
self._AbortRequest( request, 'Unable to send message' )
|
self._AbortRequest( request, 'Unable to send message' )
|
||||||
|
|
||||||
|
|
||||||
|
def DoRequestSync( self, msg, timeout = 5000 ):
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
def handler( msg ):
|
||||||
|
result[ 'response' ] = msg
|
||||||
|
|
||||||
|
def failure_handler( reason, msg ):
|
||||||
|
result[ 'response' ] = msg
|
||||||
|
result[ 'exception' ] = RuntimeError( reason )
|
||||||
|
|
||||||
|
self.DoRequest( handler, msg, failure_handler, timeout )
|
||||||
|
|
||||||
|
bug_catcher = 1000
|
||||||
|
while not result and bug_catcher >= 0:
|
||||||
|
vim.command( 'sleep 10m' )
|
||||||
|
bug_catcher -= 10
|
||||||
|
|
||||||
|
if result.get( 'exception' ) is not None:
|
||||||
|
raise result[ 'exception' ]
|
||||||
|
|
||||||
|
if result.get( 'response' ) is None:
|
||||||
|
raise RuntimeError( "No response" )
|
||||||
|
|
||||||
|
return result[ 'response' ]
|
||||||
|
|
||||||
|
|
||||||
def OnRequestTimeout( self, timer_id ):
|
def OnRequestTimeout( self, timer_id ):
|
||||||
request_id = None
|
request_id = None
|
||||||
for seq, request in self._outstanding_requests.items():
|
for seq, request in self._outstanding_requests.items():
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,14 @@ USER_CHOICES = {}
|
||||||
|
|
||||||
|
|
||||||
class DebugSession( object ):
|
class DebugSession( object ):
|
||||||
def __init__( self ):
|
def __init__( self, api_prefix ):
|
||||||
self._logger = logging.getLogger( __name__ )
|
self._logger = logging.getLogger( __name__ )
|
||||||
utils.SetUpLogging( self._logger )
|
utils.SetUpLogging( self._logger )
|
||||||
|
|
||||||
|
self._api_prefix = api_prefix
|
||||||
|
|
||||||
self._logger.info( "**** INITIALISING NEW VIMSPECTOR SESSION ****" )
|
self._logger.info( "**** INITIALISING NEW VIMSPECTOR SESSION ****" )
|
||||||
|
self._logger.info( "API is: {}".format( api_prefix ) )
|
||||||
self._logger.info( 'VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME )
|
self._logger.info( 'VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME )
|
||||||
self._logger.info( 'gadgetDir = %s',
|
self._logger.info( 'gadgetDir = %s',
|
||||||
install.GetGadgetDir( VIMSPECTOR_HOME,
|
install.GetGadgetDir( VIMSPECTOR_HOME,
|
||||||
|
|
@ -400,12 +403,35 @@ class DebugSession( object ):
|
||||||
def ShowOutput( self, category ):
|
def ShowOutput( self, category ):
|
||||||
self._outputView.ShowOutput( category )
|
self._outputView.ShowOutput( category )
|
||||||
|
|
||||||
|
def GetOutputBuffers( self ):
|
||||||
|
return self._outputView.GetCategories()
|
||||||
|
|
||||||
|
def GetCompletionsSync( self, text_line, column_in_bytes ):
|
||||||
|
if not self._server_capabilities.get( 'supportsCompletionsRequest' ):
|
||||||
|
return []
|
||||||
|
|
||||||
|
response = self._connection.DoRequestSync( {
|
||||||
|
'command': 'completions',
|
||||||
|
'arguments': {
|
||||||
|
'frameId': self._stackTraceView.GetCurrentFrame()[ 'id' ],
|
||||||
|
# TODO: encoding ? bytes/codepoints
|
||||||
|
'text': text_line,
|
||||||
|
'column': column_in_bytes
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
# TODO:
|
||||||
|
# - start / length
|
||||||
|
# - sortText
|
||||||
|
return [ i.get( 'text' ) or i[ 'label' ]
|
||||||
|
for i in response[ 'body' ][ 'targets' ] ]
|
||||||
|
|
||||||
|
|
||||||
def _SetUpUI( self ):
|
def _SetUpUI( self ):
|
||||||
vim.command( 'tabnew' )
|
vim.command( 'tabnew' )
|
||||||
self._uiTab = vim.current.tabpage
|
self._uiTab = vim.current.tabpage
|
||||||
|
|
||||||
# Code window
|
# Code window
|
||||||
self._codeView = code.CodeView( vim.current.window )
|
self._codeView = code.CodeView( vim.current.window, self._api_prefix )
|
||||||
|
|
||||||
# Call stack
|
# Call stack
|
||||||
with utils.TemporaryVimOptions( { 'splitright': False,
|
with utils.TemporaryVimOptions( { 'splitright': False,
|
||||||
|
|
@ -441,7 +467,8 @@ class DebugSession( object ):
|
||||||
vim.command( '10spl' )
|
vim.command( '10spl' )
|
||||||
vim.command( 'enew' )
|
vim.command( 'enew' )
|
||||||
self._outputView = output.OutputView( self._connection,
|
self._outputView = output.OutputView( self._connection,
|
||||||
vim.current.window )
|
vim.current.window,
|
||||||
|
self._api_prefix )
|
||||||
|
|
||||||
def ClearCurrentFrame( self ):
|
def ClearCurrentFrame( self ):
|
||||||
self.SetCurrentFrame( None )
|
self.SetCurrentFrame( None )
|
||||||
|
|
@ -482,6 +509,8 @@ class DebugSession( object ):
|
||||||
port = utils.AskForInput( 'Enter port to connect to: ' )
|
port = utils.AskForInput( 'Enter port to connect to: ' )
|
||||||
self._adapter[ 'port' ] = port
|
self._adapter[ 'port' ] = port
|
||||||
|
|
||||||
|
self._connection_type = self._api_prefix + self._connection_type
|
||||||
|
|
||||||
# TODO: Do we actually need to copy and update or does Vim do that?
|
# TODO: Do we actually need to copy and update or does Vim do that?
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
if 'env' in self._adapter:
|
if 'env' in self._adapter:
|
||||||
|
|
@ -492,19 +521,18 @@ class DebugSession( object ):
|
||||||
self._adapter[ 'cwd' ] = os.getcwd()
|
self._adapter[ 'cwd' ] = os.getcwd()
|
||||||
|
|
||||||
vim.vars[ '_vimspector_adapter_spec' ] = self._adapter
|
vim.vars[ '_vimspector_adapter_spec' ] = self._adapter
|
||||||
channel_send_func = vim.bindeval(
|
if not vim.eval( "vimspector#internal#{}#StartDebugSession( "
|
||||||
"vimspector#internal#{}#StartDebugSession( "
|
" g:_vimspector_adapter_spec "
|
||||||
" g:_vimspector_adapter_spec "
|
")".format( self._connection_type ) ):
|
||||||
")".format( self._connection_type ) )
|
|
||||||
|
|
||||||
if channel_send_func is None:
|
|
||||||
self._logger.error( "Unable to start debug server" )
|
self._logger.error( "Unable to start debug server" )
|
||||||
else:
|
else:
|
||||||
self._connection = debug_adapter_connection.DebugAdapterConnection(
|
self._connection = debug_adapter_connection.DebugAdapterConnection(
|
||||||
self,
|
self,
|
||||||
channel_send_func )
|
lambda msg: utils.Call(
|
||||||
|
"vimspector#internal#{}#Send".format( self._connection_type ),
|
||||||
|
msg ) )
|
||||||
|
|
||||||
self._logger.info( 'Debug Adapter Started' )
|
self._logger.info( 'Debug Adapter Started' )
|
||||||
|
|
||||||
def _StopDebugAdapter( self, callback = None ):
|
def _StopDebugAdapter( self, callback = None ):
|
||||||
def handler( *args ):
|
def handler( *args ):
|
||||||
|
|
@ -796,11 +824,12 @@ class DebugSession( object ):
|
||||||
self._logger.debug( 'Defaulting working directory to %s',
|
self._logger.debug( 'Defaulting working directory to %s',
|
||||||
params[ 'cwd' ] )
|
params[ 'cwd' ] )
|
||||||
|
|
||||||
buffer_number = self._codeView.LaunchTerminal( params )
|
term_id = self._codeView.LaunchTerminal( params )
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
'processId': vim.eval( 'job_info( term_getjob( {} ) )'
|
'processId': int( utils.Call(
|
||||||
'.process'.format( buffer_number ) )
|
'vimspector#internal#{}term#GetPID'.format( self._api_prefix ),
|
||||||
|
term_id ) )
|
||||||
}
|
}
|
||||||
|
|
||||||
self._connection.DoResponse( message, None, response )
|
self._connection.DoResponse( message, None, response )
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,11 @@ def CategoryToBuffer( category ):
|
||||||
|
|
||||||
|
|
||||||
class OutputView( object ):
|
class OutputView( object ):
|
||||||
def __init__( self, connection, window ):
|
def __init__( self, connection, window, api_prefix ):
|
||||||
self._window = window
|
self._window = window
|
||||||
self._connection = connection
|
self._connection = connection
|
||||||
self._buffers = {}
|
self._buffers = {}
|
||||||
|
self._api_prefix = api_prefix
|
||||||
|
|
||||||
for b in set( BUFFER_MAP.values() ):
|
for b in set( BUFFER_MAP.values() ):
|
||||||
self._CreateBuffer( b )
|
self._CreateBuffer( b )
|
||||||
|
|
@ -95,12 +96,12 @@ class OutputView( object ):
|
||||||
def Clear( self ):
|
def Clear( self ):
|
||||||
for category, tab_buffer in self._buffers.items():
|
for category, tab_buffer in self._buffers.items():
|
||||||
if tab_buffer.is_job:
|
if tab_buffer.is_job:
|
||||||
utils.CleanUpCommand( category )
|
utils.CleanUpCommand( category, self._api_prefix )
|
||||||
try:
|
try:
|
||||||
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 = {}
|
||||||
|
|
@ -116,17 +117,19 @@ class OutputView( object ):
|
||||||
|
|
||||||
def Evaluate( self, frame, expression ):
|
def Evaluate( self, frame, expression ):
|
||||||
console = self._buffers[ 'Console' ].buf
|
console = self._buffers[ 'Console' ].buf
|
||||||
utils.AppendToBuffer( console, 'Evaluating: ' + expression )
|
with utils.ModifiableScratchBuffer( console ):
|
||||||
|
utils.AppendToBuffer( console, 'Evaluating: ' + expression )
|
||||||
|
|
||||||
def print_result( message ):
|
def print_result( message ):
|
||||||
utils.AppendToBuffer( console,
|
with utils.ModifiableScratchBuffer( console ):
|
||||||
'Evaluated: ' + expression )
|
utils.AppendToBuffer( console,
|
||||||
|
'Evaluated: ' + expression )
|
||||||
|
|
||||||
result = message[ 'body' ][ 'result' ]
|
result = message[ 'body' ][ 'result' ]
|
||||||
if result is None:
|
if result is None:
|
||||||
result = 'null'
|
result = 'null'
|
||||||
|
|
||||||
utils.AppendToBuffer( console, ' Result: ' + result )
|
utils.AppendToBuffer( console, ' Result: ' + result )
|
||||||
|
|
||||||
request = {
|
request = {
|
||||||
'command': 'evaluate',
|
'command': 'evaluate',
|
||||||
|
|
@ -161,7 +164,7 @@ class OutputView( object ):
|
||||||
cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ]
|
cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ]
|
||||||
|
|
||||||
if cmd is not None:
|
if cmd is not None:
|
||||||
out, err = utils.SetUpCommandBuffer( cmd, category )
|
out, err = utils.SetUpCommandBuffer( cmd, category, self._api_prefix )
|
||||||
self._buffers[ category + '-out' ] = TabBuffer( out,
|
self._buffers[ category + '-out' ] = TabBuffer( out,
|
||||||
len( self._buffers ) )
|
len( self._buffers ) )
|
||||||
self._buffers[ category + '-out' ].is_job = True
|
self._buffers[ category + '-out' ].is_job = True
|
||||||
|
|
@ -205,3 +208,6 @@ class OutputView( object ):
|
||||||
tab_buffer.index,
|
tab_buffer.index,
|
||||||
utils.Escape( category ),
|
utils.Escape( category ),
|
||||||
'*' if tab_buffer.flag else '' ) )
|
'*' if tab_buffer.flag else '' ) )
|
||||||
|
|
||||||
|
def GetCategories( self ):
|
||||||
|
return [ category for category in self._buffers.keys() ]
|
||||||
|
|
|
||||||
|
|
@ -56,24 +56,26 @@ def OpenFileInCurrentWindow( file_name ):
|
||||||
return vim.buffers[ buffer_number ]
|
return vim.buffers[ buffer_number ]
|
||||||
|
|
||||||
|
|
||||||
def SetUpCommandBuffer( cmd, name ):
|
def SetUpCommandBuffer( cmd, name, api_prefix ):
|
||||||
bufs = vim.bindeval(
|
bufs = vim.eval(
|
||||||
'vimspector#internal#job#StartCommandWithLog( {}, "{}" )'.format(
|
'vimspector#internal#{}job#StartCommandWithLog( {}, "{}" )'.format(
|
||||||
|
api_prefix,
|
||||||
json.dumps( cmd ),
|
json.dumps( cmd ),
|
||||||
name ) )
|
name ) )
|
||||||
|
|
||||||
if bufs is None:
|
if bufs is None:
|
||||||
raise RuntimeError( "Unable to start job {}: {}".format( cmd, name ) )
|
raise RuntimeError( "Unable to start job {}: {}".format( cmd, name ) )
|
||||||
elif not all( b > 0 for b in bufs ):
|
elif not all( int( b ) > 0 for b in bufs ):
|
||||||
raise RuntimeError( "Unable to get all streams for job {}: {}".format(
|
raise RuntimeError( "Unable to get all streams for job {}: {}".format(
|
||||||
name,
|
name,
|
||||||
cmd ) )
|
cmd ) )
|
||||||
|
|
||||||
return [ vim.buffers[ b ] for b in bufs ]
|
return [ vim.buffers[ int( b ) ] for b in bufs ]
|
||||||
|
|
||||||
|
|
||||||
def CleanUpCommand( name ):
|
def CleanUpCommand( name, api_prefix ):
|
||||||
return vim.eval( 'vimspector#internal#job#CleanUpCommand( "{}" )'.format(
|
return vim.eval( 'vimspector#internal#{}job#CleanUpCommand( "{}" )'.format(
|
||||||
|
api_prefix,
|
||||||
name ) )
|
name ) )
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -102,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
|
||||||
|
|
@ -449,3 +451,19 @@ def ToUnicode( b ):
|
||||||
if isinstance( b, bytes ):
|
if isinstance( b, bytes ):
|
||||||
return b.decode( 'utf-8' )
|
return b.decode( 'utf-8' )
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
|
||||||
|
# Call a vimscript function with suplied arguments.
|
||||||
|
def Call( vimscript_function, *args ):
|
||||||
|
call = vimscript_function + '('
|
||||||
|
for index, arg in enumerate( args ):
|
||||||
|
if index > 0:
|
||||||
|
call += ', '
|
||||||
|
|
||||||
|
arg_name = 'vimspector_internal_arg_{}'.format( index )
|
||||||
|
vim.vars[ arg_name ] = arg
|
||||||
|
call += 'g:' + arg_name
|
||||||
|
|
||||||
|
call += ')'
|
||||||
|
_logger.debug( 'Calling: {}'.format( call ) )
|
||||||
|
return vim.eval( call )
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,9 @@ class VariablesView( object ):
|
||||||
for k, v in self._oldoptions.items():
|
for k, v in self._oldoptions.items():
|
||||||
vim.options[ k ] = v
|
vim.options[ k ] = v
|
||||||
|
|
||||||
|
vim.command( 'bdelete! ' + str( self._watch.win.buffer.number ) )
|
||||||
|
vim.command( 'bdelete! ' + str( self._vars.win.buffer.number ) )
|
||||||
|
|
||||||
def LoadScopes( self, frame ):
|
def LoadScopes( self, frame ):
|
||||||
def scopes_consumer( message ):
|
def scopes_consumer( message ):
|
||||||
old_scopes = self._scopes
|
old_scopes = self._scopes
|
||||||
|
|
|
||||||
51
run_tests
51
run_tests
|
|
@ -1,8 +1,25 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ "$1" == "--help" ]; then
|
||||||
|
echo "$(basename $0) <optional list of tests in form file:func>"
|
||||||
|
echo "e.g.: "
|
||||||
|
echo " - run all tests: $0"
|
||||||
|
echo " - run specific tests script: $0 signature_help.test.vim"
|
||||||
|
echo " - run specific tests fun: $0 signature_help.test.vim:Test_signatures_TopLine\(\)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
RUN_VIM="vim --clean --not-a-term"
|
RUN_VIM="vim --clean --not-a-term"
|
||||||
RUN_TEST="${RUN_VIM} -S lib/run_test.vim"
|
RUN_TEST="${RUN_VIM} -S lib/run_test.vim"
|
||||||
|
|
||||||
|
NODE_VERSION_MAJ=$(node --version \
|
||||||
|
| awk 'BEGIN { FS="." } { print substr( $1, 2 ) }')
|
||||||
|
if [ ${NODE_VERSION_MAJ} -gt "10" ]; then
|
||||||
|
echo "ERROR: Tests must be run against node 10 or earlier because python." >&2
|
||||||
|
echo "You have $(node --version)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$VIMSPECTOR_MIMODE" ]; then
|
if [ -z "$VIMSPECTOR_MIMODE" ]; then
|
||||||
if which lldb >/dev/null 2>&1; then
|
if which lldb >/dev/null 2>&1; then
|
||||||
export VIMSPECTOR_MIMODE=lldb
|
export VIMSPECTOR_MIMODE=lldb
|
||||||
|
|
@ -24,8 +41,8 @@ set -e
|
||||||
set +e
|
set +e
|
||||||
echo "%DONE - built test programs"
|
echo "%DONE - built test programs"
|
||||||
|
|
||||||
pushd tests > /dev/null
|
# Start
|
||||||
|
pushd $(dirname $0)/tests > /dev/null
|
||||||
echo "Running Vimspector Vim tests"
|
echo "Running Vimspector Vim tests"
|
||||||
|
|
||||||
RESULT=0
|
RESULT=0
|
||||||
|
|
@ -39,23 +56,45 @@ fi
|
||||||
for t in ${TESTS}; do
|
for t in ${TESTS}; do
|
||||||
echo ""
|
echo ""
|
||||||
echo "%RUN: $t"
|
echo "%RUN: $t"
|
||||||
rm -f messages debuglog
|
|
||||||
|
|
||||||
# split on : into fileName and testName
|
# split on : into fileName and testName
|
||||||
IFS=: read -s t T <<< "$t"
|
IFS=: read -s t T <<< "$t"
|
||||||
|
|
||||||
if ${RUN_TEST} --cmd 'au SwapExists * let v:swapchoice = "e"' $t $T; then
|
TESTLOGDIR=$(pwd)/logs/$t
|
||||||
|
|
||||||
|
if ${RUN_TEST} --cmd 'au SwapExists * let v:swapchoice = "e"' $t $T \
|
||||||
|
&& [ -f $t.res ]; then
|
||||||
echo "%PASS: $t PASSED"
|
echo "%PASS: $t PASSED"
|
||||||
else
|
else
|
||||||
cat messages
|
echo "%FAIL: $t FAILED - see $TESTLOGDIR"
|
||||||
echo "%FAIL: $t FAILED"
|
|
||||||
RESULT=1
|
RESULT=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -rf $TESTLOGDIR
|
||||||
|
mkdir -p $TESTLOGDIR
|
||||||
|
${RUN_VIM} --version > ${TESTLOGDIR}/vimversion
|
||||||
|
for l in messages debuglog test.log *.testlog; do
|
||||||
|
# In CI we can't view the output files, so we just have to cat them
|
||||||
|
if [ -f $l ]; then
|
||||||
|
if [ "$VIMSPECTOR_TEST_STDOUT" ]; then
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "*** START: $l ***"
|
||||||
|
cat $l
|
||||||
|
echo "*** END: $l ***"
|
||||||
|
fi
|
||||||
|
mv $l $TESTLOGDIR
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -f $t.res
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "Done running tests"
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "All done."
|
echo "All done."
|
||||||
|
|
||||||
|
|
||||||
exit $RESULT
|
exit $RESULT
|
||||||
|
|
|
||||||
1
tests/.gitignore
vendored
Normal file
1
tests/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
logs/
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"
|
"
|
||||||
" To execute only specific test functions, add a second argument. It will be
|
" To execute only specific test functions, add a second argument. It will be
|
||||||
" matched against the names of the Test_ funtion. E.g.:
|
" matched against the names of the Test_ funtion. E.g.:
|
||||||
" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
|
" ../vim -Nu NONE vimrc -S lib/run_test.vim test_channel.vim open_delay
|
||||||
" The output can be found in the "messages" file.
|
" The output can be found in the "messages" file.
|
||||||
"
|
"
|
||||||
" The test script may contain anything, only functions that start with
|
" The test script may contain anything, only functions that start with
|
||||||
|
|
@ -26,8 +26,16 @@
|
||||||
" It will be called after each Test_ function.
|
" It will be called after each Test_ function.
|
||||||
"
|
"
|
||||||
" When debugging a test it can be useful to add messages to v:errors:
|
" When debugging a test it can be useful to add messages to v:errors:
|
||||||
" call add(v:errors, "this happened")
|
" call add(v:errors, "this happened")
|
||||||
|
"
|
||||||
|
" But for real debug logging:
|
||||||
|
" call ch_log( ",,,message..." )
|
||||||
|
" Then view it in 'debuglog'
|
||||||
|
|
||||||
|
" Let a test take up to 1 minute
|
||||||
|
let s:single_test_timeout = 60000
|
||||||
|
|
||||||
|
" Restrict the runtimepath to the exact minimum needed for testing
|
||||||
set rtp=$PWD/lib,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
|
set rtp=$PWD/lib,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
|
||||||
if has('packages')
|
if has('packages')
|
||||||
let &packpath = &rtp
|
let &packpath = &rtp
|
||||||
|
|
@ -37,7 +45,7 @@ call ch_logfile( 'debuglog', 'w' )
|
||||||
|
|
||||||
" For consistency run all tests with 'nocompatible' set.
|
" For consistency run all tests with 'nocompatible' set.
|
||||||
" This also enables use of line continuation.
|
" This also enables use of line continuation.
|
||||||
set nocp viminfo+=nviminfo
|
set nocp
|
||||||
|
|
||||||
" Use utf-8 by default, instead of whatever the system default happens to be.
|
" Use utf-8 by default, instead of whatever the system default happens to be.
|
||||||
" Individual tests can overrule this at the top of the file.
|
" Individual tests can overrule this at the top of the file.
|
||||||
|
|
@ -47,11 +55,23 @@ set encoding=utf-8
|
||||||
set nomore
|
set nomore
|
||||||
|
|
||||||
" Output all messages in English.
|
" Output all messages in English.
|
||||||
lang mess C
|
lang messages C
|
||||||
|
|
||||||
" Always use forward slashes.
|
" Always use forward slashes.
|
||||||
set shellslash
|
set shellslash
|
||||||
|
|
||||||
|
func s:TestFailed()
|
||||||
|
let log = readfile( expand( '~/.vimspector.log' ) )
|
||||||
|
let logfile = s:testid_filesafe . '_vimspector.log.testlog'
|
||||||
|
call writefile( log, logfile, 's' )
|
||||||
|
call add( s:messages, 'Wrote log for failed test: ' . logfile )
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func! Abort( timer_id )
|
||||||
|
call assert_report( 'Test timed out!!!' )
|
||||||
|
qa!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func RunTheTest(test)
|
func RunTheTest(test)
|
||||||
echo 'Executing ' . a:test
|
echo 'Executing ' . a:test
|
||||||
|
|
||||||
|
|
@ -107,40 +127,38 @@ func RunTheTest(test)
|
||||||
|
|
||||||
call add(s:messages, 'Executing ' . a:test)
|
call add(s:messages, 'Executing ' . a:test)
|
||||||
let s:done += 1
|
let s:done += 1
|
||||||
|
let timer = timer_start( s:single_test_timeout, funcref( 'Abort' ) )
|
||||||
|
|
||||||
if a:test =~ 'Test_nocatch_'
|
try
|
||||||
" Function handles errors itself. This avoids skipping commands after the
|
let s:test = a:test
|
||||||
" error.
|
let s:testid = g:testpath . ':' . a:test
|
||||||
|
|
||||||
|
let test_filesafe = substitute( a:test, '[)(,:]', '_', 'g' )
|
||||||
|
let s:testid_filesafe = g:testpath . '_' . test_filesafe
|
||||||
|
|
||||||
|
au VimLeavePre * call EarlyExit(s:test)
|
||||||
exe 'call ' . a:test
|
exe 'call ' . a:test
|
||||||
else
|
au! VimLeavePre
|
||||||
try
|
catch /^\cskipped/
|
||||||
let s:test = a:test
|
call add(s:messages, ' Skipped')
|
||||||
let s:testid = g:testpath . ':' . a:test
|
call add(s:skipped,
|
||||||
let test_filesafe = substitute( a:test, ')', '_', 'g' )
|
\ 'SKIPPED ' . a:test
|
||||||
let test_filesafe = substitute( test_filesafe, '(', '_', 'g' )
|
\ . ': '
|
||||||
let test_filesafe = substitute( test_filesafe, ',', '_', 'g' )
|
\ . substitute(v:exception, '^\S*\s\+', '', ''))
|
||||||
let test_filesafe = substitute( test_filesafe, ':', '_', 'g' )
|
catch
|
||||||
let s:testid_filesafe = g:testpath . '_' . test_filesafe
|
call add(v:errors,
|
||||||
au VimLeavePre * call EarlyExit(s:test)
|
\ 'Caught exception in ' . a:test
|
||||||
exe 'call ' . a:test
|
\ . ': '
|
||||||
au! VimLeavePre
|
\ . v:exception
|
||||||
catch /^\cskipped/
|
\ . ' @ '
|
||||||
call add(s:messages, ' Skipped')
|
\ . g:testpath
|
||||||
call add(s:skipped,
|
\ . ':'
|
||||||
\ 'SKIPPED ' . a:test
|
\ . v:throwpoint)
|
||||||
\ . ': '
|
|
||||||
\ . substitute(v:exception, '^\S*\s\+', '', ''))
|
call s:TestFailed()
|
||||||
catch
|
endtry
|
||||||
call add(v:errors,
|
|
||||||
\ 'Caught exception in ' . a:test
|
call timer_stop( timer )
|
||||||
\ . ': '
|
|
||||||
\ . v:exception
|
|
||||||
\ . ' @ '
|
|
||||||
\ . g:testpath
|
|
||||||
\ . ':'
|
|
||||||
\ . v:throwpoint)
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
|
|
||||||
" In case 'insertmode' was set and something went wrong, make sure it is
|
" In case 'insertmode' was set and something went wrong, make sure it is
|
||||||
" reset to avoid trouble with anything else.
|
" reset to avoid trouble with anything else.
|
||||||
|
|
@ -203,24 +221,16 @@ endfunc
|
||||||
func AfterTheTest()
|
func AfterTheTest()
|
||||||
if len(v:errors) > 0
|
if len(v:errors) > 0
|
||||||
let s:fail += 1
|
let s:fail += 1
|
||||||
|
call s:TestFailed()
|
||||||
call add(s:errors, 'Found errors in ' . s:testid . ':')
|
call add(s:errors, 'Found errors in ' . s:testid . ':')
|
||||||
call extend(s:errors, v:errors)
|
call extend(s:errors, v:errors)
|
||||||
let v:errors = []
|
let v:errors = []
|
||||||
|
|
||||||
let log = readfile( expand( '~/.vimspector.log' ) )
|
|
||||||
let logfile = s:testid_filesafe . '.vimspector.log'
|
|
||||||
call writefile( log, logfile, 's' )
|
|
||||||
call add( s:messages, 'Wrote log for failed test: ' . logfile )
|
|
||||||
call extend( s:messages, log )
|
|
||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func EarlyExit(test)
|
func EarlyExit(test)
|
||||||
" It's OK for the test we use to test the quit detection.
|
" It's OK for the test we use to test the quit detection.
|
||||||
if a:test != 'Test_zz_quit_detected()'
|
call add(v:errors, 'Test caused Vim to exit: ' . a:test)
|
||||||
call add(v:errors, 'Test caused Vim to exit: ' . a:test)
|
|
||||||
endif
|
|
||||||
|
|
||||||
call FinishTesting()
|
call FinishTesting()
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
|
@ -233,17 +243,19 @@ func FinishTesting()
|
||||||
|
|
||||||
if s:fail == 0
|
if s:fail == 0
|
||||||
" Success, create the .res file so that make knows it's done.
|
" Success, create the .res file so that make knows it's done.
|
||||||
exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
|
call writefile( [], g:testname . '.res', 's' )
|
||||||
write
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if len(s:errors) > 0
|
if len(s:errors) > 0
|
||||||
" Append errors to test.log
|
" Append errors to test.log
|
||||||
split test.log
|
let l = []
|
||||||
call append(line('$'), '')
|
if filereadable( 'test.log' )
|
||||||
call append(line('$'), 'From ' . g:testpath . ':')
|
let l = readfile( 'test.log' )
|
||||||
call append(line('$'), s:errors)
|
endif
|
||||||
write
|
call writefile( l->extend( [ '', 'From ' . g:testpath . ':' ] )
|
||||||
|
\ ->extend( s:errors ),
|
||||||
|
\ 'test.log',
|
||||||
|
\ 's' )
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if s:done == 0
|
if s:done == 0
|
||||||
|
|
@ -264,11 +276,14 @@ func FinishTesting()
|
||||||
call extend(s:messages, s:skipped)
|
call extend(s:messages, s:skipped)
|
||||||
|
|
||||||
" Append messages to the file "messages"
|
" Append messages to the file "messages"
|
||||||
split messages
|
let l = []
|
||||||
call append(line('$'), '')
|
if filereadable( 'messages' )
|
||||||
call append(line('$'), 'From ' . g:testpath . ':')
|
let l = readfile( 'messages' )
|
||||||
call append(line('$'), s:messages)
|
endif
|
||||||
write
|
call writefile( l->extend( [ '', 'From ' . g:testpath . ':' ] )
|
||||||
|
\ ->extend( s:messages ),
|
||||||
|
\ 'messages',
|
||||||
|
\ 's' )
|
||||||
|
|
||||||
if s:fail > 0
|
if s:fail > 0
|
||||||
cquit!
|
cquit!
|
||||||
|
|
@ -317,6 +332,7 @@ endif
|
||||||
for s:test in sort(s:tests)
|
for s:test in sort(s:tests)
|
||||||
" Silence, please!
|
" Silence, please!
|
||||||
set belloff=all
|
set belloff=all
|
||||||
|
|
||||||
call RunTheTest(s:test)
|
call RunTheTest(s:test)
|
||||||
call AfterTheTest()
|
call AfterTheTest()
|
||||||
endfor
|
endfor
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue