示例#1
0
    def _Launch(self):
        self._logger.debug("LAUNCH!")
        adapter_config = self._adapter
        launch_config = {}
        launch_config.update(self._adapter.get('configuration', {}))
        launch_config.update(self._configuration['configuration'])

        request = self._configuration.get(
            'remote-request', launch_config.get('request', 'launch'))

        if request == "attach":
            self._splash_screen = utils.DisplaySplash(
                self._api_prefix, self._splash_screen,
                "Attaching to debugee...")

            self._PrepareAttach(adapter_config, launch_config)
        elif request == "launch":
            self._splash_screen = utils.DisplaySplash(self._api_prefix,
                                                      self._splash_screen,
                                                      "Launching debugee...")

            # FIXME: This cmdLine hack is not fun.
            self._PrepareLaunch(self._configuration.get('remote-cmdLine', []),
                                adapter_config, launch_config)

        # FIXME: name is mandatory. Forcefully add it (we should really use the
        # _actual_ name, but that isn't actually remembered at this point)
        if 'name' not in launch_config:
            launch_config['name'] = 'test'

        self._connection.DoRequest(lambda msg: self._OnLaunchComplete(), {
            'command': launch_config['request'],
            'arguments': launch_config
        })
示例#2
0
    def _Prepare(self):
        self._on_init_complete_handlers = []

        self._logger.debug("LAUNCH!")
        self._launch_config = {}
        self._launch_config.update(self._adapter.get('configuration', {}))
        self._launch_config.update(self._configuration['configuration'])

        request = self._configuration.get(
            'remote-request', self._launch_config.get('request', 'launch'))

        if request == "attach":
            self._splash_screen = utils.DisplaySplash(
                self._api_prefix, self._splash_screen,
                "Attaching to debugee...")

            self._PrepareAttach(self._adapter, self._launch_config)
        elif request == "launch":
            self._splash_screen = utils.DisplaySplash(self._api_prefix,
                                                      self._splash_screen,
                                                      "Launching debugee...")

            # FIXME: This cmdLine hack is not fun.
            self._PrepareLaunch(self._configuration.get('remote-cmdLine', []),
                                self._adapter, self._launch_config)

        # FIXME: name is mandatory. Forcefully add it (we should really use the
        # _actual_ name, but that isn't actually remembered at this point)
        if 'name' not in self._launch_config:
            self._launch_config['name'] = 'test'
示例#3
0
  def _StartDebugAdapter( self ):
    self._splash_screen = utils.DisplaySplash(
      self._api_prefix,
      self._splash_screen,
      "Starting debug adapter..." )

    if self._connection:
      utils.UserMessage( 'The connection is already created. Please try again',
                         persist = True )
      return

    self._logger.info( 'Starting debug adapter with: %s',
                       json.dumps( self._adapter ) )

    self._init_complete = False
    self._on_init_complete_handlers = []
    self._launch_complete = False
    self._run_on_server_exit = None

    self._connection_type = 'job'
    if 'port' in self._adapter:
      self._connection_type = 'channel'

      if self._adapter[ 'port' ] == 'ask':
        port = utils.AskForInput( 'Enter port to connect to: ' )
        if port is None:
          self._Reset()
          return
        self._adapter[ 'port' ] = port

    self._connection_type = self._api_prefix + self._connection_type

    # TODO: Do we actually need to copy and update or does Vim do that?
    env = os.environ.copy()
    if os.name == "nt":
      env = {}
    if 'env' in self._adapter:
      env.update( self._adapter[ 'env' ] )
    self._adapter[ 'env' ] = env

    if 'cwd' not in self._adapter:
      self._adapter[ 'cwd' ] = os.getcwd()

    vim.vars[ '_vimspector_adapter_spec' ] = self._adapter
    if not vim.eval( "vimspector#internal#{}#StartDebugSession( "
                     "  g:_vimspector_adapter_spec "
                     ")".format( self._connection_type ) ):
      self._logger.error( "Unable to start debug server" )
      self._splash_screen = utils.DisplaySplash( self._api_prefix,
                                                 self._splash_screen,
                                                 "Unable to start adapter" )
    else:
      self._connection = debug_adapter_connection.DebugAdapterConnection(
        self,
        lambda msg: utils.Call(
          "vimspector#internal#{}#Send".format( self._connection_type ),
          msg ) )

    self._logger.info( 'Debug Adapter Started' )
