From 7d3af848cfda7c50dd9d5f9ea86e0fb61a88806c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 26 May 2018 19:54:45 +0100 Subject: [PATCH] Separate out the display of 'requested' and 'applied' breakpoints This is a mess, with a load of duplication, but it's a step. When you request a breakpoint, we add one (in state ENABLED). You can then toggle it again to change to DISABLED. And once more to delete it. Once we start the debug server, that all changes and we just start sending the breakpoints directly to the server and updating based on the responses. This is far from ideal and somewhat jarring, but this approach allows me to play around with ideas about what the user experience should look like. --- python3/vimspector/code.py | 10 ++--- python3/vimspector/debug_session.py | 66 ++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/python3/vimspector/code.py b/python3/vimspector/code.py index c290fe3..cac4667 100644 --- a/python3/vimspector/code.py +++ b/python3/vimspector/code.py @@ -37,7 +37,6 @@ class CodeView( object ): 'breakpoints': [] } - vim.current.window = self._window vim.command( 'nnoremenu WinBar.Continute :call vimspector#Continue()' ) @@ -47,9 +46,7 @@ class CodeView( object ): vim.command( 'nnoremenu WinBar.Pause :call vimspector#Pause()' ) vim.command( 'nnoremenu WinBar.Stop :call vimspector#Stop()' ) - vim.command( 'sign define vimspectorPC text=>> texthl=Search' ) - vim.command( 'sign define vimspectorBP text=>> texthl=Error' ) - vim.command( 'sign define vimspectorBPDead text=>> texthl=Warning' ) + vim.command( 'sign define vimspectorPC text=> texthl=Search' ) def SetCurrentFrame( self, frame ): @@ -85,6 +82,8 @@ class CodeView( object ): self._signs[ 'vimspectorPC' ] = None + # TODO: You know what, move breakpoint handling out of here into its own + # thing. It really doesn't directly relate to the code view. def AddBreakpoints( self, source, breakpoints ): for breakpoint in breakpoints: if 'source' not in breakpoint: @@ -124,5 +123,6 @@ class CodeView( object ): 'sign place {0} line={1} name={2} file={3}'.format( sign_id, breakpoint[ 'line' ], - 'vimspectorBP' if breakpoint[ 'verified' ] else 'vimspectorBPDead', + 'vimspectorBP' if breakpoint[ 'verified' ] + else 'vimspectorBPDisabled', file_name ) ) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 15afcd7..959d8ac 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -27,6 +27,8 @@ from vimspector import ( code, utils, variables ) +SIGN_ID_OFFSET = 10005000 + class DebugSession( object ): def __init__( self ): @@ -41,16 +43,30 @@ class DebugSession( object ): self._currentThread = None self._currentFrame = None + self._next_sign_id = SIGN_ID_OFFSET + # TODO: Move to code view and consolidate into user-requested-breakpoints, + # and actual breakpoints ? self._breakpoints = defaultdict( dict ) self._configuration = None + vim.command( 'sign define vimspectorBP text=o texthl=Error' ) + vim.command( 'sign define vimspectorBPDisabled text=! texthl=Warning' ) + def ToggleBreakpoint( self ): + # TODO: Move this to the code view. Problem is that CodeView doesn't exist + # until we have initialised. line, column = vim.current.window.cursor file_name = vim.current.buffer.name if line in self._breakpoints[ file_name ]: - del self._breakpoints[ file_name ][ line ] + bp = self._breakpoints[ file_name ][ line ] + if bp[ 'state' ] == 'ENABLED': + bp[ 'state' ] = 'DISABLED' + else: + if 'sign_id' in bp: + vim.command( 'sign unplace {0}'.format( bp[ 'sign_id' ] ) ) + del self._breakpoints[ file_name ][ line ] else: self._breakpoints[ file_name ][ line ] = { 'state': 'ENABLED', @@ -59,6 +75,12 @@ class DebugSession( object ): # 'logMessage': ... } + if self._connection: + self._SendBreakpoints() + else: + self._ShowBreakpoints() + + def Start( self, configuration = None ): launch_config_file = utils.PathToConfigFile( '.vimspector.json' ) @@ -221,25 +243,42 @@ class DebugSession( object ): def OnEvent_initialized( self, message ): self._codeView.ClearBreakpoints() + self._SendBreakpoints() + + def _SendBreakpoints( self ): for file_name, line_breakpoints in self._breakpoints.items(): - breakpoints = [ { 'line': line } for line in line_breakpoints.keys() ] + breakpoints = [] + lines = [] + for line, bp in line_breakpoints.items(): + if bp[ 'state' ] != 'ENABLED': + continue + + if 'sign_id' in bp: + vim.command( 'sign unplace {0}'.format( bp[ 'sign_id' ] ) ) + del bp[ 'sign_id' ] + + breakpoints.append( { 'line': line } ) + lines.append( line ) + source = { 'name': os.path.basename( file_name ), 'path': file_name, } + self._connection.DoRequest( functools.partial( self._UpdateBreakpoints, source ), { 'command': 'setBreakpoints', 'arguments': { 'source': source, - 'breakpoints': breakpoints, - 'lines': [ line for line in line_breakpoints.keys() ], - 'sourceModified': False, + 'breakpoints': breakpoints }, + 'lines': lines, + 'sourceModified': False, # TODO: We can actually check this } ) + # TODO: Remove this! self._connection.DoRequest( functools.partial( self._UpdateBreakpoints, None ), { @@ -256,6 +295,23 @@ class DebugSession( object ): 'command': 'configurationDone', } ) + def _ShowBreakpoints( self ): + for file_name, line_breakpoints in self._breakpoints.items(): + for line, bp in line_breakpoints.items(): + if 'sign_id' in bp: + vim.command( 'sign unplace {0}'.format( bp[ 'sign_id' ] ) ) + else: + bp[ 'sign_id' ] = self._next_sign_id + self._next_sign_id += 1 + + vim.command( + 'sign place {0} line={1} name={2} file={3}'.format( + bp[ 'sign_id' ] , + line, + 'vimspectorBP' if bp[ 'state' ] == 'ENABLED' + else 'vimspectorBPDisabled', + file_name ) ) + def OnEvent_output( self, message ): with utils.ModifiableScratchBuffer( self._outputBuffer ): t = [ message[ 'body' ][ 'category' ] + ':' + '-' * 20 ]