Merge pull request #375 from puremourning/up-down-stack

Add commands to navigate up/down the stack in focussed thread.
This commit is contained in:
mergify[bot] 2021-03-12 22:08:46 +00:00 • committed by GitHub
commit d84ebdd0ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 229 additions and 36 deletions

View file

@ -656,18 +656,23 @@ personal and so you should work out what you like and use vim's powerful mapping
features to set your own mappings. To that end, Vimspector defines the following features to set your own mappings. To that end, Vimspector defines the following
`<Plug>` mappings: `<Plug>` mappings:
* `<Plug>VimspectorContinue` | Mapping | Function | API |
* `<Plug>VimspectorStop` | --- | --- | --- |
* `<Plug>VimspectorRestart` | `<Plug>VimspectorContinue` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` |
* `<Plug>VimspectorPause` | `<Plug>VimspectorStop` | Stop debugging. | `vimspector#Stop()` |
* `<Plug>VimspectorToggleBreakpoint` | `<Plug>VimpectorRestart` | Restart debugging with the same configuration. | `vimspector#Restart()` |
* `<Plug>VimspectorToggleConditionalBreakpoint` | `<Plug>VimspectorPause` | Pause debuggee. | `vimspector#Pause()` |
* `<Plug>VimspectorAddFunctionBreakpoint` | `<Plug>VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` |
* `<Plug>VimspectorStepOver` | `<Plug>VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` |
* `<Plug>VimspectorStepInto` | `<Plug>VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '<cexpr>' )` |
* `<Plug>VimspectorStepOut` | `<Plug>VimspectorRunToCursor` | Run to Cursor | `vimspector#RunToCursor()` |
* `<Plug>VimspectorRunToCursor` | `<Plug>VimspectorStepOver` | Step Over | `vimspector#StepOver()` |
* `<Plug>VimspectorBalloonEval` | `<Plug>VimspectorStepInto` | Step Into | `vimspector#StepInto()` |
| `<Plug>VimspectorStepOut` | Step out of current function scope | `vimspector#StepOut()` |
| `<Plug>VimspectorUpFrame` | Move up a frame in the current call stack | `vimspector#UpFrame()` |
| `<Plug>VimspectorDownFrame` | Move down a frame in the current call stack | `vimspector#DownFrame()` |
| `<Plug>VimspectorBalloonEval` | Evaluate expression under cursor (or visual) in popup | *internal* |
These map roughly 1-1 with the API functions below. These map roughly 1-1 with the API functions below.
@ -695,17 +700,17 @@ loading vimspector**:
let g:vimspector_enable_mappings = 'VISUAL_STUDIO' let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
``` ```
| Key | Function | API | | Key | Mapping | Function
| --- | --- | --- | | --- | --- | ---
| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | | `F5` | `<Plug>VimspectorContinue` | When debugging, continue. Otherwise start debugging.
| `Shift F5` | Stop debugging. | `vimspector#Stop()` | | `Shift F5` | `<Plug>VimspectorStop` | Stop debugging.
| `Ctrl Shift F5` | Restart debugging with the same configuration. | `vimspector#Restart()` | | `Ctrl Shift F5` | `<Plug>VimspectorRestart` | Restart debugging with the same configuration.
| `F6` | Pause debuggee. | `vimspector#Pause()` | | `F6` | `<Plug>VimspectorPause` | Pause debuggee.
| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | | `F9` | `<Plug>VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line.
| `Shift F9` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '<cexpr>' )` | | `Shift F9` | `<Plug>VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor
| `F10` | Step Over | `vimspector#StepOver()` | | `F10` | `<Plug>VimspectorStepOver` | Step Over
| `F11` | Step Into | `vimspector#StepInto()` | | `F11` | `<Plug>VimspectorStepInto` | Step Into
| `Shift F11` | Step out of current function scope | `vimspector#StepOut()` | | `Shift F11` | `<Plug>VimspectorStepOut` | Step out of current function scope
## Human Mode ## Human Mode
@ -720,19 +725,19 @@ loading vimspector**:
let g:vimspector_enable_mappings = 'HUMAN' let g:vimspector_enable_mappings = 'HUMAN'
``` ```
| Key | Function | API | | Key | Mapping | Function
| --- | --- | --- | | --- | --- | ---
| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | | `F5` | `<Plug>VimspectorContinue` | When debugging, continue. Otherwise start debugging.
| `F3` | Stop debugging. | `vimspector#Stop()` | | `F3` | `<Plug>VimspectorStop` | Stop debugging.
| `F4` | Restart debugging with the same configuration. | `vimspector#Restart()` | | `F4` | `<Plug>VimspectorRestart` | Restart debugging with the same configuration.
| `F6` | Pause debuggee. | `vimspector#Pause()` | | `F6` | `<Plug>VimspectorPause` | Pause debuggee.
| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | | `F9` | `<Plug>VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line.
| `<leader>F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | | `<leader>F9` | `<Plug>VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line.
| `F8` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '<cexpr>' )` | | `F8` | `<Plug>VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor
| `<leader>F8` | Run to Cursor | `vimspector#RunToCursor()` | | `<leader>F8` | `<Plug>VimspectorRunToCursor` | Run to Cursor
| `F10` | Step Over | `vimspector#StepOver()` | | `F10` | `<Plug>VimspectorStepOver` | Step Over
| `F11` | Step Into | `vimspector#StepInto()` | | `F11` | `<Plug>VimspectorStepInto` | Step Into
| `F12` | Step out of current function scope | `vimspector#StepOut()` | | `F12` | `<Plug>VimspectorStepOut` | Step out of current function scope
In addition, I recommend adding a mapping to `<Plug>VimspectorBalloonEval`, in In addition, I recommend adding a mapping to `<Plug>VimspectorBalloonEval`, in
normal and visual modes, for example: normal and visual modes, for example:
@ -746,6 +751,13 @@ nmap <Leader>di <Plug>VimspectorBalloonEval
xmap <Leader>di <Plug>VimspectorBalloonEval xmap <Leader>di <Plug>VimspectorBalloonEval
``` ```
You may also wish to add mappings for up/down the stack, for example:
```viml
nmap <LocalLeader><F11> <Plug>VimspectorUpFrame
nmap <LocalLeader><F12> <Plug>VimspectorDownFrame
```
# Usage and API # Usage and API
This section defines detailed usage instructions, organised by feature. For most This section defines detailed usage instructions, organised by feature. For most

