Skip to content

Commit a2d2104

Browse files
authored
Merge pull request #768 from puremourning/edit-breakpoints
Allow editing of breakpoint options in breakpoints window
2 parents 39657c1 + 309c0de commit a2d2104

File tree

7 files changed

+229
-47
lines changed

7 files changed

+229
-47
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,12 +910,14 @@ The following mappings apply by default in the breakpoints window:
910910
* `t`, `<F9>` - toggle, i.e. enable/disable breakpoint
911911
* `T` - toggle, i.e. enable/disable ALL breakpoints
912912
* `dd`, `<Del>` - delete the current breakpoint
913+
* `cc`, `C` - edit the current breakpoint options
913914
* `i`, `a`, `o` - add a new line breakpoint
914915
* `I`, `A`, `O` - add a new function breakpoint
915916
* `<Enter>` or double-click - jump to the line breakpoint
916917

917918
A WinBar is provided (where supported) too. This adds functions like
918-
saving/restoring sessions and clearing all breakpoints too.
919+
saving/restoring sessions, clearing all breakpoints, and resetting the exception
920+
breakpoints options.
919921

920922
### Line breakpoints
921923

autoload/vimspector.vim

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -173,33 +173,18 @@ function! vimspector#ClearBreakpoints() abort
173173
py3 _vimspector_session.ClearBreakpoints()
174174
endfunction
175175

176-
let s:extended_breakpoint_properties = [
177-
\ { 'prop': 'condition', 'msg': 'Enter condition expression' },
178-
\ { 'prop': 'hitCondition', 'msg': 'Enter hit count expression' },
179-
\ { 'prop': 'logMessage',
180-
\ 'msg': 'Enter log expression (to make log point)' },
181-
\ ]
182-
183-
function! s:AskForInput( ... ) abort
184-
return py3eval( '__import__( "vimspector", fromlist=[ "utils" ] )'
185-
\ . '.utils.AskForInput( *vim.eval( "a:000" ) )' )
176+
function! vimspector#ResetExceptionBreakpoints() abort
177+
if !s:Enabled()
178+
return
179+
endif
180+
py3 _vimspector_session.ResetExceptionBreakpoints()
186181
endfunction
187182

188-
function! s:GetAdvancedBreakpointOptions() abort
189-
let options = {}
190-
for spec in s:extended_breakpoint_properties
191-
let response = s:AskForInput( spec.msg . ': ' )
192-
if response is s:None
193-
return s:None
194-
elseif response !=# ''
195-
let options[ spec.prop ] = response
196-
endif
197-
endfor
198-
199-
return options
183+
function! s:GetAdvancedBreakpointOptions( ... ) abort
184+
return py3eval( '__import__( "vimspector", fromlist=[ "breakpoints" ] )'
185+
\ . '.breakpoints.GetAdvancedBreakpointOptions()' )
200186
endfunction
201187

202-
203188
function! vimspector#ToggleAdvancedBreakpoint() abort
204189
let options = s:GetAdvancedBreakpointOptions()
205190
if options is s:None
@@ -220,6 +205,11 @@ function! vimspector#ToggleBreakpoint( ... ) abort
220205
py3 _vimspector_session.ToggleBreakpoint( vim.eval( 'options' ) )
221206
endfunction
222207

208+
function! s:AskForInput( ... ) abort
209+
return py3eval( '__import__( "vimspector", fromlist=[ "utils" ] )'
210+
\ . '.utils.AskForInput( *vim.eval( "a:000" ) )' )
211+
endfunction
212+
223213
function! vimspector#SetAdvancedLineBreakpoint() abort
224214
if !s:Enabled()
225215
return
@@ -592,6 +582,13 @@ function! vimspector#JumpToBreakpointViewBreakpoint() abort
592582
py3 _vimspector_session.JumpToBreakpointViewBreakpoint()
593583
endfunction
594584

585+
function! vimspector#EditBreakpointOptionsViewBreakpoint() abort
586+
if !s:Enabled()
587+
return
588+
endif
589+
py3 _vimspector_session.EditBreakpointOptionsViewBreakpoint()
590+
endfunction
591+
595592
function! vimspector#JumpToNextBreakpoint() abort
596593
if !s:Enabled()
597594
return

