diff --git a/AUTHORS b/AUTHORS index 8c9c783..4952fdc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -55,4 +55,5 @@ * Kevin Yap * Matthías Páll Gissurarson * Nathan Woodrow -* Adam Schwalm \ No newline at end of file +* Adam Schwalm +* Ilia Choly diff --git a/hy/cmdline.py b/hy/cmdline.py index 84f8335..564dedb 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -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( diff --git a/hy/completer.py b/hy/completer.py index 05ac88f..19e4858 100644 --- a/hy/completer.py +++ b/hy/completer.py @@ -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 ''. + 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: