Пример #1
0
    def _GoToSymbol(self, request_data, args):
        request = self._DefaultParameters(request_data)
        request.update({'Language': 'C#', 'Filter': args[0]})
        response = self._GetResponse('/findsymbols', request)

        quickfixes = response['QuickFixes']
        if quickfixes:
            if len(quickfixes) == 1:
                ref = quickfixes[0]
                ref_file = ref['FileName']
                ref_line = ref['Line']
                lines = GetFileLines(request_data, ref_file)
                line = lines[min(len(lines), ref_line - 1)]
                return responses.BuildGoToResponseFromLocation(
                    _BuildLocation(request_data, ref_file, ref_line,
                                   ref['Column']), line)
            else:
                goto_locations = []
                for ref in quickfixes:
                    ref_file = ref['FileName']
                    ref_line = ref['Line']
                    lines = GetFileLines(request_data, ref_file)
                    line = lines[min(len(lines), ref_line - 1)]
                    goto_locations.append(
                        responses.BuildGoToResponseFromLocation(
                            _BuildLocation(request_data, ref_file, ref_line,
                                           ref['Column']), line))

                return goto_locations
        else:
            raise RuntimeError('No symbols found')
Пример #2
0
 def BuildFixItChunk(change):
     filepath = self._ServerPathToAbsolute(change['file'])
     file_contents = GetFileLines(request_data, filepath)
     return responses.FixItChunk(
         change['text'],
         BuildRange(file_contents, filepath, change['start'],
                    change['end']))
Пример #3
0
    def _CallHierarchy(self, request_data, args):
        self._Reload(request_data)

        response = self._SendRequest(
            f'provideCallHierarchy{ args[ 0 ] }Calls', {
                'file': request_data['filepath'],
                'line': request_data['line_num'],
                'offset': request_data['column_codepoint']
            })

        goto_response = []
        for hierarchy_item in response:
            description = hierarchy_item.get('from', hierarchy_item.get('to'))
            filepath = description['file']
            start_position = hierarchy_item['fromSpans'][0]['start']
            goto_line = start_position['line']
            try:
                line_value = GetFileLines(request_data,
                                          filepath)[goto_line - 1]
            except IndexError:
                continue
            goto_column = utils.CodepointOffsetToByteOffset(
                line_value, start_position['offset'])
            goto_response.append(
                responses.BuildGoToResponse(filepath, goto_line, goto_column,
                                            description['name']))

        if goto_response:
            return goto_response
        raise RuntimeError(f'No { args[ 0 ].lower() } calls found.')
Пример #4
0
  def _GoToSymbol( self, request_data, args ):
    if len( args ) < 1:
      raise RuntimeError( 'Must specify something to search for' )
    query = args[ 0 ]

    self._Reload( request_data )
    filespans = self._SendRequest( 'navto', {
      'searchValue': query,
      'file': request_data[ 'filepath' ]
    } )

    if not filespans:
      raise RuntimeError( 'Symbol not found' )

    results = [
      responses.BuildGoToResponseFromLocation(
        _BuildLocation( GetFileLines( request_data, fs[ 'file' ] ),
                        fs[ 'file' ],
                        fs[ 'start' ][ 'line' ],
                        fs[ 'start' ][ 'offset' ] ),
        fs[ 'name' ] )
      for fs in filespans
    ]

    if len( results ) == 1:
      return results[ 0 ]

    return results
Пример #5
0
    def _Format(self, request_data):
        filepath = request_data['filepath']

        self._Reload(request_data)

        # TODO: support all formatting options. See
        # https://github.com/Microsoft/TypeScript/blob/72e92a055823f1ade97d03d7526dbab8be405dde/lib/protocol.d.ts#L2060-L2077
        # for the list of options. While not standard, a way to support these
        # options, which is already adopted by a number of clients, would be to read
        # the "formatOptions" field in the tsconfig.json file.
        options = request_data['options']
        self._SendRequest(
            'configure', {
                'file': filepath,
                'formatOptions': {
                    'tabSize': options['tab_size'],
                    'indentSize': options['tab_size'],
                    'convertTabsToSpaces': options['insert_spaces'],
                }
            })

        response = self._SendRequest('format',
                                     _BuildTsFormatRange(request_data))

        contents = GetFileLines(request_data, filepath)
        chunks = [
            _BuildFixItChunkForRange(text_edit['newText'], contents, filepath,
                                     text_edit) for text_edit in response
        ]

        location = responses.Location(request_data['line_num'],
                                      request_data['column_num'], filepath)
        return responses.BuildFixItResponse(
            [responses.FixIt(location, chunks)])
Пример #6
0
def _BuildTsFormatRange(request_data):
    filepath = request_data['filepath']
    lines = GetFileLines(request_data, filepath)

    if 'range' not in request_data:
        return {
            'file': filepath,
            'line': 1,
            'offset': 1,
            'endLine': len(lines),
            'endOffset': len(lines[-1]) + 1
        }

    start = request_data['range']['start']
    start_line_num = start['line_num']
    start_line_value = lines[start_line_num - 1]
    start_codepoint = utils.ByteOffsetToCodepointOffset(
        start_line_value, start['column_num'])

    end = request_data['range']['end']
    end_line_num = end['line_num']
    end_line_value = lines[end_line_num - 1]
    end_codepoint = utils.ByteOffsetToCodepointOffset(end_line_value,
                                                      end['column_num'])

    return {
        'file': filepath,
        'line': start_line_num,
        'offset': start_codepoint,
        'endLine': end_line_num,
        'endOffset': end_codepoint
    }