示例#4
0
    def _StopDebugAdapter(self, callback=None):
        self._splash_screen = utils.DisplaySplash(
            self._api_prefix, self._splash_screen,
            "Shutting down debug adapter...")

        def handler(*args):
            self._splash_screen = utils.HideSplash(self._api_prefix,
                                                   self._splash_screen)

            if callback:
                self._logger.debug(
                    "Setting server exit handler before disconnect")
                assert not self._run_on_server_exit
                self._run_on_server_exit = callback

            vim.eval('vimspector#internal#{}#StopDebugSession()'.format(
                self._connection_type))

        arguments = {}
        if self._server_capabilities.get('supportTerminateDebuggee'):
            # If we attached, we should _not_ terminate the debuggee
            arguments['terminateDebuggee'] = False

        self._connection.DoRequest(handler, {
            'command': 'disconnect',
            'arguments': arguments,
        },
                                   failure_handler=handler,
                                   timeout=5000)
示例#5
0
    def _StopDebugAdapter(self, interactive=False, callback=None):
        self._splash_screen = utils.DisplaySplash(
            self._api_prefix, self._splash_screen,
            "Shutting down debug adapter...")

        def handler(*args):
            self._splash_screen = utils.HideSplash(self._api_prefix,
                                                   self._splash_screen)

            if callback:
                self._logger.debug(
                    "Setting server exit handler before disconnect")
                assert not self._run_on_server_exit
                self._run_on_server_exit = callback

            vim.eval('vimspector#internal#{}#StopDebugSession()'.format(
                self._connection_type))

        arguments = {}
        if (interactive
                and self._server_capabilities.get('supportTerminateDebuggee')):
            if self._stackTraceView.AnyThreadsRunning():
                choice = utils.AskForInput(
                    "Terminate debuggee [Y/N/default]? ", "")
                if choice == "Y" or choice == "y":
                    arguments['terminateDebuggee'] = True
                elif choice == "N" or choice == 'n':
                    arguments['terminateDebuggee'] = False

        self._connection.DoRequest(handler, {
            'command': 'disconnect',
            'arguments': arguments,
        },
                                   failure_handler=handler,
                                   timeout=5000)
示例#6
0
 def failure_handler(reason, msg):
     text = [
         'Launch Failed', '', reason, '',
         'Use :VimspectorReset to close'
     ]
     self._splash_screen = utils.DisplaySplash(self._api_prefix,
                                               self._splash_screen,
                                               text)
示例#7
0
    def _Initialise(self):
        self._splash_screen = utils.DisplaySplash(
            self._api_prefix, self._splash_screen,
            "Initializing debug adapter...")

        # For a good explaination as to why this sequence is the way it is, see
        # https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522
        #
        # In short, we do what VSCode does:
        # 1. Send the initialize request and wait for the reply
        # 2a. When we recieve the initialize reply, send the launch/attach request
        # 2b. When we receive the initialized notification, send the breakpoints
        #    - if supportsConfigurationDoneRequest, send it
        #    - else, send the empty exception breakpoints request
        # 3. When we have recieved both the receive the launch/attach reply *and*
        #    the connfiguration done reply (or, if we didn't send one, a response to
        #    the empty exception breakpoints request), we request threads
        # 4. The threads response triggers things like scopes and triggers setting
        #    the current frame.
        #
        def handle_initialize_response(msg):
            self._server_capabilities = msg.get('body') or {}
            self._breakpoints.SetServerCapabilities(self._server_capabilities)
            self._variablesView.SetServerCapabilities(
                self._server_capabilities)
            self._Launch()

        self._connection.DoRequest(
            handle_initialize_response, {
                'command': 'initialize',
                'arguments': {
                    'adapterID': self._adapter.get('name', 'adapter'),
                    'clientID': 'vimspector',
                    'clientName': 'vimspector',
                    'linesStartAt1': True,
                    'columnsStartAt1': True,
                    'locale': 'en_GB',
                    'pathFormat': 'path',
                    'supportsVariableType': True,
                    'supportsVariablePaging': False,
                    'supportsRunInTerminalRequest': True
                },
            })
示例#8
0
    def disconnect():
      self._splash_screen = utils.DisplaySplash(
        self._api_prefix,
        self._splash_screen,
        "Shutting down debug adapter..." )

      def handler( *args ):
        self._splash_screen = utils.HideSplash( self._api_prefix,
                                                self._splash_screen )

        if callback:
          self._logger.debug( "Setting server exit handler before disconnect" )
          assert not self._run_on_server_exit
          self._run_on_server_exit = callback

        vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
          self._connection_type ) )

      self._connection.DoRequest( handler, {
        'command': 'disconnect',
        'arguments': arguments,
      }, failure_handler = handler, timeout = 5000 )
