From 586ad3c8f2dae749fbf534be142a52e3d870c33a Mon Sep 17 00:00:00 2001 From: Evan Allgood Date: Wed, 24 Jun 2020 14:11:06 -0500 Subject: [PATCH 1/6] Redo in progress; still buggy --- bpython/cli.py | 2 +- bpython/curtsiesfrontend/repl.py | 12 +++++++++++- bpython/repl.py | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/bpython/cli.py b/bpython/cli.py index 9aee3d5c6..4c5543446 100644 --- a/bpython/cli.py +++ b/bpython/cli.py @@ -905,7 +905,7 @@ def p_key(self, key): if n > 0: self.undo(n=n) return "" - + elif key in key_dispatch[config.search_key]: self.search() return "" diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 13c393783..cbb6d2b73 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -775,6 +775,12 @@ def process_key_event(self, e): self.on_tab(back=True) elif e in key_dispatch[self.config.undo_key]: # ctrl-r for undo self.prompt_undo() + elif e in [""]: # for redo + if (self.could_be_redone): + self.push(self.could_be_redone.pop()) + open("testFile.txt", "a").write(str(self.history) + "\n") + else: + self.status_bar.message("Nothing to redo.") elif e in key_dispatch[self.config.save_key]: # ctrl-s for save greenlet.greenlet(self.write2file).switch() elif e in key_dispatch[self.config.pastebin_key]: # F8 for pastebin @@ -860,6 +866,9 @@ def readline_kill(self, e): def on_enter(self, insert_into_history=True, reset_rl_history=True): # so the cursor isn't touching a paren TODO: necessary? + if insert_into_history: + self.could_be_redone = [] + self._set_cursor_offset(-1, update_completion=False) if reset_rl_history: self.rl_history.reset() @@ -1151,6 +1160,7 @@ def push(self, line, insert_into_history=True): if insert_into_history: self.insert_into_history(line) + #self.history.append(line) self.buffer.append(line) code_to_run = "\n".join(self.buffer) @@ -1812,7 +1822,7 @@ def prompt_for_undo(): greenlet.greenlet(prompt_for_undo).switch() def reevaluate(self, insert_into_history=False): - """bpython.Repl.undo calls this""" + """bpython.Repl.undo calls this""" if self.watcher: self.watcher.reset() old_logical_lines = self.history diff --git a/bpython/repl.py b/bpython/repl.py index f966b3faa..0fa087c7a 100644 --- a/bpython/repl.py +++ b/bpython/repl.py @@ -439,7 +439,8 @@ def __init__(self, interp, config): duplicates=config.hist_duplicates, hist_size=config.hist_length ) self.s_hist = [] - self.history = [] + self.history = [] # History of commands + self.could_be_redone = [] self.evaluating = False self.matches_iter = MatchesIterator() self.funcprops = None @@ -1009,6 +1010,10 @@ def undo(self, n=1): entries = list(self.rl_history.entries) + #Most recently undone command + lastEntry = self.history[-n:] + lastEntry.reverse() + self.could_be_redone += lastEntry self.history = self.history[:-n] self.reevaluate() From 6a929a63e00f0333dfe3b27780c6b4f8004a2401 Mon Sep 17 00:00:00 2001 From: Evan Allgood Date: Wed, 24 Jun 2020 14:56:16 -0500 Subject: [PATCH 2/6] Fixed redo; added redone lines to history --- bpython/curtsiesfrontend/repl.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index cbb6d2b73..6dd4d864d 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -777,8 +777,9 @@ def process_key_event(self, e): self.prompt_undo() elif e in [""]: # for redo if (self.could_be_redone): - self.push(self.could_be_redone.pop()) - open("testFile.txt", "a").write(str(self.history) + "\n") + temp = self.could_be_redone.pop() + self.push(temp) + self.history.append(temp) else: self.status_bar.message("Nothing to redo.") elif e in key_dispatch[self.config.save_key]: # ctrl-s for save @@ -1160,7 +1161,6 @@ def push(self, line, insert_into_history=True): if insert_into_history: self.insert_into_history(line) - #self.history.append(line) self.buffer.append(line) code_to_run = "\n".join(self.buffer) @@ -1822,7 +1822,7 @@ def prompt_for_undo(): greenlet.greenlet(prompt_for_undo).switch() def reevaluate(self, insert_into_history=False): - """bpython.Repl.undo calls this""" + """bpython.Repl.undo calls this""" if self.watcher: self.watcher.reset() old_logical_lines = self.history From a8f5789323ef34b26db39d330ecca11a9b306fd2 Mon Sep 17 00:00:00 2001 From: Evan Allgood Date: Thu, 25 Jun 2020 10:17:57 -0500 Subject: [PATCH 3/6] Updated redo with Tom's suggestions: made redo configurable and improved formatting --- bpython/config.py | 2 ++ bpython/curtsiesfrontend/repl.py | 29 ++++++++++++++++------------- bpython/repl.py | 10 +++++----- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/bpython/config.py b/bpython/config.py index f074fb745..1a58bf525 100644 --- a/bpython/config.py +++ b/bpython/config.py @@ -108,6 +108,7 @@ def loadini(struct, configfile): "last_output": "F9", "left": "C-b", "pastebin": "F8", + "redo": "C-g", "reimport": "F6", "reverse_incremental_search": "M-r", "right": "C-f", @@ -193,6 +194,7 @@ def get_key_no_doublebind(command): struct.suspend_key = get_key_no_doublebind("suspend") struct.toggle_file_watch_key = get_key_no_doublebind("toggle_file_watch") struct.undo_key = get_key_no_doublebind("undo") + struct.redo_key = get_key_no_doublebind("redo") struct.reimport_key = get_key_no_doublebind("reimport") struct.reverse_incremental_search_key = get_key_no_doublebind( "reverse_incremental_search" diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 6dd4d864d..839ef4de6 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -775,13 +775,8 @@ def process_key_event(self, e): self.on_tab(back=True) elif e in key_dispatch[self.config.undo_key]: # ctrl-r for undo self.prompt_undo() - elif e in [""]: # for redo - if (self.could_be_redone): - temp = self.could_be_redone.pop() - self.push(temp) - self.history.append(temp) - else: - self.status_bar.message("Nothing to redo.") + elif e in key_dispatch[self.config.redo_key]: # ctrl-g for redo + self.prompt_redo() elif e in key_dispatch[self.config.save_key]: # ctrl-s for save greenlet.greenlet(self.write2file).switch() elif e in key_dispatch[self.config.pastebin_key]: # F8 for pastebin @@ -865,17 +860,17 @@ def readline_kill(self, e): else: self.cut_buffer = cut - def on_enter(self, insert_into_history=True, reset_rl_history=True): + def on_enter(self, new_code=True, reset_rl_history=True): # so the cursor isn't touching a paren TODO: necessary? - if insert_into_history: - self.could_be_redone = [] + if new_code: + self.redo_stack = [] self._set_cursor_offset(-1, update_completion=False) if reset_rl_history: self.rl_history.reset() self.history.append(self.current_line) - self.push(self.current_line, insert_into_history=insert_into_history) + self.push(self.current_line, insert_into_history=new_code) def on_tab(self, back=False): """Do something on tab key @@ -1821,7 +1816,15 @@ def prompt_for_undo(): greenlet.greenlet(prompt_for_undo).switch() - def reevaluate(self, insert_into_history=False): + def prompt_redo(self): + if (self.redo_stack): + temp = self.redo_stack.pop() + self.push(temp) + self.history.append(temp) + else: + self.status_bar.message("Nothing to redo.") + + def reevaluate(self, new_code=False): """bpython.Repl.undo calls this""" if self.watcher: self.watcher.reset() @@ -1845,7 +1848,7 @@ def reevaluate(self, insert_into_history=False): sys.stdin = ReevaluateFakeStdin(self.stdin, self) for line in old_logical_lines: self._current_line = line - self.on_enter(insert_into_history=insert_into_history) + self.on_enter(new_code=new_code) while self.fake_refresh_requested: self.fake_refresh_requested = False self.process_event(bpythonevents.RefreshRequestEvent()) diff --git a/bpython/repl.py b/bpython/repl.py index 0fa087c7a..96cf2b5d0 100644 --- a/bpython/repl.py +++ b/bpython/repl.py @@ -439,8 +439,8 @@ def __init__(self, interp, config): duplicates=config.hist_duplicates, hist_size=config.hist_length ) self.s_hist = [] - self.history = [] # History of commands - self.could_be_redone = [] + self.history = [] # commands executed since beginning of session + self.redo_stack = [] self.evaluating = False self.matches_iter = MatchesIterator() self.funcprops = None @@ -1011,9 +1011,9 @@ def undo(self, n=1): entries = list(self.rl_history.entries) #Most recently undone command - lastEntry = self.history[-n:] - lastEntry.reverse() - self.could_be_redone += lastEntry + last_entries = self.history[-n:] + last_entries.reverse() + self.redo_stack += last_entries self.history = self.history[:-n] self.reevaluate() From 2c866521240f1ccc32d4639a166ad302e25ecf2c Mon Sep 17 00:00:00 2001 From: Evan Allgood Date: Thu, 25 Jun 2020 10:42:58 -0500 Subject: [PATCH 4/6] prompt_undo() -> undo(), removed extraneous whitespace --- bpython/cli.py | 2 +- bpython/curtsiesfrontend/repl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bpython/cli.py b/bpython/cli.py index 4c5543446..9aee3d5c6 100644 --- a/bpython/cli.py +++ b/bpython/cli.py @@ -905,7 +905,7 @@ def p_key(self, key): if n > 0: self.undo(n=n) return "" - + elif key in key_dispatch[config.search_key]: self.search() return "" diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 839ef4de6..8880faaa6 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -776,7 +776,7 @@ def process_key_event(self, e): elif e in key_dispatch[self.config.undo_key]: # ctrl-r for undo self.prompt_undo() elif e in key_dispatch[self.config.redo_key]: # ctrl-g for redo - self.prompt_redo() + self.redo() elif e in key_dispatch[self.config.save_key]: # ctrl-s for save greenlet.greenlet(self.write2file).switch() elif e in key_dispatch[self.config.pastebin_key]: # F8 for pastebin @@ -1816,7 +1816,7 @@ def prompt_for_undo(): greenlet.greenlet(prompt_for_undo).switch() - def prompt_redo(self): + def redo(self): if (self.redo_stack): temp = self.redo_stack.pop() self.push(temp) From beb450938ec9b9f87590a68814c85d207e5a6dce Mon Sep 17 00:00:00 2001 From: Evan Allgood Date: Thu, 25 Jun 2020 13:21:28 -0500 Subject: [PATCH 5/6] Updated tests with new redo-friendly variable names (insert_into_history -> new_code) --- bpython/curtsiesfrontend/repl.py | 4 ++-- bpython/test/test_curtsies_painting.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 8880faaa6..4e8357b43 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1024,7 +1024,7 @@ def send_session_to_external_editor(self, filename=None): source = preprocess("\n".join(from_editor), self.interp.compile) lines = source.split("\n") self.history = lines - self.reevaluate(insert_into_history=True) + self.reevaluate(new_code=True) self.current_line = current_line self.cursor_offset = len(self.current_line) self.status_bar.message(_("Session edited and reevaluated")) @@ -1035,7 +1035,7 @@ def clear_modules_and_reevaluate(self): cursor, line = self.cursor_offset, self.current_line for modname in set(sys.modules.keys()) - self.original_modules: del sys.modules[modname] - self.reevaluate(insert_into_history=True) + self.reevaluate(new_code=True) self.cursor_offset, self.current_line = cursor, line self.status_bar.message( _("Reloaded at %s by user.") % (time.strftime("%X"),) diff --git a/bpython/test/test_curtsies_painting.py b/bpython/test/test_curtsies_painting.py index 2c68b6092..15424c662 100644 --- a/bpython/test/test_curtsies_painting.py +++ b/bpython/test/test_curtsies_painting.py @@ -102,7 +102,7 @@ def test_run_line(self): orig_stdout = sys.stdout sys.stdout = self.repl.stdout [self.repl.add_normal_character(c) for c in "1 + 1"] - self.repl.on_enter(insert_into_history=False) + self.repl.on_enter(new_code=False) screen = fsarray([">>> 1 + 1", "2", "Welcome to"]) self.assert_paint_ignoring_formatting(screen, (1, 1)) finally: @@ -248,7 +248,7 @@ def enter(self, line=None): self.repl._set_cursor_offset(len(line), update_completion=False) self.repl.current_line = line with output_to_repl(self.repl): - self.repl.on_enter(insert_into_history=False) + self.repl.on_enter(new_code=False) self.assertEqual(self.repl.rl_history.entries, [""]) self.send_refreshes() @@ -592,7 +592,7 @@ def test_cursor_stays_at_bottom_of_screen(self): self.repl.width = 50 self.repl.current_line = "__import__('random').__name__" with output_to_repl(self.repl): - self.repl.on_enter(insert_into_history=False) + self.repl.on_enter(new_code=False) screen = [">>> __import__('random').__name__", "'random'"] self.assert_paint_ignoring_formatting(screen) From babad306d02975e31c68ae6aa1c7b7b70cfc70c5 Mon Sep 17 00:00:00 2001 From: Evan Allgood Date: Fri, 26 Jun 2020 09:19:24 -0500 Subject: [PATCH 6/6] Added redo to sample-config --- bpython/sample-config | 1 + 1 file changed, 1 insertion(+) diff --git a/bpython/sample-config b/bpython/sample-config index 1f7c8dd65..00b6ee4ef 100644 --- a/bpython/sample-config +++ b/bpython/sample-config @@ -67,6 +67,7 @@ # toggle_file_watch = F5 # save = C-s # undo = C-r +# redo = C-g # up_one_line = C-p # down_one_line = C-n # cut_to_buffer = C-k