diff --git a/IPython/frontend/terminal/interactiveshell.py b/IPython/frontend/terminal/interactiveshell.py index 39bbc5a..94bf11c 100644 --- a/IPython/frontend/terminal/interactiveshell.py +++ b/IPython/frontend/terminal/interactiveshell.py @@ -229,21 +229,28 @@ class TerminalInteractiveShell(InteractiveShell): # handling seems rather unpredictable... self.write("\nKeyboardInterrupt in interact()\n") - def _replace_rlhist_multiline(self, source_raw): + def _replace_rlhist_multiline(self, source_raw, hlen_before_cell): """Store multiple lines as a single entry in history""" - if self.multiline_history and self.has_readline and source_raw.rstrip(): - hlen = self.readline.get_current_history_length() - # nothing changed do nothing, e.g. when rl removes consecutive dups - if self.hlen_before_cell == hlen: - return + # do nothing without readline or disabled multiline + if not self.has_readline or not self.multiline_history: + return hlen_before_cell + + # skip empty cells + if not source_raw.rstrip(): + return hlen_before_cell + + # nothing changed do nothing, e.g. when rl removes consecutive dups + hlen = self.readline.get_current_history_length() + if hlen == hlen_before_cell: + return hlen_before_cell - for i in range(hlen - self.hlen_before_cell): - self.readline.remove_history_item(hlen - i - 1) - stdin_encoding = sys.stdin.encoding or "utf-8" - self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(), - stdin_encoding)) - self.hlen_before_cell = self.readline.get_current_history_length() + for i in range(hlen - hlen_before_cell): + self.readline.remove_history_item(hlen - i - 1) + stdin_encoding = sys.stdin.encoding or "utf-8" + self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(), + stdin_encoding)) + return self.readline.get_current_history_length() def interact(self, display_banner=None): """Closely emulate the interactive Python console.""" @@ -267,7 +274,7 @@ class TerminalInteractiveShell(InteractiveShell): if self.has_readline: self.readline_startup_hook(self.pre_readline) - self.hlen_before_cell = self.readline.get_current_history_length() + hlen_b4_cell = self.readline.get_current_history_length() # exit_now is set by a call to %Exit or %Quit, through the # ask_exit callback. @@ -299,7 +306,8 @@ class TerminalInteractiveShell(InteractiveShell): try: self.write('\nKeyboardInterrupt\n') source_raw = self.input_splitter.source_raw_reset()[1] - self._replace_rlhist_multiline(source_raw) + hlen_b4_cell = \ + self._replace_rlhist_multiline(source_raw, hlen_b4_cell) more = False except KeyboardInterrupt: pass @@ -328,7 +336,8 @@ class TerminalInteractiveShell(InteractiveShell): if not more: source_raw = self.input_splitter.source_raw_reset()[1] self.run_cell(source_raw, store_history=True) - self._replace_rlhist_multiline(source_raw) + hlen_b4_cell = \ + self._replace_rlhist_multiline(source_raw, hlen_b4_cell) # We are off again... __builtin__.__dict__['__IPYTHON__active'] -= 1 diff --git a/IPython/frontend/terminal/tests/test_interactivshell.py b/IPython/frontend/terminal/tests/test_interactivshell.py index 85616eb..88d58cf 100644 --- a/IPython/frontend/terminal/tests/test_interactivshell.py +++ b/IPython/frontend/terminal/tests/test_interactivshell.py @@ -31,7 +31,7 @@ class InteractiveShellTestCase(unittest.TestCase): ip = get_ipython() ip.has_readline = False ip.readline = None - ip._replace_rlhist_multiline(u'source') + ip._replace_rlhist_multiline(u'source', 0) @skipif(not get_ipython().has_readline, 'no readline') def test_replace_multiline_hist_disabled(self): @@ -42,11 +42,12 @@ class InteractiveShellTestCase(unittest.TestCase): ghist = [u'line1', u'line2'] for h in ghist: ip.readline.add_history(h) - ip.hlen_before_cell = ip.readline.get_current_history_length() - ip._replace_rlhist_multiline(u'sourc€\nsource2') + hlen_b4_cell = ip.readline.get_current_history_length() + hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2', + hlen_b4_cell) self.assertEquals(ip.readline.get_current_history_length(), - ip.hlen_before_cell) + hlen_b4_cell) hist = self.rl_hist_entries(ip.readline, 2) self.assertEquals(hist, ghist) @@ -55,10 +56,10 @@ class InteractiveShellTestCase(unittest.TestCase): """Test that multiline replace function adds history""" ip = get_ipython() - ip.hlen_before_cell = ip.readline.get_current_history_length() - ip._replace_rlhist_multiline(u'sourc€') + hlen_b4_cell = ip.readline.get_current_history_length() + hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€', hlen_b4_cell) - self.assertEquals(ip.hlen_before_cell, + self.assertEquals(hlen_b4_cell, ip.readline.get_current_history_length()) @skipif(not get_ipython().has_readline, 'no readline') @@ -72,12 +73,13 @@ class InteractiveShellTestCase(unittest.TestCase): ip.readline.add_history(h) #start cell - ip.hlen_before_cell = ip.readline.get_current_history_length() - # nothing added to rl history, should do nothing - ip._replace_rlhist_multiline(u'sourc€\nsource2') + hlen_b4_cell = ip.readline.get_current_history_length() + # nothing added to rl history, should do nothing + hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2', + hlen_b4_cell) self.assertEquals(ip.readline.get_current_history_length(), - ip.hlen_before_cell) + hlen_b4_cell) hist = self.rl_hist_entries(ip.readline, 2) self.assertEquals(hist, ghist) @@ -90,18 +92,20 @@ class InteractiveShellTestCase(unittest.TestCase): ip.readline.add_history(u'line0') #start cell - ip.hlen_before_cell = ip.readline.get_current_history_length() + hlen_b4_cell = ip.readline.get_current_history_length() ip.readline.add_history('l€ne1') ip.readline.add_history('line2') #replace cell with single line - ip._replace_rlhist_multiline(u'l€ne1\nline2') + hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2', + hlen_b4_cell) ip.readline.add_history('l€ne3') ip.readline.add_history('line4') #replace cell with single line - ip._replace_rlhist_multiline(u'l€ne3\nline4') + hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3\nline4', + hlen_b4_cell) self.assertEquals(ip.readline.get_current_history_length(), - ip.hlen_before_cell) + hlen_b4_cell) hist = self.rl_hist_entries(ip.readline, 3) self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3\nline4']) @@ -114,24 +118,25 @@ class InteractiveShellTestCase(unittest.TestCase): ip.readline.add_history(u'line0') #start cell - ip.hlen_before_cell = ip.readline.get_current_history_length() + hlen_b4_cell = ip.readline.get_current_history_length() ip.readline.add_history('l€ne1') ip.readline.add_history('line2') - ip._replace_rlhist_multiline(u'l€ne1\nline2') + hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2', + hlen_b4_cell) ip.readline.add_history('') - ip._replace_rlhist_multiline(u'') + hlen_b4_cell = ip._replace_rlhist_multiline(u'', hlen_b4_cell) ip.readline.add_history('l€ne3') - ip._replace_rlhist_multiline(u'l€ne3') + hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3', hlen_b4_cell) ip.readline.add_history(' ') - ip._replace_rlhist_multiline(' ') + hlen_b4_cell = ip._replace_rlhist_multiline(' ', hlen_b4_cell) ip.readline.add_history('\t') ip.readline.add_history('\t ') - ip._replace_rlhist_multiline('\t') + hlen_b4_cell = ip._replace_rlhist_multiline('\t', hlen_b4_cell) ip.readline.add_history('line4') - ip._replace_rlhist_multiline(u'line4') + hlen_b4_cell = ip._replace_rlhist_multiline(u'line4', hlen_b4_cell) self.assertEquals(ip.readline.get_current_history_length(), - ip.hlen_before_cell) + hlen_b4_cell) hist = self.rl_hist_entries(ip.readline, 4) # expect no empty cells in history self.assertEquals(hist, ['line0', 'l€ne1\nline2', 'l€ne3', 'line4'])