@@ -298,16 +298,19 @@ def smarter_request_reload(desc):
298298 self .stdin = FakeStdin (self .coderunner , self , self .edit_keys )
299299
300300 self .request_paint_to_clear_screen = False # next paint should clear screen
301- self .last_events = [None ] * 50
302- self .presentation_mode = False
303- self .paste_mode = False
304- self .current_match = None
305- self .list_win_visible = False
306- self .watching_files = False
301+ self .last_events = [None ] * 50 # some commands act differently based on the prev event
302+ # this list doesn't include instances of event.Event,
303+ # only keypress-type events (no refresh screen events etc.)
304+ self .presentation_mode = False # displays prev events in a column on the right hand side
305+ self .paste_mode = False # currently processing a paste event
306+ self .current_match = None # currently tab-selected autocompletion suggestion
307+ self .list_win_visible = False # whether the infobox (suggestions, docstring) is visible
308+ self .watching_files = False # auto reloading turned on
309+ self .special_mode = None # 'reverse_incremental_search' and 'incremental_search'
307310
308311 self .original_modules = sys .modules .keys ()
309312
310- self .width = None # will both be set by a window resize event
313+ self .width = None
311314 self .height = None
312315
313316 self .status_bar .message (banner )
@@ -460,6 +463,12 @@ def process_key_event(self, e):
460463 self .down_one_line ()
461464 elif e in ("<Ctrl-d>" ,):
462465 self .on_control_d ()
466+ elif e in ("<Ctrl-r>" ,):
467+ self .incremental_search (reverse = True )
468+ elif e in ("<Ctrl-s>" ,):
469+ self .incremental_search ()
470+ elif e in ("<BACKSPACE>" , '<Ctrl-h>' ) and self .special_mode :
471+ self .add_to_incremental_search (self , backspace = True )
463472 elif e in self .edit_keys .cut_buffer_edits :
464473 self .readline_kill (e )
465474 elif e in self .edit_keys .simple_edits :
@@ -507,6 +516,21 @@ def process_key_event(self, e):
507516 else :
508517 self .add_normal_character (e )
509518
519+ def incremental_search (self , reverse = False ):
520+ if self .special_mode == None :
521+ current_line = ''
522+ if reverse :
523+ self .special_mode = 'reverse_incremental_search'
524+ else :
525+ self .special_mode = 'incremental_search'
526+ else :
527+ self ._set_current_line (self .rl_history .back (False , search = True )
528+ if reverse else
529+ self .rl_history .forward (False , search = True ),
530+ reset_rl_history = False , clear_special_mode = False )
531+ self ._set_cursor_offset (len (self .current_line ), reset_rl_history = False ,
532+ clear_special_mode = False )
533+
510534 def readline_kill (self , e ):
511535 func = self .edit_keys [e ]
512536 self .cursor_offset , self .current_line , cut = func (self .cursor_offset , self .current_line )
@@ -659,14 +683,35 @@ def toggle_file_watch(self):
659683 def add_normal_character (self , char ):
660684 if len (char ) > 1 or is_nop (char ):
661685 return
662- self .current_line = (self .current_line [:self .cursor_offset ] +
663- char +
664- self .current_line [self .cursor_offset :])
665- self .cursor_offset += 1
686+ if self .special_mode == 'reverse_incremental_search' :
687+ self .add_to_incremental_search (char )
688+ else :
689+ self .current_line = (self .current_line [:self .cursor_offset ] +
690+ char +
691+ self .current_line [self .cursor_offset :])
692+ self .cursor_offset += 1
666693 if self .config .cli_trim_prompts and self .current_line .startswith (self .ps1 ):
667694 self .current_line = self .current_line [4 :]
668695 self .cursor_offset = max (0 , self .cursor_offset - 4 )
669696
697+ def add_to_incremental_search (self , char = None , backspace = False ):
698+ if char is None and not backspace :
699+ raise ValueError ("must provide a char or set backspace to True" )
700+ saved_line = self .rl_history .saved_line
701+ if backspace :
702+ saved_line = saved_line [:- 1 ]
703+ else :
704+ saved_line += char
705+ self .update_completion ()
706+ self .rl_history .reset ()
707+ self .rl_history .enter (saved_line )
708+ if self .special_mode == 'reverse_incremental_search' :
709+ self .incremental_search (reverse = True )
710+ elif self .special_mode == 'incremental_search' :
711+ self .incremental_search ()
712+ else :
713+ raise ValueError ('add_to_incremental_search should only be called in a special mode' )
714+
670715 def update_completion (self , tab = False ):
671716 """Update visible docstring and matches, and possibly hide/show completion box"""
672717 #Update autocomplete info; self.matches_iter and self.argspec
@@ -866,6 +911,9 @@ def display_buffer_lines(self):
866911 @property
867912 def display_line_with_prompt (self ):
868913 """colored line with prompt"""
914+ if self .special_mode == 'reverse_incremental_search' :
915+ return func_for_letter (self .config .color_scheme ['prompt' ])(
916+ '(reverse-i-search)`%s\' : ' % (self .rl_history .saved_line ,)) + self .current_line_formatted
869917 return (func_for_letter (self .config .color_scheme ['prompt' ])(self .ps1 )
870918 if self .done else
871919 func_for_letter (self .config .color_scheme ['prompt_more' ])(self .ps2 )) + self .current_line_formatted
@@ -1085,21 +1133,25 @@ def __repr__(self):
10851133
10861134 def _get_current_line (self ):
10871135 return self ._current_line
1088- def _set_current_line (self , line , update_completion = True , reset_rl_history = True ):
1136+ def _set_current_line (self , line , update_completion = True , reset_rl_history = True , clear_special_mode = True ):
10891137 self ._current_line = line
10901138 if update_completion :
10911139 self .update_completion ()
10921140 if reset_rl_history :
10931141 self .rl_history .reset ()
1142+ if clear_special_mode :
1143+ self .special_mode = None
10941144 current_line = property (_get_current_line , _set_current_line , None ,
10951145 "The current line" )
10961146 def _get_cursor_offset (self ):
10971147 return self ._cursor_offset
1098- def _set_cursor_offset (self , offset , update_completion = True , reset_rl_history = True ):
1148+ def _set_cursor_offset (self , offset , update_completion = True , reset_rl_history = True , clear_special_mode = True ):
10991149 if update_completion :
11001150 self .update_completion ()
11011151 if reset_rl_history :
11021152 self .rl_history .reset ()
1153+ if clear_special_mode :
1154+ self .special_mode = None
11031155 self ._cursor_offset = offset
11041156 self .update_completion ()
11051157 cursor_offset = property (_get_cursor_offset , _set_cursor_offset , None ,
0 commit comments