test and doc updates for conditional breakpoints

use a better description of hit condition and describe the options dict.
This commit is contained in:
Ben Jackson 2020-04-26 11:14:44 +01:00
commit 77dc400077
5 changed files with 218 additions and 9 deletions

View file

@ -517,7 +517,7 @@ let g:vimspector_enable_mappings = 'HUMAN'
| `F4` | Restart debugging with the same configuration. | `vimspector#Restart()` |
| `F6` | Pause debugee. | `vimspector#Pause()` |
| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` |
| `<leader>F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( {condition, hit condition } )` |
| `<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>' )` |
| `F10` | Step Over | `vimspector#StepOver()` |
| `F11` | Step Into | `vimspector#StepInto()` |
@ -530,6 +530,8 @@ let g:vimspector_enable_mappings = 'HUMAN'
* Create `vimspector.json`. See [below](#supported-languages).
* `:call vimspector#Launch()` and select a configuration.
![debug session](https://puremourning.github.io/vimspector-web/img/vimspector-overview.png)
### Launch with options
To launch a specific debug configuration, or specify [replacement
@ -562,16 +564,35 @@ debugger](#java---partially-supported)
## Breakpoints
* Use `vimspector#ToggleBreakpoint([ { 'condition': '<condition>' } ])`
* Use `vimspector#ToggleBreakpoint([ { 'condition': '<condition expr>' } ])`
to set/disable/delete a line breakpoint, with optional condition.
* Use `vimspector#AddFunctionBreakpoint( '<name>' [, { 'condition': '<condition>' } ] )`
* Use `vimspector#AddFunctionBreakpoint( '<name>' [, { 'condition': '<condition expr>' } ] )`
to add a function breakpoint with optional condition.
Both of these functions take a single optional argument which is a dictionary of
options. The dictionary can have the following keys:
* `condition`: An optional expression evaluated to deterimie if the breakpoint
should fire. Not supported by all debug adapters. For example, to break when
`abc` is `10`, enter something like `abc == 10`, depending on the language.
* `hitCondition`: An optional expression evaluated to determine a number of
times the breakpoint should be ignored. Should (probablty?) not be used in
combination with `condition`. Not supported by all debug adapters. For
example, to break on the 3rd time hitting this line, enter `3`.
In both cases, the expression is evaluated by the debugger, so should be in
whatever dialect the debugger understands when evaluating expressions.
When using the `<leader><F9>` mapping, the user is prompted to enter these
expressions in a command line (with history).
## Stepping
* Step in/out, finish, continue, pause etc. using the WinBar.
* Step in/out, finish, continue, pause etc. using the WinBar, or mappings.
* If you really want to, the API is `vimspector#StepInto()` etc.
![code window](https://puremourning.github.io/vimspector-web/img/vimspector-code-window.png)
## Variables and scopes
* Current scope shows values of locals.
@ -579,6 +600,8 @@ debugger](#java---partially-supported)
* When changing the stack frame the locals window updates.
* While paused, hover to see values
![locals window](https://puremourning.github.io/vimspector-web/img/vimspector-locals-window.png)
## Watches
The watches window is a prompt buffer, where that's available. Enter insert mode
@ -591,11 +614,15 @@ to add a new watch expression.
* Expand result with `<CR>`.
* Delete with `<DEL>`.
![watch window](https://puremourning.github.io/vimspector-web/img/vimspector-watch-window.png)
## Stack Traces
* In the threads window, use `<CR>` to expand/collapse.
* Use `<CR>` on a stack frame to jump to it.
![stack trace](https://puremourning.github.io/vimspector-web/img/vimspector-callstack-window.png)
## Program Output
* In the outputs window use the WinBar to select the output channel.
@ -604,6 +631,8 @@ to add a new watch expression.
* The debugee prints to the stdout channel.
* Other channels may be useful for debugging.
![output window](https://puremourning.github.io/vimspector-web/img/vimspector-output-window.png)
### Console
The console window is a prompt buffer, where that's available, and can be used

View file

@ -45,8 +45,8 @@ nnoremap <Plug>VimspectorToggleBreakpoint
\ :<c-u>call vimspector#ToggleBreakpoint()<CR>
nnoremap <Plug>VimspectorToggleConditionalBreakpoint
\ :<c-u>call vimspector#ToggleBreakpoint(
\ { 'condition': input( 'Enter condition: ' ),
\ 'hitCondition': input( 'Enter hit condition: ' ) }
\ { 'condition': input( 'Enter condition expression: ' ),
\ 'hitCondition': input( 'Enter hit count expression: ' ) }
\ )<CR>
nnoremap <Plug>VimspectorAddFunctionBreakpoint
\ :<c-u>call vimspector#AddFunctionBreakpoint( expand( '<cexpr>' ) )<CR>

View file

@ -313,7 +313,7 @@ class VariablesView( object ):
if result_str is None:
result_str = 'null'
line = '{0}{1} Result: {2} '.format( ' ' * indent, icon, result_str )
line = '{0}{1} Result: {2}'.format( ' ' * indent, icon, result_str )
line = utils.AppendToBuffer( self._watch.win.buffer, line.split( '\n' ) )
self._watch.lines[ line ] = result

View file

@ -295,3 +295,158 @@ function! Test_Insert_Code_Above_Breakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 26 )
endfunction
function! SetUp_Test_Conditional_Line_Breakpoint()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Conditional_Line_Breakpoint()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 16, 1 ] )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
" Add the conditional breakpoint
call feedkeys( "\\\<F9>argc==0\<CR>\<CR>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 16,
\ 'vimspectorBPCond' )
" Disable the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 16,
\ 'vimspectorBPDisabled' )
" Delete the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
" Add breakpoint using API:
" - on line 16 condition which doesn't match
" - then an unconditional one on line 9, unconditional
" - then on line 17, condition which matches
call vimspector#ToggleBreakpoint( { 'condition': 'argc == 0' } )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 16,
\ 'vimspectorBPCond' )
call setpos( '.', [ 0, 9, 1 ] )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 9,
\ 'vimspectorBP' )
call setpos( '.', [ 0, 17, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': 'argc == 1' } )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 17,
\ 'vimspectorBPCond' )
call setpos( '.', [ 0, 1, 1 ] )
" Start debugging
call vimspector#Continue()
" break on main
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" Ignore non-matching on line 16, break on line 9
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 9, 1 )
" Condition matches on line 17
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 17, 1 )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_Conditional_Line_Breakpoint_Hit()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Conditional_Line_Breakpoint_Hit()
let fn = '../support/test/python/simple_python/main.py'
exe 'edit' fn
call setpos( '.', [ 0, 14, 1 ] )
" Add the conditional breakpoint (3 times)
call feedkeys( "\\\<F9>\<CR>3\<CR>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 14,
\ 'vimspectorBPCond' )
call vimspector#LaunchWithSettings( { 'configuration': 'run' } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 14, 1 )
" difficult to check if we really did run 3 times, so just use the watch
" window (also, tests the watch window!)
call vimspector#AddWatch( 'i' )
call WaitForAssert( {->
\ assert_equal( [ ' - Result: 2' ],
\ getbufline( 'vimspector.Watches', '$' ) )
\ } )
call vimspector#test#setup#Reset()
%bwipeout!
endfunction
function! Test_Function_Breakpoint()
lcd testdata/cpp/simple
edit simple.cpp
call vimspector#AddFunctionBreakpoint( 'foo' )
call vimspector#Launch()
" break on main
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#Continue()
" break on func
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 9, 1 )
call vimspector#test#setup#Reset()
%bwipeout!
endfunction
function! Test_Function_Breakpoint_Condition()
lcd testdata/cpp/simple
edit simple.cpp
call vimspector#AddFunctionBreakpoint( 'foo', { 'condition': '1' } )
call vimspector#Launch()
" break on main
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#Continue()
" break on func
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 9, 1 )
call vimspector#test#setup#Reset()
%bwipeout!
endfunction
" Can't find an adapter that supports conditional function breakpoints which are
" probably pretty niche anyway
"
" function! Test_Function_Breakpoint_Condition_False()
" lcd testdata/cpp/simple
" edit simple.cpp
"
" call vimspector#AddFunctionBreakpoint( 'foo', { 'condition': '0' } )
" call setpos( '.', [ 0, 17, 1 ] )
" call vimspector#ToggleBreakpoint()
" call vimspector#Launch()
" " break on main
" call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" call vimspector#Continue()
"
" " doesn't break in func, break on line 17
" call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 17, 1 )
" call vimspector#test#setup#Reset()
" %bwipeout!
" throw "xfail cpptools doesn't seem to honour conditions on function bps"
" endfunction

