Skip to content

Commit 80e7706

Browse files
committed
Use a consistent signature for matches
Also includes some PEP-8 fixes Signed-off-by: Sebastian Ramacher <sebastian+dev@ramacher.at>
1 parent 26c147d commit 80e7706

File tree

2 files changed

+103
-46
lines changed

2 files changed

+103
-46
lines changed

bpython/autocomplete.py

Lines changed: 83 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from bpython import line as lineparts
3737
from bpython._py3compat import py3
3838

39+
3940
# Autocomplete modes
4041
SIMPLE = 'simple'
4142
SUBSTRING = 'substring'
@@ -70,11 +71,13 @@ def matches(self, cursor_offset, line, **kwargs):
7071
an import or from statement, so it ought to return None.
7172
7273
Completion types are used to:
73-
* `locate(cur, line)` their initial target word to replace given a line and cursor
74+
* `locate(cur, line)` their initial target word to replace given a
75+
line and cursor
7476
* find `matches(cur, line)` that might replace that word
7577
* `format(match)` matches to be displayed to the user
7678
* determine whether suggestions should be `shown_before_tab`
77-
* `substitute(cur, line, match)` in a match for what's found with `target`
79+
* `substitute(cur, line, match)` in a match for what's found with
80+
`target`
7881
"""
7982
raise NotImplementedError
8083

@@ -98,12 +101,14 @@ def shown_before_tab(self):
98101
once that has happened."""
99102
return self._shown_before_tab
100103

104+
101105
class CumulativeCompleter(BaseCompletionType):
102106
"""Returns combined matches from several completers"""
103107

104108
def __init__(self, completers):
105109
if not completers:
106-
raise ValueError("CumulativeCompleter requires at least one completer")
110+
raise ValueError(
111+
"CumulativeCompleter requires at least one completer")
107112
self._completers = completers
108113

109114
super(CumulativeCompleter, self).__init__(True)
@@ -114,22 +119,18 @@ def locate(self, current_offset, line):
114119
def format(self, word):
115120
return self._completers[0].format(word)
116121

117-
def matches(self, cursor_offset, line, locals_, argspec, current_block, complete_magic_methods, history):
122+
def matches(self, cursor_offset, line, **kwargs):
118123
all_matches = set()
119124
for completer in self._completers:
120125
# these have to be explicitely listed to deal with the different
121126
# signatures of various matches() methods of completers
122127
matches = completer.matches(cursor_offset=cursor_offset,
123128
line=line,
124-
locals_=locals_,
125-
argspec=argspec,
126-
current_block=current_block,
127-
complete_magic_methods=complete_magic_methods,
128-
history=history)
129+
**kwargs)
129130
if matches is not None:
130131
all_matches.update(matches)
131132

132-
return sorted(all_matches)
133+
return all_matches
133134

134135

135136
class ImportCompletion(BaseCompletionType):
@@ -143,6 +144,7 @@ def locate(self, current_offset, line):
143144
def format(self, word):
144145
return after_last_dot(word)
145146

147+
146148
class FilenameCompletion(BaseCompletionType):
147149

148150
def __init__(self):
@@ -174,9 +176,14 @@ def format(self, filename):
174176
else:
175177
return filename
176178

179+
177180
class AttrCompletion(BaseCompletionType):
178181

179-
def matches(self, cursor_offset, line, locals_, **kwargs):
182+
def matches(self, cursor_offset, line, **kwargs):
183+
if 'locals_' not in kwargs:
184+
return None
185+
locals_ = kwargs['locals_']
186+
180187
r = self.locate(cursor_offset, line)
181188
if r is None:
182189
return None
@@ -195,8 +202,9 @@ def matches(self, cursor_offset, line, locals_, **kwargs):
195202
matches = set(''.join([text[:-i], m])
196203
for m in attr_matches(methodtext, locals_))
197204

198-
#TODO add open paren for methods via _callable_prefix (or decide not to)
199-
# unless the first character is a _ filter out all attributes starting with a _
205+
# TODO add open paren for methods via _callable_prefix (or decide not
206+
# to) unless the first character is a _ filter out all attributes
207+
# starting with a _
200208
if not text.split('.')[-1].startswith('_'):
201209
matches = set(match for match in matches
202210
if not match.split('.')[-1].startswith('_'))
@@ -208,9 +216,14 @@ def locate(self, current_offset, line):
208216
def format(self, word):
209217
return after_last_dot(word)
210218

