From 044804ca20b75fceddea01d193401eb57e02bd25 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 8 Jul 2020 21:22:28 +0100 Subject: [PATCH] Calculate variables on-demand; add an unused-local-port variable-function --- python3/vimspector/debug_session.py | 40 +++++++++++------- python3/vimspector/utils.py | 63 +++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index e3e1be4..244a0c4 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -177,43 +177,53 @@ class DebugSession( object ): return [ '', '' ] return os.path.splitext( p ) - self._variables = { + variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, - 'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ), 'file': current_file, - 'relativeFile': relpath( current_file, self._workspace_root ), - 'fileBasename': os.path.basename( current_file ), + } + + calculus = { + 'gadgetDir': lambda: install.GetGadgetDir( VIMSPECTOR_HOME, + install.GetOS() ), + 'relativeFile': lambda: relpath( current_file, + self._workspace_root ), + 'fileBasename': lambda: os.path.basename( current_file ), 'fileBasenameNoExtension': - splitext( os.path.basename( current_file ) )[ 0 ], - 'fileDirname': os.path.dirname( current_file ), - 'fileExtname': splitext( os.path.basename( current_file ) )[ 1 ], + lambda: splitext( os.path.basename( current_file ) )[ 0 ], + 'fileDirname': lambda: os.path.dirname( current_file ), + 'fileExtname': lambda: splitext( os.path.basename( current_file ) )[ 1 ], # NOTE: this is the window-local cwd for the current window, *not* Vim's # working directory. - 'cwd': os.getcwd(), + 'cwd': os.getcwd, + 'unusedLocalPort': utils.GetUnusedLocalPort, } # Pretend that vars passed to the launch command were typed in by the user # (they may have been in theory) USER_CHOICES.update( launch_variables ) - self._variables.update( launch_variables ) + variables.update( launch_variables ) - self._variables.update( + variables.update( utils.ParseVariables( adapter.get( 'variables', {} ), - self._variables, + variables, + calculus, USER_CHOICES ) ) - self._variables.update( + variables.update( utils.ParseVariables( configuration.get( 'variables', {} ), - self._variables, + variables, + calculus, USER_CHOICES ) ) utils.ExpandReferencesInDict( configuration, - self._variables, + variables, + calculus, USER_CHOICES ) utils.ExpandReferencesInDict( adapter, - self._variables, + variables, + calculus, USER_CHOICES ) if not adapter: diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index a12f3dc..d00c8d7 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -345,9 +345,9 @@ def IsCurrent( window, buf ): return vim.current.window == window and vim.current.window.buffer == buf -def ExpandReferencesInObject( obj, mapping, user_choices ): +def ExpandReferencesInObject( obj, mapping, calculus, user_choices ): if isinstance( obj, dict ): - ExpandReferencesInDict( obj, mapping, user_choices ) + ExpandReferencesInDict( obj, mapping, calculus, user_choices ) elif isinstance( obj, list ): j_offset = 0 obj_copy = list( obj ) @@ -360,6 +360,7 @@ def ExpandReferencesInObject( obj, mapping, user_choices ): # *${something} - expand list in place value = ExpandReferencesInString( obj_copy[ i ][ 1: ], mapping, + calculus, user_choices ) obj.pop( j ) j_offset -= 1 @@ -369,14 +370,18 @@ def ExpandReferencesInObject( obj, mapping, user_choices ): else: obj[ j ] = ExpandReferencesInObject( obj_copy[ i ], mapping, + calculus, user_choices ) elif isinstance( obj, str ): - obj = ExpandReferencesInString( obj, mapping, user_choices ) + obj = ExpandReferencesInString( obj, mapping, calculus, user_choices ) return obj -def ExpandReferencesInString( orig_s, mapping, user_choices ): +def ExpandReferencesInString( orig_s, + mapping, + calculus, + user_choices ): s = os.path.expanduser( orig_s ) s = os.path.expandvars( s ) @@ -393,15 +398,19 @@ def ExpandReferencesInString( orig_s, mapping, user_choices ): # 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 ] - 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, - orig_s, - mapping[ key ] ) + + if key in calculus: + mapping[ key ] = calculus[ key ]() + else: + 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, + orig_s, + mapping[ key ] ) except ValueError as e: UserMessage( 'Invalid $ in string {}: {}'.format( s, e ), persist = True ) @@ -412,12 +421,18 @@ def ExpandReferencesInString( orig_s, mapping, user_choices ): # 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, user_choices ): +def ExpandReferencesInDict( obj, mapping, calculus, user_choices ): for k in obj.keys(): - obj[ k ] = ExpandReferencesInObject( obj[ k ], mapping, user_choices ) + obj[ k ] = ExpandReferencesInObject( obj[ k ], + mapping, + calculus, + user_choices ) -def ParseVariables( variables_list, mapping, user_choices ): +def ParseVariables( variables_list, + mapping, + calculus, + user_choices ): new_variables = {} new_mapping = mapping.copy() @@ -431,7 +446,10 @@ def ParseVariables( variables_list, mapping, user_choices ): if 'shell' in v: new_v = v.copy() # Bit of a hack. Allows environment variables to be used. - ExpandReferencesInDict( new_v, new_mapping, user_choices ) + ExpandReferencesInDict( new_v, + new_mapping, + calculus, + user_choices ) env = os.environ.copy() env.update( new_v.get( 'env' ) or {} ) @@ -455,6 +473,7 @@ def ParseVariables( variables_list, mapping, user_choices ): else: new_variables[ n ] = ExpandReferencesInObject( v, mapping, + calculus, user_choices ) return new_variables @@ -575,3 +594,13 @@ def GetVimspectorBase(): return base.decode( 'utf-8' ) else: return base + + +def GetUnusedLocalPort(): + import socket + sock = socket.socket() + # This tells the OS to give us any free port in the range [1024 - 65535] + sock.bind( ( '', 0 ) ) + port = sock.getsockname()[ 1 ] + sock.close() + return port