diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index 9efa2e92..fd6f77e7 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -566,8 +566,7 @@ function! youcompleteme#Complete( findstart, base ) return -2 endif - py request = ycm_state.CreateCompletionRequest() - return pyeval( 'request.CompletionStartColumn()' ) + return pyeval( 'ycm_state.CreateCompletionRequest().CompletionStartColumn()' ) else return s:CompletionsForQuery( a:base ) endif @@ -577,8 +576,8 @@ endfunction function! youcompleteme#OmniComplete( findstart, base ) if a:findstart let s:omnifunc_mode = 1 - " TODO: Force semantic mode here ( needs to work) - return pyeval( 'ycm_state.CreateCompletionRequest().CompletionStartColumn()' ) + py request = ycm_state.CreateCompletionRequest( force_semantic = True ) + return pyeval( 'request.CompletionStartColumn()' ) else return s:CompletionsForQuery( a:base ) endif diff --git a/python/ycm/client/completion_request.py b/python/ycm/client/completion_request.py index d55ade1e..46298c54 100644 --- a/python/ycm/client/completion_request.py +++ b/python/ycm/client/completion_request.py @@ -24,11 +24,13 @@ from ycm.client.base_request import ( BaseRequest, BuildRequestData, class CompletionRequest( BaseRequest ): - def __init__( self ): + def __init__( self, force_semantic = False ): super( CompletionRequest, self ).__init__() self._completion_start_column = base.CompletionStartColumn() self._request_data = BuildRequestData( self._completion_start_column ) + if force_semantic: + self._request_data[ 'force_semantic' ] = True def CompletionStartColumn( self ): diff --git a/python/ycm/completers/completer.py b/python/ycm/completers/completer.py index 99daa29b..ed068b0d 100644 --- a/python/ycm/completers/completer.py +++ b/python/ycm/completers/completer.py @@ -19,7 +19,7 @@ import abc import ycm_core -from ycm.utils import ToUtf8IfNeeded +from ycm.utils import ToUtf8IfNeeded, ForceSemanticCompletion from ycm.completers.completer_utils import TriggersForFiletype NO_USER_COMMANDS = 'This completer does not define any commands.' @@ -149,7 +149,8 @@ class Completer( object ): # It's highly likely you DON'T want to override this function but the *Inner # version of it. def ComputeCandidates( self, request_data ): - if not self.ShouldUseNow( request_data ): + if ( not ForceSemanticCompletion( request_data ) and + not self.ShouldUseNow( request_data ) ): return [] if ( request_data[ 'query' ] and diff --git a/python/ycm/server/server_state.py b/python/ycm/server/server_state.py index 611b062c..2e9bd9ff 100644 --- a/python/ycm/server/server_state.py +++ b/python/ycm/server/server_state.py @@ -20,6 +20,7 @@ import imp import os from ycm import extra_conf_store +from ycm.utils import ForceSemanticCompletion from ycm.completers.general.general_completer_store import GeneralCompleterStore @@ -85,6 +86,7 @@ class ServerState( object ): except: return False + def FiletypeCompletionUsable( self, filetypes ): return ( self.CurrentFiletypeCompletionEnabled( filetypes ) and self.FiletypeCompletionAvailable( filetypes ) ) @@ -97,7 +99,9 @@ class ServerState( object ): def ShouldUseFiletypeCompleter( self, request_data ): filetypes = request_data[ 'filetypes' ] if self.FiletypeCompletionUsable( filetypes ): - return self.GetFiletypeCompleter( filetypes ).ShouldUseNow( request_data ) + return ( ForceSemanticCompletion( request_data ) or + self.GetFiletypeCompleter( filetypes ).ShouldUseNow( + request_data ) ) return False diff --git a/python/ycm/server/tests/basic_test.py b/python/ycm/server/tests/basic_test.py index b061c73c..4c1c74ac 100644 --- a/python/ycm/server/tests/basic_test.py +++ b/python/ycm/server/tests/basic_test.py @@ -30,16 +30,23 @@ bottle.debug( True ) # TODO: Split this file into multiple files. # 'contents' should be just one line of text -def RequestDataForFileWithContents( filename, contents = None ): +def RequestDataForFileWithContents( filename, + contents = None, + filetype = None ): real_contents = contents if contents else '' + filetype_to_use = filetype or 'foo' return { - 'filetypes': ['foo'], + 'query': '', + 'line_num': 0, + 'column_num': 0, + 'start_column': 0, + 'filetypes': [ filetype_to_use ], 'filepath': filename, 'line_value': real_contents, 'file_data': { filename: { 'contents': real_contents, - 'filetypes': ['foo'] + 'filetypes': [ filetype_to_use ] } } } @@ -120,6 +127,22 @@ int main() CompletionEntryMatcher( 'y' ) ) ) +@with_setup( Setup ) +def GetCompletions_ForceSemantic_Works_test(): + app = TestApp( ycmd.app ) + + completion_data = RequestDataForFileWithContents( 'foo.py', + filetype = 'python' ) + completion_data.update( { + 'force_semantic': True, + } ) + + results = app.post_json( '/completions', completion_data ).json + assert_that( results, has_items( CompletionEntryMatcher( 'abs' ), + CompletionEntryMatcher( 'open' ), + CompletionEntryMatcher( 'bool' ) ) ) + + @with_setup( Setup ) def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test(): app = TestApp( ycmd.app ) diff --git a/python/ycm/utils.py b/python/ycm/utils.py index ec63afc2..28fa7d05 100644 --- a/python/ycm/utils.py +++ b/python/ycm/utils.py @@ -77,3 +77,8 @@ def Memoize( obj ): cache[ key ] = obj( *args, **kwargs ) return cache[ key ] return memoizer + + +def ForceSemanticCompletion( request_data ): + return ( 'force_semantic' in request_data and + bool( request_data[ 'force_semantic' ] ) ) diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index 2fd1adf5..e424cd5e 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -89,11 +89,11 @@ class YouCompleteMe( object ): shell = True ) - def CreateCompletionRequest( self ): + def CreateCompletionRequest( self, force_semantic = False ): # We have to store a reference to the newly created CompletionRequest # because VimScript can't store a reference to a Python object across # function calls... Thus we need to keep this request somewhere. - self._latest_completion_request = CompletionRequest() + self._latest_completion_request = CompletionRequest( force_semantic ) return self._latest_completion_request