219+
211220
class DictKeyCompletion(BaseCompletionType):
212221

213-
def matches(self, cursor_offset, line, locals_, **kwargs):
222+
def matches(self, cursor_offset, line, **kwargs):
223+
if 'locals_' not in kwargs:
224+
return None
225+
locals_ = kwargs['locals_']
226+
214227
r = self.locate(cursor_offset, line)
215228
if r is None:
216229
return None
@@ -232,9 +245,14 @@ def locate(self, current_offset, line):
232245
def format(self, match):
233246
return match[:-1]
234247

248+
235249
class MagicMethodCompletion(BaseCompletionType):
236250

237-
def matches(self, cursor_offset, line, current_block, **kwargs):
251+
def matches(self, cursor_offset, line, **kwargs):
252+
if 'current_block' not in kwargs:
253+
return None
254+
current_block = kwargs['current_block']
255+
238256
r = self.locate(cursor_offset, line)
239257
if r is None:
240258
return None
@@ -246,13 +264,18 @@ def matches(self, cursor_offset, line, current_block, **kwargs):
246264
def locate(self, current_offset, line):
247265
return lineparts.current_method_definition_name(current_offset, line)
248266

267+
249268
class GlobalCompletion(BaseCompletionType):
250269

251-
def matches(self, cursor_offset, line, locals_, **kwargs):
270+
def matches(self, cursor_offset, line, **kwargs):
252271
"""Compute matches when text is a simple name.
253272
Return a list of all keywords, built-in functions and names currently
254273
defined in self.namespace that match.
255274
"""
275+
if 'locals_' not in kwargs:
276+
return None
277+
locals_ = kwargs['locals_']
278+
256279
r = self.locate(cursor_offset, line)
257280
if r is None:
258281
return None
@@ -272,9 +295,14 @@ def matches(self, cursor_offset, line, locals_, **kwargs):
272295
def locate(self, current_offset, line):
273296
return lineparts.current_single_word(current_offset, line)
274297

298+
275299
class ParameterNameCompletion(BaseCompletionType):
276300

277-
def matches(self, cursor_offset, line, argspec, **kwargs):
301+
def matches(self, cursor_offset, line, **kwargs):
302+
if 'argspec' not in kwargs:
303+
return None
304+
argspec = kwargs['argspec']
305+
278306
if not argspec:
279307
return None
280308
r = self.locate(cursor_offset, line)
@@ -293,6 +321,7 @@ def matches(self, cursor_offset, line, argspec, **kwargs):
293321
def locate(self, current_offset, line):
294322
return lineparts.current_word(current_offset, line)
295323

324+
296325
class StringLiteralAttrCompletion(BaseCompletionType):
297326

298327
def matches(self, cursor_offset, line, **kwargs):
@@ -309,6 +338,7 @@ def matches(self, cursor_offset, line, **kwargs):
309338
def locate(self, current_offset, line):
310339
return lineparts.current_string_literal_attr(current_offset, line)
311340

341+
312342
try:
313343
import jedi
314344
except ImportError:
@@ -317,14 +347,20 @@ def matches(self, cursor_offset, line, **kwargs):
317347
return None
318348
else:
319349
class JediCompletion(BaseCompletionType):
320-
def matches(self, cursor_offset, line, history, **kwargs):
350+
def matches(self, cursor_offset, line, **kwargs):
351+
if 'history' not in kwargs:
352+
return None
353+
history = kwargs['history']
354+
321355
if not lineparts.current_word(cursor_offset, line):
322356
return None
323357
history = '\n'.join(history) + '\n' + line
324-
script = jedi.Script(history, len(history.splitlines()), cursor_offset, 'fake.py')
358+
script = jedi.Script(history, len(history.splitlines()),
359+
cursor_offset, 'fake.py')
325360
completions = script.completions()
326361
if completions:
327-
self._orig_start = cursor_offset - (len(completions[0].name) - len(completions[0].complete))
362+
diff = len(completions[0].name) - len(completions[0].complete)
363+
self._orig_start = cursor_offset - diff
328364
else:
329365
self._orig_start = None
330366
return None
@@ -333,22 +369,31 @@ def matches(self, cursor_offset, line, history, **kwargs):
333369

