def Start(self, configuration=None): self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile('.vimspector.json') if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application') return with open(launch_config_file, 'r') as f: database = json.load(f) launch_config = database.get('configurations') adapters = database.get('adapters') if not configuration: if len(launch_config) == 1: configuration = next(iter(launch_config.keys())) else: configuration = utils.SelectFromList( 'Which launch configuration?', list(launch_config.keys())) if not configuration: return utils.ExpandReferencesInDict( launch_config[configuration], {'workspaceRoot': os.path.dirname(launch_config_file)}) adapter = launch_config[configuration].get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) utils.ExpandReferencesInDict( adapter, {'workspaceRoot': os.path.dirname(launch_config_file)}) self._StartWithConfiguration(launch_config[configuration], adapter)
def Start(self, launch_variables=None): # We mutate launch_variables, so don't mutate the default argument. # https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments if launch_variables is None: launch_variables = {} self._logger.info("User requested start debug session with %s", launch_variables) self._configuration = None self._adapter = None current_file = utils.GetBufferFilepath(vim.current.buffer) filetypes = utils.GetBufferFiletypes(vim.current.buffer) configurations = {} adapters = {} glob.glob(install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS())) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file): self._logger.debug(f'Reading gadget config: {gadget_config_file}') if not gadget_config_file or not os.path.exists( gadget_config_file): continue with open(gadget_config_file, 'r') as f: adapters.update(json.load(f).get('adapters') or {}) for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME, current_file, filetypes): self._logger.debug( f'Reading configurations from: {launch_config_file}') if not launch_config_file or not os.path.exists( launch_config_file): continue with open(launch_config_file, 'r') as f: database = json.load(f) adapters.update(database.get('adapters') or {}) configurations.update(database.get('configurations' or {})) if not configurations: utils.UserMessage('Unable to find any debug configurations. ' 'You need to tell vimspector how to launch your ' 'application.') return if 'configuration' in launch_variables: configuration_name = launch_variables.pop('configuration') elif len(configurations) == 1: configuration_name = next(iter(configurations.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(configurations.keys())) if not configuration_name or configuration_name not in configurations: return if launch_config_file: self._workspace_root = os.path.dirname(launch_config_file) else: self._workspace_root = os.path.dirname(current_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables # # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable def relpath(p, relative_to): if not p: return '' return os.path.relpath(p, relative_to) def splitext(p): if not p: return ['', ''] return os.path.splitext(p) self._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), 'fileBasenameNoExtension': splitext(os.path.basename(current_file))[0], 'fileDirname': os.path.dirname(current_file), 'fileExtname': 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(), } # 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) self._variables.update( utils.ParseVariables(adapter.get('variables', {}), self._variables, USER_CHOICES)) self._variables.update( utils.ParseVariables(configuration.get('variables', {}), self._variables, USER_CHOICES)) utils.ExpandReferencesInDict(configuration, self._variables, USER_CHOICES) utils.ExpandReferencesInDict(adapter, self._variables, USER_CHOICES) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
def Start(self, launch_variables=None): # We mutate launch_variables, so don't mutate the default argument. # https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments if launch_variables is None: launch_variables = {} self._logger.info("User requested start debug session with %s", launch_variables) self._configuration = None self._adapter = None current_file = utils.GetBufferFilepath(vim.current.buffer) filetypes = utils.GetBufferFiletypes(vim.current.buffer) configurations = {} adapters = {} glob.glob(install.GetGadgetDir(VIMSPECTOR_HOME)) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file): self._logger.debug(f'Reading gadget config: {gadget_config_file}') if not gadget_config_file or not os.path.exists( gadget_config_file): continue with open(gadget_config_file, 'r') as f: a = json.loads(minify(f.read())).get('adapters') or {} adapters.update(a) for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME, current_file, filetypes): self._logger.debug( f'Reading configurations from: {launch_config_file}') if not launch_config_file or not os.path.exists( launch_config_file): continue with open(launch_config_file, 'r') as f: database = json.loads(minify(f.read())) adapters.update(database.get('adapters') or {}) configurations.update(database.get('configurations' or {})) if not configurations: utils.UserMessage('Unable to find any debug configurations. ' 'You need to tell vimspector how to launch your ' 'application.') return if 'configuration' in launch_variables: configuration_name = launch_variables.pop('configuration') elif (len(configurations) == 1 and next(iter(configurations.values())).get("autoselect", True)): configuration_name = next(iter(configurations.keys())) else: # Find a single configuration with 'default' True and autoselect not False defaults = { n: c for n, c in configurations.items() if c.get('default', False) is True and c.get('autoselect', True) is not False } if len(defaults) == 1: configuration_name = next(iter(defaults.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(configurations.keys())) if not configuration_name or configuration_name not in configurations: return if launch_config_file: self._workspace_root = os.path.dirname(launch_config_file) else: self._workspace_root = os.path.dirname(current_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter_dict = adapters.get(adapter) if adapter_dict is None: suggested_gadgets = installer.FindGadgetForAdapter(adapter) if suggested_gadgets: response = utils.AskForInput( f"The specified adapter '{adapter}' is not " "installed. Would you like to install the following gadgets? ", ' '.join(suggested_gadgets)) if response: new_launch_variables = dict(launch_variables) new_launch_variables[ 'configuration'] = configuration_name installer.RunInstaller( self._api_prefix, False, # Don't leave open *shlex.split(response), then=lambda: self.Start(new_launch_variables)) return elif response is None: return utils.UserMessage( f"The specified adapter '{adapter}' is not " "available. Did you forget to run " "'install_gadget.py'?", persist=True, error=True) return adapter = adapter_dict # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable def relpath(p, relative_to): if not p: return '' return os.path.relpath(p, relative_to) def splitext(p): if not p: return ['', ''] return os.path.splitext(p) variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME), 'file': current_file, } calculus = { 'relativeFile': lambda: relpath(current_file, self._workspace_root), 'fileBasename': lambda: os.path.basename(current_file), 'fileBasenameNoExtension': 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, '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) variables.update(launch_variables) try: variables.update( utils.ParseVariables(adapter.get('variables', {}), variables, calculus, USER_CHOICES)) variables.update( utils.ParseVariables(configuration.get('variables', {}), variables, calculus, USER_CHOICES)) utils.ExpandReferencesInDict(configuration, variables, calculus, USER_CHOICES) utils.ExpandReferencesInDict(adapter, variables, calculus, USER_CHOICES) except KeyboardInterrupt: self._Reset() return if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
def Start(self, launch_variables={}): self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile('.vimspector.json') if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application') return with open(launch_config_file, 'r') as f: database = json.load(f) configurations = database.get('configurations') adapters = {} for gadget_config_file in [ install.GetGadgetConfigFile(VIMSPECTOR_HOME), utils.PathToConfigFile('.gadgets.json') ]: if gadget_config_file and os.path.exists(gadget_config_file): with open(gadget_config_file, 'r') as f: adapters.update(json.load(f).get('adapters') or {}) adapters.update(database.get('adapters') or {}) if len(configurations) == 1: configuration_name = next(iter(configurations.keys())) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted(list(configurations.keys()))) if not configuration_name or configuration_name not in configurations: return self._workspace_root = os.path.dirname(launch_config_file) configuration = configurations[configuration_name] adapter = configuration.get('adapter') if isinstance(adapter, str): adapter = adapters.get(adapter) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables self._variables = { 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'gadgetDir': install.GetGadgetDir(VIMSPECTOR_HOME, install.GetOS()) } self._variables.update( utils.ParseVariables(adapter.get('variables', {}))) self._variables.update( utils.ParseVariables(configuration.get('variables', {}))) self._variables.update(launch_variables) utils.ExpandReferencesInDict(configuration, self._variables) utils.ExpandReferencesInDict(adapter, self._variables) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format(configuration_name), persist=True) return self._StartWithConfiguration(configuration, adapter)
def test_ExpandReferencesInDict(self): mapping = { 'one': 'one', 'two': 'TWO', 'bool': True, 'words': 'these are some words' } calculus = { 'three': lambda: 1 + 2, } CHOICES = {'five': '5ive!'} def AskForInput(prompt, default_value=None): if default_value is not None: return default_value return 'typed text' d = { 'dollar': '$$', 'not_a_var': '$${test}', 'one': '${one}', 'two': '${one} and ${two}', 'three': '${three}', 'three_with_default': '${three_with_default:${three\\}}', # uses calculus 'four': '${four}', 'five': '${five}', 'list': ['*${words}'], 'list1': ['start', '*${words}', 'end'], 'list2': ['*${words}', '${three}'], 'list3': ['${one}', '*${words}', 'three'], 'dict#json': '{ "key": "value" }', 'bool#json': 'false', 'one_default': '${one_default:one}', 'two_default': '${two_default_1:one} and ${two_default_2:two}', 'one_default2': '${one_default2:${one\\}}', 'two_default2': '${two_default2_1:${one\\}} and ${two_default2_2:${two\\}}', 'unlikely_name#json#s': 'true', 'empty_splice': ['*${empty:}'], } e = { 'dollar': '$', 'not_a_var': '${test}', 'one': 'one', 'two': 'one and TWO', 'three': '3', 'three_with_default': '3', 'four': 'typed text', 'five': '5ive!', 'list': ['these', 'are', 'some', 'words'], 'list1': ['start', 'these', 'are', 'some', 'words', 'end'], 'list2': ['these', 'are', 'some', 'words', '3'], 'list3': ['one', 'these', 'are', 'some', 'words', 'three'], 'dict': { 'key': 'value', }, 'bool': False, 'one_default': 'one', 'two_default': 'one and two', 'one_default2': 'one', 'two_default2': 'one and TWO', 'unlikely_name#json': 'true', 'empty_splice': [], } with patch('vimspector.utils.AskForInput', side_effect=AskForInput): utils.ExpandReferencesInDict(d, mapping, calculus, CHOICES) self.assertDictEqual(d, e)
def Start( self, launch_variables = {} ): self._logger.info( "User requested start debug session with %s", launch_variables ) self._configuration = None self._adapter = None launch_config_file = utils.PathToConfigFile( '.vimspector.json' ) if not launch_config_file: utils.UserMessage( 'Unable to find .vimspector.json. You need to tell ' 'vimspector how to launch your application' ) return with open( launch_config_file, 'r' ) as f: database = json.load( f ) configurations = database.get( 'configurations' ) adapters = {} for gadget_config_file in [ install.GetGadgetConfigFile( VIMSPECTOR_HOME ), utils.PathToConfigFile( '.gadgets.json' ) ]: if gadget_config_file and os.path.exists( gadget_config_file ): with open( gadget_config_file, 'r' ) as f: adapters.update( json.load( f ).get( 'adapters' ) or {} ) adapters.update( database.get( 'adapters' ) or {} ) if len( configurations ) == 1: configuration_name = next( iter( configurations.keys() ) ) else: configuration_name = utils.SelectFromList( 'Which launch configuration?', sorted( list( configurations.keys() ) ) ) if not configuration_name or configuration_name not in configurations: return self._workspace_root = os.path.dirname( launch_config_file ) configuration = configurations[ configuration_name ] adapter = configuration.get( 'adapter' ) if isinstance( adapter, str ): adapter = adapters.get( adapter ) # TODO: Do we want some form of persistence ? e.g. self._staticVariables, # set from an api call like SetLaunchParam( 'var', 'value' ), perhaps also a # way to load .vimspector.local.json which just sets variables # # Additional vars as defined by VSCode: # # ${workspaceFolder} - the path of the folder opened in VS Code # ${workspaceFolderBasename} - the name of the folder opened in VS Code # without any slashes (/) # ${file} - the current opened file # ${relativeFile} - the current opened file relative to workspaceFolder # ${fileBasename} - the current opened file's basename # ${fileBasenameNoExtension} - the current opened file's basename with no # file extension # ${fileDirname} - the current opened file's dirname # ${fileExtname} - the current opened file's extension # ${cwd} - the task runner's current working directory on startup # ${lineNumber} - the current selected line number in the active file # ${selectedText} - the current selected text in the active file # ${execPath} - the path to the running VS Code executable current_file = utils.GetBufferFilepath( vim.current.buffer ) self._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': os.path.relpath( current_file, self._workspace_root ), 'fileBasename': os.path.basename( current_file ), 'fileBasenameNoExtension': os.path.splitext( os.path.basename( current_file ) )[ 0 ], 'fileDirname': os.path.dirname( current_file ), 'fileExtname': os.path.splitext( os.path.basename( current_file ) )[ 1 ], 'cwd': os.getcwd(), } self._variables.update( utils.ParseVariables( adapter.get( 'variables', {} ), self._variables ) ) self._variables.update( utils.ParseVariables( configuration.get( 'variables', {} ), self._variables ) ) self._variables.update( launch_variables ) utils.ExpandReferencesInDict( configuration, self._variables ) utils.ExpandReferencesInDict( adapter, self._variables ) if not adapter: utils.UserMessage( 'No adapter configured for {}'.format( configuration_name ), persist=True ) return self._StartWithConfiguration( configuration, adapter )