Merge pull request #282 from puremourning/run-to-cursor

Run to cursor
This commit is contained in:
mergify[bot] 2020-10-23 22:10:55 +00:00 committed by GitHub
commit 7b048367f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 790 additions and 241 deletions

View file

@ -108,6 +108,7 @@ And a couple of brief demos:
- breakpoints (function, line and exception breakpoints) - breakpoints (function, line and exception breakpoints)
- conditional breakpoints (function, line) - conditional breakpoints (function, line)
- step in/out/over/up, stop, restart - step in/out/over/up, stop, restart
- run to cursor
- launch and attach - launch and attach
- remote launch, remote attach - remote launch, remote attach
- locals and globals display - locals and globals display
@ -552,6 +553,7 @@ features to set your own mappings. To that end, Vimspector defines the following
* `<Plug>VimspectorStepOver` * `<Plug>VimspectorStepOver`
* `<Plug>VimspectorStepInto` * `<Plug>VimspectorStepInto`
* `<Plug>VimspectorStepOut` * `<Plug>VimspectorStepOut`
* `<Plug>VimspectorRunToCursor`
These map roughly 1-1 with the API functions below. These map roughly 1-1 with the API functions below.
@ -612,6 +614,7 @@ let g:vimspector_enable_mappings = 'HUMAN'
| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | | `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` |
| `<leader>F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | | `<leader>F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` |
| `F8` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '<cexpr>' )` | | `F8` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '<cexpr>' )` |
| `<leader>F8` | Run to Cursor | `vimspector#RunToCursor()` |
| `F10` | Step Over | `vimspector#StepOver()` | | `F10` | Step Over | `vimspector#StepOver()` |
| `F11` | Step Into | `vimspector#StepInto()` | | `F11` | Step Into | `vimspector#StepInto()` |
| `F12` | Step out of current function scope | `vimspector#StepOut()` | | `F12` | Step out of current function scope | `vimspector#StepOut()` |
@ -710,6 +713,12 @@ You can configure your choices in the `.vimspector.json`. See
* Use `vimspector#ClearBreakpoints()` * Use `vimspector#ClearBreakpoints()`
to clear all breakpoints including the memory of exception breakpoint choices. to clear all breakpoints including the memory of exception breakpoint choices.
### Run to Cursor
* Use `vimspector#RunToCursor` or `<leader><F8>`: this creates a temporary
breakpoint on the current line, then continues execution, clearing the
breakpiont when it is hit.
## Stepping ## Stepping
* Step in/out, finish, continue, pause etc. using the WinBar, or mappings. * Step in/out, finish, continue, pause etc. using the WinBar, or mappings.

View file