334370
matches = [c.name for c in completions]
335371
if any(not m.lower().startswith(matches[0][0].lower()) for m in matches):
336-
return None # Too general - giving completions starting with multiple letters
372+
# Too general - giving completions starting with multiple
373+
# letters
374+
return None
337375
else:
338376
# case-sensitive matches only
339-
return set([m for m in matches if m.startswith(first_letter)])
377+
return set(m for m in matches if m.startswith(first_letter))
340378

341379
def locate(self, cursor_offset, line):
342380
start = self._orig_start
343381
end = cursor_offset
344382
return start, end, line[start:end]
345383

346-
347384
class MultilineJediCompletion(JediCompletion):
348-
def matches(self, cursor_offset, line, current_block, history, **kwargs):
385+
def matches(self, cursor_offset, line, **kwargs):
386+
if 'current_block' not in kwargs or 'history' not in kwargs:
387+
return None
388+
current_block = kwargs['current_block']
389+
history = kwargs['history']
390+
349391
if '\n' in current_block:
350-
assert cursor_offset <= len(line), "%r %r" % (cursor_offset, line)
351-
results = JediCompletion.matches(self, cursor_offset, line, history)
392+
assert cursor_offset <= len(line), "%r %r" % (cursor_offset,
393+
line)
394+
results = super(MultilineJediCompletion,
395+
self).matches(cursor_offset, line,
396+
history=history)
352397
return results
353398
else:
354399
return None
@@ -359,9 +404,9 @@ def get_completer(completers, cursor_offset, line, **kwargs):
359404
360405
If no matches available, returns a tuple of an empty list and None
361406
362-
kwargs (all required):
363-
cursor_offset is the current cursor column
364-
line is a string of the current line
407+
cursor_offset is the current cursor column
408+
line is a string of the current line
409+
kwargs (all optional):
365410
locals_ is a dictionary of the environment
366411
argspec is an inspect.ArgSpec instance for the current function where
367412
the cursor is
@@ -372,11 +417,13 @@ def get_completer(completers, cursor_offset, line, **kwargs):
372417
"""
373418

374419
for completer in completers:
375-
matches = completer.matches(cursor_offset, line, **kwargs)
420+
matches = completer.matches(
421+
cursor_offset, line, **kwargs)
376422
if matches is not None:
377423
return sorted(matches), (completer if matches else None)
378424
return [], None
379425

426+
380427
BPYTHON_COMPLETER = (
381428
DictKeyCompletion(),
382429
StringLiteralAttrCompletion(),
@@ -388,10 +435,10 @@ def get_completer(completers, cursor_offset, line, **kwargs):
388435
CumulativeCompleter((AttrCompletion(), ParameterNameCompletion()))
389436
)
390437

391-
def get_completer_bpython(**kwargs):
438+
439+
def get_completer_bpython(cursor_offset, line, **kwargs):
392440
""""""
393-
return get_completer(BPYTHON_COMPLETER,
394-
**kwargs)
441+
return get_completer(BPYTHON_COMPLETER, cursor_offset, line, **kwargs)
395442

396443

397444
class EvaluationError(Exception):
@@ -434,6 +481,7 @@ def attr_matches(text, namespace):
434481
matches = attr_lookup(obj, expr, attr)
435482
return matches
436483

484+
437485
def attr_lookup(obj, expr, attr):
438486
"""Second half of original attr_matches method factored out so it can
439487
be wrapped in a safe try/finally block in case anything bad happens to
@@ -455,12 +503,14 @@ def attr_lookup(obj, expr, attr):
455503
matches.append("%s.%s" % (expr, word))
456504
return matches
457505

506+
458507
def _callable_postfix(value, word):
459508
"""rlcompleter's _callable_postfix done right."""
460509
with inspection.AttrCleaner(value):
461510
if inspection.is_callable(value):
462511
word += '('
463512
return word
464513

514+
465515
def method_match(word, size, text):
466516
return word[:size] == text

0 commit comments

Comments
 (0)