diff --git a/python3/vimspector/breakpoints.py b/python3/vimspector/breakpoints.py index b0347c0..5525261 100644 --- a/python3/vimspector/breakpoints.py +++ b/python3/vimspector/breakpoints.py @@ -43,7 +43,7 @@ class ProjectBreakpoints( object ): # These are the user-entered breakpoints. self._line_breakpoints = defaultdict( list ) self._func_breakpoints = [] - self._exceptionBreakpoints = None + self._exception_breakpoints = None # FIXME: Remove this. Remove breakpoints nonesense from code.py self._breakpoints_handler = None @@ -66,13 +66,12 @@ class ProjectBreakpoints( object ): def ConnectionClosed( self ): self._breakpoints_handler = None - self._exceptionBreakpoints = None self._server_capabilities = {} self._connection = None self.UpdateUI() - # for each breakpoint: - # clear its resolved status + # NOTE: we don't reset self._exception_breakpoints because we don't want to + # re-ask the user every time for the sane info. def ListBreakpoints( self ): @@ -117,7 +116,6 @@ class ProjectBreakpoints( object ): self._line_breakpoints = defaultdict( list ) self._func_breakpoints = [] - self._exceptionBreakpoints = None self.UpdateUI() @@ -250,16 +248,16 @@ class ProjectBreakpoints( object ): } ) - if self._exceptionBreakpoints is None: + if self._exception_breakpoints is None: self._SetUpExceptionBreakpoints() - if self._exceptionBreakpoints: + if self._exception_breakpoints: awaiting = awaiting + 1 self._connection.DoRequest( lambda msg: response_handler( None, None ), { 'command': 'setExceptionBreakpoints', - 'arguments': self._exceptionBreakpoints + 'arguments': self._exception_breakpoints } ) @@ -268,44 +266,36 @@ class ProjectBreakpoints( object ): def _SetUpExceptionBreakpoints( self ): - exceptionBreakpointFilters = self._server_capabilities.get( + exception_breakpoint_filters = self._server_capabilities.get( 'exceptionBreakpointFilters', [] ) - if exceptionBreakpointFilters or not self._server_capabilities.get( + if exception_breakpoint_filters or not self._server_capabilities.get( 'supportsConfigurationDoneRequest' ): - exceptionFilters = [] - if exceptionBreakpointFilters: - for f in exceptionBreakpointFilters: - response = utils.AskForInput( - "Enable exception filter '{}'? (Y/N)".format( f[ 'label' ] ) ) + exception_filters = [] + if exception_breakpoint_filters: + for f in exception_breakpoint_filters: + default_value = 'Y' if f.get( 'default' ) else 'N' - if response == 'Y': - exceptionFilters.append( f[ 'filter' ] ) - elif not response and f.get( 'default' ): - exceptionFilters.append( f[ 'filter' ] ) + result = utils.AskForInput( + "Break on {} (Y/N/default: {})? ".format( f[ 'label' ], + default_value ), + default_value ) - self._exceptionBreakpoints = { - 'filters': exceptionFilters + if result == 'Y': + exception_filters.append( f[ 'filter' ] ) + elif not result and f.get( 'default' ): + exception_filters.append( f[ 'filter' ] ) + + self._exception_breakpoints = { + 'filters': exception_filters } if self._server_capabilities.get( 'supportsExceptionOptions' ): - # FIXME Sigh. The python debug adapter requires this - # key to exist. Even though it is optional. - break_mode = utils.SelectFromList( 'When to break on exception?', - [ 'never', - 'always', - 'unhandled', - 'userHandled' ] ) - - if not break_mode: - break_mode = 'unhandled' - - path = [ { 'nagate': True, 'names': [ 'DO_NOT_MATCH' ] } ] - self._exceptionBreakpoints[ 'exceptionOptions' ] = [ { - 'path': path, - 'breakMode': break_mode - } ] + # TODO: There are more elaborate exception breakpoint options here, but + # we don't support them. It doesn't seem like any of the servers really + # pay any attention to them anyway. + self._exception_breakpoints[ 'exceptionOptions' ] = [] def _ShowBreakpoints( self ): for file_name, line_breakpoints in self._line_breakpoints.items(): diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 08e58ef..fe0873b 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -34,6 +34,9 @@ VIMSPECTOR_HOME = os.path.abspath( os.path.join( os.path.dirname( __file__ ), '..', '..' ) ) +# cache of what the user entered for any option we ask them +USER_CHOICES = {} + class DebugSession( object ): def __init__( self ): @@ -148,14 +151,26 @@ class DebugSession( object ): } self._variables.update( utils.ParseVariables( adapter.get( 'variables', {} ), - self._variables ) ) + self._variables, + USER_CHOICES ) ) self._variables.update( utils.ParseVariables( configuration.get( 'variables', {} ), - self._variables ) ) + self._variables, + USER_CHOICES ) ) + + # Pretend that vars passed to the launch command were typed in by the user + # (they may have been in theory) + # TODO: Is it right that we do this _after_ ParseVariables, rather than + # before ? + USER_CHOICES.update( launch_variables ) self._variables.update( launch_variables ) - utils.ExpandReferencesInDict( configuration, self._variables ) - utils.ExpandReferencesInDict( adapter, self._variables ) + utils.ExpandReferencesInDict( configuration, + self._variables, + USER_CHOICES ) + utils.ExpandReferencesInDict( adapter, + self._variables, + USER_CHOICES ) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format( diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 9c56e8b..00afa5f 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -261,10 +261,16 @@ def SelectFromList( prompt, options ): return None -def AskForInput( prompt ): +def AskForInput( prompt, default_value = None ): + if default_value is None: + default_option = '' + else: + default_option = ", '{}'".format( Escape( default_value ) ) + with InputSave(): try: - return vim.eval( "input( '{0}' )".format( Escape( prompt ) ) ) + return vim.eval( "input( '{}' {} )".format( Escape( prompt ), + default_option ) ) except KeyboardInterrupt: return '' @@ -306,7 +312,7 @@ def IsCurrent( window, buf ): # TODO: Should we just run the substitution on the whole JSON string instead? # That woul dallow expansion in bool and number values, such as ports etc. ? -def ExpandReferencesInDict( obj, mapping, **kwargs ): +def ExpandReferencesInDict( obj, mapping, user_choices ): def expand_refs_in_string( orig_s ): s = os.path.expanduser( orig_s ) s = os.path.expandvars( s ) @@ -318,13 +324,16 @@ def ExpandReferencesInDict( obj, mapping, **kwargs ): ++bug_catcher try: - s = string.Template( s ).substitute( mapping, **kwargs ) + s = string.Template( s ).substitute( mapping ) break except KeyError as e: # HACK: This is seemingly the only way to get the key. str( e ) returns # the key surrounded by '' for unknowable reasons. key = e.args[ 0 ] - mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ) ) + default_value = user_choices.get( key, None ) + mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ), + default_value ) + user_choices[ key ] = mapping[ key ] _logger.debug( "Value for %s not set in %s (from %s): set to %s", key, s, @@ -339,7 +348,7 @@ def ExpandReferencesInDict( obj, mapping, **kwargs ): def expand_refs_in_object( obj ): if isinstance( obj, dict ): - ExpandReferencesInDict( obj, mapping, **kwargs ) + ExpandReferencesInDict( obj, mapping, user_choices ) elif isinstance( obj, list ): for i, _ in enumerate( obj ): # FIXME: We are assuming that it is a list of string, but could be a @@ -354,7 +363,7 @@ def ExpandReferencesInDict( obj, mapping, **kwargs ): obj[ k ] = expand_refs_in_object( obj[ k ] ) -def ParseVariables( variables_list, mapping, **kwargs ): +def ParseVariables( variables_list, mapping, user_choices ): new_variables = {} new_mapping = mapping.copy() @@ -371,7 +380,7 @@ def ParseVariables( variables_list, mapping, **kwargs ): new_v = v.copy() # Bit of a hack. Allows environment variables to be used. - ExpandReferencesInDict( new_v, new_mapping, **kwargs ) + ExpandReferencesInDict( new_v, new_mapping, user_choices ) env = os.environ.copy() env.update( new_v.get( 'env' ) or {} ) diff --git a/support/test/python/simple_python/main.py b/support/test/python/simple_python/main.py index e13f337..6515c3f 100755 --- a/support/test/python/simple_python/main.py +++ b/support/test/python/simple_python/main.py @@ -4,7 +4,10 @@ class TestClass( object ): def __init__( self, value ): self._var = value - self.DoSomething() + try: + self.DoSomething() + except ValueError: + pass def DoSomething( self ): for i in range( 0, 100 ): @@ -13,6 +16,8 @@ class TestClass( object ): else: print( '{0} might be more'.format( i ) ) + raise ValueError( 'Done' ) + def Main(): t = TestClass( 18 )