python3/vimspector/breakpoints.py

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ def _UpdateView( self, breakpoint_list, show=True ):
8181
'toggle': 'ToggleBreakpointViewBreakpoint',
8282
'toggle_all': 'ToggleAllBreakpointsViewBreakpoint',
8383
'delete': 'DeleteBreakpointViewBreakpoint',
84+
'edit': 'EditBreakpointOptionsViewBreakpoint',
8485
'jump_to': 'JumpToBreakpointViewBreakpoint',
8586
'add_line': 'SetAdvancedLineBreakpoint',
86-
'add_func': 'AddAdvancedFunctionBreakpoint'
87+
'add_func': 'AddAdvancedFunctionBreakpoint',
8788
}
8889
for key, func in groups.items():
8990
for mapping in utils.GetVimList( mappings, key ):
@@ -100,27 +101,7 @@ def _UpdateView( self, breakpoint_list, show=True ):
100101

101102
utils.SetSyntax( '', 'vimspector-breakpoints', self._buffer )
102103

103-
if utils.UseWinBar():
104-
vim.command( 'nnoremenu <silent> 1.1 WinBar.Delete '
105-
':call vimspector#DeleteBreakpointViewBreakpoint()<CR>' )
106-
vim.command( 'nnoremenu <silent> 1.2 WinBar.Toggle '
107-
':call vimspector#ToggleBreakpointViewBreakpoint()<CR>' )
108-
vim.command( 'nnoremenu <silent> 1.2 WinBar.*Toggle '
109-
':call'
110-
' vimspector#ToggleAllBreakpointsViewBreakpoint()<CR>' )
111-
vim.command( 'nnoremenu <silent> 1.3 WinBar.Jump\\ To '
112-
':call vimspector#JumpToBreakpointViewBreakpoint()<CR>' )
113-
# TODO: Add tests for this function
114-
vim.command( 'nnoremenu <silent> 1.4 WinBar.+Line '
115-
':call vimspector#SetAdvancedLineBreakpoint()<CR>' )
116-
vim.command( 'nnoremenu <silent> 1.4 WinBar.+Function '
117-
':call vimspector#AddAdvancedFunctionBreakpoint()<CR>' )
118-
vim.command( 'nnoremenu <silent> 1.4 WinBar.Clear '
119-
':call vimspector#ClearBreakpoints()<CR>' )
120-
vim.command( 'nnoremenu <silent> 1.4 WinBar.Save '
121-
':call vimspector#WriteSessionFile()<CR>' )
122-
vim.command( 'nnoremenu <silent> 1.4 WinBar.Load '
123-
':call vimspector#ReadSessionFile()<CR>' )
104+
self._RenderWinBar()
124105

125106
# we want to maintain the height of the window
126107
self._win.options[ "winfixheight" ] = True
@@ -141,6 +122,28 @@ def FormatEntry( el ):
141122
utils.SetBufferContents( self._buffer,
142123
list( map( FormatEntry, breakpoint_list ) ) )
143124

125+
126+
def _RenderWinBar( self ):
127+
if not utils.UseWinBar():
128+
return
129+
130+
if not self._HasWindow():
131+
return
132+
133+
with utils.LetCurrentWindow( self._win ):
134+
utils.SetWinBar(
135+
( 'Del', 'vimspector#DeleteBreakpointViewBreakpoint()' ),
136+
( 'On/Off', 'vimspector#ToggleBreakpointViewBreakpoint()' ),
137+
( 'Edit', 'vimspector#EditBreakpointOptionsViewBreakpoint()' ),
138+
( '+Line', 'vimspector#SetAdvancedLineBreakpoint()' ),
139+
( '+Func', 'vimspector#AddAdvancedFunctionBreakpoint()' ),
140+
( 'Clr All', 'vimspector#ClearBreakpoints()' ),
141+
( 'Clr Excp', 'vimspector#ResetExceptionBreakpoints()' ),
142+
( 'Save', 'vimspector#WriteSessionFile()' ),
143+
( 'Load', 'vimspector#ReadSessionFile()' ),
144+
)
145+
146+
144147
def CloseBreakpoints( self ):
145148
if not self._HasWindow():
146149
return
@@ -336,6 +339,26 @@ def JumpToBreakpointViewBreakpoint( self ):
336339

337340
_JumpToBreakpoint( bp )
338341

342+
def EditBreakpointOptionsViewBreakpoint( self ):
343+
vbp = self._breakpoints_view.GetBreakpointForLine()
344+
if not vbp:
345+
return
346+
347+
# Try to find the actual breakpoint
348+
bp, index = self._FindLineBreakpoint( vbp.get( 'filename' ),
349+
vbp.get( 'lnum' ) )
350+
351+
if not bp:
352+
return
353+
354+
options = GetAdvancedBreakpointOptions( bp[ 'options' ] )
355+
if options is None:
356+
return
357+
358+
self.SetLineBreakpoint( vbp[ 'filename' ], vbp[ 'lnum' ], options )
359+
utils.UserMessage( "Breakpoint updated." )
360+
361+
339362
def JumpToNextBreakpoint( self, reverse=False ):
340363
bps = self._breakpoints_view._breakpoint_list
341364
if not bps:
@@ -440,6 +463,12 @@ def ClearBreakpoints( self ):
440463
self.UpdateUI()
441464

