From ae6dc782da7d1f33b099d2965e02cd9376dd2ef9 Mon Sep 17 00:00:00 2001 From: David Halter Date: Wed, 31 Jul 2013 17:16:12 +0200 Subject: [PATCH] simplify repl completion support, only use the jedi one, because the builtin completion (rlcompleter) is not context sensitive and makes the whole thing really complicated. --- jedi/utils.py | 110 ++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 84 deletions(-) diff --git a/jedi/utils.py b/jedi/utils.py index 37aa2225..31f83e49 100644 --- a/jedi/utils.py +++ b/jedi/utils.py @@ -2,92 +2,12 @@ Utilities for end-users. """ -from rlcompleter import Completer +from __future__ import absolute_import +import __main__ from jedi import Interpreter -_NON_DELIMS = ' \t\n()' -""" -:class:`rcompleter.Completer` assumes these characters to be delimiter -(i.e., :meth:`rcompleter.Completer.complete` does not expect these -characters) but :class:`JediRLCompleter` can handle them. -""" - -try: - import readline -except ImportError: - pass -else: - _READLINE_DEFAULT_DELIMS = readline.get_completer_delims() - _READLINE_JEDI_DELIMS = ''.join( - set(_READLINE_DEFAULT_DELIMS) - set(_NON_DELIMS)) - - -class JediRLCompleter(Completer): - - """ - :class:`rlcompleter.Completer` enhanced by Jedi. - - This class tries matchers defined in :class:`.Completer` first. - If they fail, :class:`jedi.Interpreter` is used. - - >>> import os - >>> completer = JediRLCompleter(locals()) - >>> completer.complete('os.path.joi', 0) # completion w/o Jedi - 'os.path.join(' - >>> completer.complete('os.path.join().s', 0) # completion with Jedi - 'os.path.join().split' - - """ - - def _jedi_matches(self, text): - completions = Interpreter(text, [self.namespace]).completions() - return [text + c.complete for c in completions] - - @staticmethod - def _split_for_default_matcher(text, delims=_NON_DELIMS): - """ - Split `text` before passing it to :meth:`Completer.attr_matches` etc. - - >>> JediRLCompleter._split_for_default_matcher('f(') - ('f(', '') - >>> JediRLCompleter._split_for_default_matcher('f().g') - ('f()', '.g') - - """ - import re - m = re.match(r"(.*[{0}])([^{0}]*)".format(re.escape(delims)), text) - if not m: - return ('', text) - return m.groups() - - def _find_matches(self, default_matcher, text): - """ - Common part for :meth:`attr_matches` and :meth:`global_matches`. - - Try `default_matcher` first and return what it returns if - it is not empty. Otherwise, try :meth:`_jedi_matches`. - - :arg default_matcher: :meth:`.Completer.attr_matches` or - :meth:`.Completer.global_matches`. - :arg str text: code to complete - """ - (pre, body) = self._split_for_default_matcher(text) - matches = default_matcher(self, body) - if matches: - return [pre + m for m in matches] - return self._jedi_matches(text) - - def attr_matches(self, text): - # NOTE: Completer is old type class so `super` cannot be used here - return self._find_matches(Completer.attr_matches, text) - - def global_matches(self, text): - # NOTE: Completer is old type class so `super` cannot be used here - return self._find_matches(Completer.global_matches, text) - - def setup_readline(): """ Install Jedi completer to :mod:`readline`. @@ -105,6 +25,28 @@ def setup_readline(): except ImportError: print("Module readline not available.") else: - readline.set_completer(JediRLCompleter().complete) + class JediRL(): + def complete(self, text, state): + """ + This complete stuff is pretty weird, a generator would make + a lot more sense, but probably due to backwards compatibility + this is still the way how it works. + + The only important part is the ``Interpreter`` call, everything + else hsa been copied from the ``rlcompleter`` std. library + module. + """ + if state == 0: + namespace = __main__.__dict__ + completions = Interpreter(text, [namespace]).completions() + self.matches = [text + c.complete for c in completions] + try: + return self.matches[state] + except IndexError: + return None + + readline.set_completer(JediRL().get_item) + readline.parse_and_bind("tab: complete") - readline.set_completer_delims(_READLINE_JEDI_DELIMS) + # No delimiters, Jedi handles that. + readline.set_completer_delims('')