@@ -353,6 +353,13 @@ def __init__(self, scr, interp, statusbar, config, idle=None):
353353 if config .cli_suggestion_width <= 0 or config .cli_suggestion_width > 1 :
354354 config .cli_suggestion_width = 0.8
355355
356+ def _get_cursor_offset (self ):
357+ return len (self .s ) - self .cpos
358+ def _set_cursor_offset (self , offset ):
359+ self .cpos = len (self .s ) - offset
360+ cursor_offset = property (_get_cursor_offset , _set_cursor_offset , None ,
361+ "The cursor offset from the beginning of the line" )
362+
356363 def addstr (self , s ):
357364 """Add a string to the current input line and figure out
358365 where it should go, depending on the cursor position."""
@@ -446,34 +453,29 @@ def clear_wrapped_lines(self):
446453 self .scr .clrtoeol ()
447454
448455 def complete (self , tab = False ):
449- """Get Autcomplete list and window."""
450- if self .paste_mode and self .list_win_visible :
451- self .scr .touchwin ()
456+ """Get Autcomplete list and window.
452457
458+ Called whenever these should be updated, and called
459+ with tab
460+ """
453461 if self .paste_mode :
462+ self .scr .touchwin () #TODO necessary?
454463 return
455464
456- if self .list_win_visible and not self .config .auto_display_list :
457- self .scr .touchwin ()
458- self .list_win_visible = False
459- self .matches_iter .update ()
460- return
461-
462- if self .config .auto_display_list or tab :
463- self .list_win_visible = repl .Repl .complete (self , tab )
464- if self .list_win_visible :
465- try :
466- self .show_list (self .matches , self .argspec )
467- except curses .error :
468- # XXX: This is a massive hack, it will go away when I get
469- # cusswords into a good enough state that we can start
470- # using it.
471- self .list_win .border ()
472- self .list_win .refresh ()
473- self .list_win_visible = False
474- if not self .list_win_visible :
475- self .scr .redrawwin ()
476- self .scr .refresh ()
465+ list_win_visible = repl .Repl .complete (self , tab )
466+ if list_win_visible :
467+ try :
468+ self .show_list (self .matches_iter .matches , topline = self .argspec , formatter = self .matches_iter .completer .format )
469+ except curses .error :
470+ # XXX: This is a massive hack, it will go away when I get
471+ # cusswords into a good enough state that we can start
472+ # using it.
473+ self .list_win .border ()
474+ self .list_win .refresh ()
475+ list_win_visible = False
476+ if not list_win_visible :
477+ self .scr .redrawwin ()
478+ self .scr .refresh ()
477479
478480 def clrtobol (self ):
479481 """Clear from cursor to beginning of line; usual C-u behaviour"""
@@ -488,9 +490,12 @@ def clrtobol(self):
488490 self .scr .redrawwin ()
489491 self .scr .refresh ()
490492
491- def current_line (self ):
492- """Return the current line."""
493+ def _get_current_line (self ):
493494 return self .s
495+ def _set_current_line (self , line ):
496+ self .s = line
497+ current_line = property (_get_current_line , _set_current_line , None ,
498+ "The characters of the current line" )
494499
495500 def cut_to_buffer (self ):
496501 """Clear from cursor to end of line, placing into cut buffer"""
@@ -501,31 +506,6 @@ def cut_to_buffer(self):
501506 self .scr .redrawwin ()
502507 self .scr .refresh ()
503508
504- def cw (self ):
505- """Return the current word, i.e. the (incomplete) word directly to the
506- left of the cursor"""
507-
508- # I don't know if autocomplete should be disabled if the cursor
509- # isn't at the end of the line, but that's what this does for now.
510- if self .cpos : return
511-
512- # look from right to left for a bad method or dictionary character
513- l = len (self .s )
514- is_method_char = lambda c : c .isalnum () or c in ('.' , '_' )
515- dict_chars = ['[' ]
516-
517- if not self .s or not (is_method_char (self .s [- 1 ])
518- or self .s [- 1 ] in dict_chars ):
519- return
520-
521- for i in range (1 , l + 1 ):
522- c = self .s [- i ]
523- if not (is_method_char (c ) or c in dict_chars ):
524- i -= 1
525- break
526-
527- return self .s [- i :]
528-
529509 def delete (self ):
530510 """Process a del"""
531511 if not self .s :
@@ -1267,7 +1247,8 @@ def write(self, s):
12671247 self .s_hist .append (s .rstrip ())
12681248
12691249
1270- def show_list (self , items , topline = None , current_item = None ):
1250+ def show_list (self , items , topline = None , formatter = None , current_item = None ):
1251+
12711252 shared = Struct ()
12721253 shared .cols = 0
12731254 shared .rows = 0
@@ -1283,20 +1264,9 @@ def show_list(self, items, topline=None, current_item=None):
12831264 self .list_win .erase ()
12841265
12851266 if items :
1286- sep = '.'
1287- separators = ['.' , os .path .sep , '[' ]
1288- lastindex = max ([items [0 ].rfind (c ) for c in separators ])
1289- if lastindex > - 1 :
1290- sep = items [0 ][lastindex ]
1291- items = [x .rstrip (sep ).rsplit (sep )[- 1 ] for x in items ]
1267+ items = [formatter (x ) for x in items ]
12921268 if current_item :
1293- current_item = current_item .rstrip (sep ).rsplit (sep )[- 1 ]
1294-
1295- if items [0 ].endswith (']' ):
1296- # dictionary key suggestions
1297- items = [x .rstrip (']' ) for x in items ]
1298- if current_item :
1299- current_item = current_item .rstrip (']' )
1269+ current_item = formatter (current_item )
13001270
13011271 if topline :
13021272 height_offset = self .mkargspec (topline , down ) + 1
@@ -1445,8 +1415,6 @@ def tab(self, back=False):
14451415 and don't indent if there are only whitespace in the line.
14461416 """
14471417
1448- mode = self .config .autocomplete_mode
1449-
14501418 # 1. check if we should add a tab character
14511419 if self .atbol () and not back :
14521420 x_pos = len (self .s ) - self .cpos
@@ -1458,66 +1426,39 @@ def tab(self, back=False):
14581426 self .print_line (self .s )
14591427 return True
14601428
1461- # 2. get the current word
1429+ # 2. run complete() if we aren't already iterating through matches
14621430 if not self .matches_iter :
14631431 self .complete (tab = True )
1464- if not self .config .auto_display_list and not self .list_win_visible :
1465- return True
1466-
1467- cw = self .current_string () or self .cw ()
1468- if not cw :
1469- return True
1470- else :
1471- cw = self .matches_iter .current_word
1432+ self .print_line (self .s )
14721433
14731434 # 3. check to see if we can expand the current word
1474- cseq = None
1475- if mode == autocomplete .SUBSTRING :
1476- if all ([len (match .split (cw )) == 2 for match in self .matches ]):
1477- seq = [cw + match .split (cw )[1 ] for match in self .matches ]
1478- cseq = os .path .commonprefix (seq )
1479- else :
1480- seq = self .matches
1481- cseq = os .path .commonprefix (seq )
1482-
1483- if cseq and mode != autocomplete .FUZZY :
1484- expanded_string = cseq [len (cw ):]
1485- self .s += expanded_string
1486- expanded = bool (expanded_string )
1435+ if self .matches_iter .is_cseq ():
1436+ #TODO resolve this error-prone situation:
1437+ # can't assign at same time to self.s and self.cursor_offset
1438+ # because for cursor_offset
1439+ # property to work correctly, self.s must already be set
1440+ temp_cursor_offset , self .s = self .matches_iter .substitute_cseq ()
1441+ self .cursor_offset = temp_cursor_offset
14871442 self .print_line (self .s )
1488- if len (self .matches ) == 1 and self .config .auto_display_list :
1489- self .scr .touchwin ()
1490- if expanded :
1491- self .matches_iter .update (cseq , self .matches )
1492- else :
1493- expanded = False
1443+ if not self .matches_iter :
1444+ self .complete ()
14941445
14951446 # 4. swap current word for a match list item
1496- if not expanded and self .matches :
1497- # reset s if this is the nth result
1498- if self .matches_iter :
1499- self .s = self .s [:- len (self .matches_iter .current ())] + cw
1500-
1447+ elif self .matches_iter .matches :
15011448 current_match = back and self .matches_iter .previous () \
15021449 or self .matches_iter .next ()
1503-
1504- # update s with the new match
1505- if current_match :
1506- try :
1507- self .show_list (self .matches , self .argspec , current_match )
1508- except curses .error :
1509- # XXX: This is a massive hack, it will go away when I get
1510- # cusswords into a good enough state that we can start
1511- # using it.
1512- self .list_win .border ()
1513- self .list_win .refresh ()
1514-
1515- if self .config .autocomplete_mode == autocomplete .SIMPLE :
1516- self .s += current_match [len (cw ):]
1517- else :
1518- self .s = self .s [:- len (cw )] + current_match
1519-
1520- self .print_line (self .s , True )
1450+ try :
1451+ self .show_list (self .matches_iter .matches , topline = self .argspec ,
1452+ formatter = self .matches_iter .completer .format ,
1453+ current_item = current_match )
1454+ except curses .error :
1455+ # XXX: This is a massive hack, it will go away when I get
1456+ # cusswords into a good enough state that we can start
1457+ # using it.
1458+ self .list_win .border ()
1459+ self .list_win .refresh ()
1460+ _ , self .s = self .matches_iter .cur_line ()
1461+ self .print_line (self .s , True )
15211462 return True
15221463
15231464 def undo (self , n = 1 ):
0 commit comments