X Tutup
Skip to content

Commit 3a1e177

Browse files
autocomplete now functions, plus temp compat layer
started tests for autocomplete.complete
1 parent 82c3f1e commit 3a1e177

File tree

2 files changed

+120
-132
lines changed

2 files changed

+120
-132
lines changed

bpython/autocomplete.py

Lines changed: 119 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from __future__ import with_statement
2525
import __builtin__
26+
import __main__
2627
import rlcompleter
2728
import line
2829
import re
@@ -48,142 +49,128 @@
4849
FUZZY = 'fuzzy'
4950

5051
class Autocomplete(rlcompleter.Completer):
51-
"""
52-
#TOMHERE TODO This doesn't need to be a class anymore - we're overriding every single method
53-
We're not really using it for the right thing anyway - we're hacking it to produce
54-
self.matches then stealing them instead of following the expected interface of calling
55-
complete each time.
56-
"""
57-
58-
def __init__(self, namespace = None, config = None):
59-
rlcompleter.Completer.__init__(self, namespace)
60-
self.locals = namespace
61-
if hasattr(config, 'autocomplete_mode'):
62-
self.autocomplete_mode = config.autocomplete_mode
52+
def __init__(self, namespace, config):
53+
self.namespace = namespace
54+
self.config = config
55+
def complete(self, cw, _):
56+
self.matches = complete(cw, namespace=self.namespace, config=self.config)
57+
58+
def complete(text, namespace=None, config=None):
59+
"""Return list of matches """
60+
if namespace is None:
61+
namespace = __main__.__dict__
62+
63+
if hasattr(config, 'autocomplete_mode'):
64+
autocomplete_mode = config.autocomplete_mode
65+
else:
66+
autocomplete_mode = SUBSTRING
67+
68+
dictpattern = re.compile('[^\[\]]+\[$')
69+
def complete_dict(text):
70+
lastbracket_index = text.rindex('[')
71+
dexpr = text[:lastbracket_index].lstrip()
72+
obj = eval(dexpr, namespace)
73+
if obj and isinstance(obj, type({})) and obj.keys():
74+
return [dexpr + "[{!r}]".format(k) for k in obj.keys()]
6375
else:
64-
self.autocomplete_mode = SUBSTRING
65-
66-
def complete(self, text, state):
67-
"""Return the next possible completion for 'text'.
68-
69-
This is called successively with state == 0, 1, 2, ... until it
70-
returns None. The completion should begin with 'text'.
71-
72-
"""
73-
if self.use_main_ns:
74-
self.namespace = __main__.__dict__
75-
76-
dictpattern = re.compile('[^\[\]]+\[$')
77-
def complete_dict(text):
78-
lastbracket_index = text.rindex('[')
79-
dexpr = text[:lastbracket_index].lstrip()
80-
obj = eval(dexpr, self.locals)
81-
if obj and isinstance(obj, type({})) and obj.keys():
82-
self.matches = [dexpr + "[{!r}]".format(k) for k in obj.keys()]
83-
else:
84-
# empty dictionary
85-
self.matches = []
86-
87-
if state == 0:
88-
if "." in text:
89-
if dictpattern.match(text):
90-
complete_dict(text)
91-
else:
92-
# Examples: 'foo.b' or 'foo[bar.'
93-
for i in range(1, len(text) + 1):
94-
if text[-i] == '[':
95-
i -= 1
96-
break
97-
methodtext = text[-i:]
98-
self.matches = [''.join([text[:-i], m]) for m in
99-
self.attr_matches(methodtext)]
100-
elif dictpattern.match(text):
101-
complete_dict(text)
102-
else:
103-
self.matches = self.global_matches(text)
104-
try:
105-
return self.matches[state]
106-
except IndexError:
107-
return None
108-
109-
def attr_matches(self, text):
110-
"""Taken from rlcompleter.py and bent to my will.
111-
"""
112-
113-
# Gna, Py 2.6's rlcompleter searches for __call__ inside the
114-
# instance instead of the type, so we monkeypatch to prevent
115-
# side-effects (__getattr__/__getattribute__)
116-
m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
117-
if not m:
76+
# empty dictionary
11877
return []
11978

