5050from bpython ._py3compat import PythonLexer , py3
5151from bpython .formatter import Parenthesis
5252from bpython .translations import _
53- from bpython .autocomplete import Autocomplete
53+ import bpython .autocomplete as autocomplete
5454
5555
5656# Needed for special handling of __abstractmethods__
@@ -280,6 +280,9 @@ def __init__(self, current_word='', matches=[]):
280280 self .current_word = current_word
281281 self .matches = list (matches )
282282 self .index = - 1
283+ self .orig_cursor_offset = None
284+ self .orig_line = None
285+ self .replacer = None
283286
284287 def __nonzero__ (self ):
285288 return self .index != - 1
@@ -303,11 +306,33 @@ def previous(self):
303306
304307 return self .matches [self .index ]
305308
306- def update (self , current_word = '' , matches = []):
307- if current_word != self .current_word :
308- self .current_word = current_word
309- self .matches = list (matches )
309+ def cur_line (self ):
310+ """Returns a cursor offset and line pair with the current substitution made"""
311+ return self .substitute (self .current ())
312+
313+ def substitute (self , match ):
314+ if match .startswith ("'" ):
315+ raise ValueError (match )
316+ start , end , word = self .replacer (self .orig_cursor_offset , self .orig_line )
317+ result = start + len (match ), self .orig_line [:start ] + match + self .orig_line [end :]
318+ return result
319+
320+ def update (self , cursor_offset , current_line , matches , replacer = None ):
321+ if cursor_offset != self .orig_cursor_offset or current_line != self .orig_line :
322+ if replacer is not None :
323+ self .replacer = replacer
324+ if matches and self .replacer is not None :
325+ self .start , self .end , self .current_word = self .replacer (cursor_offset , current_line )
326+ self .orig_cursor_offset = cursor_offset
327+ self .orig_line = current_line
310328 self .index = - 1
329+ self .matches = list (matches )
330+
331+ def clear (self ):
332+ self .cursor_offset = - 1
333+ self .current_line = ''
334+ self .current_word = ''
335+ self .replacer = None
311336
312337
313338class Interaction (object ):
@@ -378,7 +403,6 @@ def __init__(self, interp, config):
378403 self .s_hist = []
379404 self .history = []
380405 self .evaluating = False
381- self .completer = Autocomplete (self .interp .locals , config )
382406 self .matches = []
383407 self .matches_iter = MatchesIterator ()
384408 self .argspec = None
@@ -580,83 +604,30 @@ def complete(self, tab=False):
580604 (via the inspect module) and bang that on top of the completions too.
581605 The return value is whether the list_win is visible or not."""
582606
583- #TODO keep factoring out parts of complete
584- # so we can reuse code when we reimplement complete
585- # in bpython.curtsiesfrontend.repl
586- # Maybe move things to autocomplete instead of here?
587-
588607 self .set_docstring ()
589608
590- cw = self .cw ()
591- cs = self .current_string ()
592- if not cw :
593- self .matches = []
594- self .matches_iter .update ()
595- if not (cw or cs ):
596- return bool (self .argspec )
597-
598- if cs and tab :
599- self .matches = filename_matches (cs )
600- self .matches_iter .update (cs , self .matches )
601- return bool (self .matches )
602- elif cs :
603- # Do not provide suggestions inside strings, as one cannot tab
604- # them so they would be really confusing.
605- self .matches_iter .update ()
606- return False
609+ matches , replacer = autocomplete .find_matches (
610+ len (self .current_line ()) - self .cpos ,
611+ self .current_line (),
612+ self .interp .locals ,
613+ self .argspec ,
614+ self .config ,
615+ self .magic_method_completions )
607616
608- # Check for import completion
609- e = False
610- matches = importcompletion .complete (len (self .current_line ()) - self .cpos , self .current_line ())
611- if matches is not None and not matches :
612- self .matches = []
613- self .matches_iter .update ()
614- return False
617+ self .matches = matches
618+ self .matches_iter .update (len (self .current_line ()) - self .cpos ,
619+ self .current_line (), self .matches , replacer = replacer )
615620
616- if matches is None :
617- # Nope, no import, continue with normal completion
618- try :
619- self .completer .complete (cw , 0 )
620- except Exception :
621- # This sucks, but it's either that or list all the exceptions that could
622- # possibly be raised here, so if anyone wants to do that, feel free to send me
623- # a patch. XXX: Make sure you raise here if you're debugging the completion
624- # stuff !
625- raise
626- e = True
627- else :
628- matches = self .completer .matches
629- matches .extend (self .magic_method_completions (cw ))
630-
631- if not e and self .argspec :
632- matches .extend (name + '=' for name in self .argspec [1 ][0 ]
633- if isinstance (name , basestring ) and name .startswith (cw ))
634- if py3 :
635- matches .extend (name + '=' for name in self .argspec [1 ][4 ]
636- if name .startswith (cw ))
637-
638- # unless the first character is a _ filter out all attributes starting with a _
639- if not e and not cw .split ('.' )[- 1 ].startswith ('_' ):
640- matches = [match for match in matches
641- if not match .split ('.' )[- 1 ].startswith ('_' )]
642-
643- if e or not matches :
644- self .matches = []
645- self .matches_iter .update ()
646- if not self .argspec :
647- return False
621+ if matches is None or len (matches ) == 0 :
622+ return bool (self .matches or self .argspec )
648623 else :
649- # remove duplicates
650- self .matches = sorted (set (matches ))
651-
652-
653- if len (self .matches ) == 1 and not self .config .auto_display_list :
654- self .list_win_visible = True
655- self .tab ()
656- return False
657-
658- self .matches_iter .update (cw , self .matches )
659- return True
624+ if len (self .matches ) == 1 and not self .config .auto_display_list :
625+ self .list_win_visible = True
626+ self .tab ()
627+ return False
628+ self .matches_iter .update (len (self .current_line ()) - self .cpos ,
629+ self .current_line (), self .matches , replacer )
630+ return True
660631
661632 def format_docstring (self , docstring , width , height ):
662633 """Take a string and try to format it into a sane list of strings to be
0 commit comments