Skip to content

Commit

Permalink
Merge branches 'pm-master-commits' and 'snippets'
Browse files Browse the repository at this point in the history
  • Loading branch information
puremourning committed Dec 29, 2023
2 parents 11dc296 + 141121d commit 5c0dd73
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 47 deletions.
2 changes: 2 additions & 0 deletions cpp/ycm/ClangCompleter/FixIt.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ struct FixIt {
/// multiple diagnostics offering different fixit options. The text is
/// displayed to the user, allowing them choose which diagnostic to apply.
std::string text;

bool is_completion{ false };
};

} // namespace YouCompleteMe
Expand Down
3 changes: 2 additions & 1 deletion cpp/ycm/ycm_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ PYBIND11_MODULE( ycm_core, mod )
.def_readonly( "text", &FixIt::text )
.def_property_readonly( "kind", [](const py::handle) {
return py::none();
});
})
.def_readonly( "is_completion", &FixIt::is_completion );

py::bind_vector< std::vector< FixIt > >( mod, "FixItVector" );

Expand Down
87 changes: 45 additions & 42 deletions ycmd/completers/language_server/language_server_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ def _CandidatesFromCompletionItems( self,
this_tem_is_resolved = True

try:
insertion_text, extra_data, start_codepoint = (
insertion_text, snippet, extra_data, start_codepoint = (
_InsertionTextForItem( request_data, item ) )
except IncompatibleCompletionException:
LOGGER.exception( 'Ignoring incompatible completion suggestion %s',
Expand All @@ -1465,6 +1465,13 @@ def _CandidatesFromCompletionItems( self,
# We'll use this later to do the resolve.
extra_data[ 'item' ] = item

if snippet:
extra_data = {} if extra_data is None else extra_data
extra_data[ 'snippet' ] = {
'snippet': snippet,
'trigger_string': insertion_text
}

min_start_codepoint = min( min_start_codepoint, start_codepoint )

# Build a ycmd-compatible completion for the text as we received it. Later
Expand Down Expand Up @@ -2330,9 +2337,11 @@ def _SendInitialize( self, request_data ):
# the settings on the Initialize request are somehow subtly different from
# the settings supplied in didChangeConfiguration, though it's not exactly
# clear how/where that is specified.
extra_capabilities = self._settings.get( 'capabilities' , {} )
extra_capabilities.update( self.ExtraCapabilities() )
msg = lsp.Initialize( request_id,
self._project_directory,
self.ExtraCapabilities(),
extra_capabilities,
self._settings.get( 'ls', {} ) )

def response_handler( response, message ):
Expand Down Expand Up @@ -3006,32 +3015,32 @@ def _InsertionTextForItem( request_data, item ):
Returns a tuple (
- insertion_text = the text to insert
- snippet = optional snippet text
- fixits = ycmd fixit which needs to be applied additionally when
selecting this completion
- start_codepoint = the start column at which the text should be inserted
)"""
# We do not support completion types of "Snippet". This is implicit in that we
# don't say it is a "capability" in the initialize request.
# Abort this request if the server is buggy and ignores us.
assert lsp.INSERT_TEXT_FORMAT[
item.get( 'insertTextFormat' ) or 1 ] == 'PlainText'

fixits = None

start_codepoint = request_data[ 'start_codepoint' ]
label = item[ 'label' ]
insertion_text_is_snippet = False
# We will always have one of insertText or label
if 'insertText' in item and item[ 'insertText' ]:
# 1 = PlainText
# 2 = Snippet
if lsp.INSERT_TEXT_FORMAT[ item.get( 'insertTextFormat', 1 ) ] == 'Snippet':
insertion_text_is_snippet = True

insertion_text = item[ 'insertText' ]
else:
insertion_text = item[ 'label' ]

additional_text_edits = []
fixits = []
filepath = request_data[ 'filepath' ]
contents = None

# Per the protocol, textEdit takes precedence over insertText, and must be
# on the same line (and containing) the originally requested position. These
# are a pain, and require fixing up later in some cases, as most of our
# clients won't be able to apply arbitrary edits (only 'completion', as
# opposed to 'content assist').
# Per the protocol, textEdit takes precedence over insertText, and the initial
# range of the edit must be on the same line (and containing) the originally
# requested position.
if 'textEdit' in item and item[ 'textEdit' ]:
text_edit = item[ 'textEdit' ]
start_codepoint = _GetCompletionItemStartCodepointOrReject( text_edit,
Expand All @@ -3040,25 +3049,13 @@ def _InsertionTextForItem( request_data, item ):
insertion_text = text_edit[ 'newText' ]

if '\n' in insertion_text:
# jdt.ls can return completions which generate code, such as
# getters/setters and entire anonymous classes.
#
# In order to support this we would need to do something like:
# - invent some insertion_text based on label/insertText (or perhaps
# '<snippet>'
# - insert a textEdit in additionalTextEdits which deletes this
# insertion
# - or perhaps just modify this textEdit to undo that change?
# - or perhaps somehow support insertion_text of '' (this doesn't work
# because of filtering/sorting, etc.).
# - insert this textEdit in additionalTextEdits
#
# These textEdits would need a lot of fixing up and is currently out of
# scope.
#
# These sorts of completions aren't really in the spirit of ycmd at the
# moment anyway. So for now, we just ignore this candidate.
raise IncompatibleCompletionException( insertion_text )
# If there's a newline in the completion, we have to use a snippet engine
# because Vim (the main client) doesn't support completions with multiple
# lines in them, but given that snippet completions work, we can just
# assume this is a snippet without tabstops...
# The main issue is that if the competion does contain things that look
# like tabstops...
insertion_text_is_snippet = True
else:
# Calculate the start codepoint based on the overlapping text in the
# insertion text and the existing text. This is the behavior of Visual
Expand All @@ -3067,21 +3064,27 @@ def _InsertionTextForItem( request_data, item ):
start_codepoint -= FindOverlapLength( request_data[ 'prefix' ],
insertion_text )

additional_text_edits.extend( item.get( 'additionalTextEdits' ) or [] )

additional_text_edits = item.get( 'additionalTextEdits' ) or []
if additional_text_edits:
filepath = request_data[ 'filepath' ]
contents = GetFileLines( request_data, filepath )

# We might have already extracted the contents
if contents is None:
contents = GetFileLines( request_data, filepath )

chunks = [ responses.FixItChunk( e[ 'newText' ],
_BuildRange( contents,
filepath,
e[ 'range' ] ) )
for e in additional_text_edits ]

fixits = responses.BuildFixItResponse(
[ responses.FixIt( chunks[ 0 ].range.start_, chunks ) ] )
fixits.append( responses.FixIt( chunks[ 0 ].range.start_, chunks ) )

extra_data = responses.BuildFixItResponse( fixits ) if fixits else None

if insertion_text_is_snippet:
return label, insertion_text, extra_data, start_codepoint

return insertion_text, fixits, start_codepoint
return insertion_text, None, extra_data, start_codepoint


def FindOverlapLength( line_value, insertion_text ):
Expand Down
13 changes: 10 additions & 3 deletions ycmd/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,12 +260,18 @@ class Kind:
REFACTOR = 'refactor'


def __init__( self, location: Location, chunks, text = '', kind = None ):
def __init__( self,
location: Location,
chunks,
text = '',
kind = None,
is_completion = False ):
"""location of type Location, chunks of type list<FixItChunk>"""
self.location = location
self.chunks = chunks
self.text = text
self.kind = kind
self.is_completion = is_completion


class FixItChunk:
Expand Down Expand Up @@ -326,15 +332,16 @@ def BuildFixItData( fixit ):
'command': fixit.command,
'text': fixit.text,
'kind': fixit.kind,
'resolve': fixit.resolve
'resolve': fixit.resolve,
}
else:
result = {
'location': BuildLocationData( fixit.location ),
'chunks' : [ BuildFixitChunkData( x ) for x in fixit.chunks ],
'text': fixit.text,
'kind': fixit.kind,
'resolve': False
'resolve': False,
'is_completion': fixit.is_completion,
}

if result[ 'kind' ] is None:
Expand Down
11 changes: 10 additions & 1 deletion ycmd/tests/java/testdata/extra_confs/.ycm_extra_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@ def Settings( **kwargs ):
assert kwargs[ 'language' ] == 'java'
return {
'ls': { 'java.rename.enabled' : False },
'formatting_options': { 'org.eclipse.jdt.core.formatter.lineSplit': 30, }
'formatting_options': { 'org.eclipse.jdt.core.formatter.lineSplit': 30, },
# 'capabilities': {
# 'textDocument': {
# 'completion': {
# 'completionItem': {
# 'snippetSupport': True
# }
# }
# }
# }
}

0 comments on commit 5c0dd73

Please sign in to comment.