示例#9
0
    def _StartDebugAdapter(self):
        self._splash_screen = utils.DisplaySplash(self._api_prefix,
                                                  self._splash_screen,
                                                  "Starting debug adapter...")

        if self._connection:
            utils.UserMessage(
                'The connection is already created. Please try again',
                persist=True)
            return

        # There is the problem with the current flow when we try to use a debugger
        # which is located fully on the remote server e.g container or SSH Server.
        # The problem is in the order: it tries to connect to debugger before it is even started
        # To solve that problem, I offer adding an optional boolean key "bootstrap" to a configuration.
        # If we have that key, we should perform launch or attach commands to first bootstrap a remote debugger.
        # Then we can skip that step in the _Launch() function
        if self._adapter.get('bootstrap'):
            self._BootstrapRemoteDebugger()

        self._logger.info('Starting debug adapter with: %s',
                          json.dumps(self._adapter))

        self._init_complete = False
        self._on_init_complete_handlers = []
        self._launch_complete = False
        self._run_on_server_exit = None

        self._connection_type = 'job'
        if 'port' in self._adapter:
            self._connection_type = 'channel'

            if self._adapter['port'] == 'ask':
                port = utils.AskForInput('Enter port to connect to: ')
                if port is None:
                    self._Reset()
                    return
                self._adapter['port'] = port

        self._connection_type = self._api_prefix + self._connection_type

        # TODO: Do we actually need to copy and update or does Vim do that?
        env = os.environ.copy()
        if 'env' in self._adapter:
            env.update(self._adapter['env'])
        self._adapter['env'] = env

        if 'cwd' not in self._adapter:
            self._adapter['cwd'] = os.getcwd()

        vim.vars['_vimspector_adapter_spec'] = self._adapter
        if not vim.eval("vimspector#internal#{}#StartDebugSession( "
                        "  g:_vimspector_adapter_spec "
                        ")".format(self._connection_type)):
            self._logger.error("Unable to start debug server")
            self._splash_screen = utils.DisplaySplash(
                self._api_prefix, self._splash_screen,
                "Unable to start adapter")
        else:
            self._connection = debug_adapter_connection.DebugAdapterConnection(
                self, lambda msg: utils.Call(
                    "vimspector#internal#{}#Send".format(self._connection_type
                                                         ), msg))

        self._logger.info('Debug Adapter Started')
示例#10
0
  def _StartDebugAdapter( self ):
    self._splash_screen = utils.DisplaySplash(
      self._api_prefix,
      self._splash_screen,
      "Starting debug adapter..." )

    if self._connection:
      utils.UserMessage( 'The connection is already created. Please try again',
                         persist = True )
      return

    self._logger.info( 'Starting debug adapter with: %s',
                       json.dumps( self._adapter ) )

    self._init_complete = False
    self._launch_complete = False
    self._run_on_server_exit = None

    self._connection_type = 'job'
    if 'port' in self._adapter:
      self._connection_type = 'channel'

      if self._adapter[ 'port' ] == 'ask':
        port = utils.AskForInput( 'Enter port to connect to: ' )
        if port is None:
          self._Reset()
          return
        self._adapter[ 'port' ] = port

    self._connection_type = self._api_prefix + self._connection_type
    self._logger.debug( f"Connection Type: { self._connection_type }" )

    self._adapter[ 'env' ] = self._adapter.get( 'env', {} )

    if 'cwd' not in self._adapter:
      self._adapter[ 'cwd' ] = os.getcwd()

    vim.vars[ '_vimspector_adapter_spec' ] = self._adapter
    if not vim.eval( "vimspector#internal#{}#StartDebugSession( "
                     "  g:_vimspector_adapter_spec "
                     ")".format( self._connection_type ) ):
      self._logger.error( "Unable to start debug server" )
      self._splash_screen = utils.DisplaySplash( self._api_prefix,
                                                 self._splash_screen,
                                                 "Unable to start adapter" )
    else:
      if 'custom_handler' in self._adapter:
        spec = self._adapter[ 'custom_handler' ]
        if isinstance( spec, dict ):
          module = spec[ 'module' ]
          cls = spec[ 'class' ]
        else:
          module, cls = spec.rsplit( '.', 1 )

        CustomHandler = getattr( importlib.import_module( module ), cls )
        handlers = [ CustomHandler( self ), self ]
      else:
        handlers = [ self ]

      self._connection = debug_adapter_connection.DebugAdapterConnection(
        handlers,
        lambda msg: utils.Call(
          "vimspector#internal#{}#Send".format( self._connection_type ),
          msg ) )

    self._logger.info( 'Debug Adapter Started' )