#!/usr/bin/env python # # Copyright (C) 2011, 2012 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 . import abc from threading import Thread, Event from ycm.completers.completer import Completer class ThreadedCompleter( Completer ): """A subclass of Completer that abstracts away the use of a background thread. This is a great class to subclass for your custom completer. It will provide you with async computation of candidates when you implement the ComputeCandidates() method; no need to worry about threads, locks, events or similar. If you use this class as the base class for your Completer, you DON'T need to provide implementations for the CandidatesForQueryAsync(), AsyncCandidateRequestReady() and CandidatesFromStoredRequest() functions. Just implement ComputeCandidates(). For examples of subclasses of this class, see the following files: python/completers/general/filename_completer.py """ def __init__( self ): super( ThreadedCompleter, self ).__init__() self._query_ready = Event() self._candidates_ready = Event() self._candidates = None self._start_completion_thread() def _start_completion_thread( self ): self._completion_thread = Thread( target=self.SetCandidates ) self._completion_thread.daemon = True self._completion_thread.start() def CandidatesForQueryAsyncInner( self, query, start_column ): self._candidates = None self._candidates_ready.clear() self._query = query self._start_column = start_column self._query_ready.set() def AsyncCandidateRequestReadyInner( self ): return WaitAndClearIfSet( self._candidates_ready, timeout=0.005 ) def CandidatesFromStoredRequestInner( self ): return self._candidates or [] @abc.abstractmethod def ComputeCandidates( self, query, start_column ): """This function should compute the candidates to show to the user. The return value should be of the same type as that for CandidatesFromStoredRequest().""" pass def SetCandidates( self ): while True: try: WaitAndClearIfSet( self._query_ready ) self._candidates = self.ComputeCandidates( self._query, self._start_column ) except: self._query_ready.clear() self._candidates = [] self._candidates_ready.set() def WaitAndClearIfSet( event, timeout=None ): """Given an |event| and a |timeout|, waits for the event a maximum of timeout seconds. After waiting, clears the event if it's set and returns the state of the event before it was cleared.""" # We can't just do flag_is_set = event.wait( timeout ) because that breaks on # Python 2.6 event.wait( timeout ) flag_is_set = event.is_set() if flag_is_set: event.clear() return flag_is_set