From 3b115831a07f2bea861861b8924ad6ea027862a7 Mon Sep 17 00:00:00 2001 From: micbou Date: Tue, 27 Mar 2018 03:22:31 +0200 Subject: [PATCH] Fix applying fixit twice after completion --- python/ycm/client/completion_request.py | 78 ++++++----------------- python/ycm/tests/postcomplete_test.py | 83 +++++++------------------ 2 files changed, 39 insertions(+), 122 deletions(-) diff --git a/python/ycm/client/completion_request.py b/python/ycm/client/completion_request.py index 6038ed66..dbd2b3b6 100644 --- a/python/ycm/client/completion_request.py +++ b/python/ycm/client/completion_request.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 Google Inc. +# Copyright (C) 2013-2018 YouCompleteMe contributors # # This file is part of YouCompleteMe. # @@ -93,34 +93,21 @@ class CompletionRequest( BaseRequest ): def _GetCompletionsUserMayHaveCompleted( self ): completed_item = vimsupport.GetVariableValue( 'v:completed_item' ) - completions = self.RawResponse()[ 'completions' ] - if 'user_data' in completed_item and completed_item[ 'user_data' ]: - # Vim supports user_data (8.0.1493) or later, so we actually know the - # _exact_ element that was selected, having put its index in the - # user_data field. + # If Vim supports user_data (8.0.1493 or later), we actually know the + # _exact_ element that was selected, having put its index in the + # user_data field. Otherwise, we have to guess by matching the values in the + # completed item and the list of completions. Sometimes this returns + # multiple possibilities, which is essentially unresolvable. + if 'user_data' not in completed_item: + completions = self.RawResponse()[ 'completions' ] + return _FilterToMatchingCompletions( completed_item, completions ) + + if completed_item[ 'user_data' ]: + completions = self.RawResponse()[ 'completions' ] return [ completions[ int( completed_item[ 'user_data' ] ) ] ] - # Otherwise, we have to guess by matching the values in the completed item - # and the list of completions. Sometimes this returns multiple - # possibilities, which is essentially unresolvable. - - result = _FilterToMatchingCompletions( completed_item, completions, True ) - result = list( result ) - - if result: - return result - - if _HasCompletionsThatCouldBeCompletedWithMoreText( completed_item, - completions ): - # Since the way that YCM works leads to CompleteDone called on every - # character, return blank if the completion might not be done. This won't - # match if the completion is ended with typing a non-keyword character. - return [] - - result = _FilterToMatchingCompletions( completed_item, completions, False ) - - return list( result ) + return [] def _OnCompleteDone_Csharp( self ): @@ -178,13 +165,10 @@ def _GetFixItCompletion( completion ): return completion[ 'extra_data' ][ 'fixits' ] -def _FilterToMatchingCompletions( completed_item, - completions, - full_match_only ): +def _FilterToMatchingCompletions( completed_item, completions ): """Filter to completions matching the item Vim said was completed""" - match_keys = ( [ 'word', 'abbr', 'menu', 'info' ] if full_match_only - else [ 'word' ] ) - + match_keys = [ 'word', 'abbr', 'menu', 'info' ] + matched_completions = [] for index, completion in enumerate( completions ): item = _ConvertCompletionDataToVimData( index, completion ) @@ -193,34 +177,8 @@ def _FilterToMatchingCompletions( completed_item, ToUnicode( item.get( key, "" ) ) ) if all( [ matcher( i ) for i in match_keys ] ): - yield completion - - -def _HasCompletionsThatCouldBeCompletedWithMoreText( completed_item, - completions ): - if not completed_item: - return False - - completed_word = ToUnicode( completed_item[ 'word' ] ) - if not completed_word: - return False - - # Sometimes CompleteDone is called after the next character is inserted. - # If so, use inserted character to filter possible completions further. - text = vimsupport.TextBeforeCursor() - reject_exact_match = True - if text and text[ -1 ] != completed_word[ -1 ]: - reject_exact_match = False - completed_word += text[ -1 ] - - for index, completion in enumerate( completions ): - word = ToUnicode( - _ConvertCompletionDataToVimData( index, completion )[ 'word' ] ) - if reject_exact_match and word == completed_word: - continue - if word.startswith( completed_word ): - return True - return False + matched_completions.append( completion ) + return matched_completions def _ConvertCompletionDataToVimData( completion_identifier, completion_data ): diff --git a/python/ycm/tests/postcomplete_test.py b/python/ycm/tests/postcomplete_test.py index d76e7596..813dc39b 100644 --- a/python/ycm/tests/postcomplete_test.py +++ b/python/ycm/tests/postcomplete_test.py @@ -33,11 +33,9 @@ from nose.tools import eq_, ok_ from ycm import vimsupport from ycmd.utils import ToBytes -from ycm.client.completion_request import ( - CompletionRequest, - _FilterToMatchingCompletions, - _GetRequiredNamespaceImport, - _HasCompletionsThatCouldBeCompletedWithMoreText ) +from ycm.client.completion_request import ( CompletionRequest, + _FilterToMatchingCompletions, + _GetRequiredNamespaceImport ) def CompleteItemIs( word, abbr = None, menu = None, @@ -185,88 +183,36 @@ def OnCompleteDone_NoActionIfNotDone_test( *args ): def FilterToCompletedCompletions_MatchIsReturned_test(): completions = [ BuildCompletion( insertion_text = 'Test' ) ] - result = _FilterToMatchingCompletions( CompleteItemIs( 'Test' ), - completions, - False ) + result = _FilterToMatchingCompletions( CompleteItemIs( 'Test' ), completions ) eq_( list( result ), completions ) def FilterToCompletedCompletions_ShortTextDoesntRaise_test(): completions = [ BuildCompletion( insertion_text = 'AAA' ) ] - result = _FilterToMatchingCompletions( CompleteItemIs( 'A' ), - completions, - False ) + result = _FilterToMatchingCompletions( CompleteItemIs( 'A' ), completions ) eq_( list( result ), [] ) def FilterToCompletedCompletions_ExactMatchIsReturned_test(): completions = [ BuildCompletion( insertion_text = 'Test' ) ] - result = _FilterToMatchingCompletions( CompleteItemIs( 'Test' ), - completions, - False ) + result = _FilterToMatchingCompletions( CompleteItemIs( 'Test' ), completions ) eq_( list( result ), completions ) def FilterToCompletedCompletions_NonMatchIsntReturned_test(): completions = [ BuildCompletion( insertion_text = 'A' ) ] result = _FilterToMatchingCompletions( CompleteItemIs( ' Quote' ), - completions, - False ) + completions ) eq_( list( result ), [] ) def FilterToCompletedCompletions_Unicode_test(): completions = [ BuildCompletion( insertion_text = '†es†' ) ] result = _FilterToMatchingCompletions( CompleteItemIs( '†es†' ), - completions, - False ) + completions ) eq_( list( result ), completions ) -@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' ) -def HasCompletionsThatCouldBeCompletedWithMoreText_MatchIsReturned_test( - *args ): - completions = [ BuildCompletion( insertion_text = 'Test' ) ] - ok_( _HasCompletionsThatCouldBeCompletedWithMoreText( CompleteItemIs( 'Te' ), - completions ) ) - - -@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' ) -def HasCompletionsThatCouldBeCompletedWithMoreText_ShortTextDoesntRaise_test( - *args ): - completions = [ BuildCompletion( insertion_text = 'AAA' ) ] - ok_( not _HasCompletionsThatCouldBeCompletedWithMoreText( - CompleteItemIs( 'X' ), - completions ) ) - - -@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' ) -def HasCompletionsThatCouldBeCompletedWithMoreText_ExactMatchIsntReturned_test( - *args ): - completions = [ BuildCompletion( insertion_text = 'Test' ) ] - ok_( not _HasCompletionsThatCouldBeCompletedWithMoreText( - CompleteItemIs( 'Test' ), - completions ) ) - - -@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = ' Quote' ) -def HasCompletionsThatCouldBeCompletedWithMoreText_NonMatchIsntReturned_test( - *args ): - completions = [ BuildCompletion( insertion_text = "A" ) ] - ok_( not _HasCompletionsThatCouldBeCompletedWithMoreText( - CompleteItemIs( ' Quote' ), - completions ) ) - - -@patch( 'ycm.vimsupport.TextBeforeCursor', return_value = 'Uniç' ) -def HasCompletionsThatCouldBeCompletedWithMoreText_Unicode_test( - *args ): - completions = [ BuildCompletion( insertion_text = 'Uniçø∂¢' ) ] - ok_( _HasCompletionsThatCouldBeCompletedWithMoreText( - CompleteItemIs( 'Uniç' ), - completions ) ) - - def GetRequiredNamespaceImport_ReturnNoneForNoExtraData_test(): eq_( _GetRequiredNamespaceImport( {} ), None ) @@ -351,6 +297,19 @@ def GetCompletionsUserMayHaveCompleted_UseUserData1_test( *args ): [ BuildCompletionNamespace( 'namespace2' ) ] ) +@patch( 'ycm.vimsupport.GetVariableValue', + GetVariableValue_CompleteItemIs( 'Test', user_data='' ) ) +def GetCompletionsUserMayHaveCompleted_EmptyUserData_test( *args ): + # Identical completions but none is selected. + completions = [ + BuildCompletionNamespace( 'namespace1' ), + BuildCompletionNamespace( 'namespace2' ) + ] + + with _SetupForCsharpCompletionDone( completions ) as request: + eq_( request._GetCompletionsUserMayHaveCompleted(), [] ) + + @patch( 'ycm.vimsupport.GetVariableValue', GetVariableValue_CompleteItemIs( 'Test' ) ) def PostCompleteCsharp_EmptyDoesntInsertNamespace_test( *args ):