From 1dd053671e7e7fb1a2e7277a3babc45adf5d638c Mon Sep 17 00:00:00 2001 From: Jorgen Stenarson Date: Thu, 14 Apr 2011 20:36:47 +0200 Subject: [PATCH] Finalizing incremental search --- pyreadline/lineeditor/history.py | 31 ++++++++++++--------- pyreadline/modes/emacs.py | 46 +++++++++++++++++++++----------- pyreadline/test/test_history.py | 14 +++++++++- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/pyreadline/lineeditor/history.py b/pyreadline/lineeditor/history.py index 2368566..8498435 100644 --- a/pyreadline/lineeditor/history.py +++ b/pyreadline/lineeditor/history.py @@ -140,6 +140,7 @@ class LineHistory(object): def reverse_search_history(self, searchfor, startpos=None): if startpos is None: startpos = self.history_cursor + origpos = startpos result = lineobj.ReadLineTextBuffer("") @@ -150,21 +151,25 @@ class LineHistory(object): #If we get a new search without change in search term it means #someone pushed ctrl-r and we should find the next match - if self.last_search_for == searchfor: + if self.last_search_for == searchfor and startpos > 0: startpos -= 1 for idx, line in list(enumerate(self.history))[startpos:0:-1]: if searchfor in line: startpos = idx break - result = self.history[startpos] + if self.history: + result = self.history[startpos].get_line_text() + else: + result = u"" self.history_cursor = startpos self.last_search_for = searchfor - return result.get_line_text() + log(u"reverse_search_history: old:%d new:%d result:%r"%(origpos, self.history_cursor, result)) + return result def forward_search_history(self, searchfor, startpos=None): if startpos is None: - startpos = self.history_cursor + startpos = min(self.history_cursor, max(0, self.get_current_history_length()-1)) origpos = startpos result = lineobj.ReadLineTextBuffer("") @@ -176,22 +181,20 @@ class LineHistory(object): #If we get a new search without change in search term it means #someone pushed ctrl-r and we should find the next match - if self.last_search_for == searchfor: + if self.last_search_for == searchfor and startpos < self.get_current_history_length()-1: startpos += 1 for idx, line in list(enumerate(self.history))[startpos:]: if searchfor in line: startpos = idx break - if len(self.history) == startpos: - if origpos == len(self.history): - return u"" - else: - return self.history[origpos] + + if self.history: + result = self.history[startpos].get_line_text() else: - result = self.history[startpos] + result = u"" self.history_cursor = startpos self.last_search_for = searchfor - return result.get_line_text() + return result def _search(self, direction, partial): try: @@ -247,7 +250,10 @@ class LineHistory(object): return q if __name__==u"__main__": + import pdb q = LineHistory() + r = LineHistory() + s = LineHistory() RL = lineobj.ReadLineTextBuffer q.add_history(RL(u"aaaa")) q.add_history(RL(u"aaba")) @@ -255,3 +261,4 @@ if __name__==u"__main__": q.add_history(RL(u"akca")) q.add_history(RL(u"bbb")) q.add_history(RL(u"ako")) + r.add_history(RL(u"ako")) diff --git a/pyreadline/modes/emacs.py b/pyreadline/modes/emacs.py index 234c96d..013cabe 100644 --- a/pyreadline/modes/emacs.py +++ b/pyreadline/modes/emacs.py @@ -31,7 +31,18 @@ class IncrementalSearchPromptMode(object): pass def _process_incremental_search_keyevent(self, keyinfo): + log("_process_incremental_search_keyevent") keytuple = keyinfo.tuple() + #dispatch_func = self.key_dispatch.get(keytuple, default) + revtuples = [] + fwdtuples = [] + for ktuple, func in self.key_dispatch.iteritems(): + if func == self.reverse_search_history: + revtuples.append(ktuple) + elif func == self.forward_search_history: + fwdtuples.append(ktuple) + + log(u"IncrementalSearchPromptMode %s %s"%(keyinfo, keytuple)) if keyinfo.keyname == u'backspace': self.subsearch_query = self.subsearch_query[:-1] @@ -47,25 +58,29 @@ class IncrementalSearchPromptMode(object): self._history.history_cursor = len(self._history.history) if keyinfo.keyname == u'escape': self.l_buffer.set_line(self.subsearch_old_line) - return False + return True elif keyinfo.keyname: pass - elif keytuple == self.subsearch_init_event: - self._history.history_cursor += self.subsearch_direction + elif keytuple in revtuples: + self.subsearch_fun = self._history.reverse_search_history + self.subsearch_prompt = u"reverse-i-search%d`%s': " + self.line = self.subsearch_fun(self.subsearch_query) + elif keytuple in fwdtuples: + self.subsearch_fun = self._history.forward_search_history + self.subsearch_prompt = u"forward-i-search%d`%s': " self.line = self.subsearch_fun(self.subsearch_query) elif keyinfo.control == False and keyinfo.meta == False: self.subsearch_query += keyinfo.char self.line = self.subsearch_fun(self.subsearch_query) else: pass - self.prompt = self.subsearch_prompt%self.subsearch_query + self.prompt = self.subsearch_prompt%(self._history.history_cursor, self.subsearch_query) self.l_buffer.set_line(self.line) - def _init_incremental_search(self, searchfun, direction, init_event): + def _init_incremental_search(self, searchfun, init_event): u"""Initialize search prompt """ - self.subsearch_init_event = init_event.tuple() - self.subsearch_direction = direction + log("init_incremental_search") self.subsearch_query = u'' self.subsearch_fun = searchfun self.subsearch_old_line = self.l_buffer.get_line_text() @@ -79,12 +94,12 @@ class IncrementalSearchPromptMode(object): self.previous_func != self.forward_search_history): self.subsearch_query = self.l_buffer[0:Point].get_line_text() - if self.subsearch_direction < 0: - self.subsearch_prompt = u"reverse-i-search`%s': " + if self.subsearch_fun == self.reverse_search_history: + self.subsearch_prompt = u"reverse-i-search%d`%s': " else: - self.subsearch_prompt = u"forward-i-search`%s': " + self.subsearch_prompt = u"forward-i-search%d`%s': " - self.prompt = self.subsearch_prompt%"" + self.prompt = self.subsearch_prompt%(self._history.history_cursor, "") if self.subsearch_query: self.line = self._process_incremental_search_keyevent(init_event) @@ -302,16 +317,16 @@ class EmacsMode(DigitArgumentMode, IncrementalSearchPromptMode, def reverse_search_history(self, e): # (C-r) u'''Search backward starting at the current line and moving up through the history as necessary. This is an incremental search.''' - self._init_incremental_search(self._history.reverse_search_history, - -1, e) + log("rev_search_history") + self._init_incremental_search(self._history.reverse_search_history, e) self.finalize() def forward_search_history(self, e): # (C-s) u'''Search forward starting at the current line and moving down through the the history as necessary. This is an incremental search.''' - self._init_incremental_search(self._history.forward_search_history, - 1, e) + log("fwd_search_history") + self._init_incremental_search(self._history.forward_search_history, e) self.finalize() def history_search_forward(self, e): # () @@ -644,6 +659,7 @@ class EmacsMode(DigitArgumentMode, IncrementalSearchPromptMode, self._bind_key(u'Alt->', self.end_of_history) self._bind_key(u'Control-r', self.reverse_search_history) self._bind_key(u'Control-s', self.forward_search_history) + self._bind_key(u'Control-Shift-r', self.forward_search_history) self._bind_key(u'Alt-p', self.non_incremental_reverse_search_history) self._bind_key(u'Alt-n', diff --git a/pyreadline/test/test_history.py b/pyreadline/test/test_history.py index cdf9624..a39a016 100644 --- a/pyreadline/test/test_history.py +++ b/pyreadline/test/test_history.py @@ -112,7 +112,7 @@ class Test_history_search_incr_fwd_backwd(unittest.TestCase): def test_forward_1(self): q = self.q - self.assertEqual(q.forward_search_history(u"a"), u"") + self.assertEqual(q.forward_search_history(u"a"), u"ako") def test_forward_2(self): q = self.q @@ -124,6 +124,18 @@ class Test_history_search_incr_fwd_backwd(unittest.TestCase): self.assertEqual(q.forward_search_history(u"ak"), u"akca") self.assertEqual(q.forward_search_history(u"ako"), u"ako") +class Test_empty_history_search_incr_fwd_backwd(unittest.TestCase): + def setUp(self): + self.q = q = LineHistory() + + def test_backward_1(self): + q = self.q + self.assertEqual(q.reverse_search_history(u"b"), u"") + + def test_forward_1(self): + q = self.q + self.assertEqual(q.forward_search_history(u"a"), u"") + #---------------------------------------------------------------------- # utility functions