442465

466+
def ResetExceptionBreakpoints( self ):
467+
# TODO: Should exceptoni breakpoints be per-session!?
468+
self._exception_breakpoints = None
469+
self.UpdateUI()
470+
471+
443472
def _FindLineBreakpoint( self, file_name, line ):
444473
for bp, index in self._AllBreakpointsOnLine( file_name, line ):
445474
return bp, index
@@ -1172,3 +1201,27 @@ def _SignToLine( self, file_name, bp ):
11721201
bp[ 'line' ] = int( signs[ 0 ][ 'signs' ][ 0 ][ 'lnum' ] )
11731202

11741203
return
1204+
1205+
1206+
_extended_breakpoint_properties = [
1207+
{ 'prop': 'condition', 'msg': 'Enter condition expression' },
1208+
{ 'prop': 'hitCondition', 'msg': 'Enter hit count expression' },
1209+
{ 'prop': 'logMessage',
1210+
'msg': 'Enter log expression (to make log point)' },
1211+
]
1212+
1213+
1214+
def GetAdvancedBreakpointOptions( existing_options = None ):
1215+
options = {}
1216+
if existing_options:
1217+
options.update( existing_options )
1218+
1219+
for spec in _extended_breakpoint_properties:
1220+
response = utils.AskForInput( spec[ 'msg' ] + ': ',
1221+
options.get( spec[ 'prop' ] ) )
1222+
if response is None:
1223+
return None
1224+
elif response:
1225+
options[ spec[ 'prop' ] ] = response
1226+
1227+
return options

python3/vimspector/debug_session.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,6 +2093,9 @@ def DeleteBreakpointViewBreakpoint( self ):
20932093
def JumpToBreakpointViewBreakpoint( self ):
20942094
self._breakpoints.JumpToBreakpointViewBreakpoint()
20952095

2096+
def EditBreakpointOptionsViewBreakpoint( self ):
2097+
self._breakpoints.EditBreakpointOptionsViewBreakpoint()
2098+
20962099
def JumpToNextBreakpoint( self ):
20972100
self._breakpoints.JumpToNextBreakpoint()
20982101

@@ -2170,6 +2173,9 @@ def ClearLineBreakpoint( self, file_name, line_num ):
21702173
def ClearBreakpoints( self ):
21712174
return self._breakpoints.ClearBreakpoints()
21722175

2176+
def ResetExceptionBreakpoints( self ):
2177+
return self._breakpoints.ResetExceptionBreakpoints()
2178+
21732179
def AddFunctionBreakpoint( self, function, options ):
21742180
return self._breakpoints.AddFunctionBreakpoint( function, options )
21752181

python3/vimspector/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@
100100
'toggle': [ 't', '<F9>' ],
101101
'toggle_all': [ 'T' ],
102102
'delete': [ 'dd', '<Del>' ],
103+
'edit': [ 'cc', 'C' ],
103104
'add_line': [ 'i', 'a', 'o', '<Insert>' ],
104105
'add_func': [ 'I', 'A', 'O', '<leader><Insert>' ],
105-
'jump_to': [ '<2-LeftMouse>', '<Enter>' ]
106+
'jump_to': [ '<2-LeftMouse>', '<Enter>' ],
106107
}
107108
},
108109

