Calculate variables on-demand; add an unused-local-port variable-function

This commit is contained in:
Ben Jackson 2020-07-08 21:22:28 +01:00
commit 044804ca20
2 changed files with 71 additions and 32 deletions

View file

@ -177,43 +177,53 @@ class DebugSession( object ):
return [ '', '' ] return [ '', '' ]
return os.path.splitext( p ) return os.path.splitext( p )
self._variables = { variables = {
'dollar': '$', # HACK. Hote '$$' also works. 'dollar': '$', # HACK. Hote '$$' also works.
'workspaceRoot': self._workspace_root, 'workspaceRoot': self._workspace_root,
'workspaceFolder': self._workspace_root, 'workspaceFolder': self._workspace_root,
'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ),
'file': current_file, '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': 'fileBasenameNoExtension':
splitext( os.path.basename( current_file ) )[ 0 ], lambda: splitext( os.path.basename( current_file ) )[ 0 ],
'fileDirname': os.path.dirname( current_file ), 'fileDirname': lambda: os.path.dirname( current_file ),
'fileExtname': splitext( os.path.basename( current_file ) )[ 1 ], 'fileExtname': lambda: splitext( os.path.basename( current_file ) )[ 1 ],
# NOTE: this is the window-local cwd for the current window, *not* Vim's # NOTE: this is the window-local cwd for the current window, *not* Vim's
# working directory. # 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 # Pretend that vars passed to the launch command were typed in by the user
# (they may have been in theory) # (they may have been in theory)
USER_CHOICES.update( launch_variables ) USER_CHOICES.update( launch_variables )
self._variables.update( launch_variables ) variables.update( launch_variables )
self._variables.update( variables.update(
utils.ParseVariables( adapter.get( 'variables', {} ), utils.ParseVariables( adapter.get( 'variables', {} ),
self._variables, variables,
calculus,
USER_CHOICES ) ) USER_CHOICES ) )
self._variables.update( variables.update(
utils.ParseVariables( configuration.get( 'variables', {} ), utils.ParseVariables( configuration.get( 'variables', {} ),
self._variables, variables,
calculus,
USER_CHOICES ) ) USER_CHOICES ) )
utils.ExpandReferencesInDict( configuration, utils.ExpandReferencesInDict( configuration,
self._variables, variables,
calculus,
USER_CHOICES ) USER_CHOICES )
utils.ExpandReferencesInDict( adapter, utils.ExpandReferencesInDict( adapter,
self._variables, variables,
calculus,
USER_CHOICES ) USER_CHOICES )
if not adapter: if not adapter:

View file

@ -345,9 +345,9 @@ def IsCurrent( window, buf ):
return vim.current.window == window and vim.current.window.buffer == 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 ): if isinstance( obj, dict ):
ExpandReferencesInDict( obj, mapping, user_choices ) ExpandReferencesInDict( obj, mapping, calculus, user_choices )
elif isinstance( obj, list ): elif isinstance( obj, list ):
j_offset = 0 j_offset = 0
obj_copy = list( obj ) obj_copy = list( obj )
@ -360,6 +360,7 @@ def ExpandReferencesInObject( obj, mapping, user_choices ):
# *${something} - expand list in place # *${something} - expand list in place
value = ExpandReferencesInString( obj_copy[ i ][ 1: ], value = ExpandReferencesInString( obj_copy[ i ][ 1: ],
mapping, mapping,
calculus,
user_choices ) user_choices )
obj.pop( j ) obj.pop( j )
j_offset -= 1 j_offset -= 1
@ -369,14 +370,18 @@ def ExpandReferencesInObject( obj, mapping, user_choices ):
else: else:
obj[ j ] = ExpandReferencesInObject( obj_copy[ i ], obj[ j ] = ExpandReferencesInObject( obj_copy[ i ],
mapping, mapping,
calculus,
user_choices ) user_choices )
elif isinstance( obj, str ): elif isinstance( obj, str ):
obj = ExpandReferencesInString( obj, mapping, user_choices ) obj = ExpandReferencesInString( obj, mapping, calculus, user_choices )
return obj 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.expanduser( orig_s )
s = os.path.expandvars( 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 # HACK: This is seemingly the only way to get the key. str( e ) returns
# the key surrounded by '' for unknowable reasons. # the key surrounded by '' for unknowable reasons.
key = e.args[ 0 ] key = e.args[ 0 ]
default_value = user_choices.get( key, None )
mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ), if key in calculus:
default_value ) mapping[ key ] = calculus[ key ]()
user_choices[ key ] = mapping[ key ] else:
_logger.debug( "Value for %s not set in %s (from %s): set to %s", default_value = user_choices.get( key, None )
key, mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ),
s, default_value )
orig_s, user_choices[ key ] = mapping[ 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: except ValueError as e:
UserMessage( 'Invalid $ in string {}: {}'.format( s, e ), UserMessage( 'Invalid $ in string {}: {}'.format( s, e ),
persist = True ) 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? # 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. ? # 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(): 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_variables = {}
new_mapping = mapping.copy() new_mapping = mapping.copy()
@ -431,7 +446,10 @@ def ParseVariables( variables_list, mapping, user_choices ):
if 'shell' in v: if 'shell' in v:
new_v = v.copy() new_v = v.copy()
# Bit of a hack. Allows environment variables to be used. # 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 = os.environ.copy()
env.update( new_v.get( 'env' ) or {} ) env.update( new_v.get( 'env' ) or {} )
@ -455,6 +473,7 @@ def ParseVariables( variables_list, mapping, user_choices ):
else: else:
new_variables[ n ] = ExpandReferencesInObject( v, new_variables[ n ] = ExpandReferencesInObject( v,
mapping, mapping,
calculus,
user_choices ) user_choices )
return new_variables return new_variables
@ -575,3 +594,13 @@ def GetVimspectorBase():
return base.decode( 'utf-8' ) return base.decode( 'utf-8' )
else: else:
return base 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