Merge pull request #756 from icholy/master

Fix issues with tab completion.
This commit is contained in:
Berker Peksag 2015-01-19 19:30:47 +02:00
commit 8d6f9c3d84
3 changed files with 44 additions and 25 deletions

View File

@ -53,6 +53,11 @@ if PY3:
else: else:
long_type = long # NOQA long_type = long # NOQA
if PY3:
string_types = str,
else:
string_types = basestring, # NOQA
if PY3: if PY3:
exec('def raise_empty(t, *args): raise t(*args) from None') exec('def raise_empty(t, *args): raise t(*args) from None')
else: else:

View File

@ -220,12 +220,12 @@ def run_repl(hr=None, spy=False):
sys.ps1 = "=> " sys.ps1 = "=> "
sys.ps2 = "... " sys.ps2 = "... "
ns = {} namespace = {'__name__': '__console__', '__doc__': ''}
with completion(Completer(namespace=ns)): with completion(Completer(namespace)):
if not hr: if not hr:
hr = HyREPL(spy, locals=ns) hr = HyREPL(spy, namespace)
hr.interact("{appname} {version} using " hr.interact("{appname} {version} using "
"{py}({build}) {pyversion} on {os}".format( "{py}({build}) {pyversion} on {os}".format(

View File

@ -29,6 +29,7 @@ import os
import re import re
import sys import sys
from contextlib import contextmanager from contextlib import contextmanager
from hy._compat import string_types
docomplete = True docomplete = True
@ -53,27 +54,31 @@ import hy.compiler
from hy._compat import builtins from hy._compat import builtins
PATH = [hy.compiler._compile_table,
hy.macros._hy_macros,
builtins.__dict__]
class Completer(object): class Completer(object):
def __init__(self, namespace=None):
if namespace and not isinstance(namespace, dict):
raise TypeError('namespace must be a dictionary')
def __init__(self, namespace={}):
if not isinstance(namespace, dict):
raise TypeError('namespace must be a dictionary')
self.namespace = namespace self.namespace = namespace
self.path = [hy.compiler._compile_table,
builtins.__dict__,
hy.macros._hy_macros[None],
namespace]
self.reader_path = [hy.macros._hy_reader[None]]
if '__name__' in namespace:
module_name = namespace['__name__']
self.path.append(hy.macros._hy_macros[module_name])
self.reader_path.append(hy.macros._hy_reader[module_name])
def attr_matches(self, text): def attr_matches(self, text):
# Borrowed from IPython's completer # Borrowed from IPython's completer
m = re.match(r"(\S+(\.[\w-]+)*)\.([\w-]*)$", text)
# Another option, seems to work great. Catches things like ''.<tab>
m = re.match(r"(\S+(\.\w+)*)\.([\w-]*)$", text)
if m: if m:
expr, attr = m.group(1, 3) expr, attr = m.group(1, 3)
attr = attr.replace("-", "_") attr = attr.replace("-", "_")
expr = expr.replace("-", "_")
else: else:
return [] return []
@ -83,29 +88,38 @@ class Completer(object):
except Exception: except Exception:
return [] return []
# Build match list to return
n = len(attr) n = len(attr)
matches = [] matches = []
for w in words: for w in words:
if w[:n] == attr: if w[:n] == attr:
matches.append("%s.%s" % (expr, w.replace("_", "-"))) matches.append("{}.{}".format(
expr.replace("_", "-"), w.replace("_", "-")))
return matches return matches
def global_matches(self, text): def global_matches(self, text):
path = PATH
if self.namespace:
path.append(self.namespace)
matches = [] matches = []
for p in path: for p in self.path:
p = filter(lambda x: isinstance(x, str), p.keys()) for k in p.keys():
p = [x.replace("_", "-") for x in p] if isinstance(k, string_types):
[matches.append(x) for x in k = k.replace("_", "-")
filter(lambda x: x.startswith(text), p)] if k.startswith(text):
matches.append(k)
return matches
def reader_matches(self, text):
text = text[1:]
matches = []
for p in self.reader_path:
for k in p.keys():
if isinstance(k, string_types):
if k.startswith(text):
matches.append("#{}".format(k))
return matches return matches
def complete(self, text, state): def complete(self, text, state):
if "." in text: if text.startswith("#"):
matches = self.reader_matches(text)
elif "." in text:
matches = self.attr_matches(text) matches = self.attr_matches(text)
else: else:
matches = self.global_matches(text) matches = self.global_matches(text)