diff --git a/python/ycm/omni_completer.py b/python/ycm/omni_completer.py index d40da07b..4fc98bfc 100644 --- a/python/ycm/omni_completer.py +++ b/python/ycm/omni_completer.py @@ -79,17 +79,18 @@ class OmniCompleter( Completer ): return [] try: - return_value = vimsupport.GetIntValue( self._omnifunc + '(1,"")' ) - if return_value < 0: - # FIXME: Technically, if the return is -1 we should raise an error + start_column = vimsupport.GetIntValue( self._omnifunc + '(1,"")' ) + if start_column < 0: + # FIXME: Technically, if the returned value is -1 we should raise an + # error. return [] # Use the start column calculated by the omnifunc, rather than our own # interpretation. This is important for certain languages where our # identifier detection is either incorrect or not compatible with the # behaviour of the omnifunc. Note: do this before calling the omnifunc - # because it affects the value returned by 'query' - request_data[ 'start_column' ] = return_value + 1 + # because it affects the value returned by 'query'. + request_data[ 'start_column' ] = start_column + 1 # Calling directly the omnifunc may move the cursor position. This is the # case with the default Vim omnifunc for C-family languages @@ -99,6 +100,12 @@ class OmniCompleter( Completer ): # So, we restore the cursor position after calling the omnifunc. line, column = vimsupport.CurrentLineAndColumn() + # Vim internally moves the cursor to the start column before calling again + # the omnifunc. Some omnifuncs like the one defined by the + # LanguageClient-neovim plugin depend on this behavior to compute the list + # of candidates. + vimsupport.SetCurrentLineAndColumn( line, start_column ) + omnifunc_call = [ self._omnifunc, "(0,'", vimsupport.EscapeForVim( request_data[ 'query' ] ), diff --git a/python/ycm/tests/omni_completer_test.py b/python/ycm/tests/omni_completer_test.py index 9ddd9c52..59e633f4 100644 --- a/python/ycm/tests/omni_completer_test.py +++ b/python/ycm/tests/omni_completer_test.py @@ -649,6 +649,41 @@ def OmniCompleter_GetCompletions_RestoreCursorPositionAfterOmnifuncCall_test( ) +@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1, + 'g:ycm_semantic_triggers': TRIGGERS } ) +def OmniCompleter_GetCompletions_MoveCursorPositionAtStartColumn_test( ycm ): + # This omnifunc relies on the cursor being moved at the start column when + # called the second time like LanguageClient#complete from the + # LanguageClient-neovim plugin. + def Omnifunc( findstart, base ): + if findstart: + return 5 + if vimsupport.CurrentColumn() == 5: + return [ 'length' ] + return [] + + current_buffer = VimBuffer( 'buffer', + contents = [ 'String test', + '', + 'test.le' ], + filetype = FILETYPE, + omnifunc = Omnifunc ) + + with MockVimBuffers( [ current_buffer ], [ current_buffer ], ( 3, 7 ) ): + ycm.SendCompletionRequest() + assert_that( + vimsupport.CurrentLineAndColumn(), + contains( 2, 7 ) + ) + assert_that( + ycm.GetCompletionResponse(), + has_entries( { + 'completions': ToBytesOnPY2( [ 'length' ] ), + 'completion_start_column': 6 + } ) + ) + + @YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0, 'g:ycm_semantic_triggers': TRIGGERS } ) def OmniCompleter_GetCompletions_NoCache_NoSemanticTrigger_test( ycm ):