support/test/python/simple_python/.vimspector.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@
126126
}
127127
}
128128
},
129+
"run - no exception bp override": {
130+
"adapter": "debugpy",
131+
"configuration": {
132+
"request": "launch",
133+
"type": "python",
134+
"cwd": "${workspaceRoot}",
135+
"program": "${file}",
136+
"stopOnEntry": false,
137+
"console": "integratedTerminal"
138+
}
139+
},
129140
"run - debugpy-python2": {
130141
"adapter": "debugpy-python2",
131142
"configuration": {

tests/breakpoints.test.vim

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,118 @@ function! Test_Conditional_Line_Breakpoint()
569569
%bwipeout!
570570
endfunction
571571

572+
function! Test_Conditional_Line_Breakpoint_Edit()
573+
lcd testdata/cpp/simple
574+
edit simple.cpp
575+
call setpos( '.', [ 0, 16, 1 ] )
576+
577+
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
578+
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
579+
580+
" Add breakpoint using API:
581+
" - add it using a condition which doesn't match (argc == 0)
582+
" - then edit it to use a condition which matches (argc == 1)
583+
call vimspector#SetLineBreakpoint( 'simple.cpp', 17,
584+
\ { 'condition': 'argc == 0' } )
585+
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
586+
\ 'VimspectorBP',
587+
\ 17,
588+
\ 'vimspectorBPCond',
589+
\ 9 )
590+
591+
call vimspector#ListBreakpoints()
592+
call s:CheckBreakpointView( [
593+
\ 'simple.cpp:17 Line breakpoint - ENABLED: {"condition": "argc == 0"}'
594+
\ ] )
595+
let bname = bufname( winbufnr( g:vimspector_session_windows.breakpoints ) )
596+
call vimspector#test#signs#AssertCursorIsAtLineInBuffer(
597+
\ bname,
598+
\ 1,
599+
\ 1 )
600+
601+
call feedkeys( 'cc'
602+
\ .. "\<C-u>argc == 1\<CR>"
603+
\ .. "1\<CR>"
604+
\ .. "\<CR>",
605+
\ 'xt' )
606+
607+
call s:CheckBreakpointView( [
608+
\ 'simple.cpp:17 Line breakpoint - ENABLED: {"condition": "argc == 1", "hitCondition": "1"}'
609+
\ ] )
610+
611+
wincmd p
612+
call vimspector#ListBreakpoints()
613+
call setpos( '.', [ 0, 1, 1 ] )
614+
615+
" Start debugging
616+
call vimspector#LaunchWithSettings( #{ configuration: 'run-to-breakpoint' } )
617+
618+
" Condition matches on line 17
619+
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 17, 1 )
620+
621+
call vimspector#test#setup#Reset()
622+
623+
lcd -
624+
%bwipeout!
625+
endfunction
626+
627+
function! Test_Conditional_Line_Breakpoint_Edit_While_Connected()
628+
lcd testdata/cpp/simple
629+
edit simple.cpp
630+
call setpos( '.', [ 0, 16, 1 ] )
631+
632+
call vimspector#Launch()
633+
" break on main
634+
call vimspector#test#signs#AssertCursorIsAtLineInBuffer(
635+
\ 'simple.cpp',
636+
\ s:break_main_line, 1 )
637+
638+
" Add breakpoint using API:
639+
" - add it using a condition which doesn't match (argc == 0)
640+
" - then edit it to use a condition which matches (argc == 1)
641+
call vimspector#SetLineBreakpoint( 'simple.cpp', 17,
642+
\ { 'condition': 'argc == 0' } )
643+
call WaitForAssert( { ->
644+
\ vimspector#test#signs#AssertSignGroupSingletonAtLine(
645+
\ 'VimspectorBP',
646+
\ 17,
647+
\ 'vimspectorBPCond',
648+
\ 9 ) } )
649+
650+
call vimspector#ListBreakpoints()
651+
call s:CheckBreakpointView( [
652+
\ 'simple.cpp:17 Line breakpoint - VERIFIED: {"condition": "argc == 0"}'
653+
\ ] )
654+
let bname = bufname( winbufnr( g:vimspector_session_windows.breakpoints ) )
655+
call vimspector#test#signs#AssertCursorIsAtLineInBuffer(
656+
\ bname,
657+
\ 1,
658+
\ 1 )
659+
660+
call feedkeys( 'cc'
661+
\ .. "\<C-u>argc == 1\<CR>"
662+
\ .. "1\<CR>"
663+
\ .. "\<CR>",
664+
\ 'xt' )
665+
666+
call s:CheckBreakpointView( [
667+
\ 'simple.cpp:17 Line breakpoint - VERIFIED: {"condition": "argc == 1", "hitCondition": "1"}'
668+
\ ] )
669+
670+
wincmd p
671+
call vimspector#ListBreakpoints()
672+
call setpos( '.', [ 0, 1, 1 ] )
673+
674+
" Condition matches on line 17
675+
call vimspector#Continue()
676+
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 17, 1 )
677+
call vimspector#test#setup#Reset()
678+
679+
lcd -
680+
%bwipeout!
681+
endfunction
682+
683+
572684
function! SetUp_Test_Conditional_Line_Breakpoint_Disable()
573685
let g:vimspector_enable_mappings = 'HUMAN'
574686
call s:PushSetting( 'vimspector_toggle_disables_breakpoint', 1 )

0 commit comments

Comments
 (0)