Exemple #1
0
  def _ShowBreakpoints( self ):
    for file_name, line_breakpoints in self._line_breakpoints.items():
      for bp in line_breakpoints:
        self._SignToLine( file_name, bp )
        if 'sign_id' in bp:
          signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
        else:
          bp[ 'sign_id' ] = self._next_sign_id
          self._next_sign_id += 1

        line = bp[ 'line' ]
        if 'server_bp' in bp:
          server_bp = bp[ 'server_bp' ]
          line = server_bp.get( 'line', line )
          verified = server_bp[ 'verified' ]
        else:
          verified = self._connection is None

        sign = ( 'vimspectorBPDisabled'
                   if bp[ 'state' ] != 'ENABLED' or not verified
                 else 'vimspectorBPLog'
                   if 'logMessage' in bp[ 'options' ]
                 else 'vimspectorBPCond'
                   if 'condition' in bp[ 'options' ]
                   or 'hitCondition' in bp[ 'options' ]
                 else 'vimspectorBP' )

        if utils.BufferExists( file_name ):
          signs.PlaceSign( bp[ 'sign_id' ],
                           'VimspectorBP',
                           sign,
                           file_name,
                           line )
Exemple #2
0
  def _DrawThreads( self ):
    self._line_to_frame.clear()
    self._line_to_thread.clear()

    if self._current_thread_sign_id:
      signs.UnplaceSign( self._current_thread_sign_id, 'VimspectorStackTrace' )
    else:
      self._current_thread_sign_id = 1

    with utils.ModifiableScratchBuffer( self._buf ):
      with utils.RestoreCursorPosition():
        utils.ClearBuffer( self._buf )

        for thread in self._threads:
          icon = '+' if not thread.IsExpanded() else '-'
          line = utils.AppendToBuffer(
            self._buf,
            f'{icon} Thread {thread.id}: {thread.thread["name"]} '
            f'({thread.State()})' )

          if self._current_thread == thread.id:
            # TODO - Scroll the window such that this line is visible (e.g. at
            # the top)
            signs.PlaceSign( self._current_thread_sign_id,
                             'VimspectorStackTrace',
                             'vimspectorCurrentThread',
                             self._buf.name,
                             line )

          self._line_to_thread[ line ] = thread
          self._DrawStackTrace( thread )
Exemple #3
0
    def Clear(self):
        if self._signs['vimspectorPC']:
            signs.UnplaceSign(self._signs['vimspectorPC'], 'VimspectorCode')
            self._signs['vimspectorPC'] = None

        self._UndisplayPC()
        self.current_syntax = None
Exemple #4
0
  def Clear( self ):
    self._current_frame = None
    self._current_thread = None
    self._current_syntax = ""
    self._threads.clear()
    self._sources = {}
    self._requesting_threads = StackTraceView.ThreadRequestState.NO
    self._pending_thread_request = None
    if self._current_thread_sign_id:
      signs.UnplaceSign( self._current_thread_sign_id, 'VimspectorStackTrace' )
    self._current_thread_sign_id = 0
    if self._current_frame_sign_id:
      signs.UnplaceSign( self._current_frame_sign_id, 'VimspectorStackTrace' )
    self._current_frame_sign_id = 0

    with utils.ModifiableScratchBuffer( self._buf ):
      utils.ClearBuffer( self._buf )
Exemple #5
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 self._signs[ 'vimspectorPC' ]:
      signs.UnplaceSign( self._signs[ 'vimspectorPC' ], 'VimspectorCode' )
      self._signs[ 'vimspectorPC' ] = None

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

    if 'path' not in frame[ 'source' ]:
      return False

    self._signs[ 'vimspectorPC' ] = self._next_sign_id
    self._next_sign_id += 1

    try:
      signs.PlaceSign( self._signs[ 'vimspectorPC' ],
                       'VimspectorCode',
                       'vimspectorPC',
                       frame[ 'source' ][ 'path' ],
                       frame[ 'line' ] )
    except vim.error as e:
      # Ignore 'invalid buffer name'
      if 'E158' not in str( e ):
        raise

    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' ] )

    return True
