Skip to content

Commit 34155ab

Browse files
committed
Add alternate autocomplete_mode
1 parent 6b0a281 commit 34155ab

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed

bpython/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def loadini(struct, configfile):
5656
'color_scheme': 'default',
5757
'complete_magic_methods' : True,
5858
'magic_methods' : MAGIC_METHODS,
59+
'autocomplete_mode':2,
5960
'dedent_after': 1,
6061
'flush_output': True,
6162
'highlight_show_source': True,
@@ -147,6 +148,7 @@ def loadini(struct, configfile):
147148
'complete_magic_methods')
148149
methods = config.get('general', 'magic_methods')
149150
struct.magic_methods = [meth.strip() for meth in methods.split(",")]
151+
struct.autocomplete_mode = config.get('general', 'autocomplete_mode')
150152

151153
struct.gtk_font = config.get('gtk', 'font')
152154

bpython/repl.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#
2323

2424
from __future__ import with_statement
25+
import __builtin__
26+
import __main__
27+
2528
import code
2629
import codecs
2730
import errno
@@ -384,6 +387,7 @@ def __init__(self, interp, config):
384387
# instance instead of the type, so we monkeypatch to prevent
385388
# side-effects (__getattr__/__getattribute__)
386389
self.completer._callable_postfix = self._callable_postfix
390+
self.completer.global_matches = self.global_matches
387391
self.matches = []
388392
self.matches_iter = MatchesIterator()
389393
self.argspec = None
@@ -455,7 +459,7 @@ def attr_lookup(self, obj, expr, attr):
455459
matches = []
456460
n = len(attr)
457461
for word in words:
458-
if word[:n] == attr and word != "__builtins__":
462+
if self.method_match(word, n, attr) and word != "__builtins__":
459463
matches.append("%s.%s" % (expr, word))
460464
return matches
461465

@@ -495,6 +499,33 @@ def current_string(self, concatenate=False):
495499
return ''
496500
return ''.join(string)
497501

502+
def global_matches(self, text):
503+
"""Compute matches when text is a simple name.
504+
Return a list of all keywords, built-in functions and names currently
505+
defined in self.namespace that match.
506+
"""
507+
508+
hash = {}
509+
n = len(text)
510+
import keyword
511+
for word in keyword.kwlist:
512+
if self.method_match(word, n, text):
513+
hash[word] = 1
514+
for nspace in [__builtin__.__dict__, __main__.__dict__]:
515+
for word, val in nspace.items():
516+
if self.method_match(word, len(text), text) and word != "__builtins__":
517+
hash[self._callable_postfix(val, word)] = 1
518+
matches = hash.keys()
519+
matches.sort()
520+
return matches
521+
522+
def method_match(self, word, size, text):
523+
if self.config.autocomplete_mode == "1":
524+
return word[:size] == text
525+
else:
526+
s = r'.*%s.*' % '.*'.join(list(text))
527+
return re.search(s, word)
528+
498529
def get_object(self, name):
499530
attributes = name.split('.')
500531
obj = eval(attributes.pop(0), self.interp.locals)

bpython/test/test_repl.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,26 @@ def test_update(self):
130130
self.assertNotEqual(list(slice), self.matches)
131131
self.assertEqual(list(newslice), newmatches)
132132

133-
class TestRepl(repl.Repl):
133+
134+
class FakeRepl(repl.Repl):
134135
def __init__(self):
135136
config_struct = config.Struct()
136137
config.loadini(config_struct, os.devnull)
137138
repl.Repl.__init__(self, repl.Interpreter(), config_struct)
138139
self.input_line = ""
140+
self.current_word = ""
141+
self.cpos = 0
139142

140143
def current_line(self):
141144
return self.input_line
142145

146+
def cw(self):
147+
return self.current_word
148+
149+
143150
class TestArgspec(unittest.TestCase):
144151
def setUp(self):
145-
self.repl = TestRepl()
152+
self.repl = FakeRepl()
146153
self.repl.push("def spam(a, b, c):\n", False)
147154
self.repl.push(" pass\n", False)
148155
self.repl.push("\n", False)
@@ -195,6 +202,32 @@ def test_nonexistent_name(self):
195202
self.setInputLine("spamspamspam(")
196203
self.assertFalse(self.repl.get_args())
197204

205+
class TestRepl(unittest.TestCase):
206+
def setUp(self):
207+
self.repl = FakeRepl()
208+
self.repl.config.autocomplete_mode = "1"
209+
210+
211+
def test_default_complete(self):
212+
self.repl.input_line = "d"
213+
self.repl.current_word = "d"
214+
215+
self.assertTrue(self.repl.complete())
216+
self.assertTrue(hasattr(self.repl.completer,'matches'))
217+
self.assertEqual(self.repl.completer.matches,
218+
['def', 'del', 'delattr(', 'dict(', 'dir(', 'divmod('])
219+
220+
def test_alternate_complete(self):
221+
self.repl.input_line = "doc"
222+
self.repl.current_word = "doc"
223+
self.repl.config.autocomplete_mode = "2"
224+
225+
self.assertTrue(self.repl.complete())
226+
self.assertTrue(hasattr(self.repl.completer,'matches'))
227+
self.assertEqual(self.repl.completer.matches,
228+
['UnboundLocalError(', '__doc__'])
229+
230+
198231

199232
if __name__ == '__main__':
200233
unittest.main()

0 commit comments

Comments
 (0)