Exemple #1
0
    def SetCurrentFrame(self, frame):
        """Returns True if the code window was updated with the frame, False
    otherwise. False means either the frame is junk, we couldn't find the file
    (or don't have the data) or the code window no longer exits."""

        if not frame or not frame.get('source'):
            self._UndisplayPC()
            return False

        if 'path' not in frame['source']:
            self._UndisplayPC()
            return False

        self._current_frame = frame

        if not self._window.valid:
            return False

        utils.JumpToWindow(self._window)
        try:
            utils.OpenFileInCurrentWindow(frame['source']['path'])
        except vim.error:
            self._logger.exception(
                'Unexpected vim error opening file {}'.format(
                    frame['source']['path']))
            return False

        # SIC: column is 0-based, line is 1-based in vim. Why? Nobody knows.
        # Note: max() with 0 because some debug adapters (go) return 0 for the
        # column.
        try:
            self._window.cursor = (frame['line'], max(frame['column'] - 1, 0))
        except vim.error:
            self._logger.exception(
                "Unable to jump to %s:%s in %s, maybe the file "
                "doesn't exist", frame['line'], frame['column'],
                frame['source']['path'])
            return False

        self.current_syntax = utils.ToUnicode(
            vim.current.buffer.options['syntax'])
        self.filetype = '.'.join(utils.GetBufferFiletypes(vim.current.buffer))

        self.ShowBreakpoints()

        return True
    def GetConfigurations(self):
        current_file = utils.GetBufferFilepath(vim.current.buffer)
        filetypes = utils.GetBufferFiletypes(vim.current.buffer)
        configurations = {}

        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()))
                configurations.update(database.get('configurations' or {}))

        return launch_config_file, configurations
    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)
Exemple #4
0
    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)