diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index 5f56f40e..7f0b09f7 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -23,11 +23,9 @@ set cpo&vim let s:script_folder_path = escape( expand( ':p:h' ), '\' ) let s:force_semantic = 0 let s:completion_stopped = 0 -let s:default_completion = { - \ 'start_column': -1, - \ 'candidates': [] - \ } -let s:completion = s:default_completion +" These two variables are initialized in youcompleteme#Enable. +let s:default_completion = {} +let s:completion = {} let s:previous_allowed_buffer_number = 0 let s:pollers = { \ 'completion': { @@ -147,6 +145,9 @@ function! youcompleteme#Enable() let s:pollers.server_ready.id = timer_start( \ s:pollers.server_ready.wait_milliseconds, \ function( 's:PollServerReady' ) ) + + let s:default_completion = s:Pyeval( 'vimsupport.NO_COMPLETIONS' ) + let s:completion = s:default_completion endfunction @@ -811,11 +812,7 @@ function! s:PollCompletion( ... ) return endif - let response = s:Pyeval( 'ycm_state.GetCompletionResponse()' ) - let s:completion = { - \ 'start_column': response.completion_start_column, - \ 'candidates': response.completions - \ } + let s:completion = s:Pyeval( 'ycm_state.GetCompletionResponse()' ) call s:Complete() endfunction @@ -824,16 +821,17 @@ function! s:Complete() " Do not call user's completion function if the start column is after the " current column or if there are no candidates. Close the completion menu " instead. This avoids keeping the user in completion mode. - if s:completion.start_column > col( '.' ) || empty( s:completion.candidates ) + if s:completion.completion_start_column > s:completion.column || + \ empty( s:completion.completions ) call s:CloseCompletionMenu() else " invokes the user's completion function (which we have set to " youcompleteme#CompleteFunc), and tells Vim to select the previous - " completion candidate. This is necessary because by default, Vim selects the - " first candidate when completion is invoked, and selecting a candidate - " automatically replaces the current text with it. Calling forces Vim to - " deselect the first candidate and in turn preserve the user's current text - " until he explicitly chooses to replace it with a completion. + " completion candidate. This is necessary because by default, Vim selects + " the first candidate when completion is invoked, and selecting a candidate + " automatically replaces the current text with it. Calling forces Vim + " to deselect the first candidate and in turn preserve the user's current + " text until he explicitly chooses to replace it with a completion. call s:SendKeys( "\\\" ) endif endfunction @@ -841,9 +839,25 @@ endfunction function! youcompleteme#CompleteFunc( findstart, base ) if a:findstart - return s:completion.start_column - 1 + " When auto-wrapping is enabled, Vim wraps the current line after the + " completion request is sent but before calling this function. The starting + " column returned by the server is invalid in that case and must be + " recomputed. + if s:completion.line != line( '.' ) + " Given + " scb: column where the completion starts before auto-wrapping + " cb: cursor column before auto-wrapping + " sca: column where the completion starts after auto-wrapping + " ca: cursor column after auto-wrapping + " we have + " ca - sca = cb - scb + " sca = scb + ca - cb + let s:completion.completion_start_column += + \ col( '.' ) - s:completion.column + endif + return s:completion.completion_start_column - 1 endif - return s:completion.candidates + return s:completion.completions endfunction diff --git a/python/ycm/client/completion_request.py b/python/ycm/client/completion_request.py index 5acefc24..4729571d 100644 --- a/python/ycm/client/completion_request.py +++ b/python/ycm/client/completion_request.py @@ -28,6 +28,7 @@ from ycmd.utils import ToUnicode from ycm.client.base_request import ( BaseRequest, DisplayServerException, MakeServerException ) from ycm import vimsupport +from ycm.vimsupport import NO_COMPLETIONS _logger = logging.getLogger( __name__ ) @@ -56,12 +57,12 @@ class CompletionRequest( BaseRequest ): def RawResponse( self ): if not self._response_future: - return { 'completions': [], 'completion_start_column': -1 } + return NO_COMPLETIONS response = self.HandleFuture( self._response_future, truncate_message = True ) if not response: - return { 'completions': [], 'completion_start_column': -1 } + return NO_COMPLETIONS # Vim may not be able to convert the 'errors' entry to its internal format # so we remove it from the response. @@ -71,6 +72,8 @@ class CompletionRequest( BaseRequest ): _logger.error( exception ) DisplayServerException( exception, truncate_message = True ) + response[ 'line' ] = self.request_data[ 'line_num' ] + response[ 'column' ] = self.request_data[ 'column_num' ] return response diff --git a/python/ycm/client/omni_completion_request.py b/python/ycm/client/omni_completion_request.py index 35b639ca..d27243cc 100644 --- a/python/ycm/client/omni_completion_request.py +++ b/python/ycm/client/omni_completion_request.py @@ -41,15 +41,19 @@ class OmniCompletionRequest( CompletionRequest ): def RawResponse( self ): return { - 'completions': _ConvertVimDatasToCompletionDatas( self._results ), - 'completion_start_column': self.request_data[ 'start_column' ] + 'line': self.request_data[ 'line_num' ], + 'column': self.request_data[ 'column_num' ], + 'completion_start_column': self.request_data[ 'start_column' ], + 'completions': _ConvertVimDatasToCompletionDatas( self._results ) } def Response( self ): return { - 'completions': self._results, - 'completion_start_column': self.request_data[ 'start_column' ] + 'line': self.request_data[ 'line_num' ], + 'column': self.request_data[ 'column_num' ], + 'completion_start_column': self.request_data[ 'start_column' ], + 'completions': self._results } diff --git a/python/ycm/tests/client/omni_completion_request_tests.py b/python/ycm/tests/client/omni_completion_request_tests.py index aba42412..d4ead04d 100644 --- a/python/ycm/tests/client/omni_completion_request_tests.py +++ b/python/ycm/tests/client/omni_completion_request_tests.py @@ -34,6 +34,8 @@ def BuildOmnicompletionRequest( results, start_column = 1 ): omni_completer.ComputeCandidates = MagicMock( return_value = results ) request_data = { + 'line_num': 1, + 'column_num': 1, 'start_column': start_column } request = OmniCompletionRequest( omni_completer, request_data ) @@ -53,8 +55,10 @@ def Response_FromOmniCompleter_test(): request = BuildOmnicompletionRequest( results ) eq_( request.Response(), { - 'completions': results, - 'completion_start_column': 1 + 'line': 1, + 'column': 1, + 'completion_start_column': 1, + 'completions': results } ) diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index 03c0f7f4..70ab6c3d 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -59,6 +59,13 @@ SIGN_ID_FOR_BUFFER = defaultdict( lambda: SIGN_BUFFER_ID_INITIAL_VALUE ) SIGN_PLACE_REGEX = re.compile( r"^.*=(?P\d+).*=(?P\d+).*=(?PYcm\w+)$" ) +NO_COMPLETIONS = { + 'line': -1, + 'column': -1, + 'completion_start_column': -1, + 'completions': [] +} + def CurrentLineAndColumn(): """Returns the 0-based current line and 0-based current column."""