From dca5682e21d688e070dfaaa76dde044bd33091e0 Mon Sep 17 00:00:00 2001 From: micbou Date: Thu, 9 Aug 2018 14:42:12 +0200 Subject: [PATCH] Move cursor to start column before calling again omnifunc 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. --- python/ycm/omni_completer.py | 17 ++++++++---- python/ycm/tests/omni_completer_test.py | 35 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) 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 ):