Skip to content

Commit 2cfa83b

Browse files
committed
Re-introduce autocompletion modes
Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
1 parent 4d26621 commit 2cfa83b

File tree

2 files changed

+53
-26
lines changed

2 files changed

+53
-26
lines changed

bpython/autocomplete.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,32 @@ def after_last_dot(name):
6868
return name.rstrip('.').rsplit('.')[-1]
6969

7070

71+
def method_match_simple(word, size, text):
72+
return word[:size] == text
73+
74+
75+
def method_match_substring(word, size, text):
76+
return text in word
77+
78+
79+
def method_match_fuzzy(word, size, text):
80+
s = r'.*%s.*' % '.*'.join(list(text))
81+
return re.search(s, word)
82+
83+
84+
MODES_MAP = {
85+
SIMPLE: method_match_simple,
86+
SUBSTRING: method_match_substring,
87+
FUZZY: method_match_fuzzy
88+
}
89+
90+
7191
class BaseCompletionType(object):
7292
"""Describes different completion types"""
7393

74-
def __init__(self, shown_before_tab=True):
94+
def __init__(self, shown_before_tab=True, mode=SIMPLE):
7595
self._shown_before_tab = shown_before_tab
96+
self.method_match = MODES_MAP[mode]
7697

7798
def matches(self, cursor_offset, line, **kwargs):
7899
"""Returns a list of possible matches given a line and cursor, or None
@@ -112,17 +133,20 @@ def shown_before_tab(self):
112133
once that has happened."""
113134
return self._shown_before_tab
114135

136+
def method_match(self, word, size, text):
137+
return word[:size] == text
138+
115139

116140
class CumulativeCompleter(BaseCompletionType):
117141
"""Returns combined matches from several completers"""
118142

119-
def __init__(self, completers):
143+
def __init__(self, completers, mode=SIMPLE):
120144
if not completers:
121145
raise ValueError(
122146
"CumulativeCompleter requires at least one completer")
123147
self._completers = completers
124148

125-
super(CumulativeCompleter, self).__init__(True)
149+
super(CumulativeCompleter, self).__init__(True, mode)
126150

127151
def locate(self, current_offset, line):
128152
return self._completers[0].locate(current_offset, line)
@@ -158,8 +182,8 @@ def format(self, word):
158182

159183
class FilenameCompletion(BaseCompletionType):
160184

161-
def __init__(self):
162-
super(FilenameCompletion, self).__init__(False)
185+
def __init__(self, mode=SIMPLE):
186+
super(FilenameCompletion, self).__init__(False, mode)
163187

164188
if sys.version_info[:2] >= (3, 4):
165189
def safe_glob(self, pathname):
@@ -282,7 +306,7 @@ def attr_lookup(self, obj, expr, attr):
282306
matches = []
283307
n = len(attr)
284308
for word in words:
285-
if method_match(word, n, attr) and word != "__builtins__":
309+
if self.method_match(word, n, attr) and word != "__builtins__":
286310
matches.append("%s.%s" % (expr, word))
287311
return matches
288312

@@ -354,11 +378,11 @@ def matches(self, cursor_offset, line, **kwargs):
354378
matches = set()
355379
n = len(text)
356380
for word in KEYWORDS:
357-
if method_match(word, n, text):
381+
if self.method_match(word, n, text):
358382
matches.add(word)
359383
for nspace in (builtins.__dict__, locals_):
360384
for word, val in iteritems(nspace):
361-
if method_match(word, n, text) and word != "__builtins__":
385+
if self.method_match(word, n, text) and word != "__builtins__":
362386
word = try_decode(word, 'ascii')
363387
# if identifier isn't ascii, don't complete (syntax error)
364388
if word is None:
@@ -508,28 +532,31 @@ def get_completer(completers, cursor_offset, line, **kwargs):
508532
"""
509533

510534
for completer in completers:
511-
matches = completer.matches(
512-
cursor_offset, line, **kwargs)
535+
matches = completer.matches(cursor_offset, line, **kwargs)
513536
if matches is not None:
514537
return sorted(matches), (completer if matches else None)
515538
return [], None
516539

517540

518-
BPYTHON_COMPLETER = (
519-
DictKeyCompletion(),
520-
StringLiteralAttrCompletion(),
521-
ImportCompletion(),
522-
FilenameCompletion(),
523-
MagicMethodCompletion(),
524-
MultilineJediCompletion(),
525-
GlobalCompletion(),
526-
CumulativeCompleter((AttrCompletion(), ParameterNameCompletion()))
527-
)
541+
def get_default_completer(mode=SIMPLE):
542+
return (
543+
DictKeyCompletion(mode=mode),
544+
StringLiteralAttrCompletion(mode=mode),
545+
ImportCompletion(mode=mode),
546+
FilenameCompletion(mode=mode),
547+
MagicMethodCompletion(mode=mode),
548+
MultilineJediCompletion(mode=mode),
549+
GlobalCompletion(mode=mode),
550+
CumulativeCompleter((AttrCompletion(mode=mode),
551+
ParameterNameCompletion(mode=mode)),
552+
mode=mode)
553+
)
528554

529555

530556
def get_completer_bpython(cursor_offset, line, **kwargs):
531557
""""""
532-
return get_completer(BPYTHON_COMPLETER, cursor_offset, line, **kwargs)
558+
return get_completer(get_default_completer(),
559+
cursor_offset, line, **kwargs)
533560

534561

535562
class EvaluationError(Exception):
@@ -552,7 +579,3 @@ def _callable_postfix(value, word):
552579
if inspection.is_callable(value):
553580
word += '('
554581
return word
555-
556-
557-
def method_match(word, size, text):
558-
return word[:size] == text

bpython/repl.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,9 @@ def __init__(self, interp, config):
384384
except EnvironmentError:
385385
pass
386386

387+
self.completers = autocomplete.get_default_completer(
388+
config.autocomplete_mode)
389+
387390
@property
388391
def ps1(self):
389392
try:
@@ -595,7 +598,8 @@ def complete(self, tab=False):
595598

596599
self.set_docstring()
597600

598-
matches, completer = autocomplete.get_completer_bpython(
601+
matches, completer = autocomplete.get_completer(
602+
self.completers,
599603
cursor_offset=self.cursor_offset,
600604
line=self.current_line,
601605
locals_=self.interp.locals,

0 commit comments

Comments
 (0)