@@ -298,16 +298,19 @@ def smarter_request_reload(desc):
298298self .stdin = FakeStdin (self .coderunner ,self ,self .edit_keys )
299299
300300self .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
308311self .original_modules = sys .modules .keys ()
309312
310- self .width = None # will both be set by a window resize event
313+ self .width = None
311314self .height = None
312315
313316self .status_bar .message (banner )
@@ -460,6 +463,12 @@ def process_key_event(self, e):
460463self .down_one_line ()
461464elif e in ("<Ctrl-d>" ,):
462465self .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 )
463472elif e in self .edit_keys .cut_buffer_edits :
464473self .readline_kill (e )
465474elif e in self .edit_keys .simple_edits :
@@ -507,6 +516,21 @@ def process_key_event(self, e):
507516else :
508517self .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+
510534def readline_kill (self ,e ):
511535func = self .edit_keys [e ]
512536self .cursor_offset ,self .current_line ,cut = func (self .cursor_offset ,self .current_line )
@@ -659,14 +683,35 @@ def toggle_file_watch(self):
659683def add_normal_character (self ,char ):
660684if len (char )> 1 or is_nop (char ):
661685return
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
666693if self .config .cli_trim_prompts and self .current_line .startswith (self .ps1 ):
667694self .current_line = self .current_line [4 :]
668695self .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+
670715def 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
867912def 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
869917return (func_for_letter (self .config .color_scheme ['prompt' ])(self .ps1 )
870918if self .done else
871919func_for_letter (self .config .color_scheme ['prompt_more' ])(self .ps2 ))+ self .current_line_formatted
@@ -1085,21 +1133,25 @@ def __repr__(self):
10851133
10861134def _get_current_line (self ):
10871135return 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 ):
10891137self ._current_line = line
10901138if update_completion :
10911139self .update_completion ()
10921140if reset_rl_history :
10931141self .rl_history .reset ()
1142+ if clear_special_mode :
1143+ self .special_mode = None
10941144current_line = property (_get_current_line ,_set_current_line ,None ,
10951145"The current line" )
10961146def _get_cursor_offset (self ):
10971147return 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 ):
10991149if update_completion :
11001150self .update_completion ()
11011151if reset_rl_history :
11021152self .rl_history .reset ()
1153+ if clear_special_mode :
1154+ self .special_mode = None
11031155self ._cursor_offset = offset
11041156self .update_completion ()
11051157cursor_offset = property (_get_cursor_offset ,_set_cursor_offset ,None ,