Add ability to set a variable value
This works only for things which have known variablesReference, so particularly currently only for scopes and theoretically for members. I think this can work for watches too. will need to check.
This commit is contained in:
parent
1d38b8198f
commit
d8d6eb2286
3 changed files with 101 additions and 8 deletions
|
|
@ -209,6 +209,13 @@ function! vimspector#ExpandVariable() abort
|
||||||
py3 _vimspector_session.ExpandVariable()
|
py3 _vimspector_session.ExpandVariable()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! vimspector#SetVariableValue() abort
|
||||||
|
if !s:Enabled()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
py3 _vimspector_session.SetVariableValue()
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! vimspector#DeleteWatch() abort
|
function! vimspector#DeleteWatch() abort
|
||||||
if !s:Enabled()
|
if !s:Enabled()
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -525,6 +525,11 @@ class DebugSession( object ):
|
||||||
def ExpandVariable( self, buf = None, line_num = None ):
|
def ExpandVariable( self, buf = None, line_num = None ):
|
||||||
self._variablesView.ExpandVariable( buf, line_num )
|
self._variablesView.ExpandVariable( buf, line_num )
|
||||||
|
|
||||||
|
@IfConnected()
|
||||||
|
def SetVariableValue( self ):
|
||||||
|
# TODO: , buf = None, line_num = None ):
|
||||||
|
self._variablesView.SetVariableValue()
|
||||||
|
|
||||||
@IfConnected()
|
@IfConnected()
|
||||||
def AddWatch( self, expression ):
|
def AddWatch( self, expression ):
|
||||||
self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(),
|
self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(),
|
||||||
|
|
@ -999,6 +1004,7 @@ class DebugSession( object ):
|
||||||
def handle_initialize_response( msg ):
|
def handle_initialize_response( msg ):
|
||||||
self._server_capabilities = msg.get( 'body' ) or {}
|
self._server_capabilities = msg.get( 'body' ) or {}
|
||||||
self._breakpoints.SetServerCapabilities( self._server_capabilities )
|
self._breakpoints.SetServerCapabilities( self._server_capabilities )
|
||||||
|
self._variablesView.SetServerCapabilities( self._server_capabilities )
|
||||||
self._Launch()
|
self._Launch()
|
||||||
|
|
||||||
self._connection.DoRequest( handle_initialize_response, {
|
self._connection.DoRequest( handle_initialize_response, {
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,9 @@ class Expandable:
|
||||||
a 'variablesReference' to be resolved by the 'variables' request. Records the
|
a 'variablesReference' to be resolved by the 'variables' request. Records the
|
||||||
current state expanded/collapsed. Implementations just implement
|
current state expanded/collapsed. Implementations just implement
|
||||||
VariablesReference to get the variables."""
|
VariablesReference to get the variables."""
|
||||||
def __init__( self ):
|
def __init__( self, container: 'Expandable' = None ):
|
||||||
self.variables: typing.List[ 'Variable' ] = None
|
self.variables: typing.List[ 'Variable' ] = None
|
||||||
|
self.container: Expandable = container
|
||||||
# None is Falsy and represents collapsed _by default_. WHen set to False,
|
# None is Falsy and represents collapsed _by default_. WHen set to False,
|
||||||
# this means the user explicitly collapsed it. When True, the user expanded
|
# this means the user explicitly collapsed it. When True, the user expanded
|
||||||
# it (or we expanded it by default).
|
# it (or we expanded it by default).
|
||||||
|
|
@ -48,6 +49,9 @@ class Expandable:
|
||||||
def IsExpandable( self ):
|
def IsExpandable( self ):
|
||||||
return self.VariablesReference() > 0
|
return self.VariablesReference() > 0
|
||||||
|
|
||||||
|
def IsContained( self ):
|
||||||
|
return self.container is not None
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def VariablesReference( self ):
|
def VariablesReference( self ):
|
||||||
assert False
|
assert False
|
||||||
|
|
@ -92,8 +96,8 @@ class WatchFailure( WatchResult ):
|
||||||
|
|
||||||
class Variable( Expandable ):
|
class Variable( Expandable ):
|
||||||
"""Holds one level of an expanded value tree. Also itself expandable."""
|
"""Holds one level of an expanded value tree. Also itself expandable."""
|
||||||
def __init__( self, variable: dict ):
|
def __init__( self, container: Expandable, variable: dict ):
|
||||||
super().__init__()
|
super().__init__( container = container )
|
||||||
self.variable = variable
|
self.variable = variable
|
||||||
# A new variable appearing is marked as changed
|
# A new variable appearing is marked as changed
|
||||||
self.changed = True
|
self.changed = True
|
||||||
|
|
@ -156,6 +160,7 @@ class VariablesView( object ):
|
||||||
|
|
||||||
self._connection = None
|
self._connection = None
|
||||||
self._current_syntax = ''
|
self._current_syntax = ''
|
||||||
|
self._server_capabilities = None
|
||||||
|
|
||||||
self._variable_eval: Scope = None
|
self._variable_eval: Scope = None
|
||||||
self._variable_eval_view: View = None
|
self._variable_eval_view: View = None
|
||||||
|
|
@ -165,12 +170,17 @@ class VariablesView( object ):
|
||||||
':<C-u>call vimspector#ExpandVariable()<CR>' )
|
':<C-u>call vimspector#ExpandVariable()<CR>' )
|
||||||
vim.command( 'nnoremap <silent> <buffer> <2-LeftMouse> '
|
vim.command( 'nnoremap <silent> <buffer> <2-LeftMouse> '
|
||||||
':<C-u>call vimspector#ExpandVariable()<CR>' )
|
':<C-u>call vimspector#ExpandVariable()<CR>' )
|
||||||
|
vim.command( 'nnoremap <silent> <buffer> <C-CR> '
|
||||||
|
':<C-u>call vimspector#SetVariableValue()<CR>' )
|
||||||
|
|
||||||
# Set up the "Variables" buffer in the variables_win
|
# Set up the "Variables" buffer in the variables_win
|
||||||
self._scopes: typing.List[ Scope ] = []
|
self._scopes: typing.List[ Scope ] = []
|
||||||
self._vars = View( variables_win, {}, self._DrawScopes )
|
self._vars = View( variables_win, {}, self._DrawScopes )
|
||||||
utils.SetUpHiddenBuffer( self._vars.buf, 'vimspector.Variables' )
|
utils.SetUpHiddenBuffer( self._vars.buf, 'vimspector.Variables' )
|
||||||
with utils.LetCurrentWindow( variables_win ):
|
with utils.LetCurrentWindow( variables_win ):
|
||||||
|
if utils.UseWinBar():
|
||||||
|
vim.command( 'nnoremenu <silent> 1.1 WinBar.Set '
|
||||||
|
':call vimspector#SetVariableValue()<CR>' )
|
||||||
AddExpandMappings()
|
AddExpandMappings()
|
||||||
|
|
||||||
# Set up the "Watches" buffer in the watches_win (and create a WinBar in
|
# Set up the "Watches" buffer in the watches_win (and create a WinBar in
|
||||||
|
|
@ -194,6 +204,8 @@ class VariablesView( object ):
|
||||||
':call vimspector#ExpandVariable()<CR>' )
|
':call vimspector#ExpandVariable()<CR>' )
|
||||||
vim.command( 'nnoremenu 1.3 WinBar.Delete '
|
vim.command( 'nnoremenu 1.3 WinBar.Delete '
|
||||||
':call vimspector#DeleteWatch()<CR>' )
|
':call vimspector#DeleteWatch()<CR>' )
|
||||||
|
vim.command( 'nnoremenu <silent> 1.1 WinBar.Set '
|
||||||
|
':call vimspector#SetVariableValue()<CR>' )
|
||||||
|
|
||||||
# Set the (global!) balloon expr if supported
|
# Set the (global!) balloon expr if supported
|
||||||
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
|
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
|
||||||
|
|
@ -231,11 +243,21 @@ class VariablesView( object ):
|
||||||
def ConnectionUp( self, connection ):
|
def ConnectionUp( self, connection ):
|
||||||
self._connection = connection
|
self._connection = connection
|
||||||
|
|
||||||
|
def SetServerCapabilities( self, capabilities ):
|
||||||
|
self._server_capabilities = capabilities
|
||||||
|
|
||||||
|
if self._server_capabilities.get( 'supportsSetVariable' ):
|
||||||
|
# TODO add a winbar item ? add a mapping ?
|
||||||
|
pass
|
||||||
|
|
||||||
def ConnectionClosed( self ):
|
def ConnectionClosed( self ):
|
||||||
self.Clear()
|
self.Clear()
|
||||||
self._connection = None
|
self._connection = None
|
||||||
|
self._server_capabilities = None
|
||||||
|
|
||||||
def Reset( self ):
|
def Reset( self ):
|
||||||
|
self._server_capabilities = None
|
||||||
|
|
||||||
for k, v in self._oldoptions.items():
|
for k, v in self._oldoptions.items():
|
||||||
vim.options[ k ] = v
|
vim.options[ k ] = v
|
||||||
|
|
||||||
|
|
@ -447,7 +469,7 @@ class VariablesView( object ):
|
||||||
watch.result = WatchFailure( reason )
|
watch.result = WatchFailure( reason )
|
||||||
self._DrawWatches()
|
self._DrawWatches()
|
||||||
|
|
||||||
def ExpandVariable( self, buf = None, line_num = None ):
|
def _GetVariable( self, buf = None, line_num = None ):
|
||||||
if buf is None:
|
if buf is None:
|
||||||
buf = vim.current.buffer
|
buf = vim.current.buffer
|
||||||
|
|
||||||
|
|
@ -462,12 +484,17 @@ class VariablesView( object ):
|
||||||
and buf == self._variable_eval_view.buf ):
|
and buf == self._variable_eval_view.buf ):
|
||||||
view = self._variable_eval_view
|
view = self._variable_eval_view
|
||||||
else:
|
else:
|
||||||
return
|
return None
|
||||||
|
|
||||||
if line_num not in view.lines:
|
if line_num not in view.lines:
|
||||||
return
|
return None
|
||||||
|
|
||||||
variable = view.lines[ line_num ]
|
return view.lines[ line_num ], view
|
||||||
|
|
||||||
|
def ExpandVariable( self, buf = None, line_num = None ):
|
||||||
|
variable, view = self._GetVariable( buf, line_num )
|
||||||
|
if variable is None:
|
||||||
|
return
|
||||||
|
|
||||||
if variable.IsExpanded():
|
if variable.IsExpanded():
|
||||||
# Collapse
|
# Collapse
|
||||||
|
|
@ -488,6 +515,59 @@ class VariablesView( object ):
|
||||||
},
|
},
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
def SetVariableValue( self ):
|
||||||
|
variable: Variable
|
||||||
|
view: View
|
||||||
|
|
||||||
|
variable, view = self._GetVariable( buf = None, line_num = None )
|
||||||
|
if variable is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not variable.IsContained():
|
||||||
|
return
|
||||||
|
|
||||||
|
new_value = utils.AskForInput( 'New Value: ',
|
||||||
|
variable.variable.get( 'value', '' ) )
|
||||||
|
|
||||||
|
if new_value is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def handler( message ):
|
||||||
|
# Annoyingly the response to setVariable request doesn't return a
|
||||||
|
# Variable, but some part of it, so take a copy of the existing Variable
|
||||||
|
# dict and update it, then call its update method with the updated copy.
|
||||||
|
new_variable = dict( variable.variable )
|
||||||
|
new_variable.update( message[ 'body' ] )
|
||||||
|
|
||||||
|
# Clear any existing known children (FIXME: Is this the right thing to do)
|
||||||
|
variable.variables = None
|
||||||
|
|
||||||
|
# If the variable is expanded, re-request its children
|
||||||
|
if variable.IsExpanded():
|
||||||
|
self._connection.DoRequest( partial( self._ConsumeVariables,
|
||||||
|
view.draw,
|
||||||
|
variable ), {
|
||||||
|
'command': 'variables',
|
||||||
|
'arguments': {
|
||||||
|
'variablesReference': variable.VariablesReference()
|
||||||
|
},
|
||||||
|
} )
|
||||||
|
|
||||||
|
variable.Update( new_variable )
|
||||||
|
view.draw()
|
||||||
|
|
||||||
|
self._connection.DoRequest( handler, {
|
||||||
|
'command': 'setVariable',
|
||||||
|
'arguments': {
|
||||||
|
'variablesReference': variable.container.VariablesReference(),
|
||||||
|
'name': variable.variable[ 'name' ],
|
||||||
|
'value': new_value
|
||||||
|
},
|
||||||
|
} )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _DrawVariables( self, view, variables, indent, is_short = False ):
|
def _DrawVariables( self, view, variables, indent, is_short = False ):
|
||||||
assert indent > 0
|
assert indent > 0
|
||||||
for variable in variables:
|
for variable in variables:
|
||||||
|
|
@ -609,7 +689,7 @@ class VariablesView( object ):
|
||||||
found = True
|
found = True
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
variable = Variable( variable_body )
|
variable = Variable( parent, variable_body )
|
||||||
else:
|
else:
|
||||||
variable.Update( variable_body )
|
variable.Update( variable_body )
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue