1
0
forked from VimPlug/jedi

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.

This commit is contained in:
David Halter
2013-07-31 17:16:12 +02:00
parent ea2f9ebd4c
commit ae6dc782da

View File

@@ -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('')