120-
expr, attr = m.group(1, 3)
121-
if expr.isdigit():
122-
# Special case: float literal, using attrs here will result in
123-
# a SyntaxError
124-
return []
125-
obj = eval(expr, self.locals)
126-
with inspection.AttrCleaner(obj):
127-
matches = self.attr_lookup(obj, expr, attr)
128-
return matches
129-
130-
def attr_lookup(self, obj, expr, attr):
131-
"""Second half of original attr_matches method factored out so it can
132-
be wrapped in a safe try/finally block in case anything bad happens to
133-
restore the original __getattribute__ method."""
134-
words = dir(obj)
135-
if hasattr(obj, '__class__'):
136-
words.append('__class__')
137-
words = words + rlcompleter.get_class_members(obj.__class__)
138-
if has_abc and not isinstance(obj.__class__, abc.ABCMeta):
139-
try:
140-
words.remove('__abstractmethods__')
141-
except ValueError:
142-
pass
143-
144-
matches = []
145-
n = len(attr)
146-
for word in words:
147-
if self.method_match(word, n, attr) and word != "__builtins__":
148-
matches.append("%s.%s" % (expr, word))
149-
return matches
150-
151-
def _callable_postfix(self, value, word):
152-
"""rlcompleter's _callable_postfix done right."""
153-
with inspection.AttrCleaner(value):
154-
if inspection.is_callable(value):
155-
word += '('
156-
return word
157-
158-
def global_matches(self, text):
159-
"""Compute matches when text is a simple name.
160-
Return a list of all keywords, built-in functions and names currently
161-
defined in self.namespace that match.
162-
"""
163-
164-
hash = {}
165-
n = len(text)
166-
import keyword
167-
for word in keyword.kwlist:
168-
if self.method_match(word, n, text):
169-
hash[word] = 1
170-
for nspace in [__builtin__.__dict__, self.namespace]:
171-
for word, val in nspace.items():
172-
if self.method_match(word, len(text), text) and word != "__builtins__":
173-
hash[self._callable_postfix(val, word)] = 1
174-
matches = hash.keys()
175-
matches.sort()
176-
return matches
177-
178-
def method_match(self, word, size, text):
179-
if self.autocomplete_mode == SIMPLE:
180-
return word[:size] == text
181-
elif self.autocomplete_mode == SUBSTRING:
182-
s = r'.*%s.*' % text
183-
return re.search(s, word)
79+
if "." in text:
80+
if dictpattern.match(text):
81+
return complete_dict(text)
18482
else:
185-
s = r'.*%s.*' % '.*'.join(list(text))
186-
return re.search(s, word)
83+
# Examples: 'foo.b' or 'foo[bar.'
84+
for i in range(1, len(text) + 1):
85+
if text[-i] == '[':
86+
i -= 1
87+
break
88+
methodtext = text[-i:]
89+
return [''.join([text[:-i], m]) for m in
90+
attr_matches(methodtext, namespace, autocomplete_mode)]
91+
elif dictpattern.match(text):
92+
return complete_dict(text)
93+
else:
94+
return global_matches(text, namespace, autocomplete_mode)
95+
96+
def attr_matches(text, namespace, autocomplete_mode):
97+
"""Taken from rlcompleter.py and bent to my will.
98+
"""
99+
100+
# Gna, Py 2.6's rlcompleter searches for __call__ inside the
101+
# instance instead of the type, so we monkeypatch to prevent
102+
# side-effects (__getattr__/__getattribute__)
103+
m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
104+
if not m:
105+
return []
106+
107+
expr, attr = m.group(1, 3)
108+
if expr.isdigit():
109+
# Special case: float literal, using attrs here will result in
110+
# a SyntaxError
111+
return []
112+
obj = eval(expr, namespace)
113+
with inspection.AttrCleaner(obj):
114+
matches = attr_lookup(obj, expr, attr, autocomplete_mode)
115+
return matches
116+
117+
def attr_lookup(obj, expr, attr, autocomplete_mode):
118+
"""Second half of original attr_matches method factored out so it can
119+
be wrapped in a safe try/finally block in case anything bad happens to
120+
restore the original __getattribute__ method."""
121+
words = dir(obj)
122+
if hasattr(obj, '__class__'):
123+
words.append('__class__')
124+
words = words + rlcompleter.get_class_members(obj.__class__)
125+
if has_abc and not isinstance(obj.__class__, abc.ABCMeta):
126+
try:
127+
words.remove('__abstractmethods__')
128+
except ValueError:
129+
pass
130+
131+
matches = []
132+
n = len(attr)
133+
for word in words:
134+
if method_match(word, n, attr, autocomplete_mode) and word != "__builtins__":
135+
matches.append("%s.%s" % (expr, word))
136+
return matches
137+
138+
def _callable_postfix(value, word):
139+
"""rlcompleter's _callable_postfix done right."""
140+
with inspection.AttrCleaner(value):
141+
if inspection.is_callable(value):
142+
word += '('
143+
return word
144+
145+
def global_matches(text, namespace, autocomplete_mode):
146+
"""Compute matches when text is a simple name.
147+
Return a list of all keywords, built-in functions and names currently
148+
defined in self.namespace that match.
149+
"""
150+
151+
hash = {}
152+
n = len(text)
153+
import keyword
154+
for word in keyword.kwlist:
155+
if method_match(word, n, text, autocomplete_mode):
156+
hash[word] = 1
157+
for nspace in [__builtin__.__dict__, namespace]:
158+
for word, val in nspace.items():
159+
if method_match(word, len(text), text, autocomplete_mode) and word != "__builtins__":
160+
hash[_callable_postfix(val, word)] = 1
161+
matches = hash.keys()
162+
matches.sort()
163+
return matches
164+
165+
def method_match(word, size, text, autocomplete_mode):
166+
if autocomplete_mode == SIMPLE:
167+
return word[:size] == text
168+
elif autocomplete_mode == SUBSTRING:
169+
s = r'.*%s.*' % text
170+
return re.search(s, word)
171+
else:
172+
s = r'.*%s.*' % '.*'.join(list(text))
173+
return re.search(s, word)
187174

188175
def filename_matches(cs):
189176
matches = []

bpython/repl.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ def complete(self, tab=False):
622622
# possibly be raised here, so if anyone wants to do that, feel free to send me
623623
# a patch. XXX: Make sure you raise here if you're debugging the completion
624624
# stuff !
625+
raise
625626
e = True
626627
else:
627628
matches = self.completer.matches

0 commit comments

Comments
 (0)
X Tutup