@ -27,45 +27,57 @@ EOF
endfunction endfunction
let s:enabled = vimspector#internal#state#Reset() let s:enabled = v:null
function! s:Initialised() abort
return s:enabled != v:null
endfunction
function! s:Enabled() abort
if !s:Initialised()
let s:enabled = vimspector#internal#state#Reset()
endif
return s:enabled
endfunction
function! vimspector#Launch() abort function! vimspector#Launch() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Start() py3 _vimspector_session.Start()
endfunction endfunction
function! vimspector#LaunchWithSettings( settings ) abort function! vimspector#LaunchWithSettings( settings ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Start( launch_variables = vim.eval( 'a:settings' ) ) py3 _vimspector_session.Start( launch_variables = vim.eval( 'a:settings' ) )
endfunction endfunction
function! vimspector#Reset() abort function! vimspector#Reset() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Reset() py3 _vimspector_session.Reset()
endfunction endfunction
function! vimspector#Restart() abort function! vimspector#Restart() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Restart() py3 _vimspector_session.Restart()
endfunction endfunction
function! vimspector#ClearBreakpoints() abort function! vimspector#ClearBreakpoints() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.ClearBreakpoints() py3 _vimspector_session.ClearBreakpoints()
endfunction endfunction
function! vimspector#ToggleBreakpoint( ... ) abort function! vimspector#ToggleBreakpoint( ... ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
if a:0 == 0 if a:0 == 0
@ -76,8 +88,43 @@ function! vimspector#ToggleBreakpoint( ... ) abort
py3 _vimspector_session.ToggleBreakpoint( vim.eval( 'options' ) ) py3 _vimspector_session.ToggleBreakpoint( vim.eval( 'options' ) )
endfunction endfunction
function! vimspector#SetLineBreakpoint( file_name, line_num, ... ) abort
if !s:Enabled()
return
endif
if a:0 == 0
let options = {}
else
let options = a:1
endif
py3 _vimspector_session.SetLineBreakpoint(
\ vim.eval( 'a:file_name' ),
\ int( vim.eval( 'a:line_num' ) ),
\ vim.eval( 'options' ) )
endfunction
function! vimspector#ClearLineBreakpoint( file_name, line_num ) abort
if !s:Enabled()
return
endif
py3 _vimspector_session.ClearLineBreakpoint(
\ vim.eval( 'a:file_name' ),
\ int( vim.eval( 'a:line_num' ) ) )
endfunction
function! vimspector#RunToCursor() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.RunTo(
\ vim.eval( "expand( '%' )" ),
\ int( vim.eval( "line( '.' )" ) ) )
endfunction
function! vimspector#AddFunctionBreakpoint( function, ... ) abort function! vimspector#AddFunctionBreakpoint( function, ... ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
if a:0 == 0 if a:0 == 0
@ -90,70 +137,70 @@ function! vimspector#AddFunctionBreakpoint( function, ... ) abort
endfunction endfunction
function! vimspector#StepOver() abort function! vimspector#StepOver() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.StepOver() py3 _vimspector_session.StepOver()
endfunction endfunction
function! vimspector#StepInto() abort function! vimspector#StepInto() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.StepInto() py3 _vimspector_session.StepInto()
endfunction endfunction
function! vimspector#StepOut() abort function! vimspector#StepOut() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.StepOut() py3 _vimspector_session.StepOut()
endfunction endfunction
function! vimspector#Continue() abort function! vimspector#Continue() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Continue() py3 _vimspector_session.Continue()
endfunction endfunction
function! vimspector#Pause() abort function! vimspector#Pause() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Pause() py3 _vimspector_session.Pause()
endfunction endfunction
function! vimspector#Stop() abort function! vimspector#Stop() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.Stop() py3 _vimspector_session.Stop()
endfunction endfunction
function! vimspector#ExpandVariable() abort function! vimspector#ExpandVariable() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.ExpandVariable() py3 _vimspector_session.ExpandVariable()
endfunction endfunction
function! vimspector#DeleteWatch() abort function! vimspector#DeleteWatch() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.DeleteWatch() py3 _vimspector_session.DeleteWatch()
endfunction endfunction
function! vimspector#GoToFrame() abort function! vimspector#GoToFrame() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.ExpandFrameOrThread() py3 _vimspector_session.ExpandFrameOrThread()
endfunction endfunction
function! vimspector#AddWatch( ... ) abort function! vimspector#AddWatch( ... ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
if a:0 == 0 if a:0 == 0
@ -170,7 +217,7 @@ function! vimspector#AddWatch( ... ) abort
endfunction endfunction
function! vimspector#AddWatchPrompt( expr ) abort function! vimspector#AddWatchPrompt( expr ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
stopinsert stopinsert
@ -179,7 +226,7 @@ function! vimspector#AddWatchPrompt( expr ) abort
endfunction endfunction
function! vimspector#Evaluate( expr ) abort function! vimspector#Evaluate( expr ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.ShowOutput( 'Console' ) py3 _vimspector_session.ShowOutput( 'Console' )
@ -187,7 +234,7 @@ function! vimspector#Evaluate( expr ) abort
endfunction endfunction
function! vimspector#EvaluateConsole( expr ) abort function! vimspector#EvaluateConsole( expr ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
stopinsert stopinsert
@ -196,7 +243,7 @@ function! vimspector#EvaluateConsole( expr ) abort
endfunction endfunction
function! vimspector#ShowOutput( ... ) abort function! vimspector#ShowOutput( ... ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
if a:0 == 1 if a:0 == 1
@ -207,7 +254,7 @@ function! vimspector#ShowOutput( ... ) abort
endfunction endfunction
function! vimspector#ShowOutputInWindow( win_id, category ) abort function! vimspector#ShowOutputInWindow( win_id, category ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 __import__( 'vimspector', py3 __import__( 'vimspector',
@ -217,21 +264,21 @@ function! vimspector#ShowOutputInWindow( win_id, category ) abort
endfunction endfunction
function! vimspector#ToggleLog() abort function! vimspector#ToggleLog() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.ToggleLog() py3 _vimspector_session.ToggleLog()
endfunction endfunction
function! vimspector#ListBreakpoints() abort function! vimspector#ListBreakpoints() abort
if !s:enabled if !s:Enabled()
return return
endif endif
py3 _vimspector_session.ListBreakpoints() py3 _vimspector_session.ListBreakpoints()
endfunction endfunction
function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
let buffers = py3eval( '_vimspector_session.GetOutputBuffers() ' let buffers = py3eval( '_vimspector_session.GetOutputBuffers() '
@ -262,7 +309,7 @@ def _vimspector_GetExprCompletions( ArgLead, prev_non_keyword_char ):
EOF EOF
function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
@ -390,7 +437,7 @@ function! vimspector#OmniFuncConsole( find_start, query ) abort
endfunction endfunction
function! vimspector#Install( bang, ... ) abort function! vimspector#Install( bang, ... ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
let prefix = vimspector#internal#state#GetAPIPrefix() let prefix = vimspector#internal#state#GetAPIPrefix()
@ -402,7 +449,7 @@ function! vimspector#Install( bang, ... ) abort
endfunction endfunction
function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
return py3eval( '"\n".join(' return py3eval( '"\n".join('
@ -412,7 +459,7 @@ function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort
endfunction endfunction
function! vimspector#Update( bang, ... ) abort function! vimspector#Update( bang, ... ) abort
if !s:enabled if !s:Enabled()
return return
endif endif
@ -425,7 +472,7 @@ function! vimspector#Update( bang, ... ) abort
endfunction endfunction
function! vimspector#AbortInstall() abort function! vimspector#AbortInstall() abort
if !s:enabled if !s:Enabled()
return return
endif endif
@ -434,6 +481,25 @@ function! vimspector#AbortInstall() abort
endfunction endfunction
function! vimspector#OnBufferCreated( file_name ) abort
if len( a:file_name ) == 0
return
endif
" Don't actually load up vimsepctor python in autocommands that trigger
" regularly. We'll only create the session obkect in s:Enabled()
if !s:Initialised()
return
endif
if !s:Enabled()
return
endif
py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) )
endfunction
" Boilerplate {{{ " Boilerplate {{{
let &cpoptions=s:save_cpo let &cpoptions=s:save_cpo
unlet s:save_cpo unlet s:save_cpo

View file

@ -62,6 +62,9 @@ nnoremap <silent> <Plug>VimspectorStepInto
nnoremap <silent> <Plug>VimspectorStepOut nnoremap <silent> <Plug>VimspectorStepOut
\ :<c-u>call vimspector#StepOut()<CR> \ :<c-u>call vimspector#StepOut()<CR>
nnoremap <silent> <Plug>VimspectorRunToCursor
\ :<c-u>call vimspector#RunToCursor()<CR>
if s:mappings ==# 'VISUAL_STUDIO' if s:mappings ==# 'VISUAL_STUDIO'
nmap <F5> <Plug>VimspectorContinue nmap <F5> <Plug>VimspectorContinue
nmap <S-F5> <Plug>VimspectorStop nmap <S-F5> <Plug>VimspectorStop
@ -80,6 +83,7 @@ elseif s:mappings ==# 'HUMAN'
nmap <F9> <Plug>VimspectorToggleBreakpoint nmap <F9> <Plug>VimspectorToggleBreakpoint
nmap <leader><F9> <Plug>VimspectorToggleConditionalBreakpoint nmap <leader><F9> <Plug>VimspectorToggleConditionalBreakpoint
nmap <F8> <Plug>VimspectorAddFunctionBreakpoint nmap <F8> <Plug>VimspectorAddFunctionBreakpoint
nmap <leader><F8> <Plug>VimspectorRunToCursor
nmap <F10> <Plug>VimspectorStepOver nmap <F10> <Plug>VimspectorStepOver
nmap <F11> <Plug>VimspectorStepInto nmap <F11> <Plug>VimspectorStepInto
nmap <F12> <Plug>VimspectorStepOut nmap <F12> <Plug>VimspectorStepOut
@ -116,9 +120,14 @@ command! -bar -nargs=0
" Dummy autocommands so that we can call this whenever " Dummy autocommands so that we can call this whenever
augroup VimspectorUserAutoCmds augroup VimspectorUserAutoCmds
au! autocmd!
au User VimspectorUICreated silent autocmd User VimspectorUICreated silent
au User VimspectorTerminalOpened silent autocmd User VimspectorTerminalOpened silent
augroup END
augroup Vimspector
autocmd!
autocmd BufNew * call vimspector#OnBufferCreated( expand( '<afile>' ) )
augroup END augroup END
" boilerplate {{{ " boilerplate {{{

View file

@ -141,50 +141,119 @@ class ProjectBreakpoints( object ):
self.UpdateUI() self.UpdateUI()
def _FindLineBreakpoint( self, file_name, line ):
file_name = os.path.abspath( file_name )
for index, bp in enumerate( self._line_breakpoints[ file_name ] ):
self._SignToLine( file_name, bp )
if bp[ 'line' ] == line:
return bp, index
return None, None
def _PutLineBreakpoint( self, file_name, line, options ):
self._line_breakpoints[ os.path.abspath( file_name ) ].append( {
'state': 'ENABLED',
'line': line,
'options': options,
# 'sign_id': <filled in when placed>,
#
# Used by other breakpoint types (specified in options):
# 'condition': ...,
# 'hitCondition': ...,
# 'logMessage': ...
} )
def _DeleteLineBreakpoint( self, bp, file_name, index ):
if 'sign_id' in bp:
signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
del self._line_breakpoints[ os.path.abspath( file_name ) ][ index ]
def ToggleBreakpoint( self, options ): def ToggleBreakpoint( self, options ):
line, column = vim.current.window.cursor line, _ = vim.current.window.cursor
file_name = vim.current.buffer.name file_name = vim.current.buffer.name
if not file_name: if not file_name:
return return
found_bp = False bp, index = self._FindLineBreakpoint( file_name, line )
action = 'New' if bp is None:
for index, bp in enumerate( self._line_breakpoints[ file_name ] ): # ADD
self._SignToLine( file_name, bp ) self._PutLineBreakpoint( file_name, line, options )
if bp[ 'line' ] == line: elif bp[ 'state' ] == 'ENABLED' and not self._connection:
found_bp = True # DISABLE
if bp[ 'state' ] == 'ENABLED' and not self._connection: bp[ 'state' ] = 'DISABLED'
bp[ 'state' ] = 'DISABLED' else:
action = 'Disable' # DELETE
else: self._DeleteLineBreakpoint( bp, file_name, index )
if 'sign_id' in bp:
signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
del self._line_breakpoints[ file_name ][ index ]
action = 'Delete'
break
self._logger.debug( "Toggle found bp at {}:{} ? {} ({})".format(
file_name,
line,
found_bp,
action ) )
if not found_bp:
self._line_breakpoints[ file_name ].append( {
'state': 'ENABLED',
'line': line,
'options': options,
# 'sign_id': <filled in when placed>,
#
# Used by other breakpoint types (specified in options):
# 'condition': ...,
# 'hitCondition': ...,
# 'logMessage': ...
} )
self.UpdateUI() self.UpdateUI()
def SetLineBreakpoint( self, file_name, line_num, options, then = None ):
bp, _ = self._FindLineBreakpoint( file_name, line_num )
if bp is not None:
bp[ 'options' ] = options
return
self._PutLineBreakpoint( file_name, line_num, options )
self.UpdateUI( then )
def ClearLineBreakpoint( self, file_name, line_num ):
bp, index = self._FindLineBreakpoint( file_name, line_num )
if bp is None:
return
self._DeleteLineBreakpoint( bp, file_name, index )
self.UpdateUI()
def ClearTemporaryBreakpoint( self, file_name, line_num ):
bp, index = self._FindLineBreakpoint( file_name, line_num )
if bp is None:
return
if bp[ 'options' ].get( 'temporary' ):
self._DeleteLineBreakpoint( bp, file_name, index )
self.UpdateUI()
def ClearTemporaryBreakpoints( self ):
for file_name, breakpoints in self._line_breakpoints.items():
self._line_breakpoints[ file_name ] = list( filter(
lambda bp: not bp[ 'options' ].get( 'temporary' ),
breakpoints ) )
def _UpdateTemporaryBreakpoints( self, breakpoints, temp_idxs ):
# adjust any temporary breakpoints to match the server result
# TODO: Maybe now is the time to ditch the split breakpoints nonesense
for temp_idx, user_bp in temp_idxs:
if temp_idx >= len( breakpoints ):
# Just can't trust servers ?
self._logger.debug( "Server Error - invalid breakpoints list did not "
"contain entry for temporary breakpoint at index "
f"{ temp_idx } i.e. { user_bp }" )
continue
bp = breakpoints[ temp_idx ]
if 'line' not in bp or not bp[ 'verified' ]:
utils.UserMessage(
"Unable to set temporary breakpoint at line "
f"{ user_bp[ 'line' ] } execution will continue...",
persist = True,
error = True )
self._logger.debug( f"Updating temporary breakpoint { user_bp } line "
f"{ user_bp[ 'line' ] } to { bp[ 'line' ] }" )
# if it was moved, update the user-breakpoint so that we unset it
# again properly
user_bp[ 'line' ] = bp[ 'line' ]
def AddFunctionBreakpoint( self, function, options ): def AddFunctionBreakpoint( self, function, options ):
self._func_breakpoints.append( { self._func_breakpoints.append( {
'state': 'ENABLED', 'state': 'ENABLED',
@ -200,11 +269,13 @@ class ProjectBreakpoints( object ):
self.UpdateUI() self.UpdateUI()
def UpdateUI( self ): def UpdateUI( self, then = None ):
if self._connection: if self._connection:
self.SendBreakpoints() self.SendBreakpoints( then )
else: else:
self._ShowBreakpoints() self._ShowBreakpoints()
if then:
then()
def SetBreakpointsHandler( self, handler ): def SetBreakpointsHandler( self, handler ):
@ -230,9 +301,12 @@ class ProjectBreakpoints( object ):
if awaiting == 0 and doneHandler: if awaiting == 0 and doneHandler:
doneHandler() doneHandler()
def response_handler( source, msg ): def response_handler( source, msg, temp_idxs = [] ):
if msg: if msg:
self._breakpoints_handler.AddBreakpoints( source, msg ) self._breakpoints_handler.AddBreakpoints( source, msg )
breakpoints = ( msg.get( 'body' ) or {} ).get( 'breakpoints' ) or []
self._UpdateTemporaryBreakpoints( breakpoints, temp_idxs )
response_received() response_received()
@ -243,9 +317,9 @@ class ProjectBreakpoints( object ):
# TODO: add the _configured_breakpoints to line_breakpoints # TODO: add the _configured_breakpoints to line_breakpoints
# TODO: the line numbers might have changed since pressing the F9 key!
for file_name, line_breakpoints in self._line_breakpoints.items(): for file_name, line_breakpoints in self._line_breakpoints.items():
temp_idxs = []
breakpoints = [] breakpoints = []
for bp in line_breakpoints: for bp in line_breakpoints:
self._SignToLine( file_name, bp ) self._SignToLine( file_name, bp )
@ -259,8 +333,15 @@ class ProjectBreakpoints( object ):
dap_bp = {} dap_bp = {}
dap_bp.update( bp[ 'options' ] ) dap_bp.update( bp[ 'options' ] )
dap_bp.update( { 'line': bp[ 'line' ] } ) dap_bp.update( { 'line': bp[ 'line' ] } )
dap_bp.pop( 'temporary', None )
if bp[ 'options' ].get( 'temporary' ):
temp_idxs.append( [ len( breakpoints ), bp ] )
breakpoints.append( dap_bp ) breakpoints.append( dap_bp )
source = { source = {
'name': os.path.basename( file_name ), 'name': os.path.basename( file_name ),
'path': file_name, 'path': file_name,
@ -271,7 +352,10 @@ class ProjectBreakpoints( object ):
# The source=source here is critical to ensure that we capture each # The source=source here is critical to ensure that we capture each
# source in the iteration, rather than ending up passing the same source # source in the iteration, rather than ending up passing the same source
# to each callback. # to each callback.
lambda msg, source=source: response_handler( source, msg ), lambda msg, source=source, temp_idxs=temp_idxs: response_handler(
source,
msg,
temp_idxs = temp_idxs ),
{ {
'command': 'setBreakpoints', 'command': 'setBreakpoints',
'arguments': { 'arguments': {
@ -372,6 +456,12 @@ class ProjectBreakpoints( object ):
# pay any attention to them anyway. # pay any attention to them anyway.
self._exception_breakpoints[ 'exceptionOptions' ] = [] self._exception_breakpoints[ 'exceptionOptions' ] = []
def Refresh( self, file_name ):
# TODO: Just this file ?
self._ShowBreakpoints()
def _ShowBreakpoints( self ): def _ShowBreakpoints( self ):
for file_name, line_breakpoints in self._line_breakpoints.items(): for file_name, line_breakpoints in self._line_breakpoints.items():
for bp in line_breakpoints: for bp in line_breakpoints:
@ -386,17 +476,21 @@ class ProjectBreakpoints( object ):
else 'vimspectorBPCond' if 'condition' in bp[ 'options' ] else 'vimspectorBPCond' if 'condition' in bp[ 'options' ]
else 'vimspectorBP' ) else 'vimspectorBP' )
signs.PlaceSign( bp[ 'sign_id' ], if utils.BufferExists( file_name ):
'VimspectorBP', signs.PlaceSign( bp[ 'sign_id' ],
sign, 'VimspectorBP',
file_name, sign,
bp[ 'line' ] ) file_name,
bp[ 'line' ] )
def _SignToLine( self, file_name, bp ): def _SignToLine( self, file_name, bp ):
if 'sign_id' not in bp: if 'sign_id' not in bp:
return bp[ 'line' ] return bp[ 'line' ]
if not utils.BufferExists( file_name ):
return bp[ 'line' ]
signs = vim.eval( "sign_getplaced( '{}', {} )".format( signs = vim.eval( "sign_getplaced( '{}', {} )".format(
utils.Escape( file_name ), utils.Escape( file_name ),
json.dumps( { 'id': bp[ 'sign_id' ], 'group': 'VimspectorBP', } ) ) ) json.dumps( { 'id': bp[ 'sign_id' ], 'group': 'VimspectorBP', } ) ) )

View file

@ -93,16 +93,12 @@ class CodeView( object ):
sign = 'vimspectorPCBP' sign = 'vimspectorPCBP'
break break
try: if utils.BufferExists( frame[ 'source' ][ 'path' ] ):
signs.PlaceSign( self._signs[ 'vimspectorPC' ], signs.PlaceSign( self._signs[ 'vimspectorPC' ],
'VimspectorCode', 'VimspectorCode',
sign, sign,
frame[ 'source' ][ 'path' ], frame[ 'source' ][ 'path' ],
frame[ 'line' ] ) frame[ 'line' ] )
except vim.error as e:
# Ignore 'invalid buffer name'
if 'E158' not in str( e ):
raise
def SetCurrentFrame( self, frame ): def SetCurrentFrame( self, frame ):
@ -215,6 +211,11 @@ class CodeView( object ):
return return
def Refresh( self, file_name ):
# TODO: jsut the file ?
self.ShowBreakpoints()
def _UndisplaySigns( self ): def _UndisplaySigns( self ):
for sign_id in self._signs[ 'breakpoints' ]: for sign_id in self._signs[ 'breakpoints' ]:
signs.UnplaceSign( sign_id, 'VimspectorCode' ) signs.UnplaceSign( sign_id, 'VimspectorCode' )
@ -236,12 +237,13 @@ class CodeView( object ):
sign_id = self._next_sign_id sign_id = self._next_sign_id
self._next_sign_id += 1 self._next_sign_id += 1
self._signs[ 'breakpoints' ].append( sign_id ) self._signs[ 'breakpoints' ].append( sign_id )
signs.PlaceSign( sign_id, if utils.BufferExists( file_name ):
'VimspectorCode', signs.PlaceSign( sign_id,
'vimspectorBP' if breakpoint[ 'verified' ] 'VimspectorCode',
else 'vimspectorBPDisabled', 'vimspectorBP' if breakpoint[ 'verified' ]
file_name, else 'vimspectorBPDisabled',
breakpoint[ 'line' ] ) file_name,
breakpoint[ 'line' ] )
# We need to also check if there's a breakpoint on this PC line and chnge # We need to also check if there's a breakpoint on this PC line and chnge
# the PC # the PC

View file

@ -77,6 +77,7 @@ class DebugSession( object ):
self._launch_complete = False self._launch_complete = False
self._on_init_complete_handlers = [] self._on_init_complete_handlers = []
self._server_capabilities = {} self._server_capabilities = {}
self.ClearTemporaryBreakpoints()
def Start( self, launch_variables = None ): def Start( self, launch_variables = None ):
# We mutate launch_variables, so don't mutate the default argument. # We mutate launch_variables, so don't mutate the default argument.
@ -560,6 +561,13 @@ class DebugSession( object ):
return response[ 'body' ][ 'targets' ] return response[ 'body' ][ 'targets' ]
def RefreshSigns( self, file_name ):
if self._connection:
self._codeView.Refresh( file_name )
else:
self._breakpoints.Refresh( file_name )
def _SetUpUI( self ): def _SetUpUI( self ):
vim.command( 'tab split' ) vim.command( 'tab split' )
self._uiTab = vim.current.tabpage self._uiTab = vim.current.tabpage
@ -622,7 +630,7 @@ class DebugSession( object ):
self.SetCurrentFrame( None ) self.SetCurrentFrame( None )
@RequiresUI() @RequiresUI()
def SetCurrentFrame( self, frame ): def SetCurrentFrame( self, frame, reason = '' ):
if not frame: if not frame:
self._stackTraceView.Clear() self._stackTraceView.Clear()
self._variablesView.Clear() self._variablesView.Clear()
@ -630,11 +638,16 @@ class DebugSession( object ):
if not self._codeView.SetCurrentFrame( frame ): if not self._codeView.SetCurrentFrame( frame ):
return False return False
if frame: # the codeView.SetCurrentFrame already checked the frame was valid and
self._variablesView.SetSyntax( self._codeView.current_syntax ) # countained a valid source
self._stackTraceView.SetSyntax( self._codeView.current_syntax ) self._variablesView.SetSyntax( self._codeView.current_syntax )
self._variablesView.LoadScopes( frame ) self._stackTraceView.SetSyntax( self._codeView.current_syntax )
self._variablesView.EvaluateWatches() self._variablesView.LoadScopes( frame )
self._variablesView.EvaluateWatches()
if reason == 'stopped':
self._breakpoints.ClearTemporaryBreakpoint( frame[ 'source' ][ 'path' ],
frame[ 'line' ] )
return True return True
@ -1165,6 +1178,26 @@ class DebugSession( object ):
def ToggleBreakpoint( self, options ): def ToggleBreakpoint( self, options ):
return self._breakpoints.ToggleBreakpoint( options ) return self._breakpoints.ToggleBreakpoint( options )
def RunTo( self, file_name, line ):
self.ClearTemporaryBreakpoints()
self.SetLineBreakpoint( file_name,
line,
{ 'temporary': True },
lambda: self.Continue() )
def ClearTemporaryBreakpoints( self ):
return self._breakpoints.ClearTemporaryBreakpoints()
def SetLineBreakpoint( self, file_name, line_num, options, then = None ):
return self._breakpoints.SetLineBreakpoint( file_name,
line_num,
options,
then )
def ClearLineBreakpoint( self, file_name, line_num ):
return self._breakpoints.ClearLineBreakpoint( file_name, line_num )
def ClearBreakpoints( self ): def ClearBreakpoints( self ):
if self._connection: if self._connection:
self._codeView.ClearBreakpoints() self._codeView.ClearBreakpoints()

View file

@ -29,7 +29,7 @@ def DefineSign( name, text, double_text, texthl, col = 'right', **kwargs ):
vim.command( cmd ) vim.command( cmd )
def PlaceSign( sign_id, group, name, file, line ): def PlaceSign( sign_id, group, name, file_name, line ):
priority = settings.Dict( 'sign_priority' )[ name ] priority = settings.Dict( 'sign_priority' )[ name ]
cmd = ( f'sign place { sign_id } ' cmd = ( f'sign place { sign_id } '
@ -37,7 +37,7 @@ def PlaceSign( sign_id, group, name, file, line ):
f'name={ name } ' f'name={ name } '
f'priority={ priority } ' f'priority={ priority } '
f'line={ line } ' f'line={ line } '
f'file={ file }' ) f'file={ file_name }' )
vim.command( cmd ) vim.command( cmd )

View file

@ -149,12 +149,15 @@ class StackTraceView( object ):
self._DrawStackTrace( thread ) self._DrawStackTrace( thread )
def _LoadStackTrace( self, thread, infer_current_frame ): def _LoadStackTrace( self,
thread,
infer_current_frame,
reason = '' ):
def consume_stacktrace( message ): def consume_stacktrace( message ):
thread[ '_frames' ] = message[ 'body' ][ 'stackFrames' ] thread[ '_frames' ] = message[ 'body' ][ 'stackFrames' ]
if infer_current_frame: if infer_current_frame:
for frame in thread[ '_frames' ]: for frame in thread[ '_frames' ]:
if self._JumpToFrame( frame ): if self._JumpToFrame( frame, reason ):
break break
self._DrawThreads() self._DrawThreads()
@ -183,11 +186,11 @@ class StackTraceView( object ):
else: else:
self._LoadStackTrace( thread, False ) self._LoadStackTrace( thread, False )
def _JumpToFrame( self, frame ): def _JumpToFrame( self, frame, reason = '' ):
def do_jump(): def do_jump():
if 'line' in frame and frame[ 'line' ] > 0: if 'line' in frame and frame[ 'line' ] > 0:
self._current_frame = frame self._current_frame = frame
return self._session.SetCurrentFrame( self._current_frame ) return self._session.SetCurrentFrame( self._current_frame, reason )
return False return False
source = frame.get( 'source' ) or {} source = frame.get( 'source' ) or {}
@ -211,7 +214,7 @@ class StackTraceView( object ):
if self._current_thread is not None: if self._current_thread is not None:
for thread in self._threads: for thread in self._threads:
if thread[ 'id' ] == self._current_thread: if thread[ 'id' ] == self._current_thread:
self._LoadStackTrace( thread, True ) self._LoadStackTrace( thread, True, 'stopped' )
return return
self.LoadThreads( True ) self.LoadThreads( True )

View file

@ -45,14 +45,20 @@ _logger = logging.getLogger( __name__ )
SetUpLogging( _logger ) SetUpLogging( _logger )
def BufferNumberForFile( file_name ): def BufferNumberForFile( file_name, create = True ):
return int( vim.eval( "bufnr( '{0}', 1 )".format( Escape( file_name ) ) ) ) return int( vim.eval( "bufnr( '{0}', {1} )".format(
Escape( file_name ),
int( create ) ) ) )
def BufferForFile( file_name ): def BufferForFile( file_name ):
return vim.buffers[ BufferNumberForFile( file_name ) ] return vim.buffers[ BufferNumberForFile( file_name ) ]
def BufferExists( file_name ):
return bool( int ( vim.eval( f"bufexists( '{ Escape( file_name ) }' )" ) ) )
def NewEmptyBuffer(): def NewEmptyBuffer():
bufnr = int( vim.eval( 'bufadd("")' ) ) bufnr = int( vim.eval( 'bufadd("")' ) )
Call( 'bufload', bufnr ) Call( 'bufload', bufnr )

View file

@ -52,6 +52,11 @@
}, },
"run - default": { "run - default": {
"adapter": "debugpy", "adapter": "debugpy",
"variables": {
"MAKE_ENV_OUTPUT": {
"shell": "${workspaceRoot}/make_env.sh"
}
},
"configuration": { "configuration": {
"request": "launch", "request": "launch",
"type": "python", "type": "python",
@ -60,8 +65,8 @@
"stopOnEntry#json": "${StopOnEntry:true}", "stopOnEntry#json": "${StopOnEntry:true}",
"console": "integratedTerminal", "console": "integratedTerminal",
"args#json": "${args:[]}", "args#json": "${args:[]}",
"env#json": "${env:{\\}}", "igored#json#s": "string not json",
"igored#json#s": "string not json" "env#json": "${MAKE_ENV_OUTPUT}"
}, },
"breakpoints": { "breakpoints": {
"exception": { "exception": {

View file

@ -0,0 +1,9 @@
#!/usr/bin/env bash
cat <<"EOF"
{
"Something": "Value1",
"SomethingElse": "Value2"
}
EOF

View file

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
def Main():
print( os.environ.get( 'Something', 'ERROR' ) )
print( os.environ.get( 'SomethingElse', 'ERROR' ) )
for k, v in os.environ:
print( f'{ k } = "{ v }"' )
Main()

View file

@ -6,38 +6,6 @@ function! ClearDown()
call vimspector#test#setup#ClearDown() call vimspector#test#setup#ClearDown()
endfunction endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Mappings_Are_Added_HUMAN()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Mappings_Are_Added_VISUAL_STUDIO()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
function! Test_Mappings_Are_Added_VISUAL_STUDIO()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Signs_Placed_Using_API_Are_Shown() function! SetUp_Test_Signs_Placed_Using_API_Are_Shown()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO' let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction endfunction
@ -78,68 +46,6 @@ function! Test_Signs_Placed_Using_API_Are_Shown()
%bwipeout! %bwipeout!
endfunction endfunction
function! SetUp_Test_Use_Mappings_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Use_Mappings_HUMAN()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 15, 1 ] )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Disable the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBPDisabled',
\ 9 )
" Delete the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add it again
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Here we go. Start Debugging
call feedkeys( "\<F5>", 'xt' )
call assert_equal( 2, len( gettabinfo() ) )
let cur_tabnr = tabpagenr()
call assert_equal( 5, len( gettabinfo( cur_tabnr )[ 0 ].windows ) )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" Step
call feedkeys( "\<F10>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cp', 16 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_StopAtEntry() function! SetUp_Test_StopAtEntry()
let g:vimspector_enable_mappings = 'HUMAN' let g:vimspector_enable_mappings = 'HUMAN'
endfunction endfunction
@ -200,8 +106,8 @@ function Test_DisableBreakpointWhileDebugging()
\ 16 ) \ 16 )
\ } ) \ } )
" Add the breakpoint call setpos( '.', [ 0, 1, 1 ] )
call feedkeys( "\<F9>", 'xt' ) call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
call WaitForAssert( {-> call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupSingletonAtLine( \ vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode', \ 'VimspectorCode',
@ -211,7 +117,6 @@ function Test_DisableBreakpointWhileDebugging()
\ } ) \ } )
" Run to breakpoint " Run to breakpoint
call setpos( '.', [ 0, 15, 1 ] )
call feedkeys( "\<F5>", 'xt' ) call feedkeys( "\<F5>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {-> call WaitForAssert( {->
@ -258,6 +163,58 @@ function Test_DisableBreakpointWhileDebugging()
%bwipeout! %bwipeout!
endfunction endfunction
function! Test_Add_Breakpoints_In_File_Then_Open()
lcd testdata/cpp/simple
" Set and clear without file open
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
call vimspector#ClearLineBreakpoint( 'simple.cpp', 16 )
" Clear non-set breakpoint
call vimspector#ClearLineBreakpoint( 'simple.cpp', 1 )
" Re-add
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
" Open and expect sign to be added
edit simple.cpp
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 16,
\ 'vimspectorBP',
\ 9 )
call vimspector#LaunchWithSettings( { 'configuration': 'run-to-breakpoint' } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! Test_Add_Breakpoints_In_NonOpenedFile_RunToBreak()
lcd testdata/cpp/simple
" add
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
call vimspector#LaunchWithSettings( {
\ 'configuration': 'run-to-breakpoint-specify-file',
\ 'prog': 'simple'
\ } )
call WaitFor( {-> bufexists( 'simple.cpp' ) } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 16,
\ 'vimspectorPCBP',
\ 200 )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_Insert_Code_Above_Breakpoint() function! SetUp_Test_Insert_Code_Above_Breakpoint()
let g:vimspector_enable_mappings = 'HUMAN' let g:vimspector_enable_mappings = 'HUMAN'
endfunction endfunction
@ -308,7 +265,6 @@ function! Test_Insert_Code_Above_Breakpoint()
" Delete it " Delete it
call feedkeys( "\<F9>", 'xt' ) call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 26 ) call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 26 )
endfunction endfunction
function! SetUp_Test_Conditional_Line_Breakpoint() function! SetUp_Test_Conditional_Line_Breakpoint()
@ -360,8 +316,11 @@ function! Test_Conditional_Line_Breakpoint()
\ 'vimspectorBP', \ 'vimspectorBP',
\ 9 ) \ 9 )
call setpos( '.', [ 0, 17, 1 ] ) call setpos( '.', [ 0, 1, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': 'argc == 1' } ) call vimspector#SetLineBreakpoint(
\ 'simple.cpp',
\ 17,
\ { 'condition': 'argc == 1' } )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP', \ 'VimspectorBP',
\ 17, \ 17,
@ -724,7 +683,6 @@ function! Test_Custom_Breakpoint_Priority_Partial()
unlet! g:vimspector_sign_priority unlet! g:vimspector_sign_priority
endfunction endfunction
function! Test_Add_Line_BP_In_Other_File_While_Debugging() function! Test_Add_Line_BP_In_Other_File_While_Debugging()
let moo = 'moo.py' let moo = 'moo.py'
let cow = 'cow.py' let cow = 'cow.py'

View file

@ -7,38 +7,6 @@ function! ClearDown()
call vimspector#test#setup#ClearDown() call vimspector#test#setup#ClearDown()
endfunction endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Mappings_Are_Added_HUMAN()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Mappings_Are_Added_VISUAL_STUDIO()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
function! Test_Mappings_Are_Added_VISUAL_STUDIO()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Signs_Placed_Using_API_Are_Shown() function! SetUp_Test_Signs_Placed_Using_API_Are_Shown()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO' let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction endfunction
@ -132,7 +100,7 @@ function! Test_Use_Mappings_HUMAN()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {-> call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cp', 16 ) \ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
\ } ) \ } )
call vimspector#test#setup#Reset() call vimspector#test#setup#Reset()

View file

@ -45,3 +45,28 @@ function! Test_Go_Simple()
lcd - lcd -
%bwipeout! %bwipeout!
endfunction endfunction
function! Test_Run_To_Cursor()
let fn='hello-world.go'
lcd ../support/test/go/hello_world
exe 'edit ' . fn
call vimspector#SetLineBreakpoint( fn, 4 )
call vimspector#Launch()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 4, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 4 )
\ } )
call cursor( 5, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 5, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 5 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction

View file

@ -1,6 +1,7 @@
function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer, function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer,
\ line, \ line,
\ column ) abort \ column ) abort
call WaitFor( {-> bufexists( a:buffer ) } )
call WaitForAssert( {-> call WaitForAssert( {->
\ assert_equal( fnamemodify( a:buffer, ':p' ), \ assert_equal( fnamemodify( a:buffer, ':p' ),
\ fnamemodify( bufname( '%' ), ':p' ), \ fnamemodify( bufname( '%' ), ':p' ),
@ -15,6 +16,7 @@ function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer,
endfunction endfunction
function! vimspector#test#signs#AssertPCIsAtLineInBuffer( buffer, line ) abort function! vimspector#test#signs#AssertPCIsAtLineInBuffer( buffer, line ) abort
call WaitFor( {-> bufexists( a:buffer ) } )
let signs = sign_getplaced( a:buffer, { let signs = sign_getplaced( a:buffer, {
\ 'group': 'VimspectorCode', \ 'group': 'VimspectorCode',
\ } ) \ } )

123
tests/mappings.test.vim Normal file
View file

@ -0,0 +1,123 @@
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Mappings_Are_Added_HUMAN()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
call assert_true( hasmapto( 'vimspector#RunToCursor()' ) )
endfunction
function! SetUp_Test_Mappings_Are_Added_VISUAL_STUDIO()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
function! Test_Mappings_Are_Added_VISUAL_STUDIO()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Use_Mappings_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Use_Mappings_HUMAN()
call ThisTestIsFlaky()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 15, 1 ] )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Disable the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBPDisabled',
\ 9 )
" Delete the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add and clear using API
call vimspector#SetLineBreakpoint( 'simple.cpp', 15 )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
call vimspector#ClearLineBreakpoint( 'simple.cpp', 15 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add it again
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Here we go. Start Debugging
call feedkeys( "\<F5>", 'xt' )
call assert_equal( 2, len( gettabinfo() ) )
let cur_tabnr = tabpagenr()
call assert_equal( 5, len( gettabinfo( cur_tabnr )[ 0 ].windows ) )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" Step
call feedkeys( "\<F10>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
\ } )
" Run to cursor
call cursor( 9, 1 )
call feedkeys( "\\\<F8>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 9, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 9 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction

View file

@ -0,0 +1,200 @@
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function s:Start()
call vimspector#SetLineBreakpoint( 'moo.py', 13 )
call vimspector#Launch()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 1, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 1 )
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 13, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 13 )
endfunction
function Test_Run_To_Cursor_Simple()
" Run to a position that will certainly be executed
lcd ../support/test/python/multiple_files
call vimspector#SetLineBreakpoint( 'moo.py', 13 )
call s:Start()
call cursor( 8, 27 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 8, 27 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 8 )
\ } )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 9, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 9 )
" Check there is no breakpoint set on line 8
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 8 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipe!
endfunction
function Test_Run_To_Cursor_On_NonBreaking_Line()
" Run to a position that will certainly be executed, but is not a real line
lcd ../support/test/python/multiple_files
call vimspector#SetLineBreakpoint( 'moo.py', 13 )
call s:Start()
call cursor( 7, 1 )
" Interestingly, debugpy moves the breakpoint to the previous line, which is
" kinda annoying
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 6, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 6 )
\ } )
call vimspector#StepOver()
" It's a loop, so we go up a line
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 5, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 5 )
" Check there is no breakpoint set on lines 7 and 6:
" 7 - where we put the 'temporary' breakpoint
" 6 - where it got placed
"
" FIXME: This is broken, we don't _know_ that the breakpoint that was hit was
" the temporary one, and there's no way to know.
"
" I wonder if the relocated breakpoint can be matched with the _original_
" breakpoint
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 7 )
\ } )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 6 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipe!
endfunction
function Test_Run_To_Cursor_Different_File()
" Run into a different file
" Run to a position that will certainly be executed, but is not a real line
lcd ../support/test/python/multiple_files
call vimspector#SetLineBreakpoint( 'moo.py', 13 )
call s:Start()
edit cow.py
call cursor( 2, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'cow.py', 2, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'cow.py', 2 )
\ } )
bu moo.py
call cursor( 9, 12 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 9, 12 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 9 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipe!
endfunction
function Test_Run_To_Cursor_Hit_Another_Breakpoint()
" Run to cursor, but hit a non-temporary breakpoint
lcd ../support/test/python/multiple_files
call vimspector#SetLineBreakpoint( 'moo.py', 13 )
call s:Start()
call vimspector#SetLineBreakpoint( 'moo.py', 5 )
call cursor( 6, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 5, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 5 )
\ } )
" The temporary breakpoint is still there
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorBP',
\ 9 )
call vimspector#ClearLineBreakpoint( 'moo.py', 5 )
call cursor( 8, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 8, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 8 )
\ } )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 6 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipe!
endfunction
function! Test_InvalidBreakpoint()
" Run to cursor, but hit a non-temporary breakpoint
lcd ../support/test/python/multiple_files
call vimspector#SetLineBreakpoint( 'moo.py', 13 )
call s:Start()
call vimspector#SetLineBreakpoint( 'moo.py', 9 )
edit .vimspector.json
call cursor( 1, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 9, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 9 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipe!
endfunction
function! Test_StartDebuggingWithRunToCursor()
lcd ../support/test/python/multiple_files
edit moo.py
call cursor( 9, 1 )
call vimspector#RunToCursor()
" Stop on entry is still hit
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 1, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 1 )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 9,
\ 'vimspectorBP',
\ 9 )
call vimspector#Continue()
" Runs to cursor
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 9, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 9 )
call vimspector#StepOver()
" And claers the temp breakpoint
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 8, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 8 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 9 )
\ } )
lcd -
endfunction

View file

@ -46,6 +46,28 @@
} }
} }
}, },
"run-to-breakpoint-specify-file": {
"adapter": "vscode-cpptools",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/${prog}",
"cwd": "${workspaceRoot}",
"externalConsole": false,
"stopAtEntry": false,
"stopOnEntry": false,
"MImode": "${VIMSPECTOR_MIMODE}"
},
"breakpoints": {
"exception": {
"cpp_catch": "",
"cpp_throw": "",
"objc_catch": "",
"objc_throw": "",
"swift_catch": "",
"swift_throw": ""
}
}
},
"calculate-some-variable": { "calculate-some-variable": {
"adapter": "vscode-cpptools", "adapter": "vscode-cpptools",
"variables": { "variables": {