From fa627712e29d9f94ce48cf8311bd6e1aa728abed Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 20 May 2018 21:38:11 +0100 Subject: [PATCH] Support jumping up/down the stack Split out stack trace view into its own thing. Support jumping to code location. --- autoload/vimspector.vim | 4 ++ python3/vimspector/debug_session.py | 46 +++++-------------- python3/vimspector/stack_trace.py | 69 +++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 35 deletions(-) create mode 100644 python3/vimspector/stack_trace.py diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 7166b8b..3b1a960 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -150,6 +150,10 @@ function! vimspector#ExpandVariable() abort py3 _vimspector_session.ExpandVariable() endfunction +function! vimspector#GoToFrame() abort + py3 _vimspector_session.GoToFrame() +endfunction + " Boilerplate {{{ let &cpo=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index bf326e2..81e1cc1 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -16,7 +16,7 @@ import logging import vim -from vimspector import utils, variables, debug_adapter_connection +from vimspector import debug_adapter_connection, stack_trace, utils, variables _logger = logging.getLogger( __name__ ) @@ -31,7 +31,6 @@ class DebugSession( object ): self._uiTab = None self._codeWindow = None - self._callStackBuffer = None self._threadsBuffer = None self._outputBuffer = None @@ -65,8 +64,9 @@ class DebugSession( object ): # Call stack vim.command( 'spl' ) vim.command( 'enew' ) - self._callStackBuffer = vim.current.buffer - utils.SetUpScratchBuffer( self._callStackBuffer ) + self._stackTraceView = stack_trace.StackTraceView( self, + self._connection, + vim.current.buffer ) # Output/logging vim.command( 'spl' ) @@ -81,7 +81,8 @@ class DebugSession( object ): vim.current.buffer ) - def _LoadFrame( self, frame ): + def SetCurrentFrame( self, frame ): + self._currentFrame = frame vim.current.window = self._codeWindow buffer_number = vim.eval( 'bufnr( "{0}", 1 )'.format( frame[ 'source' ][ 'path' ] ) ) @@ -95,6 +96,7 @@ class DebugSession( object ): self._codeWindow.cursor = ( frame[ 'line' ], frame[ 'column' ] ) self._variablesView.LoadScopes( frame ) + def OnChannelData( self, data ): self._connection.OnData( data ) @@ -152,6 +154,9 @@ class DebugSession( object ): def ExpandVariable( self ): self._variablesView.ExpandVariable() + def GoToFrame( self ): + self._stackTraceView.GoToFrame() + def _Initialise( self ): def handler( message ) : self._connection.DoRequest( None, { @@ -218,33 +223,4 @@ class DebugSession( object ): 'command': 'threads', } ) - def stacktrace_printer( message ): - with utils.ModifiableScratchBuffer( self._callStackBuffer ): - self._callStackBuffer.options[ 'modifiable' ] = True - self._callStackBuffer.options[ 'readonly' ] = False - - self._callStackBuffer[:] = None - self._callStackBuffer.append( 'Backtrace: ' ) - - stackFrames = message[ 'body' ][ 'stackFrames' ] - - if stackFrames: - self._currentFrame = stackFrames[ 0 ] - else: - self._currentFrame = None - - for frame in stackFrames: - self._callStackBuffer.append( - '{0}: {1}@{2}:{3}'.format( frame[ 'id' ], - frame[ 'name' ], - frame[ 'source' ][ 'name' ], - frame[ 'line' ] ) ) - - self._LoadFrame( self._currentFrame ) - - self._connection.DoRequest( stacktrace_printer, { - 'command': 'stackTrace', - 'arguments': { - 'threadId': self._currentThread, - } - } ) + self._stackTraceView.LoadStackTrace( self._currentThread ) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py new file mode 100644 index 0000000..37c31a6 --- /dev/null +++ b/python3/vimspector/stack_trace.py @@ -0,0 +1,69 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2018 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import vim + +from vimspector import utils + +_logger = logging.getLogger( __name__ ) + + +class StackTraceView( object ): + def __init__( self, session, connection, buf ): + self._buf = buf + self._session = session + self._connection = connection + + utils.SetUpScratchBuffer( self._buf ) + vim.current.buffer = self._buf + vim.command( 'nnoremap :call vimspector#GoToFrame()' ) + + self._line_to_frame = {} + + def LoadStackTrace( self, thread_id ): + self._connection.DoRequest( self._PrintStackTrace, { + 'command': 'stackTrace', + 'arguments': { + 'threadId': thread_id, + } + } ) + + def GoToFrame( self ): + if vim.current.buffer != self._buf: + return + + current_line = vim.current.window.cursor[ 0 ] + if current_line not in self._line_to_frame: + return + + self._session.SetCurrentFrame( self._line_to_frame[ current_line ] ) + + def _PrintStackTrace( self, message ): + with utils.ModifiableScratchBuffer( self._buf ): + self._buf[:] = None + self._buf.append( 'Stack trace' ) + + stackFrames = message[ 'body' ][ 'stackFrames' ] + + for frame in stackFrames: + self._buf.append( + '{0}: {1}@{2}:{3}'.format( frame[ 'id' ], + frame[ 'name' ], + frame[ 'source' ][ 'name' ], + frame[ 'line' ] ) ) + self._line_to_frame[ len( self._buf ) ] = frame + + self._session.SetCurrentFrame( stackFrames[ 0 ] )