Very basic support for watch expressions

You can currently only add them, not remoove them and you have to pass
the expression in the function call, but once added the variable
breakdown works nicely.
This commit is contained in:
Ben Jackson 2018-05-27 16:59:06 +01:00
commit 533b2aa0d5
3 changed files with 56 additions and 5 deletions

View file

@ -69,6 +69,10 @@ function! vimspector#GoToFrame() abort
py3 _vimspector_session.GoToFrame() py3 _vimspector_session.GoToFrame()
endfunction endfunction
function! vimspector#AddWatch( expr ) abort
py3 _vimspector_session.AddWatch( vim.eval( 'a:expr' ) )
endfunction
" Boilerplate {{{ " Boilerplate {{{
let &cpo=s:save_cpo let &cpo=s:save_cpo
unlet s:save_cpo unlet s:save_cpo

View file

@ -180,6 +180,9 @@ class DebugSession( object ):
def ExpandVariable( self ): def ExpandVariable( self ):
self._variablesView.ExpandVariable() self._variablesView.ExpandVariable()
def AddWatch( self, expression ):
self._variablesView.AddWatch( self._currentFrame, expression )
def GoToFrame( self ): def GoToFrame( self ):
self._stackTraceView.GoToFrame() self._stackTraceView.GoToFrame()
@ -221,6 +224,7 @@ class DebugSession( object ):
self._currentFrame = frame self._currentFrame = frame
self._codeView.SetCurrentFrame( frame ) self._codeView.SetCurrentFrame( frame )
self._variablesView.LoadScopes( frame ) self._variablesView.LoadScopes( frame )
self._variablesView.EvaluateWatches()
def _StartDebugAdapter( self ): def _StartDebugAdapter( self ):
self._logger.info( 'Starting debug adapter with: {0}'.format( json.dumps( self._logger.info( 'Starting debug adapter with: {0}'.format( json.dumps(

View file

@ -33,6 +33,9 @@ class VariablesView( object ):
# children. Otherwise, we haven't or shouldn't. # children. Otherwise, we haven't or shouldn't.
self._scopes = [] self._scopes = []
# This is basically the same as scopes, but the top level is an "expression"
self._watches = []
vim.current.buffer = buf vim.current.buffer = buf
vim.command( vim.command(
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' ) 'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
@ -55,7 +58,7 @@ class VariablesView( object ):
}, },
} ) } )
self._DrawScopes() self._DrawScopesAndWatches()
self._connection.DoRequest( scopes_consumer, { self._connection.DoRequest( scopes_consumer, {
'command': 'scopes', 'command': 'scopes',
@ -64,6 +67,36 @@ class VariablesView( object ):
}, },
} ) } )
def AddWatch( self, frame, expression ):
watch = {
'expression': expression,
'frameId': frame[ 'id' ],
'context': 'watch',
}
self._watches.append( watch )
self.EvaluateWatches()
def EvaluateWatches( self ):
for watch in self._watches:
self._connection.DoRequest( partial( self._UpdateWatchExpression,
watch ), {
'command': 'evaluate',
'arguments': watch,
} )
def _UpdateWatchExpression( self, watch, message ):
watch[ 'result' ] = message[ 'body' ]
if 'variablesReference' in watch[ 'result' ]:
self._connection.DoRequest(
partial( self._ConsumeVariables, watch[ 'result' ] ), {
'command': 'variables',
'arguments': {
'variablesReference': watch[ 'result' ][ 'variablesReference' ]
},
} )
self._DrawScopesAndWatches()
def ExpandVariable( self ): def ExpandVariable( self ):
if vim.current.window.buffer != self._buf: if vim.current.window.buffer != self._buf:
return return
@ -75,7 +108,7 @@ class VariablesView( object ):
variable = self._line_to_variable[ current_line ] variable = self._line_to_variable[ current_line ]
if '_variables' in variable: if '_variables' in variable:
del variable[ '_variables' ] del variable[ '_variables' ]
self._DrawScopes() self._DrawScopesAndWatches()
else: else:
self._connection.DoRequest( partial( self._ConsumeVariables, variable ), { self._connection.DoRequest( partial( self._ConsumeVariables, variable ), {
'command': 'variables', 'command': 'variables',
@ -93,13 +126,13 @@ class VariablesView( object ):
'_variables' not in variable ) else '-', '_variables' not in variable ) else '-',
name = variable[ 'name' ], name = variable[ 'name' ],
type_ = variable.get( 'type', '<unknown type>' ), type_ = variable.get( 'type', '<unknown type>' ),
value = variable[ 'value' ] ) ) value = variable[ 'value' ] ).split( '\n' ) )
self._line_to_variable[ len( self._buf ) ] = variable self._line_to_variable[ len( self._buf ) ] = variable
if '_variables' in variable: if '_variables' in variable:
self._DrawVariables( variable[ '_variables' ], indent + 2 ) self._DrawVariables( variable[ '_variables' ], indent + 2 )
def _DrawScopes( self ): def _DrawScopesAndWatches( self ):
self._line_to_variable = {} self._line_to_variable = {}
with utils.RestoreCursorPosition(): with utils.RestoreCursorPosition():
with utils.ModifiableScratchBuffer( self._buf ): with utils.ModifiableScratchBuffer( self._buf ):
@ -110,6 +143,16 @@ class VariablesView( object ):
indent = 2 indent = 2
self._DrawVariables( scope[ '_variables' ], indent ) self._DrawVariables( scope[ '_variables' ], indent )
self._buf.append( 'Watches: ----' )
for watch in self._watches:
self._buf.append( 'Expression: ' + watch[ 'expression' ] )
if 'result' in watch:
result = watch[ 'result' ]
line = ' Result: ' + result[ 'result' ]
self._buf.append( line.split( '\n' ) )
if '_variables' in result:
indent = 4
self._DrawVariables( result[ '_variables' ], indent )
def _ConsumeVariables( self, parent, message ): def _ConsumeVariables( self, parent, message ):
for variable in message[ 'body' ][ 'variables' ]: for variable in message[ 'body' ][ 'variables' ]:
@ -118,4 +161,4 @@ class VariablesView( object ):
parent[ '_variables' ].append( variable ) parent[ '_variables' ].append( variable )
self._DrawScopes() self._DrawScopesAndWatches()