Пример #7
0
 def BuildRefResponse( ref ):
   filepath = self._ServerPathToAbsolute( ref[ 'file' ] )
   return responses.BuildGoToResponseFromLocation(
     _BuildLocation( GetFileLines( request_data, filepath ),
       filepath,
       ref[ 'start' ][ 'line' ],
       ref[ 'start' ][ 'ch' ] ) )
Пример #8
0
def _BuildFixItChunksForFile( request_data, new_name, file_replacement ):
  """Returns a list of FixItChunk for each replacement range for the supplied
  file."""
  # On Windows, TSServer annoyingly returns file path as C:/blah/blah,
  # whereas all other paths in Python are of the C:\\blah\\blah form. We use
  # normpath to have python do the conversion for us.
  file_path = os.path.normpath( file_replacement[ 'file' ] )
  file_contents = GetFileLines( request_data, file_path )
  return [ _BuildFixItChunkForRange( new_name, file_contents, file_path, r )
           for r in file_replacement[ 'locs' ] ]
Пример #9
0
    def _TsDiagnosticToYcmdDiagnostic(self, request_data, ts_diagnostic):
        filepath = request_data['filepath']

        ts_fixes = self._SendRequest(
            'getCodeFixes', {
                'file': filepath,
                'startLine': ts_diagnostic['startLocation']['line'],
                'startOffset': ts_diagnostic['startLocation']['offset'],
                'endLine': ts_diagnostic['endLocation']['line'],
                'endOffset': ts_diagnostic['endLocation']['offset'],
                'errorCodes': [ts_diagnostic['code']]
            })
        location = responses.Location(request_data['line_num'],
                                      request_data['column_num'], filepath)

        fixits = []
        for fix in ts_fixes:
            description = fix['description']
            # TSServer returns these fixits for every error in JavaScript files.
            # Ignore them since they are not useful.
            if description in [
                    'Ignore this error message',
                    'Disable checking for this file'
            ]:
                continue

            fixit = responses.FixIt(
                location, _BuildFixItForChanges(request_data, fix['changes']),
                description)
            fixits.append(fixit)

        contents = GetFileLines(request_data, filepath)

        ts_start_location = ts_diagnostic['startLocation']
        ts_start_line = ts_start_location['line']
        start_offset = utils.CodepointOffsetToByteOffset(
            contents[ts_start_line - 1], ts_start_location['offset'])

        ts_end_location = ts_diagnostic['endLocation']
        ts_end_line = ts_end_location['line']
        end_offset = utils.CodepointOffsetToByteOffset(
            contents[ts_end_line - 1], ts_end_location['offset'])

        location_start = responses.Location(ts_start_line, start_offset,
                                            filepath)
        location_end = responses.Location(ts_end_line, end_offset, filepath)

        location_extent = responses.Range(location_start, location_end)

        return responses.Diagnostic([location_extent],
                                    location_start,
                                    location_extent,
                                    ts_diagnostic['message'],
                                    'ERROR',
                                    fixits=fixits)
Пример #10
0
    def _GoToDefinition(self, request_data):
        query = {
            'type': 'definition',
        }

        response = self._GetResponse(query, request_data['column_codepoint'],
                                     request_data)

        filepath = self._ServerPathToAbsolute(response['file'])
        return responses.BuildGoToResponseFromLocation(
            _BuildLocation(GetFileLines(request_data, filepath), filepath,
                           response['start']['line'], response['start']['ch']))
Пример #11
0
def _BuildLocation(request_data, filename, line_num, column_num):
    if line_num <= 0:
        return None
    # OmniSharp sometimes incorrectly returns 0 for the column number. Assume the
    # column is 1 in that case.
    if column_num <= 0:
        column_num = 1
    contents = GetFileLines(request_data, filename)
    line_value = contents[line_num - 1]
    return responses.Location(
        line_num, CodepointOffsetToByteOffset(line_value, column_num),
        filename)
Пример #12
0
def _BuildFixItForChanges(request_data, changes):
    """Returns a list of FixItChunk given a list of TSServer changes."""
    chunks = []
    for change in changes:
        # On Windows, TSServer annoyingly returns file path as C:/blah/blah,
        # whereas all other paths in Python are of the C:\\blah\\blah form. We use
        # normpath to have python do the conversion for us.
        file_path = os.path.normpath(change['fileName'])
        file_contents = GetFileLines(request_data, file_path)
        for text_change in change['textChanges']:
            chunks.append(
                _BuildFixItChunkForRange(text_change['newText'], file_contents,
                                         file_path, text_change))
    return chunks
