From 73fea03d7816da6ecf4544ce9c0ebb456c913085 Mon Sep 17 00:00:00 2001 From: micbou Date: Sun, 5 Aug 2018 21:22:32 +0200 Subject: [PATCH 1/2] Convert strings from omnifunc into dictionaries Vim allows each item of the list returned by an omnifunc to be either a string or a dictionary but ycmd only supports lists where items are all strings or all dictionaries. Convert all strings into dictionaries. --- python/ycm/omni_completer.py | 9 +- python/ycm/tests/omni_completer_test.py | 106 ++++++++++++++++++------ 2 files changed, 90 insertions(+), 25 deletions(-) diff --git a/python/ycm/omni_completer.py b/python/ycm/omni_completer.py index f369efd7..58ba0308 100644 --- a/python/ycm/omni_completer.py +++ b/python/ycm/omni_completer.py @@ -123,7 +123,14 @@ class OmniCompleter( Completer ): if not hasattr( items, '__iter__' ): raise TypeError( OMNIFUNC_NOT_LIST ) - return list( filter( bool, items ) ) + # Vim allows each item of the list to be either a string or a dictionary + # but ycmd only supports lists where items are all strings or all + # dictionaries. Convert all strings into dictionaries. + for index, item in enumerate( items ): + if not isinstance( item, dict ): + items[ index ] = { 'word': item } + + return items except ( TypeError, ValueError, vim.error ) as error: vimsupport.PostVimMessage( diff --git a/python/ycm/tests/omni_completer_test.py b/python/ycm/tests/omni_completer_test.py index 86e06140..13032846 100644 --- a/python/ycm/tests/omni_completer_test.py +++ b/python/ycm/tests/omni_completer_test.py @@ -57,7 +57,11 @@ def OmniCompleter_GetCompletions_Cache_List_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'a', 'b', 'cdef' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' }, + { 'word': 'cdef' } + ] ), 'completion_start_column': 6 } ) ) @@ -105,7 +109,11 @@ def OmniCompleter_GetCompletions_NoCache_List_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'a', 'b', 'cdef' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' }, + { 'word': 'cdef' } + ] ), 'completion_start_column': 6 } ) ) @@ -131,7 +139,11 @@ def OmniCompleter_GetCompletions_NoCache_ListFilter_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'a', 'b', 'cdef' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' }, + { 'word': 'cdef' } + ] ), 'completion_start_column': 6 } ) ) @@ -157,7 +169,11 @@ def OmniCompleter_GetCompletions_NoCache_UseFindStart_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'a', 'b', 'cdef' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' }, + { 'word': 'cdef' } + ] ), 'completion_start_column': 1 } ) ) @@ -207,7 +223,7 @@ def OmniCompleter_GetCompletions_Cache_Object_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': [ 'CDtEF' ], + 'completions': [ { 'word': 'CDtEF' } ], 'completion_start_column': 6 } ) ) @@ -427,9 +443,11 @@ def OmniCompleter_GetCompletions_Cache_List_Unicode_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': [ 'å_unicode_identifier', - 'πππππππ yummy πie', - '†est' ], + 'completions': [ + { 'word': 'å_unicode_identifier' }, + { 'word': 'πππππππ yummy πie' }, + { 'word': '†est' } + ], 'completion_start_column': 13 } ) ) @@ -453,9 +471,11 @@ def OmniCompleter_GetCompletions_NoCache_List_Unicode_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ '†est', - 'å_unicode_identifier', - 'πππππππ yummy πie' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': '†est' }, + { 'word': 'å_unicode_identifier' }, + { 'word': 'πππππππ yummy πie' } + ] ), 'completion_start_column': 13 } ) ) @@ -479,7 +499,7 @@ def OmniCompleter_GetCompletions_Cache_List_Filter_Unicode_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': [ 'πππππππ yummy πie' ], + 'completions': [ { 'word': 'πππππππ yummy πie' } ], 'completion_start_column': 13 } ) ) @@ -503,7 +523,7 @@ def OmniCompleter_GetCompletions_NoCache_List_Filter_Unicode_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'πππππππ yummy πie' ] ), + 'completions': ToBytesOnPY2( [ { 'word': 'πππππππ yummy πie' } ] ), 'completion_start_column': 13 } ) ) @@ -643,7 +663,7 @@ def OmniCompleter_GetCompletions_RestoreCursorPositionAfterOmnifuncCall_test( assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'length' ] ), + 'completions': ToBytesOnPY2( [ { 'word': 'length' } ] ), 'completion_start_column': 6 } ) ) @@ -678,7 +698,7 @@ def OmniCompleter_GetCompletions_MoveCursorPositionAtStartColumn_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'length' ] ), + 'completions': ToBytesOnPY2( [ { 'word': 'length' } ] ), 'completion_start_column': 6 } ) ) @@ -711,14 +731,14 @@ def StartColumnCompliance( ycm, def OmniCompleter_GetCompletions_StartColumnCompliance_test(): - yield StartColumnCompliance, -4, [ 'foo' ], 3 + yield StartColumnCompliance, -4, [ { 'word': 'foo' } ], 3 yield StartColumnCompliance, -3, [], 1 yield StartColumnCompliance, -2, [], 1 - yield StartColumnCompliance, -1, [ 'foo' ], 3 - yield StartColumnCompliance, 0, [ 'foo' ], 1 - yield StartColumnCompliance, 1, [ 'foo' ], 2 - yield StartColumnCompliance, 2, [ 'foo' ], 3 - yield StartColumnCompliance, 3, [ 'foo' ], 3 + yield StartColumnCompliance, -1, [ { 'word': 'foo' } ], 3 + yield StartColumnCompliance, 0, [ { 'word': 'foo' } ], 1 + yield StartColumnCompliance, 1, [ { 'word': 'foo' } ], 2 + yield StartColumnCompliance, 2, [ { 'word': 'foo' } ], 3 + yield StartColumnCompliance, 3, [ { 'word': 'foo' } ], 3 @YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0, @@ -763,12 +783,42 @@ def OmniCompleter_GetCompletions_NoCache_ForceSemantic_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'test' ] ), + 'completions': ToBytesOnPY2( [ { 'word': 'test' } ] ), 'completion_start_column': 1 } ) ) +@YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 1, + 'g:ycm_semantic_triggers': TRIGGERS } ) +def OmniCompleter_GetCompletions_ConvertStringsToDictionaries_test( ycm ): + def Omnifunc( findstart, base ): + if findstart: + return 5 + return [ + { 'word': 'a' }, + 'b' + ] + + current_buffer = VimBuffer( 'buffer', + contents = [ 'test.' ], + filetype = FILETYPE, + omnifunc = Omnifunc ) + + with MockVimBuffers( [ current_buffer ], [ current_buffer ], ( 1, 7 ) ): + ycm.SendCompletionRequest() + assert_that( + ycm.GetCompletionResponse(), + has_entries( { + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' } + ] ), + 'completion_start_column': 6 + } ) + ) + + @YouCompleteMeInstance( { 'g:ycm_cache_omnifunc': 0, 'g:ycm_filetype_specific_completion_to_disable': { FILETYPE: 1 }, @@ -843,7 +893,11 @@ def OmniCompleter_GetCompletions_FiletypeDisabled_ForceSemantic_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'a', 'b', 'cdef' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' }, + { 'word': 'cdef' } + ] ), 'completion_start_column': 6 } ) ) @@ -869,7 +923,11 @@ def OmniCompleter_GetCompletions_AllFiletypesDisabled_ForceSemantic_test( ycm ): assert_that( ycm.GetCompletionResponse(), has_entries( { - 'completions': ToBytesOnPY2( [ 'a', 'b', 'cdef' ] ), + 'completions': ToBytesOnPY2( [ + { 'word': 'a' }, + { 'word': 'b' }, + { 'word': 'cdef' } + ] ), 'completion_start_column': 6 } ) ) From 926e32d6e5cad5758b2a5af3dca2872e0f5b3396 Mon Sep 17 00:00:00 2001 From: micbou Date: Sun, 19 Aug 2018 20:40:46 +0200 Subject: [PATCH 2/2] Simplify AdjustCandidateInsertionText function Candidates are always dictionaries containing the 'word' key. --- python/ycm/base.py | 20 +++++++------------- python/ycm/tests/base_test.py | 33 ++++++++++++++++----------------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/python/ycm/base.py b/python/ycm/base.py index 1fb73dba..ee3c99b3 100644 --- a/python/ycm/base.py +++ b/python/ycm/base.py @@ -111,22 +111,16 @@ def AdjustCandidateInsertionText( candidates ): new_candidates = [] for candidate in candidates: - if isinstance( candidate, dict ): - new_candidate = candidate.copy() + new_candidate = candidate.copy() - if 'abbr' not in new_candidate: - new_candidate[ 'abbr' ] = new_candidate[ 'word' ] + if 'abbr' not in new_candidate: + new_candidate[ 'abbr' ] = new_candidate[ 'word' ] - new_candidate[ 'word' ] = NewCandidateInsertionText( - new_candidate[ 'word' ], - text_after_cursor ) + new_candidate[ 'word' ] = NewCandidateInsertionText( + new_candidate[ 'word' ], + text_after_cursor ) - new_candidates.append( new_candidate ) - - elif isinstance( candidate, str ) or isinstance( candidate, bytes ): - new_candidates.append( - { 'abbr': candidate, - 'word': NewCandidateInsertionText( candidate, text_after_cursor ) } ) + new_candidates.append( new_candidate ) return new_candidates diff --git a/python/ycm/tests/base_test.py b/python/ycm/tests/base_test.py index 9f7516d1..a7249b61 100644 --- a/python/ycm/tests/base_test.py +++ b/python/ycm/tests/base_test.py @@ -57,49 +57,49 @@ def MockTextAfterCursor( text ): def AdjustCandidateInsertionText_Basic_test(): with MockTextAfterCursor( 'bar' ): eq_( [ { 'abbr': 'foobar', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( [ 'foobar' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar' } ] ) ) def AdjustCandidateInsertionText_ParenInTextAfterCursor_test(): with MockTextAfterCursor( 'bar(zoo' ): eq_( [ { 'abbr': 'foobar', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( [ 'foobar' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar' } ] ) ) def AdjustCandidateInsertionText_PlusInTextAfterCursor_test(): with MockTextAfterCursor( 'bar+zoo' ): eq_( [ { 'abbr': 'foobar', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( [ 'foobar' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar' } ] ) ) def AdjustCandidateInsertionText_WhitespaceInTextAfterCursor_test(): with MockTextAfterCursor( 'bar zoo' ): eq_( [ { 'abbr': 'foobar', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( [ 'foobar' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar' } ] ) ) def AdjustCandidateInsertionText_MoreThanWordMatchingAfterCursor_test(): with MockTextAfterCursor( 'bar.h' ): eq_( [ { 'abbr': 'foobar.h', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( [ 'foobar.h' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar.h' } ] ) ) with MockTextAfterCursor( 'bar(zoo' ): eq_( [ { 'abbr': 'foobar(zoo', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( [ 'foobar(zoo' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar(zoo' } ] ) ) def AdjustCandidateInsertionText_NotSuffix_test(): with MockTextAfterCursor( 'bar' ): eq_( [ { 'abbr': 'foofoo', 'word': 'foofoo' } ], - base.AdjustCandidateInsertionText( [ 'foofoo' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foofoo' } ] ) ) def AdjustCandidateInsertionText_NothingAfterCursor_test(): with MockTextAfterCursor( '' ): - eq_( [ 'foofoo', - 'zobar' ], - base.AdjustCandidateInsertionText( [ 'foofoo', - 'zobar' ] ) ) + eq_( [ { 'word': 'foofoo' }, + { 'word': 'zobar' } ], + base.AdjustCandidateInsertionText( [ { 'word': 'foofoo' }, + { 'word': 'zobar' } ] ) ) def AdjustCandidateInsertionText_MultipleStrings_test(): @@ -108,17 +108,16 @@ def AdjustCandidateInsertionText_MultipleStrings_test(): { 'abbr': 'zobar', 'word': 'zo' }, { 'abbr': 'qbar', 'word': 'q' }, { 'abbr': 'bar', 'word': '' }, ], - base.AdjustCandidateInsertionText( [ 'foobar', - 'zobar', - 'qbar', - 'bar' ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar' }, + { 'word': 'zobar' }, + { 'word': 'qbar' }, + { 'word': 'bar' } ] ) ) def AdjustCandidateInsertionText_DictInput_test(): with MockTextAfterCursor( 'bar' ): eq_( [ { 'abbr': 'foobar', 'word': 'foo' } ], - base.AdjustCandidateInsertionText( - [ { 'word': 'foobar' } ] ) ) + base.AdjustCandidateInsertionText( [ { 'word': 'foobar' } ] ) ) def AdjustCandidateInsertionText_DontTouchAbbr_test():