From c7be1f1b47f5cc31f5dcca55f5fd244b35fc7498 Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Mon, 7 Oct 2013 15:47:48 -0700 Subject: [PATCH] Omni completion works again --- autoload/youcompleteme.vim | 2 + python/ycm/client/completion_request.py | 10 ++-- python/ycm/client/omni_completion_request.py | 39 +++++++++++++ python/ycm/completers/all/omni_completer.py | 58 ++++++++------------ python/ycm/youcompleteme.py | 23 +++----- 5 files changed, 78 insertions(+), 54 deletions(-) create mode 100644 python/ycm/client/omni_completion_request.py diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index fd6f77e7..de3bc3c9 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -308,6 +308,8 @@ function! s:SetCompleteFunc() let &completefunc = 'youcompleteme#Complete' let &l:completefunc = 'youcompleteme#Complete' + " TODO: This makes startup slower because it blocks on the server. Explore + " other options. if pyeval( 'ycm_state.NativeFiletypeCompletionUsable()' ) let &omnifunc = 'youcompleteme#OmniComplete' let &l:omnifunc = 'youcompleteme#OmniComplete' diff --git a/python/ycm/client/completion_request.py b/python/ycm/client/completion_request.py index 46298c54..977a1122 100644 --- a/python/ycm/client/completion_request.py +++ b/python/ycm/client/completion_request.py @@ -28,9 +28,11 @@ class CompletionRequest( BaseRequest ): super( CompletionRequest, self ).__init__() self._completion_start_column = base.CompletionStartColumn() - self._request_data = BuildRequestData( self._completion_start_column ) + + # This field is also used by the omni_completion_request subclass + self.request_data = BuildRequestData( self._completion_start_column ) if force_semantic: - self._request_data[ 'force_semantic' ] = True + self.request_data[ 'force_semantic' ] = True def CompletionStartColumn( self ): @@ -38,8 +40,8 @@ class CompletionRequest( BaseRequest ): def Start( self, query ): - self._request_data[ 'query' ] = query - self._response_future = self.PostDataToHandlerAsync( self._request_data, + self.request_data[ 'query' ] = query + self._response_future = self.PostDataToHandlerAsync( self.request_data, 'completions' ) diff --git a/python/ycm/client/omni_completion_request.py b/python/ycm/client/omni_completion_request.py new file mode 100644 index 00000000..2eb26a41 --- /dev/null +++ b/python/ycm/client/omni_completion_request.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# +# Copyright (C) 2013 Strahinja Val Markovic +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + +from ycm.client.completion_request import CompletionRequest + + +class OmniCompletionRequest( CompletionRequest ): + def __init__( self, omni_completer ): + super( OmniCompletionRequest, self ).__init__() + self._omni_completer = omni_completer + + + def Start( self, query ): + self.request_data[ 'query' ] = query + self._results = self._omni_completer.ComputeCandidates( self.request_data ) + + + def Done( self ): + return True + + + def Response( self ): + return self._results diff --git a/python/ycm/completers/all/omni_completer.py b/python/ycm/completers/all/omni_completer.py index d0a51786..41d81452 100644 --- a/python/ycm/completers/all/omni_completer.py +++ b/python/ycm/completers/all/omni_completer.py @@ -28,14 +28,17 @@ OMNIFUNC_NOT_LIST = ( 'Omnifunc did not return a list or a dict with a "words" ' class OmniCompleter( Completer ): def __init__( self, user_options ): super( OmniCompleter, self ).__init__( user_options ) - self.omnifunc = None - self.stored_candidates = None + self._omnifunc = None def SupportedFiletypes( self ): return [] + def Available( self ): + return bool( self._omnifunc ) + + def ShouldUseCache( self ): return bool( self.user_options[ 'cache_omnifunc' ] ) @@ -47,31 +50,31 @@ class OmniCompleter( Completer ): def ShouldUseNowInner( self, request_data ): - if not self.omnifunc: + if not self._omnifunc: return False return super( OmniCompleter, self ).ShouldUseNowInner( request_data ) - def CandidatesForQueryAsync( self, request_data ): + def ComputeCandidates( self, request_data ): if self.ShouldUseCache(): - return super( OmniCompleter, self ).CandidatesForQueryAsync( + return super( OmniCompleter, self ).ComputeCandidates( request_data ) else: - return self.CandidatesForQueryAsyncInner( request_data ) + if self.ShouldUseNowInner( request_data ): + return self.ComputeCandidatesInner( request_data ) + return [] - def CandidatesForQueryAsyncInner( self, request_data ): - if not self.omnifunc: - self.stored_candidates = None - return + def ComputeCandidatesInner( self, request_data ): + if not self._omnifunc: + return [] try: - return_value = int( vim.eval( self.omnifunc + '(1,"")' ) ) + return_value = int( vim.eval( self._omnifunc + '(1,"")' ) ) if return_value < 0: - self.stored_candidates = None - return + return [] - omnifunc_call = [ self.omnifunc, + omnifunc_call = [ self._omnifunc, "(0,'", vimsupport.EscapeForVim( request_data[ 'query' ] ), "')" ] @@ -79,34 +82,17 @@ class OmniCompleter( Completer ): items = vim.eval( ''.join( omnifunc_call ) ) if 'words' in items: - items = items['words'] + items = items[ 'words' ] if not hasattr( items, '__iter__' ): raise TypeError( OMNIFUNC_NOT_LIST ) - self.stored_candidates = filter( bool, items ) - except (TypeError, ValueError) as error: + return filter( bool, items ) + except ( TypeError, ValueError ) as error: vimsupport.PostVimMessage( OMNIFUNC_RETURNED_BAD_VALUE + ' ' + str( error ) ) - self.stored_candidates = None - return - - - - def AsyncCandidateRequestReadyInner( self ): - return True + return [] def OnFileReadyToParse( self, request_data ): - self.omnifunc = vim.eval( '&omnifunc' ) - - - def CandidatesFromStoredRequest( self ): - if self.ShouldUseCache(): - return super( OmniCompleter, self ).CandidatesFromStoredRequest() - else: - return self.CandidatesFromStoredRequestInner() - - - def CandidatesFromStoredRequestInner( self ): - return self.stored_candidates if self.stored_candidates else [] + self._omnifunc = vim.eval( '&omnifunc' ) diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index d6a7a2bb..3e64e1f3 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -29,6 +29,7 @@ from ycm.completers.general import syntax_parse from ycm.client.base_request import BaseRequest, BuildRequestData from ycm.client.command_request import SendCommandRequest from ycm.client.completion_request import CompletionRequest +from ycm.client.omni_completion_request import OmniCompletionRequest from ycm.client.event_notification import ( SendEventNotificationAsync, EventNotification ) @@ -93,7 +94,12 @@ class YouCompleteMe( object ): # 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( force_semantic ) + if ( not self.NativeFiletypeCompletionAvailable() and + self.CurrentFiletypeCompletionEnabled() and + self._omnicomp.Available() ): + self._latest_completion_request = OmniCompletionRequest( self._omnicomp ) + else: + self._latest_completion_request = CompletionRequest( force_semantic ) return self._latest_completion_request @@ -122,25 +128,14 @@ class YouCompleteMe( object ): return False - # TODO: This may not be needed at all when the server is ready. Evaluate this - # later. - # def FiletypeCompletionAvailable( self ): - # return bool( self.GetFiletypeCompleter() ) - - def NativeFiletypeCompletionUsable( self ): return ( self.CurrentFiletypeCompletionEnabled() and self.NativeFiletypeCompletionAvailable() ) - # TODO: This may not be needed at all when the server is ready. Evaluate this - # later. - # def FiletypeCompletionUsable( self ): - # return ( self.CurrentFiletypeCompletionEnabled() and - # self.FiletypeCompletionAvailable() ) - - def OnFileReadyToParse( self ): + self._omnicomp.OnFileReadyToParse( None ) + extra_data = {} if self._user_options[ 'collect_identifiers_from_tags_files' ]: extra_data[ 'tag_files' ] = _GetTagFiles()