@@ -298,16 +298,19 @@ def smarter_request_reload(desc):
298
298
self .stdin = FakeStdin (self .coderunner , self , self .edit_keys )
299
299
300
300
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'
307
310
308
311
self .original_modules = sys .modules .keys ()
309
312
310
- self .width = None # will both be set by a window resize event
313
+ self .width = None
311
314
self .height = None
312
315
313
316
self .status_bar .message (banner )
@@ -460,6 +463,12 @@ def process_key_event(self, e):
460
463
self .down_one_line ()
461
464
elif e in ("<Ctrl-d>" ,):
462
465
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 )
463
472
elif e in self .edit_keys .cut_buffer_edits :
464
473
self .readline_kill (e )
465
474
elif e in self .edit_keys .simple_edits :
@@ -507,6 +516,21 @@ def process_key_event(self, e):
507
516
else :
508
517
self .add_normal_character (e )
509
518
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
+
510
534
def readline_kill (self , e ):
511
535
func = self .edit_keys [e ]
512
536
self .cursor_offset , self .current_line , cut = func (self .cursor_offset , self .current_line )
@@ -659,14 +683,35 @@ def toggle_file_watch(self):
659
683
def add_normal_character (self , char ):
660
684
if len (char ) > 1 or is_nop (char ):
661
685
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
666
693
if self .config .cli_trim_prompts and self .current_line .startswith (self .ps1 ):
667
694
self .current_line = self .current_line [4 :]
668
695
self .cursor_offset = max (0 , self .cursor_offset - 4 )
669
696
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
+
670
715
def update_completion (self , tab = False ):
671
716
"""Update visible docstring and matches, and possibly hide/show completion box"""
672
717
#Update autocomplete info; self.matches_iter and self.argspec
@@ -866,6 +911,9 @@ def display_buffer_lines(self):
866
911
@property
867
912
def display_line_with_prompt (self ):
868
913
"""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
869
917
return (func_for_letter (self .config .color_scheme ['prompt' ])(self .ps1 )
870
918
if self .done else
871
919
func_for_letter (self .config .color_scheme ['prompt_more' ])(self .ps2 )) + self .current_line_formatted
@@ -1085,21 +1133,25 @@ def __repr__(self):
1085
1133
1086
1134
def _get_current_line (self ):
1087
1135
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 ):
1089
1137
self ._current_line = line
1090
1138
if update_completion :
1091
1139
self .update_completion ()
1092
1140
if reset_rl_history :
1093
1141
self .rl_history .reset ()
1142
+ if clear_special_mode :
1143
+ self .special_mode = None
1094
1144
current_line = property (_get_current_line , _set_current_line , None ,
1095
1145
"The current line" )
1096
1146
def _get_cursor_offset (self ):
1097
1147
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 ):
1099
1149
if update_completion :
1100
1150
self .update_completion ()
1101
1151
if reset_rl_history :
1102
1152
self .rl_history .reset ()
1153
+ if clear_special_mode :
1154
+ self .special_mode = None
1103
1155
self ._cursor_offset = offset
1104
1156
self .update_completion ()
1105
1157
cursor_offset = property (_get_cursor_offset , _set_cursor_offset , None ,
0 commit comments