completer.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #!/usr/bin/env python
  2. #
  3. # Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
  4. #
  5. # This file is part of YouCompleteMe.
  6. #
  7. # YouCompleteMe is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # YouCompleteMe is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
  19. import abc
  20. import vim
  21. import ycm_core
  22. from ycm import vimsupport
  23. from collections import defaultdict
  24. NO_USER_COMMANDS = 'This completer does not define any commands.'
  25. MIN_NUM_CHARS = int( vimsupport.GetVariableValue(
  26. "g:ycm_min_num_of_chars_for_completion" ) )
  27. class Completer( object ):
  28. """A base class for all Completers in YCM.
  29. Here's several important things you need to know if you're writing a custom
  30. Completer. The following are functions that the Vim part of YCM will be
  31. calling on your Completer:
  32. ShouldUseNow() is called with the start column of where a potential completion
  33. string should start. For instance, if the user's input is 'foo.bar' and the
  34. cursor is on the 'r' in 'bar', start_column will be the 0-based index of 'b'
  35. in the line. Your implementation of ShouldUseNow() should return True if your
  36. semantic completer should be used and False otherwise.
  37. This is important to get right. You want to return False if you can't provide
  38. completions because then the identifier completer will kick in, and that's
  39. better than nothing.
  40. Note that it's HIGHLY likely that you want to override the ShouldUseNowInner()
  41. function instead of ShouldUseNow() directly (although chances are that you
  42. probably won't have any need to override either). ShouldUseNow() will call
  43. your *Inner version of the function and will also make sure that the
  44. completion cache is taken into account. You'll see this pattern repeated
  45. throughout the Completer API; YCM calls the "main" version of the function and
  46. that function calls the *Inner version while taking into account the cache.
  47. The cache is important and is a nice performance boost. When the user types in
  48. "foo.", your completer will return a list of all member functions and
  49. variables that can be accessed on the "foo" object. The Completer API caches
  50. this list. The user will then continue typing, let's say "foo.ba". On every
  51. keystroke after the dot, the Completer API will take the cache into account
  52. and will NOT re-query your completer but will in fact provide fuzzy-search on
  53. the candidate strings that were stored in the cache.
  54. CandidatesForQueryAsync() is the main entry point when the user types. For
  55. "foo.bar", the user query is "bar" and completions matching this string should
  56. be shown. The job of CandidatesForQueryAsync() is to merely initiate this
  57. request, which will hopefully be processed in a background thread.
  58. AsyncCandidateRequestReady() is the function that is repeatedly polled until
  59. it returns True. If CandidatesForQueryAsync() started a background task of
  60. collecting the required completions, AsyncCandidateRequestReady() would check
  61. the state of that task and return False until it was completed.
  62. CandidatesFromStoredRequest() should return the list of candidates. This is
  63. what YCM calls after AsyncCandidateRequestReady() returns True. The format of
  64. the result can be a list of strings or a more complicated list of
  65. dictionaries. See ':h complete-items' for the format, and clang_completer.py
  66. to see how its used in practice.
  67. You also need to implement the SupportedFiletypes() function which should
  68. return a list of strings, where the strings are Vim filetypes your completer
  69. supports.
  70. clang_completer.py is a good example of a "complicated" completer that
  71. maintains its own internal cache and therefore directly overrides the "main"
  72. functions in the API instead of the *Inner versions. A good example of a
  73. simple completer that does not do this is omni_completer.py.
  74. If you're confident your completer doesn't need a background task (think
  75. again, you probably do) because you can "certainly" furnish a response in
  76. under 10ms, then you can perform your backend processing in a synchronous
  77. fashion. You may also need to do this because of technical restrictions (much
  78. like omni_completer.py has to do it because accessing Vim internals is not
  79. thread-safe). But even if you're certain, still try to do the processing in a
  80. background thread. Your completer is unlikely to be merged if it does not,
  81. because synchronous processing will block Vim's GUI thread and that's a very,
  82. VERY bad thing (so try not to do it!).
  83. The On* functions are provided for your convenience. They are called when
  84. their specific events occur. For instance, the identifier completer collects
  85. all the identifiers in the file in OnFileReadyToParse() which gets called when
  86. the user stops typing for 2 seconds (Vim's CursorHold and CursorHoldI events).
  87. One special function is OnUserCommand. It is called when the user uses the
  88. command :YcmCompleter and is passed all extra arguments used on command
  89. invocation (e.g. OnUserCommand(['first argument', 'second'])). This can be
  90. used for completer-specific commands such as reloading external
  91. configuration.
  92. When the command is called with no arguments you should print a short summary
  93. of the supported commands or point the user to the help section where this
  94. information can be found."""
  95. __metaclass__ = abc.ABCMeta
  96. def __init__( self ):
  97. self.triggers_for_filetype = TriggersForFiletype()
  98. self.completions_future = None
  99. self.completions_cache = None
  100. self.completion_start_column = None
  101. # It's highly likely you DON'T want to override this function but the *Inner
  102. # version of it.
  103. def ShouldUseNow( self, start_column ):
  104. inner_says_yes = self.ShouldUseNowInner( start_column )
  105. if not inner_says_yes:
  106. self.completions_cache = None
  107. previous_results_were_empty = ( self.completions_cache and
  108. self.completions_cache.CacheValid(
  109. start_column ) and
  110. not self.completions_cache.raw_completions )
  111. return inner_says_yes and not previous_results_were_empty
  112. def ShouldUseNowInner( self, start_column ):
  113. line = vim.current.line
  114. line_length = len( line )
  115. if not line_length or start_column - 1 >= line_length:
  116. return False
  117. filetype = self._CurrentFiletype()
  118. triggers = self.triggers_for_filetype[ filetype ]
  119. for trigger in triggers:
  120. index = -1
  121. trigger_length = len( trigger )
  122. while True:
  123. line_index = start_column + index
  124. if line_index < 0 or line[ line_index ] != trigger[ index ]:
  125. break
  126. if abs( index ) == trigger_length:
  127. return True
  128. index -= 1
  129. return False
  130. def QueryLengthAboveMinThreshold( self, start_column ):
  131. query_length = vimsupport.CurrentColumn() - start_column
  132. return query_length >= MIN_NUM_CHARS
  133. # It's highly likely you DON'T want to override this function but the *Inner
  134. # version of it.
  135. def CandidatesForQueryAsync( self, query, start_column ):
  136. self.completion_start_column = start_column
  137. if query and self.completions_cache and self.completions_cache.CacheValid(
  138. start_column ):
  139. self.completions_cache.filtered_completions = (
  140. self.FilterAndSortCandidates(
  141. self.completions_cache.raw_completions,
  142. query ) )
  143. else:
  144. self.completions_cache = None
  145. self.CandidatesForQueryAsyncInner( query, start_column )
  146. def DefinedSubcommands( self ):
  147. return []
  148. def EchoUserCommandsHelpMessage( self ):
  149. subcommands = self.DefinedSubcommands()
  150. if subcommands:
  151. vimsupport.EchoText( 'Supported commands are:\n' +
  152. '\n'.join( subcommands ) +
  153. '\nSee the docs for information on what they do.' )
  154. else:
  155. vimsupport.EchoText( 'No supported subcommands' )
  156. def FilterAndSortCandidates( self, candidates, query ):
  157. if not candidates:
  158. return []
  159. if hasattr( candidates, 'words' ):
  160. candidates = candidates.words
  161. items_are_objects = 'word' in candidates[ 0 ]
  162. matches = ycm_core.FilterAndSortCandidates(
  163. candidates,
  164. 'word' if items_are_objects else '',
  165. query )
  166. return matches
  167. def CandidatesForQueryAsyncInner( self, query, start_column ):
  168. pass
  169. # It's highly likely you DON'T want to override this function but the *Inner
  170. # version of it.
  171. def AsyncCandidateRequestReady( self ):
  172. if self.completions_cache:
  173. return True
  174. else:
  175. return self.AsyncCandidateRequestReadyInner()
  176. def AsyncCandidateRequestReadyInner( self ):
  177. if not self.completions_future:
  178. # We return True so that the caller can extract the default value from the
  179. # future
  180. return True
  181. return self.completions_future.ResultsReady()
  182. # It's highly likely you DON'T want to override this function but the *Inner
  183. # version of it.
  184. def CandidatesFromStoredRequest( self ):
  185. if self.completions_cache:
  186. return self.completions_cache.filtered_completions
  187. else:
  188. self.completions_cache = CompletionsCache()
  189. self.completions_cache.raw_completions = self.CandidatesFromStoredRequestInner()
  190. self.completions_cache.line, _ = vimsupport.CurrentLineAndColumn()
  191. self.completions_cache.column = self.completion_start_column
  192. return self.completions_cache.raw_completions
  193. def CandidatesFromStoredRequestInner( self ):
  194. if not self.completions_future:
  195. return []
  196. return self.completions_future.GetResults()
  197. def OnFileReadyToParse( self ):
  198. pass
  199. def OnCursorMovedInsertMode( self ):
  200. pass
  201. def OnCursorMovedNormalMode( self ):
  202. pass
  203. def OnBufferVisit( self ):
  204. pass
  205. def OnBufferUnload( self, deleted_buffer_file ):
  206. pass
  207. def OnCursorHold( self ):
  208. pass
  209. def OnInsertLeave( self ):
  210. pass
  211. def OnUserCommand( self, arguments ):
  212. vimsupport.PostVimMessage( NO_USER_COMMANDS )
  213. def OnCurrentIdentifierFinished( self ):
  214. pass
  215. def DiagnosticsForCurrentFileReady( self ):
  216. return False
  217. def GetDiagnosticsForCurrentFile( self ):
  218. return []
  219. def ShowDetailedDiagnostic( self ):
  220. pass
  221. def GettingCompletions( self ):
  222. return False
  223. def _CurrentFiletype( self ):
  224. filetypes = vimsupport.CurrentFiletypes()
  225. supported = self.SupportedFiletypes()
  226. for filetype in filetypes:
  227. if filetype in supported:
  228. return filetype
  229. return filetypes[0]
  230. @abc.abstractmethod
  231. def SupportedFiletypes( self ):
  232. pass
  233. def DebugInfo( self ):
  234. return ''
  235. class CompletionsCache( object ):
  236. def __init__( self ):
  237. self.line = -1
  238. self.column = -1
  239. self.raw_completions = []
  240. self.filtered_completions = []
  241. def CacheValid( self, start_column ):
  242. completion_line, _ = vimsupport.CurrentLineAndColumn()
  243. completion_column = start_column
  244. return completion_line == self.line and completion_column == self.column
  245. def TriggersForFiletype():
  246. triggers = vim.eval( 'g:ycm_semantic_triggers' )
  247. triggers_for_filetype = defaultdict( list )
  248. for key, value in triggers.iteritems():
  249. filetypes = key.split( ',' )
  250. for filetype in filetypes:
  251. triggers_for_filetype[ filetype ].extend( value )
  252. return triggers_for_filetype