View file

@ -234,6 +234,20 @@ function! vimspector#GoToFrame() abort
py3 _vimspector_session.ExpandFrameOrThread() py3 _vimspector_session.ExpandFrameOrThread()
endfunction endfunction
function! vimspector#UpFrame() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.UpFrame()
endfunction
function! vimspector#DownFrame() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.DownFrame()
endfunction
function! vimspector#AddWatch( ... ) abort function! vimspector#AddWatch( ... ) abort
if !s:Enabled() if !s:Enabled()
return return

View file

@ -67,6 +67,11 @@ nnoremap <silent> <Plug>VimspectorBalloonEval
xnoremap <silent> <Plug>VimspectorBalloonEval xnoremap <silent> <Plug>VimspectorBalloonEval
\ :<c-u>call vimspector#ShowEvalBalloon( 1 )<CR> \ :<c-u>call vimspector#ShowEvalBalloon( 1 )<CR>
nnoremap <silent> <Plug>VimspectorUpFrame
\ :<c-u>call vimspector#UpFrame()<CR>
nnoremap <silent> <Plug>VimspectorDownFrame
\ :<c-u>call vimspector#DownFrame()<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

View file

@ -571,6 +571,14 @@ class DebugSession( object ):
def ExpandFrameOrThread( self ): def ExpandFrameOrThread( self ):
self._stackTraceView.ExpandFrameOrThread() self._stackTraceView.ExpandFrameOrThread()
@IfConnected()
def UpFrame( self ):
self._stackTraceView.UpFrame()
@IfConnected()
def DownFrame( self ):
self._stackTraceView.DownFrame()
def ToggleLog( self ): def ToggleLog( self ):
if self._HasUI(): if self._HasUI():
return self.ShowOutput( 'Vimspector' ) return self.ShowOutput( 'Vimspector' )

View file