Exemple #6
0
  def ClearBreakpoints( self ):
    # These are the user-entered breakpoints.
    for file_name, breakpoints in self._line_breakpoints.items():
      for bp in breakpoints:
        self._SignToLine( file_name, bp )
        if 'sign_id' in bp:
          signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )

    self._line_breakpoints = defaultdict( list )
    self._func_breakpoints = []
    self._exception_breakpoints = None

    self.UpdateUI()
Exemple #7
0
  def _ClearServerBreakpointData( self ):
    for _, breakpoints in self._line_breakpoints.items():
      for bp in breakpoints:
        if 'server_bp' in bp:
          # Unplace the sign. If the sign was moved by the server, then we don't
          # want a subsequent call to _SignToLine to override the user's
          # breakpoint location with the server one. This is not what users
          # typicaly expect, and we may (soon) call something that eagerly calls
          # _SignToLine, such as _ShowBreakpoints,
          if 'sign_id' in bp:
            signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
            del bp[ 'sign_id' ]

          del bp[ 'server_bp' ]
Exemple #8
0
    def _ShowBreakpoints(self):
        for file_name, line_breakpoints in self._line_breakpoints.items():
            for bp in line_breakpoints:
                self._SignToLine(file_name, bp)
                if 'sign_id' in bp:
                    signs.UnplaceSign(bp['sign_id'], 'VimspectorBP')
                else:
                    bp['sign_id'] = self._next_sign_id
                    self._next_sign_id += 1

                sign = ('vimspectorBPDisabled'
                        if bp['state'] != 'ENABLED' else 'vimspectorBPCond'
                        if 'condition' in bp['options'] else 'vimspectorBP')

                signs.PlaceSign(bp['sign_id'], 'VimspectorBP', sign, file_name,
                                bp['line'])
Exemple #9
0
  def _DrawStackTrace( self, thread: Thread ):
    if not thread.IsExpanded():
      return

    if self._current_frame_sign_id:
      signs.UnplaceSign( self._current_frame_sign_id, 'VimspectorStackTrace' )
    else:
      self._current_frame_sign_id = 2

    for frame in thread.stacktrace:
      if frame.get( 'source' ):
        source = frame[ 'source' ]
      else:
        source = { 'name': '<unknown>' }

      if 'name' not in source:
        source[ 'name' ] = os.path.basename( source.get( 'path', 'unknwon' ) )

      if frame.get( 'presentationHint' ) == 'label':
        # Sigh. FOr some reason, it's OK for debug adapters to completely ignore
        # the protocol; it seems that the chrome adapter sets 'label' and
        # doesn't set 'line'
        line = utils.AppendToBuffer(
          self._buf,
          '  {0}: {1}'.format( frame[ 'id' ], frame[ 'name' ] ) )
      else:
        line = utils.AppendToBuffer(
          self._buf,
          '  {0}: {1}@{2}:{3}'.format( frame[ 'id' ],
                                       frame[ 'name' ],
                                       source[ 'name' ],
                                       frame[ 'line' ] ) )

      if ( self._current_frame is not None and
           self._current_frame[ 'id' ] == frame[ 'id' ] ):
        signs.PlaceSign( self._current_frame_sign_id,
                         'VimspectorStackTrace',
                         'vimspectorCurrentFrame',
                         self._buf.name,
                         line )

      self._line_to_frame[ line ] = ( thread, frame )
Exemple #10
0
    def ToggleBreakpoint(self, options):
        line, column = vim.current.window.cursor
        file_name = vim.current.buffer.name

        if not file_name:
            return

        found_bp = False
        action = 'New'
        for index, bp in enumerate(self._line_breakpoints[file_name]):
            self._SignToLine(file_name, bp)
            if bp['line'] == line:
                found_bp = True
                if bp['state'] == 'ENABLED' and not self._connection:
                    bp['state'] = 'DISABLED'
                    action = 'Disable'
                else:
                    if 'sign_id' in bp:
                        signs.UnplaceSign(bp['sign_id'], 'VimspectorBP')
                    del self._line_breakpoints[file_name][index]
                    action = 'Delete'
                break

        self._logger.debug("Toggle found bp at {}:{} ? {} ({})".format(
            file_name, line, found_bp, action))

        if not found_bp:
            self._line_breakpoints[file_name].append({
                'state': 'ENABLED',
                'line': line,
                'options': options,
                # 'sign_id': <filled in when placed>,
                #
                # Used by other breakpoint types (specified in options):
                # 'condition': ...,
                # 'hitCondition': ...,
                # 'logMessage': ...
            })

        self.UpdateUI()
