Adapt attribute completion from IPython completer

This commit is contained in:
Ilia Choly 2015-01-14 14:39:28 -05:00
parent 19b55384f8
commit a5654e33ee
3 changed files with 42 additions and 5 deletions

View File

@ -55,4 +55,5 @@
* Kevin Yap <me@kevinyap.ca>
* Matthías Páll Gissurarson <mpg@mpg.is>
* Nathan Woodrow <woodrow.nathan@gmail.com>
* Adam Schwalm <adamschwalm@gmail.com>
* Adam Schwalm <adamschwalm@gmail.com>
* Ilia Choly <ilia.choly@gmail.com>

View File

@ -41,6 +41,7 @@ from hy.compiler import hy_compile, HyTypeError
from hy.importer import (ast_compile, import_buffer_to_module,
import_file_to_ast, import_file_to_hst)
from hy.completer import completion
from hy.completer import Completer
from hy.macros import macro, require
from hy.models.expression import HyExpression
@ -219,9 +220,12 @@ def run_repl(hr=None, spy=False):
sys.ps1 = "=> "
sys.ps2 = "... "
with completion():
ns = {}
with completion(Completer(namespace=ns)):
if not hr:
hr = HyREPL(spy)
hr = HyREPL(spy, locals=ns)
hr.interact("{appname} {version} using "
"{py}({build}) {pyversion} on {os}".format(

View File

@ -26,6 +26,7 @@
# DEALINGS IN THE SOFTWARE.
import os
import re
import sys
from contextlib import contextmanager
@ -64,19 +65,50 @@ class Completer(object):
self.namespace = namespace
def complete(self, text, state):
def attr_matches(self, text):
# Borrowed from IPython's completer
# Another option, seems to work great. Catches things like ''.<tab>
m = re.match(r"(\S+(\.\w+)*)\.([\w-]*)$", text)
if m:
expr, attr = m.group(1, 3)
attr = attr.replace("-", "_")
else:
return []
try:
obj = eval(expr, self.namespace)
words = dir(obj)
except Exception:
return []
# Build match list to return
n = len(attr)
matches = []
for w in words:
if w[:n] == attr:
matches.append("%s.%s" % (expr, w.replace("_", "-")))
return matches
def global_matches(self, text):
path = PATH
if self.namespace:
path.append(self.namespace)
matches = []
for p in path:
p = filter(lambda x: isinstance(x, str), p.keys())
p = [x.replace("_", "-") for x in p]
[matches.append(x) for x in
filter(lambda x: x.startswith(text), p)]
return matches
def complete(self, text, state):
if "." in text:
matches = self.attr_matches(text)
else:
matches = self.global_matches(text)
try:
return matches[state]
except IndexError: