Skip to content

Commit 4d9767b

Browse files
Merge branch 'array-item-autocomplete'
This implementation modifies the interpreter locals dictionary, which was required to reuse more code.
2 parents 9f45c32 + ce1eb1a commit 4d9767b

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

bpython/autocomplete.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,44 @@ def list_attributes(self, obj):
335335
return dir(obj)
336336

337337

338+
class ArrayItemMembersCompletion(BaseCompletionType):
339+
340+
def __init__(self, shown_before_tab=True, mode=SIMPLE):
341+
self._shown_before_tab = shown_before_tab
342+
self.completer = AttrCompletion(mode=mode)
343+
344+
def matches(self, cursor_offset, line, **kwargs):
345+
if 'locals_' not in kwargs:
346+
return None
347+
locals_ = kwargs['locals_']
348+
349+
r = self.locate(cursor_offset, line)
350+
if r is None:
351+
return None
352+
member_part = r[2]
353+
_, _, dexpr = lineparts.current_array_with_indexer(cursor_offset, line)
354+
try:
355+
locals_['temp_val_from_array'] = safe_eval(dexpr, locals_)
356+
except (EvaluationError, IndexError):
357+
return set()
358+
359+
temp_line = line.replace(member_part, 'temp_val_from_array.')
360+
361+
matches = self.completer.matches(len(temp_line), temp_line, **kwargs)
362+
matches_with_correct_name = \
363+
set(match.replace('temp_val_from_array.', member_part) for match in matches)
364+
365+
del locals_['temp_val_from_array']
366+
367+
return matches_with_correct_name
368+
369+
def locate(self, current_offset, line):
370+
return lineparts.current_array_item_member_name(current_offset, line)
371+
372+
def format(self, match):
373+
return after_last_dot(match)
374+
375+
338376
class DictKeyCompletion(BaseCompletionType):
339377

340378
def matches(self, cursor_offset, line, **kwargs):
@@ -565,6 +603,7 @@ def get_default_completer(mode=SIMPLE):
565603
MagicMethodCompletion(mode=mode),
566604
MultilineJediCompletion(mode=mode),
567605
GlobalCompletion(mode=mode),
606+
ArrayItemMembersCompletion(mode=mode),
568607
CumulativeCompleter((AttrCompletion(mode=mode),
569608
ParameterNameCompletion(mode=mode)),
570609
mode=mode)

bpython/line.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,27 @@ def current_string_literal_attr(cursor_offset, line):
226226
if m.start(4) <= cursor_offset and m.end(4) >= cursor_offset:
227227
return LinePart(m.start(4), m.end(4), m.group(4))
228228
return None
229+
230+
231+
current_array_with_indexer_re = LazyReCompile(
232+
r'''([\w_][\w0-9._]*(?:\[[a-zA-Z0-9_"']+\])+)\.(.*)''')
233+
234+
235+
def current_array_with_indexer(cursor_offset, line):
236+
"""an array and indexer, e.g. foo[1]"""
237+
matches = current_array_with_indexer_re.finditer(line)
238+
for m in matches:
239+
if m.start(1) <= cursor_offset and m.end(1) <= cursor_offset:
240+
return LinePart(m.start(1), m.end(1), m.group(1))
241+
242+
243+
current_array_item_member_name_re = LazyReCompile(
244+
r'''([\w_][\w0-9._]*(?:\[[a-zA-Z0-9_"']+\])+\.)(.*)''')
245+
246+
247+
def current_array_item_member_name(cursor_offset, line):
248+
"""the member name after an array indexer, e.g. foo[1].bar"""
249+
matches = current_array_item_member_name_re.finditer(line)
250+
for m in matches:
251+
if m.start(2) <= cursor_offset and m.end(2) >= cursor_offset:
252+
return LinePart(m.start(1), m.end(2), m.group(1))

bpython/test/test_autocomplete.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,22 @@ def __getattr__(self, attr):
263263
self.com.matches(4, 'a.__', locals_=locals_))
264264

265265

266+
class TestArrayItemCompletion(unittest.TestCase):
267+
@classmethod
268+
def setUpClass(cls):
269+
cls.com = autocomplete.ArrayItemMembersCompletion()
270+
271+
def test_att_matches_found_on_instance(self):
272+
self.assertSetEqual(self.com.matches(5, 'a[0].', locals_={'a': [Foo()]}),
273+
set(['a[0].method', 'a[0].a', 'a[0].b']))
274+
275+
@skip_old_style
276+
def test_att_matches_found_on_old_style_instance(self):
277+
self.assertSetEqual(self.com.matches(5, 'a[0].',
278+
locals_={'a': [OldStyleFoo()]}),
279+
set(['a[0].method', 'a[0].a', 'a[0].b']))
280+
281+
266282
class TestMagicMethodCompletion(unittest.TestCase):
267283

268284
def test_magic_methods_complete_after_double_underscores(self):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy