Event and completion request are now async
This results in a much snappier Vim.
This commit is contained in:
parent
e08dd4ab33
commit
9d0a6c96d7
@ -40,6 +40,8 @@ function! youcompleteme#Enable()
|
|||||||
py import sys
|
py import sys
|
||||||
py import vim
|
py import vim
|
||||||
exe 'python sys.path.insert( 0, "' . s:script_folder_path . '/../python" )'
|
exe 'python sys.path.insert( 0, "' . s:script_folder_path . '/../python" )'
|
||||||
|
py from ycm import utils
|
||||||
|
py utils.AddThirdPartyFoldersToSysPath()
|
||||||
py from ycm import base
|
py from ycm import base
|
||||||
py from ycm import vimsupport
|
py from ycm import vimsupport
|
||||||
py from ycm import user_options_store
|
py from ycm import user_options_store
|
||||||
@ -497,13 +499,11 @@ python << EOF
|
|||||||
def GetCompletions( query ):
|
def GetCompletions( query ):
|
||||||
request = ycm_state.GetCurrentCompletionRequest()
|
request = ycm_state.GetCurrentCompletionRequest()
|
||||||
request.Start( query )
|
request.Start( query )
|
||||||
results_ready = False
|
while not request.Done():
|
||||||
while not results_ready:
|
|
||||||
results_ready = request.Done()
|
|
||||||
if bool( int( vim.eval( 'complete_check()' ) ) ):
|
if bool( int( vim.eval( 'complete_check()' ) ) ):
|
||||||
return { 'words' : [], 'refresh' : 'always'}
|
return { 'words' : [], 'refresh' : 'always'}
|
||||||
|
|
||||||
results = base.AdjustCandidateInsertionText( request.Results() )
|
results = base.AdjustCandidateInsertionText( request.Response() )
|
||||||
return { 'words' : results, 'refresh' : 'always' }
|
return { 'words' : results, 'refresh' : 'always' }
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
import vim
|
import vim
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
from requests_futures.sessions import FuturesSession
|
||||||
from ycm import vimsupport
|
from ycm import vimsupport
|
||||||
|
|
||||||
HEADERS = {'content-type': 'application/json'}
|
HEADERS = {'content-type': 'application/json'}
|
||||||
@ -46,22 +47,22 @@ class BaseRequest( object ):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
# This is the blocking version of the method. See below for async.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def PostDataToHandler( data, handler ):
|
def PostDataToHandler( data, handler ):
|
||||||
response = requests.post( _BuildUri( handler ),
|
return JsonFromFuture( BaseRequest.PostDataToHandlerAsync( data,
|
||||||
data = json.dumps( data ),
|
handler ) )
|
||||||
headers = HEADERS )
|
|
||||||
if response.status_code == requests.codes.server_error:
|
|
||||||
raise ServerError( response.json()[ 'message' ] )
|
|
||||||
|
|
||||||
# We let Requests handle the other status types, we only handle the 500
|
|
||||||
# error code.
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
if response.text:
|
# This returns a future! Use JsonFromFuture to get the value.
|
||||||
return response.json()
|
@staticmethod
|
||||||
return None
|
def PostDataToHandlerAsync( data, handler ):
|
||||||
|
return BaseRequest.session.post( _BuildUri( handler ),
|
||||||
|
data = json.dumps( data ),
|
||||||
|
headers = HEADERS )
|
||||||
|
|
||||||
|
|
||||||
|
session = FuturesSession( max_workers = 4 )
|
||||||
server_location = 'http://localhost:6666'
|
server_location = 'http://localhost:6666'
|
||||||
|
|
||||||
|
|
||||||
@ -83,6 +84,20 @@ def BuildRequestData( start_column = None, query = None ):
|
|||||||
return request_data
|
return request_data
|
||||||
|
|
||||||
|
|
||||||
|
def JsonFromFuture( future ):
|
||||||
|
response = future.result()
|
||||||
|
if response.status_code == requests.codes.server_error:
|
||||||
|
raise ServerError( response.json()[ 'message' ] )
|
||||||
|
|
||||||
|
# We let Requests handle the other status types, we only handle the 500
|
||||||
|
# error code.
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
if response.text:
|
||||||
|
return response.json()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _BuildUri( handler ):
|
def _BuildUri( handler ):
|
||||||
return ''.join( [ BaseRequest.server_location, '/', handler ] )
|
return ''.join( [ BaseRequest.server_location, '/', handler ] )
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import vim
|
import vim
|
||||||
import time
|
|
||||||
from ycm.client.base_request import BaseRequest, BuildRequestData, ServerError
|
from ycm.client.base_request import BaseRequest, BuildRequestData, ServerError
|
||||||
from ycm import vimsupport
|
from ycm import vimsupport
|
||||||
from ycm.utils import ToUtf8IfNeeded
|
from ycm.utils import ToUtf8IfNeeded
|
||||||
@ -70,10 +69,8 @@ class CommandRequest( BaseRequest ):
|
|||||||
|
|
||||||
def SendCommandRequest( arguments, completer ):
|
def SendCommandRequest( arguments, completer ):
|
||||||
request = CommandRequest( arguments, completer )
|
request = CommandRequest( arguments, completer )
|
||||||
|
# This is a blocking call.
|
||||||
request.Start()
|
request.Start()
|
||||||
while not request.Done():
|
|
||||||
time.sleep( 0.1 )
|
|
||||||
|
|
||||||
request.RunPostCommandActionsIfNeeded()
|
request.RunPostCommandActionsIfNeeded()
|
||||||
return request.Response()
|
return request.Response()
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
|
|
||||||
from ycm import base
|
from ycm import base
|
||||||
from ycm import vimsupport
|
from ycm import vimsupport
|
||||||
from ycm.client.base_request import BaseRequest, BuildRequestData
|
from ycm.client.base_request import ( BaseRequest, BuildRequestData,
|
||||||
|
JsonFromFuture )
|
||||||
|
|
||||||
|
|
||||||
class CompletionRequest( BaseRequest ):
|
class CompletionRequest( BaseRequest ):
|
||||||
@ -30,27 +31,26 @@ class CompletionRequest( BaseRequest ):
|
|||||||
self._request_data = BuildRequestData( self._completion_start_column )
|
self._request_data = BuildRequestData( self._completion_start_column )
|
||||||
|
|
||||||
|
|
||||||
# TODO: Do we need this anymore?
|
|
||||||
# def ShouldComplete( self ):
|
|
||||||
# return ( self._do_filetype_completion or
|
|
||||||
# self._ycm_state.ShouldUseGeneralCompleter( self._request_data ) )
|
|
||||||
|
|
||||||
|
|
||||||
def CompletionStartColumn( self ):
|
def CompletionStartColumn( self ):
|
||||||
return self._completion_start_column
|
return self._completion_start_column
|
||||||
|
|
||||||
|
|
||||||
def Start( self, query ):
|
def Start( self, query ):
|
||||||
self._request_data[ 'query' ] = query
|
self._request_data[ 'query' ] = query
|
||||||
self._response = self.PostDataToHandler( self._request_data,
|
self._response_future = self.PostDataToHandlerAsync( self._request_data,
|
||||||
'get_completions' )
|
'get_completions' )
|
||||||
|
|
||||||
|
|
||||||
def Results( self ):
|
def Done( self ):
|
||||||
if not self._response:
|
return self._response_future.done()
|
||||||
|
|
||||||
|
|
||||||
|
def Response( self ):
|
||||||
|
if not self._response_future:
|
||||||
return []
|
return []
|
||||||
try:
|
try:
|
||||||
return [ _ConvertCompletionDataToVimData( x ) for x in self._response ]
|
return [ _ConvertCompletionDataToVimData( x )
|
||||||
|
for x in JsonFromFuture( self._response_future ) ]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
vimsupport.PostVimMessage( str( e ) )
|
vimsupport.PostVimMessage( str( e ) )
|
||||||
return []
|
return []
|
||||||
|
@ -41,7 +41,7 @@ class EventNotification( BaseRequest ):
|
|||||||
# quietly to the Vim message log because nothing bad will happen if the
|
# quietly to the Vim message log because nothing bad will happen if the
|
||||||
# server misses some events and we don't want to annoy the user.
|
# server misses some events and we don't want to annoy the user.
|
||||||
try:
|
try:
|
||||||
self.PostDataToHandler( request_data, 'event_notification' )
|
self.PostDataToHandlerAsync( request_data, 'event_notification' )
|
||||||
except:
|
except:
|
||||||
vimsupport.EchoText( traceback.format_exc() )
|
vimsupport.EchoText( traceback.format_exc() )
|
||||||
|
|
||||||
|
@ -30,6 +30,9 @@ sys.path.insert( 0, os.path.join(
|
|||||||
os.path.dirname( os.path.abspath( __file__ ) ),
|
os.path.dirname( os.path.abspath( __file__ ) ),
|
||||||
'../..' ) )
|
'../..' ) )
|
||||||
|
|
||||||
|
from ycm import utils
|
||||||
|
utils.AddThirdPartyFoldersToSysPath()
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import bottle
|
import bottle
|
||||||
|
@ -52,3 +52,15 @@ def TerminateProcess( pid ):
|
|||||||
ctypes.windll.kernel32.CloseHandle( handle )
|
ctypes.windll.kernel32.CloseHandle( handle )
|
||||||
else:
|
else:
|
||||||
os.kill( pid, signal.SIGTERM )
|
os.kill( pid, signal.SIGTERM )
|
||||||
|
|
||||||
|
|
||||||
|
def AddThirdPartyFoldersToSysPath():
|
||||||
|
path_to_third_party = os.path.join(
|
||||||
|
os.path.dirname( os.path.abspath( __file__ ) ),
|
||||||
|
'../../third_party' )
|
||||||
|
|
||||||
|
for folder in os.listdir( path_to_third_party ):
|
||||||
|
sys.path.insert( 0, os.path.realpath( os.path.join( path_to_third_party,
|
||||||
|
folder ) ) )
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,6 +165,7 @@ class YouCompleteMe( object ):
|
|||||||
|
|
||||||
|
|
||||||
def OnVimLeave( self ):
|
def OnVimLeave( self ):
|
||||||
|
# TODO: There should be a faster way of shutting down the server
|
||||||
self._server_popen.terminate()
|
self._server_popen.terminate()
|
||||||
os.remove( self._temp_options_filename )
|
os.remove( self._temp_options_filename )
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user