Exemple #11
0
 def _UndisplayPC( self, clear_pc = True ):
   if clear_pc:
     self._current_frame = None
   if self._signs[ 'vimspectorPC' ]:
     signs.UnplaceSign( self._signs[ 'vimspectorPC' ], 'VimspectorCode' )
     self._signs[ 'vimspectorPC' ] = None
Exemple #12
0
  def _UndisplaySigns( self ):
    for sign_id in self._signs[ 'breakpoints' ]:
      signs.UnplaceSign( sign_id, 'VimspectorCode' )

    self._signs[ 'breakpoints' ] = []
Exemple #13
0
  def SendBreakpoints( self, doneHandler = None ):
    if self._awaiting_bp_responses > 0:
      self._pending_send_breakpoints = ( doneHandler, )
      return

    self._awaiting_bp_responses = 0

    def response_received( *failure_args ):
      self._awaiting_bp_responses -= 1

      if failure_args and self._connection:
        reason, msg = failure_args
        utils.UserMessage( 'Unable to set breakpoint: {0}'.format( reason ),
                           persist = True,
                           error = True )

      if self._awaiting_bp_responses > 0:
        return

      if doneHandler:
        doneHandler()

      if bool( self._pending_send_breakpoints ):
        args = self._pending_send_breakpoints
        self._pending_send_breakpoints = None
        self.SendBreakpoints( *args )


    def response_handler( msg, bp_idxs = [] ):
      server_bps = ( msg.get( 'body' ) or {} ).get( 'breakpoints' ) or []
      self._UpdateServerBreakpoints( server_bps, bp_idxs )
      response_received()


    # NOTE: Must do this _first_ otherwise we might send requests and get
    # replies before we finished sending all the requests.
    if self._exception_breakpoints is None:
      self._SetUpExceptionBreakpoints( self._configured_breakpoints )


    # TODO: add the _configured_breakpoints to line_breakpoints

    for file_name, line_breakpoints in self._line_breakpoints.items():
      bp_idxs = []
      breakpoints = []
      for bp in line_breakpoints:
        bp.pop( 'server_bp', None )

        self._SignToLine( file_name, bp )
        if 'sign_id' in bp:
          signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )

        if bp[ 'state' ] != 'ENABLED':
          continue

        dap_bp = {}
        dap_bp.update( bp[ 'options' ] )
        dap_bp.update( { 'line': bp[ 'line' ] } )

        dap_bp.pop( 'temporary', None )

        bp_idxs.append( [ len( breakpoints ), bp ] )

        breakpoints.append( dap_bp )


      source = {
        'name': os.path.basename( file_name ),
        'path': file_name,
      }

      self._awaiting_bp_responses += 1
      self._connection.DoRequest(
        # The source=source here is critical to ensure that we capture each
        # source in the iteration, rather than ending up passing the same source
        # to each callback.
        lambda msg, bp_idxs=bp_idxs: response_handler( msg, bp_idxs ),
        {
          'command': 'setBreakpoints',
          'arguments': {
            'source': source,
            'breakpoints': breakpoints,
            'sourceModified': False, # TODO: We can actually check this
          },
        },
        failure_handler = response_received
      )

    # TODO: Add the _configured_breakpoints to function breakpoints

    if self._server_capabilities.get( 'supportsFunctionBreakpoints' ):
      self._awaiting_bp_responses += 1
      breakpoints = []
      for bp in self._func_breakpoints:
        bp.pop( 'server_bp', None )
        if bp[ 'state' ] != 'ENABLED':
          continue
        dap_bp = {}
        dap_bp.update( bp[ 'options' ] )
        dap_bp.update( { 'name': bp[ 'function' ] } )
        breakpoints.append( dap_bp )

      # FIXME(Ben): The function breakpoints response actually returns
      # 'Breakpoint' objects. The point is that there is a server_bp for each
      # function breakpoint as well as every line breakpoint. We need to
      # implement that:
      #  - pass the indices in here
      #  - make _FindPostedBreakpoint also search function breakpionts
      #  - make sure that ConnectionClosed also cleares the server_bp data for
      #    function breakpionts
      #  - make sure that we have tests for this, because i'm sure we don't!
      self._connection.DoRequest(
        lambda msg: response_handler( msg ),
        {
          'command': 'setFunctionBreakpoints',
          'arguments': {
            'breakpoints': breakpoints,
          }
        },
        failure_handler = response_received
      )

    if self._exception_breakpoints:
      self._awaiting_bp_responses += 1
      self._connection.DoRequest(
        lambda msg: response_received(),
        {
          'command': 'setExceptionBreakpoints',
          'arguments': self._exception_breakpoints
        },
        failure_handler = response_received
      )

    if self._awaiting_bp_responses == 0 and doneHandler:
      doneHandler()