@ -367,6 +367,46 @@ class StackTraceView( object ):
self._JumpToFrame( frame ) self._JumpToFrame( frame )
def _GetFrameOffset( self, delta ):
thread: Thread
for thread in self._threads:
if thread.id != self._current_thread:
continue
if not thread.stacktrace:
return
frame_idx = None
for index, frame in enumerate( thread.stacktrace ):
if frame == self._current_frame:
frame_idx = index
break
if frame_idx is not None:
target_idx = frame_idx + delta
if target_idx >= 0 and target_idx < len( thread.stacktrace ):
return thread.stacktrace[ target_idx ]
break
def UpFrame( self ):
frame = self._GetFrameOffset( 1 )
if not frame:
utils.UserMessage( 'Top of stack' )
else:
self._JumpToFrame( frame, 'up' )
def DownFrame( self ):
frame = self._GetFrameOffset( -1 )
if not frame:
utils.UserMessage( 'Bottom of stack' )
else:
self._JumpToFrame( frame, 'down' )
def AnyThreadsRunning( self ): def AnyThreadsRunning( self ):
for thread in self._threads: for thread in self._threads:
if thread.state != Thread.TERMINATED: if thread.state != Thread.TERMINATED:

View file

@ -356,3 +356,117 @@ function! Test_Multiple_Threads_Step()
call vimspector#test#setup#Reset() call vimspector#test#setup#Reset()
%bwipe! %bwipe!
endfunction endfunction
function! Test_UpDownStack()
let fn='../support/test/python/simple_python/main.py'
exe 'edit ' . fn
call setpos( '.', [ 0, 6, 1 ] )
call vimspector#SetLineBreakpoint( fn, 15 )
call vimspector#LaunchWithSettings( { 'configuration': 'run' } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 )
call WaitForAssert( {->
\ AssertMatchist(
\ [
\ '- Thread 1: MainThread (paused)',
\ ' 2: DoSomething@main.py:15',
\ ' 3: __init__@main.py:8',
\ ' 4: Main@main.py:23',
\ ' 5: <module>@main.py:29',
\ ],
\ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#DownFrame()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 )
call WaitForAssert( {->
\ AssertMatchist(
\ [
\ '- Thread 1: MainThread (paused)',
\ ' 2: DoSomething@main.py:15',
\ ' 3: __init__@main.py:8',
\ ' 4: Main@main.py:23',
\ ' 5: <module>@main.py:29',
\ ],
\ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#UpFrame()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 )
call WaitForAssert( {->
\ AssertMatchist(
\ [
\ '- Thread 1: MainThread (paused)',
\ ' 2: DoSomething@main.py:15',
\ ' 3: __init__@main.py:8',
\ ' 4: Main@main.py:23',
\ ' 5: <module>@main.py:29',
\ ],
\ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ),
\ 1,
\ '$' )
\ )
\ } )
call feedkeys( "\<Plug>VimspectorUpFrame", 'x' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 23, 1 )
call WaitForAssert( {->
\ AssertMatchist(
\ [
\ '- Thread 1: MainThread (paused)',
\ ' 2: DoSomething@main.py:15',
\ ' 3: __init__@main.py:8',
\ ' 4: Main@main.py:23',
\ ' 5: <module>@main.py:29',
\ ],
\ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ),
\ 1,
\ '$' )
\ )
\ } )
call feedkeys( "\<Plug>VimspectorDownFrame", 'x' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 )
call WaitForAssert( {->
\ AssertMatchist(
\ [
\ '- Thread 1: MainThread (paused)',
\ ' 2: DoSomething@main.py:15',
\ ' 3: __init__@main.py:8',
\ ' 4: Main@main.py:23',
\ ' 5: <module>@main.py:29',
\ ],
\ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#DownFrame()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 )
call WaitForAssert( {->
\ AssertMatchist(
\ [
\ '- Thread 1: MainThread (paused)',
\ ' 2: DoSomething@main.py:15',
\ ' 3: __init__@main.py:8',
\ ' 4: Main@main.py:23',
\ ' 5: <module>@main.py:29',
\ ],
\ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#ClearBreakpoints()
call vimspector#test#setup#Reset()
%bwipe!
endfunction