Skip to content

Commit

Permalink
Add support for file operations in CodeActions
Browse files Browse the repository at this point in the history
  • Loading branch information
bstaletic committed Oct 13, 2024
1 parent 47371eb commit 39e7d9a
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 14 deletions.
28 changes: 22 additions & 6 deletions ycmd/completers/language_server/language_server_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3590,21 +3590,37 @@ def WorkspaceEditToFixIt( request_data,
if not workspace_edit:
return None

chunks = []
if 'changes' in workspace_edit:
chunks = []
# We sort the filenames to make the response stable. Edits are applied in
# strict sequence within a file, but apply to files in arbitrary order.
# However, it's important for the response to be stable for the tests.
for uri in sorted( workspace_edit[ 'changes' ].keys() ):
chunks.extend( TextEditToChunks( request_data,
uri,
workspace_edit[ 'changes' ][ uri ] ) )
else:
chunks = []
if 'documentChanges' in workspace_edit:
for text_document_edit in workspace_edit[ 'documentChanges' ]:
uri = text_document_edit[ 'textDocument' ][ 'uri' ]
edits = text_document_edit[ 'edits' ]
chunks.extend( TextEditToChunks( request_data, uri, edits ) )
kind = text_document_edit.get( 'kind', '' )
if 'edits' in text_document_edit:
uri = text_document_edit[ 'textDocument' ][ 'uri' ]
edits = text_document_edit[ 'edits' ]
chunks.extend( TextEditToChunks( request_data, uri, edits ) )
elif kind == 'rename':
chunks.append(
responses.RenameChunk(
old_filepath = lsp.UriToFilePath(
text_document_edit[ 'oldUri' ] ),
new_filepath = lsp.UriToFilePath(
text_document_edit[ 'newUri' ] ) ) )
elif kind == 'delete':
chunks.append(
responses.DeleteChunk(
lsp.UriToFilePath( text_document_edit[ 'uri' ] ) ) )
elif kind == 'create':
chunks.append(
responses.CreateChunk(
lsp.UriToFilePath( text_document_edit[ 'uri' ] ) ) )
return responses.FixIt(
responses.Location( request_data[ 'line_num' ],
request_data[ 'column_num' ],
Expand Down
6 changes: 5 additions & 1 deletion ycmd/completers/language_server/language_server_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,11 @@ def Initialize( request_id,
'didChangeWatchedFiles': {
'dynamicRegistration': True
},
'workspaceEdit': { 'documentChanges': True, },
'workspaceEdit': {
'resourceOperations': [ 'create', 'rename', 'delete' ],
'documentChanges': True,
'failureHandling': 'abort'
},
'symbol': {
'symbolKind': {
'valueSet': list( range( 1, len( SYMBOL_KIND ) ) ),
Expand Down
52 changes: 45 additions & 7 deletions ycmd/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,44 @@ def __init__( self, location: Location, chunks, text = '', kind = None ):
self.kind = kind


class DeleteChunk:
def __init__( self, filepath ):
self.filepath = filepath
self.kind = 'delete'

def ToYcmdProtocol( self ):
return {
'filepath': self.filepath,
'kind': self.kind
}


class CreateChunk:
def __init__( self, filepath ):
self.filepath = filepath
self.kind = 'create'

def ToYcmdProtocol( self ):
return {
'filepath': self.filepath,
'kind': self.kind
}


class RenameChunk:
def __init__( self, old_filepath, new_filepath ):
self.old_filepath = old_filepath
self.new_filepath = new_filepath
self.kind = 'rename'

def ToYcmdProtocol( self ):
return {
'new_filepath': self.new_filepath,
'old_filepath': self.old_filepath,
'kind': self.kind
}


class FixItChunk:
"""An individual replacement within a FixIt (aka Refactor)"""

Expand All @@ -276,6 +314,12 @@ def __init__( self, replacement_text: str, range: Range ):
self.replacement_text = replacement_text
self.range = range

def ToYcmdProtocol( self ):
return {
'replacement_text': self.replacement_text,
'range': BuildRangeData( self.range ),
}


def BuildDiagnosticData( diagnostic ):
kind = ( diagnostic.kind_.name if hasattr( diagnostic.kind_, 'name' )
Expand Down Expand Up @@ -314,12 +358,6 @@ def BuildFixItResponse( fixits ):
can be used to apply arbitrary changes to arbitrary files and is suitable for
both quick fix and refactor operations"""

def BuildFixitChunkData( chunk ):
return {
'replacement_text': chunk.replacement_text,
'range': BuildRangeData( chunk.range ),
}

def BuildFixItData( fixit ):
if hasattr( fixit, 'resolve' ):
result = {
Expand All @@ -331,7 +369,7 @@ def BuildFixItData( fixit ):
else:
result = {
'location': BuildLocationData( fixit.location ),
'chunks' : [ BuildFixitChunkData( x ) for x in fixit.chunks ],
'chunks' : [ x.ToYcmdProtocol() for x in fixit.chunks ],
'text': fixit.text,
'kind': fixit.kind,
'resolve': False
Expand Down

0 comments on commit 39e7d9a

Please sign in to comment.