Пример #13
0
 def _GoToReferences(self, request_data):
     self._Reload(request_data)
     response = self._SendRequest(
         'references', {
             'file': request_data['filepath'],
             'line': request_data['line_num'],
             'offset': request_data['column_codepoint']
         })
     return [
         responses.BuildGoToResponseFromLocation(
             _BuildLocation(GetFileLines(request_data, ref['file']),
                            ref['file'], ref['start']['line'],
                            ref['start']['offset']), ref['lineText'])
         for ref in response['refs']
     ]
Пример #14
0
  def _TsDiagnosticToYcmdDiagnostic( self, request_data, ts_diagnostic ):
    filepath = request_data[ 'filepath' ]

    ts_fixes = self._SendRequest( 'getCodeFixes', {
      'file':        filepath,
      'startLine':   ts_diagnostic[ 'startLocation' ][ 'line' ],
      'startOffset': ts_diagnostic[ 'startLocation' ][ 'offset' ],
      'endLine':     ts_diagnostic[ 'endLocation' ][ 'line' ],
      'endOffset':   ts_diagnostic[ 'endLocation' ][ 'offset' ],
      'errorCodes':  [ ts_diagnostic[ 'code' ] ]
    } )
    location = responses.Location( request_data[ 'line_num' ],
                                   request_data[ 'column_num' ],
                                   filepath )

    fixits = [ responses.FixIt( location,
                                _BuildFixItForChanges( request_data,
                                                       fix[ 'changes' ] ),
                                fix[ 'description' ] )
               for fix in ts_fixes ]

    contents = GetFileLines( request_data, filepath )

    ts_start_location = ts_diagnostic[ 'startLocation' ]
    ts_start_line = ts_start_location[ 'line' ]
    start_offset = utils.CodepointOffsetToByteOffset(
      contents[ ts_start_line - 1 ],
      ts_start_location[ 'offset' ] )

    ts_end_location = ts_diagnostic[ 'endLocation' ]
    ts_end_line = ts_end_location[ 'line' ]
    end_offset = utils.CodepointOffsetToByteOffset(
      contents[ ts_end_line - 1 ],
      ts_end_location[ 'offset' ] )

    location_start = responses.Location( ts_start_line, start_offset, filepath )
    location_end = responses.Location( ts_end_line, end_offset, filepath )

    location_extent = responses.Range( location_start, location_end )

    return responses.Diagnostic( [ location_extent ],
                                 location_start,
                                 location_extent,
                                 ts_diagnostic[ 'message' ],
                                 'ERROR',
                                 fixits = fixits )
Пример #15
0
    def _GoToDefinition(self, request_data):
        self._Reload(request_data)
        filespans = self._SendRequest(
            'definition', {
                'file': request_data['filepath'],
                'line': request_data['line_num'],
                'offset': request_data['column_codepoint']
            })

        if not filespans:
            raise RuntimeError('Could not find definition.')

        span = filespans[0]
        return responses.BuildGoToResponseFromLocation(
            _BuildLocation(GetFileLines(request_data,
                                        span['file']), span['file'],
                           span['start']['line'], span['start']['offset']))
Пример #16
0
  def _GoToImplementation( self, request_data ):
    self._Reload( request_data )
    try:
      filespans = self._SendRequest( 'implementation', {
        'file':   request_data[ 'filepath' ],
        'line':   request_data[ 'line_num' ],
        'offset': request_data[ 'column_codepoint' ]
      } )
    except RuntimeError:
      raise RuntimeError( 'No implementation found.' )

    results = []
    for span in filespans:
      filename = span[ 'file' ]
      start = span[ 'start' ]
      lines = GetFileLines( request_data, span[ 'file' ] )
      line_num = start[ 'line' ]
      results.append( responses.BuildGoToResponseFromLocation(
        _BuildLocation( lines, filename, line_num, start[ 'offset' ] ),
        lines[ line_num - 1 ] ) )
    return results
Пример #17
0
    def GetDetailedDiagnostic(self, request_data):
        self._UpdateServerWithFileContents(request_data)

        current_line_lsp = request_data['line_num'] - 1
        current_file = request_data['filepath']

        if not self._latest_diagnostics:
            return responses.BuildDisplayMessageResponse(
                'Diagnostics are not ready yet.')

        with self._server_info_mutex:
            diagnostics = list(
                self._latest_diagnostics[lsp.FilePathToUri(current_file)])

        if not diagnostics:
            return responses.BuildDisplayMessageResponse(
                'No diagnostics for current file.')

        current_column = lsp.CodepointsToUTF16CodeUnits(
            GetFileLines(request_data, current_file)[current_line_lsp],
            request_data['column_codepoint'])
        minimum_distance = None

        message = 'No diagnostics for current line.'
        for diagnostic in diagnostics:
            start = diagnostic['range']['start']
            end = diagnostic['range']['end']
            if current_line_lsp < start['line'] or end[
                    'line'] < current_line_lsp:
                continue
            point = {'line': current_line_lsp, 'character': current_column}
            distance = DistanceOfPointToRange(point, diagnostic['range'])
            if minimum_distance is None or distance < minimum_distance:
                message = diagnostic['message']
                if distance == 0:
                    break
                minimum_distance = distance

        return responses.BuildDisplayMessageResponse(message)