View file

@ -32,11 +32,12 @@
" call ch_log( ",,,message..." )
" Then view it in 'debuglog'
" Let a test take up to 1 minute
" Let a test take up to 1 minute, unless debugging
let s:single_test_timeout = 60000
" Restrict the runtimepath to the exact minimum needed for testing
set runtimepath=$PWD/lib,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
let &rtp = getcwd() . '/lib'
set runtimepath+=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
if has('packages')
let &packpath = &runtimepath
endif
@ -70,6 +71,10 @@ func s:TestFailed()
endfunc
func! Abort( timer_id )
if exists( '&debugfunc' ) && &debugfunc != ''
return
endif
call assert_report( 'Test timed out!!!' )
qa!
endfunc
@ -152,6 +157,26 @@ func RunTheTest(test)
\ 'SKIPPED ' . a:test
\ . ': '
\ . substitute(v:exception, '^\S*\s\+', '', ''))
catch /^\cxfail/
if len( v:errors ) == 0
call add(v:errors,
\ 'Expected failure but no error in ' . a:test
\ . ': '
\ . v:exception
\ . ' @ '
\ . g:testpath
\ . ':'
\ . v:throwpoint)
call s:TestFailed()
else
let v:errors = []
call add(s:messages, ' XFAIL' )
call add(s:skipped,
\ 'XFAIL ' . a:test
\ . ': '
\ . substitute(v:exception, '^\S*\s\+', '', ''))
endif
catch
call add(v:errors,
\ 'Caught exception in ' . a:test