Exemple #14
0
 def _DeleteLineBreakpoint( self, bp, file_name, index ):
   if 'sign_id' in bp:
     signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
   del self._line_breakpoints[ utils.NormalizePath( file_name ) ][ index ]
Exemple #15
0
    def SendBreakpoints(self, doneHandler=None):
        assert self._breakpoints_handler is not None

        # Clear any existing breakpoints prior to sending new ones
        self._breakpoints_handler.ClearBreakpoints()

        awaiting = 0

        def response_received():
            nonlocal awaiting
            awaiting = awaiting - 1
            if awaiting == 0 and doneHandler:
                doneHandler()

        def response_handler(source, msg):
            if msg:
                self._breakpoints_handler.AddBreakpoints(source, msg)
            response_received()

        # NOTE: Must do this _first_ otherwise we might send requests and get
        # replies before we finished sending all the requests.
        if self._exception_breakpoints is None:
            self._SetUpExceptionBreakpoints(self._configured_breakpoints)

        # TODO: add the _configured_breakpoints to line_breakpoints
        # TODO: the line numbers might have changed since pressing the F9 key!

        for file_name, line_breakpoints in self._line_breakpoints.items():
            breakpoints = []
            for bp in line_breakpoints:
                self._SignToLine(file_name, bp)
                if 'sign_id' in bp:
                    signs.UnplaceSign(bp['sign_id'], 'VimspectorBP')
                    del bp['sign_id']

                if bp['state'] != 'ENABLED':
                    continue

                dap_bp = {}
                dap_bp.update(bp['options'])
                dap_bp.update({'line': bp['line']})
                breakpoints.append(dap_bp)

            source = {
                'name': os.path.basename(file_name),
                'path': file_name,
            }

            awaiting = awaiting + 1
            self._connection.DoRequest(
                # The source=source here is critical to ensure that we capture each
                # source in the iteration, rather than ending up passing the same source
                # to each callback.
                lambda msg, source=source: response_handler(source, msg),
                {
                    'command': 'setBreakpoints',
                    'arguments': {
                        'source': source,
                        'breakpoints': breakpoints,
                    },
                    'sourceModified':
                    False,  # TODO: We can actually check this
                },
                failure_handler=lambda *_: response_received())

        # TODO: Add the _configured_breakpoints to function breakpoints

        if self._server_capabilities.get('supportsFunctionBreakpoints'):
            awaiting = awaiting + 1
            breakpoints = []
            for bp in self._func_breakpoints:
                if bp['state'] != 'ENABLED':
                    continue
                dap_bp = {}
                dap_bp.update(bp['options'])
                dap_bp.update({'name': bp['function']})
                breakpoints.append(dap_bp)

            self._connection.DoRequest(
                lambda msg: response_handler(None, msg), {
                    'command': 'setFunctionBreakpoints',
                    'arguments': {
                        'breakpoints': breakpoints,
                    }
                },
                failure_handler=lambda *_: response_received())

        if self._exception_breakpoints:
            awaiting = awaiting + 1
            self._connection.DoRequest(
                lambda msg: response_handler(None, None), {
                    'command': 'setExceptionBreakpoints',
                    'arguments': self._exception_breakpoints
                },
                failure_handler=lambda *_: response_received())

        if awaiting == 0 and doneHandler:
            doneHandler()
