Separate watches and scopes
They are related (and share code) but make more sense separately
This commit is contained in:
parent
fcf19a6d52
commit
fa775f4499
4 changed files with 82 additions and 43 deletions
|
|
@ -277,8 +277,16 @@ class DebugSession( object ):
|
||||||
# Variables
|
# Variables
|
||||||
vim.command( 'spl' )
|
vim.command( 'spl' )
|
||||||
vim.command( 'enew' )
|
vim.command( 'enew' )
|
||||||
|
vars_win = vim.current.window
|
||||||
|
|
||||||
|
# Watches
|
||||||
|
vim.command( 'spl' )
|
||||||
|
vim.command( 'enew' )
|
||||||
|
watch_win = vim.current.window
|
||||||
|
|
||||||
self._variablesView = variables.VariablesView( self._connection,
|
self._variablesView = variables.VariablesView( self._connection,
|
||||||
vim.current.buffer )
|
vars_win,
|
||||||
|
watch_win )
|
||||||
|
|
||||||
|
|
||||||
with utils.TemporaryVimOption( 'splitbelow', True ):
|
with utils.TemporaryVimOption( 'splitbelow', True ):
|
||||||
|
|
@ -520,7 +528,8 @@ class DebugSession( object ):
|
||||||
file_name ) )
|
file_name ) )
|
||||||
|
|
||||||
def OnEvent_output( self, message ):
|
def OnEvent_output( self, message ):
|
||||||
self._outputView.OnOutput( message[ 'body' ] )
|
if self._outputView:
|
||||||
|
self._outputView.OnOutput( message[ 'body' ] )
|
||||||
|
|
||||||
def OnEvent_stopped( self, message ):
|
def OnEvent_stopped( self, message ):
|
||||||
event = message[ 'body' ]
|
event = message[ 'body' ]
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,9 @@ class StackTraceView( object ):
|
||||||
|
|
||||||
if not message[ 'body' ][ 'threads' ]:
|
if not message[ 'body' ][ 'threads' ]:
|
||||||
# This is a protocol error. It is required to return at least one!
|
# This is a protocol error. It is required to return at least one!
|
||||||
raise ValueError( 'Server returned no threads. Is it running?' )
|
utils.UserMessage( 'Server returned no threads. Is it running?',
|
||||||
|
persist = True )
|
||||||
|
return
|
||||||
|
|
||||||
for thread in message[ 'body' ][ 'threads' ]:
|
for thread in message[ 'body' ][ 'threads' ]:
|
||||||
self._threads.append( thread )
|
self._threads.append( thread )
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ def RestoreCursorPosition():
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def RestorCurrentWindow():
|
def RestorCurrentWindow():
|
||||||
|
# TODO: Don't trigger autoccommands when shifting windows
|
||||||
old_window = vim.current.window
|
old_window = vim.current.window
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
|
|
@ -85,6 +86,7 @@ def RestorCurrentWindow():
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def RestoreCurrentBuffer( window ):
|
def RestoreCurrentBuffer( window ):
|
||||||
|
# TODO: Don't trigger autoccommands when shifting buffers
|
||||||
old_buffer = window.buffer
|
old_buffer = window.buffer
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,21 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import vim
|
import vim
|
||||||
|
from collections import namedtuple
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from vimspector import utils
|
from vimspector import utils
|
||||||
|
|
||||||
|
View = namedtuple( 'View', [ 'win', 'lines', 'draw' ] )
|
||||||
|
|
||||||
class VariablesView( object ):
|
class VariablesView( object ):
|
||||||
def __init__( self, connection, buf ):
|
def __init__( self, connection, variables_win, watches_win ):
|
||||||
vim.current.buffer = buf
|
self._vars = View( variables_win, {}, self._DrawScopes )
|
||||||
|
self._watch = View( watches_win, {}, self._DrawWatches )
|
||||||
self._buf = buf
|
|
||||||
self._connection = connection
|
self._connection = connection
|
||||||
|
|
||||||
# Allows us to hit <CR> to expand/collapse variables
|
# Allows us to hit <CR> to expand/collapse variables
|
||||||
self._line_to_variable = {}
|
vim.current.window = self._vars.win
|
||||||
vim.command(
|
vim.command(
|
||||||
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
||||||
|
|
||||||
|
|
@ -45,11 +46,15 @@ class VariablesView( object ):
|
||||||
# above. It also has a special _line key which is where we printed it (last)
|
# above. It also has a special _line key which is where we printed it (last)
|
||||||
self._watches = []
|
self._watches = []
|
||||||
|
|
||||||
# Allows us to delete manual watches
|
# Allows us to hit <CR> to expand/collapse variables
|
||||||
|
vim.current.window = self._watch.win
|
||||||
|
vim.command(
|
||||||
|
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
||||||
vim.command(
|
vim.command(
|
||||||
'nnoremap <buffer> <DEL> :call vimspector#DeleteWatch()<CR>' )
|
'nnoremap <buffer> <DEL> :call vimspector#DeleteWatch()<CR>' )
|
||||||
|
|
||||||
utils.SetUpScratchBuffer( self._buf, 'vimspector.Variables' )
|
utils.SetUpScratchBuffer( self._vars.win.buffer, 'vimspector.Variables' )
|
||||||
|
utils.SetUpScratchBuffer( self._watch.win.buffer, 'vimspector.Watches' )
|
||||||
|
|
||||||
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
|
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
|
||||||
has_balloon_term = int( vim.eval( "has( 'balloon_eval_term' )" ) )
|
has_balloon_term = int( vim.eval( "has( 'balloon_eval_term' )" ) )
|
||||||
|
|
@ -73,8 +78,10 @@ class VariablesView( object ):
|
||||||
|
|
||||||
|
|
||||||
def Clear( self ):
|
def Clear( self ):
|
||||||
with utils.ModifiableScratchBuffer( self._buf ):
|
with utils.ModifiableScratchBuffer( self._vars.win.buffer ):
|
||||||
self._buf[:] = None
|
self._vars.win.buffer[:] = None
|
||||||
|
with utils.ModifiableScratchBuffer( self._watch.win.buffer ):
|
||||||
|
self._watch.win.buffer[:] = None
|
||||||
|
|
||||||
def ConnectionClosed( self ):
|
def ConnectionClosed( self ):
|
||||||
self.Clear()
|
self.Clear()
|
||||||
|
|
@ -91,14 +98,16 @@ class VariablesView( object ):
|
||||||
self._scopes = []
|
self._scopes = []
|
||||||
for scope in message[ 'body' ][ 'scopes' ]:
|
for scope in message[ 'body' ][ 'scopes' ]:
|
||||||
self._scopes.append( scope )
|
self._scopes.append( scope )
|
||||||
self._connection.DoRequest( partial( self._ConsumeVariables, scope ), {
|
self._connection.DoRequest( partial( self._ConsumeVariables,
|
||||||
|
self._DrawScopes,
|
||||||
|
scope ), {
|
||||||
'command': 'variables',
|
'command': 'variables',
|
||||||
'arguments': {
|
'arguments': {
|
||||||
'variablesReference': scope[ 'variablesReference' ]
|
'variablesReference': scope[ 'variablesReference' ]
|
||||||
},
|
},
|
||||||
} )
|
} )
|
||||||
|
|
||||||
self._DrawScopesAndWatches()
|
self._DrawScopes()
|
||||||
|
|
||||||
self._connection.DoRequest( scopes_consumer, {
|
self._connection.DoRequest( scopes_consumer, {
|
||||||
'command': 'scopes',
|
'command': 'scopes',
|
||||||
|
|
@ -117,7 +126,8 @@ class VariablesView( object ):
|
||||||
self.EvaluateWatches()
|
self.EvaluateWatches()
|
||||||
|
|
||||||
def DeleteWatch( self ):
|
def DeleteWatch( self ):
|
||||||
if vim.current.window.buffer != self._buf:
|
if vim.current.window != self._watch.win:
|
||||||
|
utils.UserMessage( 'Not a watch window' )
|
||||||
return
|
return
|
||||||
|
|
||||||
current_line = vim.current.window.cursor[ 0 ]
|
current_line = vim.current.window.cursor[ 0 ]
|
||||||
|
|
@ -125,9 +135,12 @@ class VariablesView( object ):
|
||||||
for index, watch in enumerate( self._watches ):
|
for index, watch in enumerate( self._watches ):
|
||||||
if '_line' in watch and watch[ '_line' ] == current_line:
|
if '_line' in watch and watch[ '_line' ] == current_line:
|
||||||
del self._watches[ index ]
|
del self._watches[ index ]
|
||||||
self._DrawScopesAndWatches()
|
utils.UserMessage( 'Deleted' )
|
||||||
|
self._DrawWatches()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
utils.UserMessage( 'No watch found' )
|
||||||
|
|
||||||
def EvaluateWatches( self ):
|
def EvaluateWatches( self ):
|
||||||
for watch in self._watches:
|
for watch in self._watches:
|
||||||
self._connection.DoRequest( partial( self._UpdateWatchExpression,
|
self._connection.DoRequest( partial( self._UpdateWatchExpression,
|
||||||
|
|
@ -138,22 +151,26 @@ class VariablesView( object ):
|
||||||
|
|
||||||
def _UpdateWatchExpression( self, watch, message ):
|
def _UpdateWatchExpression( self, watch, message ):
|
||||||
watch[ '_result' ] = message[ 'body' ]
|
watch[ '_result' ] = message[ 'body' ]
|
||||||
self._DrawScopesAndWatches()
|
self._DrawWatches()
|
||||||
|
|
||||||
def ExpandVariable( self ):
|
def ExpandVariable( self ):
|
||||||
if vim.current.window.buffer != self._buf:
|
if vim.current.window == self._vars.win:
|
||||||
|
view = self._vars
|
||||||
|
elif vim.current.window == self._watch.win:
|
||||||
|
view = self._watch
|
||||||
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
current_line = vim.current.window.cursor[ 0 ]
|
current_line = vim.current.window.cursor[ 0 ]
|
||||||
if current_line not in self._line_to_variable:
|
if current_line not in view.lines:
|
||||||
return
|
return
|
||||||
|
|
||||||
variable = self._line_to_variable[ current_line ]
|
variable = view.lines[ current_line ]
|
||||||
|
|
||||||
if '_variables' in variable:
|
if '_variables' in variable:
|
||||||
# Collapse
|
# Collapse
|
||||||
del variable[ '_variables' ]
|
del variable[ '_variables' ]
|
||||||
self._DrawScopesAndWatches()
|
view.draw()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Expand. (only if there is anything to expand)
|
# Expand. (only if there is anything to expand)
|
||||||
|
|
@ -162,17 +179,19 @@ class VariablesView( object ):
|
||||||
if variable[ 'variablesReference' ] <= 0:
|
if variable[ 'variablesReference' ] <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._connection.DoRequest( partial( self._ConsumeVariables, variable ), {
|
self._connection.DoRequest( partial( self._ConsumeVariables,
|
||||||
|
view.draw,
|
||||||
|
variable ), {
|
||||||
'command': 'variables',
|
'command': 'variables',
|
||||||
'arguments': {
|
'arguments': {
|
||||||
'variablesReference': variable[ 'variablesReference' ]
|
'variablesReference': variable[ 'variablesReference' ]
|
||||||
},
|
},
|
||||||
} )
|
} )
|
||||||
|
|
||||||
def _DrawVariables( self, variables, indent ):
|
def _DrawVariables( self, view, variables, indent ):
|
||||||
for variable in variables:
|
for variable in variables:
|
||||||
self._line_to_variable[ len( self._buf ) + 1 ] = variable
|
view.lines[ len( view.win.buffer ) + 1 ] = variable
|
||||||
self._buf.append(
|
view.win.buffer.append(
|
||||||
'{indent}{icon} {name} ({type_}): {value}'.format(
|
'{indent}{icon} {name} ({type_}): {value}'.format(
|
||||||
indent = ' ' * indent,
|
indent = ' ' * indent,
|
||||||
icon = '+' if ( variable[ 'variablesReference' ] > 0 and
|
icon = '+' if ( variable[ 'variablesReference' ] > 0 and
|
||||||
|
|
@ -182,41 +201,48 @@ class VariablesView( object ):
|
||||||
value = variable.get( 'value', '<unknown value>' ) ).split( '\n' ) )
|
value = variable.get( 'value', '<unknown value>' ) ).split( '\n' ) )
|
||||||
|
|
||||||
if '_variables' in variable:
|
if '_variables' in variable:
|
||||||
self._DrawVariables( variable[ '_variables' ], indent + 2 )
|
self._DrawVariables( view, variable[ '_variables' ], indent + 2 )
|
||||||
|
|
||||||
def _DrawScopesAndWatches( self ):
|
def _DrawScopes( self ):
|
||||||
self._line_to_variable = {}
|
self._vars.lines.clear()
|
||||||
with utils.RestoreCursorPosition():
|
with utils.RestoreCursorPosition():
|
||||||
with utils.ModifiableScratchBuffer( self._buf ):
|
with utils.ModifiableScratchBuffer( self._vars.win.buffer ):
|
||||||
self._buf[:] = None
|
self._vars.win.buffer[:] = None
|
||||||
for scope in self._scopes:
|
for scope in self._scopes:
|
||||||
self._DrawScope( 0, scope )
|
self._DrawScope( 0, scope )
|
||||||
|
|
||||||
self._buf.append( 'Watches: ----' )
|
def _DrawWatches( self ):
|
||||||
|
self._watch.lines.clear()
|
||||||
|
with utils.RestoreCursorPosition():
|
||||||
|
with utils.ModifiableScratchBuffer( self._watch.win.buffer ):
|
||||||
|
self._watch.win.buffer[:] = None
|
||||||
|
self._watch.win.buffer.append( 'Watches: ----' )
|
||||||
for watch in self._watches:
|
for watch in self._watches:
|
||||||
self._buf.append( 'Expression: ' + watch[ 'expression' ] )
|
self._watch.win.buffer.append(
|
||||||
watch[ '_line' ] = len( self._buf )
|
'Expression: ' + watch[ 'expression' ] )
|
||||||
|
watch[ '_line' ] = len( self._watch.win.buffer )
|
||||||
self._DrawWatchResult( 2, watch )
|
self._DrawWatchResult( 2, watch )
|
||||||
|
|
||||||
def _DrawScope( self, indent, scope ):
|
def _DrawScope( self, indent, scope ):
|
||||||
icon = '+' if ( scope[ 'variablesReference' ] > 0 and
|
icon = '+' if ( scope[ 'variablesReference' ] > 0 and
|
||||||
'_variables' not in scope ) else '-'
|
'_variables' not in scope ) else '-'
|
||||||
|
|
||||||
self._line_to_variable[ len( self._buf ) + 1 ] = scope
|
self._vars.lines[ len( self._vars.win.buffer ) + 1 ] = scope
|
||||||
self._buf.append( '{0}{1} Scope: {2}'.format( ' ' * indent,
|
self._vars.win.buffer.append( '{0}{1} Scope: {2}'.format(
|
||||||
icon,
|
' ' * indent,
|
||||||
scope[ 'name' ] ) )
|
icon,
|
||||||
|
scope[ 'name' ] ) )
|
||||||
|
|
||||||
if '_variables' in scope:
|
if '_variables' in scope:
|
||||||
indent += 2
|
indent += 2
|
||||||
self._DrawVariables( scope[ '_variables' ], indent )
|
self._DrawVariables( self._vars, scope[ '_variables' ], indent )
|
||||||
|
|
||||||
def _DrawWatchResult( self, indent, watch ):
|
def _DrawWatchResult( self, indent, watch ):
|
||||||
if '_result' not in watch:
|
if '_result' not in watch:
|
||||||
return
|
return
|
||||||
|
|
||||||
result = watch[ '_result' ]
|
result = watch[ '_result' ]
|
||||||
self._line_to_variable[ len( self._buf ) + 1 ] = result
|
self._watch.lines[ len( self._watch.win.buffer ) + 1 ] = result
|
||||||
|
|
||||||
icon = '+' if ( result[ 'variablesReference' ] > 0 and
|
icon = '+' if ( result[ 'variablesReference' ] > 0 and
|
||||||
'_variables' not in result ) else '-'
|
'_variables' not in result ) else '-'
|
||||||
|
|
@ -224,20 +250,20 @@ class VariablesView( object ):
|
||||||
line = '{0}{1} Result: {2} '.format( ' ' * indent,
|
line = '{0}{1} Result: {2} '.format( ' ' * indent,
|
||||||
icon,
|
icon,
|
||||||
result[ 'result' ] )
|
result[ 'result' ] )
|
||||||
self._buf.append( line.split( '\n' ) )
|
self._watch.win.buffer.append( line.split( '\n' ) )
|
||||||
|
|
||||||
if '_variables' in result:
|
if '_variables' in result:
|
||||||
indent = 4
|
indent = 4
|
||||||
self._DrawVariables( result[ '_variables' ], indent )
|
self._DrawVariables( self._watch, result[ '_variables' ], indent )
|
||||||
|
|
||||||
def _ConsumeVariables( self, parent, message ):
|
def _ConsumeVariables( self, draw, parent, message ):
|
||||||
for variable in message[ 'body' ][ 'variables' ]:
|
for variable in message[ 'body' ][ 'variables' ]:
|
||||||
if '_variables' not in parent:
|
if '_variables' not in parent:
|
||||||
parent[ '_variables' ] = []
|
parent[ '_variables' ] = []
|
||||||
|
|
||||||
parent[ '_variables' ].append( variable )
|
parent[ '_variables' ].append( variable )
|
||||||
|
|
||||||
self._DrawScopesAndWatches()
|
draw()
|
||||||
|
|
||||||
def ShowBalloon( self, frame, expression ):
|
def ShowBalloon( self, frame, expression ):
|
||||||
if not self._connection:
|
if not self._connection:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue