From a53d68f04301833b30a9a8e3acf02ba793c49d82 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 10 Mar 2021 12:29:40 +0000 Subject: [PATCH 1/2] Add up and down frame mappings --- autoload/vimspector.vim | 14 ++++ plugin/vimspector.vim | 5 ++ python3/vimspector/debug_session.py | 8 ++ python3/vimspector/stack_trace.py | 40 ++++++++++ tests/stack_trace.test.vim | 114 ++++++++++++++++++++++++++++ 5 files changed, 181 insertions(+) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index e94a177..a547e5c 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -234,6 +234,20 @@ function! vimspector#GoToFrame() abort py3 _vimspector_session.ExpandFrameOrThread() 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 if !s:Enabled() return diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 53855ef..37509a7 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -67,6 +67,11 @@ nnoremap VimspectorBalloonEval xnoremap VimspectorBalloonEval \ :call vimspector#ShowEvalBalloon( 1 ) +nnoremap VimspectorUpFrame + \ :call vimspector#UpFrame() +nnoremap VimspectorDownFrame + \ :call vimspector#DownFrame() + if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorContinue nmap VimspectorStop diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 16f69be..4d8c816 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -571,6 +571,14 @@ class DebugSession( object ): def ExpandFrameOrThread( self ): self._stackTraceView.ExpandFrameOrThread() + @IfConnected() + def UpFrame( self ): + self._stackTraceView.UpFrame() + + @IfConnected() + def DownFrame( self ): + self._stackTraceView.DownFrame() + def ToggleLog( self ): if self._HasUI(): return self.ShowOutput( 'Vimspector' ) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index c32cead..ae14e68 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -367,6 +367,46 @@ class StackTraceView( object ): 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 ): for thread in self._threads: if thread.state != Thread.TERMINATED: diff --git a/tests/stack_trace.test.vim b/tests/stack_trace.test.vim index 569376c..a65ea5e 100644 --- a/tests/stack_trace.test.vim +++ b/tests/stack_trace.test.vim @@ -356,3 +356,117 @@ function! Test_Multiple_Threads_Step() call vimspector#test#setup#Reset() %bwipe! 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: @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: @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: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call feedkeys( "\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: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call feedkeys( "\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: @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: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + + call vimspector#ClearBreakpoints() + call vimspector#test#setup#Reset() + %bwipe! +endfunction From 6b67d165b92d1fe858ebd427507836021e0f0623 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 12 Mar 2021 21:50:37 +0000 Subject: [PATCH 2/2] Update docs for new mappings --- README.md | 84 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 42d4765..2152a9c 100644 --- a/README.md +++ b/README.md @@ -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 `` mappings: -* `VimspectorContinue` -* `VimspectorStop` -* `VimspectorRestart` -* `VimspectorPause` -* `VimspectorToggleBreakpoint` -* `VimspectorToggleConditionalBreakpoint` -* `VimspectorAddFunctionBreakpoint` -* `VimspectorStepOver` -* `VimspectorStepInto` -* `VimspectorStepOut` -* `VimspectorRunToCursor` -* `VimspectorBalloonEval` +| Mapping | Function | API | +| --- | --- | --- | +| `VimspectorContinue` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | +| `VimspectorStop` | Stop debugging. | `vimspector#Stop()` | +| `VimpectorRestart` | Restart debugging with the same configuration. | `vimspector#Restart()` | +| `VimspectorPause` | Pause debuggee. | `vimspector#Pause()` | +| `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | +| `VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | +| `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | +| `VimspectorRunToCursor` | Run to Cursor | `vimspector#RunToCursor()` | +| `VimspectorStepOver` | Step Over | `vimspector#StepOver()` | +| `VimspectorStepInto` | Step Into | `vimspector#StepInto()` | +| `VimspectorStepOut` | Step out of current function scope | `vimspector#StepOut()` | +| `VimspectorUpFrame` | Move up a frame in the current call stack | `vimspector#UpFrame()` | +| `VimspectorDownFrame` | Move down a frame in the current call stack | `vimspector#DownFrame()` | +| `VimspectorBalloonEval` | Evaluate expression under cursor (or visual) in popup | *internal* | + These map roughly 1-1 with the API functions below. @@ -695,17 +700,17 @@ loading vimspector**: let g:vimspector_enable_mappings = 'VISUAL_STUDIO' ``` -| Key | Function | API | -| --- | --- | --- | -| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | -| `Shift F5` | Stop debugging. | `vimspector#Stop()` | -| `Ctrl Shift F5` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debuggee. | `vimspector#Pause()` | -| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | -| `Shift F9` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | -| `F10` | Step Over | `vimspector#StepOver()` | -| `F11` | Step Into | `vimspector#StepInto()` | -| `Shift F11` | Step out of current function scope | `vimspector#StepOut()` | +| Key | Mapping | Function +| --- | --- | --- +| `F5` | `VimspectorContinue` | When debugging, continue. Otherwise start debugging. +| `Shift F5` | `VimspectorStop` | Stop debugging. +| `Ctrl Shift F5` | `VimspectorRestart` | Restart debugging with the same configuration. +| `F6` | `VimspectorPause` | Pause debuggee. +| `F9` | `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. +| `Shift F9` | `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor +| `F10` | `VimspectorStepOver` | Step Over +| `F11` | `VimspectorStepInto` | Step Into +| `Shift F11` | `VimspectorStepOut` | Step out of current function scope ## Human Mode @@ -720,19 +725,19 @@ loading vimspector**: let g:vimspector_enable_mappings = 'HUMAN' ``` -| Key | Function | API | -| --- | --- | --- | -| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | -| `F3` | Stop debugging. | `vimspector#Stop()` | -| `F4` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debuggee. | `vimspector#Pause()` | -| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | -| `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( '' )` | -| `F8` | Run to Cursor | `vimspector#RunToCursor()` | -| `F10` | Step Over | `vimspector#StepOver()` | -| `F11` | Step Into | `vimspector#StepInto()` | -| `F12` | Step out of current function scope | `vimspector#StepOut()` | +| Key | Mapping | Function +| --- | --- | --- +| `F5` | `VimspectorContinue` | When debugging, continue. Otherwise start debugging. +| `F3` | `VimspectorStop` | Stop debugging. +| `F4` | `VimspectorRestart` | Restart debugging with the same configuration. +| `F6` | `VimspectorPause` | Pause debuggee. +| `F9` | `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. +| `F9` | `VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. +| `F8` | `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor +| `F8` | `VimspectorRunToCursor` | Run to Cursor +| `F10` | `VimspectorStepOver` | Step Over +| `F11` | `VimspectorStepInto` | Step Into +| `F12` | `VimspectorStepOut` | Step out of current function scope In addition, I recommend adding a mapping to `VimspectorBalloonEval`, in normal and visual modes, for example: @@ -746,6 +751,13 @@ nmap di VimspectorBalloonEval xmap di VimspectorBalloonEval ``` +You may also wish to add mappings for up/down the stack, for example: + +```viml +nmap VimspectorUpFrame +nmap VimspectorDownFrame +``` + # Usage and API This section defines detailed usage instructions, organised by feature. For most