Exemple #16
0
    def SendBreakpoints(self, doneHandler=None):
        assert self._breakpoints_handler is not None

        # Clear any existing breakpoints prior to sending new ones
        self._breakpoints_handler.ClearBreakpoints()

        awaiting = 0

        def response_received(*failure_args):
            nonlocal awaiting
            awaiting = awaiting - 1

            if failure_args and self._connection:
                reason, msg = failure_args
                utils.UserMessage(
                    'Unable to set breakpoint: {0}'.format(reason),
                    persist=True,
                    error=True)

            if awaiting == 0 and doneHandler:
                doneHandler()

        def response_handler(source, msg, temp_idxs=[]):
            if msg:
                self._breakpoints_handler.AddBreakpoints(source, msg)

                breakpoints = (msg.get('body') or {}).get('breakpoints') or []
                self._UpdateTemporaryBreakpoints(breakpoints, temp_idxs)
            response_received()

        # NOTE: Must do this _first_ otherwise we might send requests and get
        # replies before we finished sending all the requests.
        if self._exception_breakpoints is None:
            self._SetUpExceptionBreakpoints(self._configured_breakpoints)

        # TODO: add the _configured_breakpoints to line_breakpoints

        for file_name, line_breakpoints in self._line_breakpoints.items():
            temp_idxs = []
            breakpoints = []
            for bp in line_breakpoints:
                self._SignToLine(file_name, bp)
                if 'sign_id' in bp:
                    signs.UnplaceSign(bp['sign_id'], 'VimspectorBP')
                    del bp['sign_id']

                if bp['state'] != 'ENABLED':
                    continue

                dap_bp = {}
                dap_bp.update(bp['options'])
                dap_bp.update({'line': bp['line']})

                dap_bp.pop('temporary', None)

                if bp['options'].get('temporary'):
                    temp_idxs.append([len(breakpoints), bp])

                breakpoints.append(dap_bp)

            source = {
                'name': os.path.basename(file_name),
                'path': file_name,
            }

            awaiting = awaiting + 1
            self._connection.DoRequest(
                # The source=source here is critical to ensure that we capture each
                # source in the iteration, rather than ending up passing the same source
                # to each callback.
                lambda msg, source=source, temp_idxs=temp_idxs:
                response_handler(source, msg, temp_idxs=temp_idxs),
                {
                    'command': 'setBreakpoints',
                    'arguments': {
                        'source': source,
                        'breakpoints': breakpoints,
                    },
                    'sourceModified':
                    False,  # TODO: We can actually check this
                },
                failure_handler=response_received)

        # TODO: Add the _configured_breakpoints to function breakpoints

        if self._server_capabilities.get('supportsFunctionBreakpoints'):
            awaiting = awaiting + 1
            breakpoints = []
            for bp in self._func_breakpoints:
                if bp['state'] != 'ENABLED':
                    continue
                dap_bp = {}
                dap_bp.update(bp['options'])
                dap_bp.update({'name': bp['function']})
                breakpoints.append(dap_bp)

            self._connection.DoRequest(lambda msg: response_handler(None, msg),
                                       {
                                           'command': 'setFunctionBreakpoints',
                                           'arguments': {
                                               'breakpoints': breakpoints,
                                           }
                                       },
                                       failure_handler=response_received)

        if self._exception_breakpoints:
            awaiting = awaiting + 1
            self._connection.DoRequest(
                lambda msg: response_handler(None, None), {
                    'command': 'setExceptionBreakpoints',
                    'arguments': self._exception_breakpoints
                },
                failure_handler=response_received)

        if awaiting == 0 and doneHandler:
            doneHandler()