[tor-commits] [nyx/master] Proper handler chaining

atagar at torproject.org atagar at torproject.org
Sun Jul 31 23:32:40 UTC 2016


commit ec9788b0fbca919e250d4c7ce1dc10dc4c8e9fb5
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Jul 19 09:43:20 2016 -0700

    Proper handler chaining
    
    Our tab completion handler was hardcoded to call the history handler. Fine if
    tab and history completion are always done together (as they are at the moment)
    but clearly a bug. Fixing this so any combination of handlers can be used.
---
 nyx/curses.py     | 33 +++++++++++++++++++--------------
 test/subwindow.py | 14 ++++++++------
 2 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/nyx/curses.py b/nyx/curses.py
index 3767cd3..a6a8b2d 100644
--- a/nyx/curses.py
+++ b/nyx/curses.py
@@ -86,6 +86,7 @@ import collections
 import curses
 import curses.ascii
 import curses.textpad
+import functools
 import os
 import threading
 
@@ -280,12 +281,15 @@ def str_input(x, y, initial_text = '', backlog = None, tab_completion = None):
     curses_subwindow.addstr(0, 0, initial_text[:width - 1])
 
     textbox = curses.textpad.Textbox(curses_subwindow, insert_mode = True)
-    if tab_completion is not None:
-      user_input = textbox.edit(lambda key: _handle_tab_completion(textbox, key, backlog, tab_completion)).strip()
-    elif backlog is not None:
-      user_input = textbox.edit(lambda key: _handle_history_key(textbox, key, backlog)).strip()
-    else:
-      user_input = textbox.edit(lambda key: _handle_key(textbox, key)).strip()
+    handler = _handle_key
+
+    if backlog:
+      handler = functools.partial(_handle_history_key, handler, backlog)
+
+    if tab_completion:
+      handler = functools.partial(_handle_tab_completion, handler, tab_completion)
+
+    user_input = textbox.edit(lambda key: handler(textbox, key)).strip()
 
     try:
       curses.curs_set(0)  # hide cursor
@@ -328,14 +332,15 @@ def _handle_key(textbox, key):
     return key
 
 
-def _handle_history_key(textbox, key, backlog):
+def _handle_history_key(next_handler, backlog, textbox, key):
   """
   Handles history validation. When the up/down arrow keys are pressed,
   the relative previous/next commands are shown.
 
+  :param func next_handler: handler to invoke after this
+  :param list backlog: backlog of all previous commands entered
   :param Textbox textbox: current textbox context
   :param int key: key pressed
-  :param list backlog: backlog of all previous commands entered
 
   :returns: **None** if up/down arrow key is pressed or calls function
     to write key to the textbox
@@ -370,19 +375,19 @@ def _handle_history_key(textbox, key, backlog):
     HISTORY_DICT['selection_index'] = new_selection
     return None
 
-  return _handle_key(textbox, key)
+  return next_handler(textbox, key)
 
 
-def _handle_tab_completion(textbox, key, backlog, tab_completion):
+def _handle_tab_completion(next_handler, tab_completion, textbox, key):
   """
   Handles tab completion. If the tab key is pressed, the current textbox
   contents are checked for probable commands.
 
-  :param Textbox textbox: current textbox context
-  :param int key: key pressed
-  :param list backlog: backlog of all previous commands entered
+  :param func next_handler: handler to invoke after this
   :param Autocompleter.matches tab_completion: function to suggest probable
     commands based on current content
+  :param Textbox textbox: current textbox context
+  :param int key: key pressed
 
   :returns: **None** when tab key is pressed or calls function to handle
     history validation
@@ -409,7 +414,7 @@ def _handle_tab_completion(textbox, key, backlog, tab_completion):
 
     return None
 
-  return _handle_history_key(textbox, key, backlog)
+  return next_handler(textbox, key)
 
 
 def curses_attr(*attributes):
diff --git a/test/subwindow.py b/test/subwindow.py
index 3f58278..559c451 100644
--- a/test/subwindow.py
+++ b/test/subwindow.py
@@ -68,6 +68,8 @@ EXPECTED_SCROLLBAR_BOTTOM = """
 -+
 """.strip()
 
+NO_OP_HANDLER = lambda key, textbox: None
+
 
 class TestCurses(unittest.TestCase):
   @require_curses
@@ -156,21 +158,20 @@ class TestCurses(unittest.TestCase):
     key_pressed = ord('a')
     self.assertEqual(key_pressed, nyx.curses._handle_key(textbox, key_pressed))
 
-  @patch('nyx.curses._handle_key')
-  def test_handle_history_key(self, mock_handle_key):
+  def test_handle_history_key(self):
     backlog = ['GETINFO version']
     dimensions = (40, 80)
 
     textbox = Mock()
     textbox.win.getyx.return_value = dimensions
-    self.assertIsNone(nyx.curses._handle_history_key(textbox, curses.KEY_UP, []))
+    self.assertIsNone(nyx.curses._handle_history_key(NO_OP_HANDLER, [], textbox, curses.KEY_UP))
 
     textbox = Mock()
     textbox.win.getyx.return_value = dimensions
     textbox.win.getmaxyx.return_value = dimensions
     textbox.win.addstr = Mock()
     textbox.win.move = Mock()
-    nyx.curses._handle_history_key(textbox, curses.KEY_UP, backlog)
+    nyx.curses._handle_history_key(NO_OP_HANDLER, backlog, textbox, curses.KEY_UP)
     self.assertTrue(textbox.win.clear.called)
     expected_addstr_call = call(dimensions[0], 0, backlog[0])
     self.assertEqual(expected_addstr_call, textbox.win.addstr.call_args)
@@ -178,7 +179,8 @@ class TestCurses(unittest.TestCase):
     self.assertEqual(expected_move_call, textbox.win.move.call_args)
 
     textbox = Mock()
-    nyx.curses._handle_history_key(textbox, curses.KEY_LEFT, [])
+    mock_handle_key = Mock()
+    nyx.curses._handle_history_key(mock_handle_key, [], textbox, curses.KEY_LEFT)
     self.assertTrue(mock_handle_key.called)
 
   @patch('nyx.curses._handle_history_key')
@@ -193,7 +195,7 @@ class TestCurses(unittest.TestCase):
     textbox.win.move = Mock()
     tab_completion = Mock()
     tab_completion.return_value = [tab_completion_content]
-    nyx.curses._handle_tab_completion(textbox, 9, [], tab_completion)
+    nyx.curses._handle_tab_completion(NO_OP_HANDLER, tab_completion, textbox, 9)
     self.assertTrue(textbox.win.clear.called)
     expected_addstr_call = call(dimensions[0], 0, tab_completion_content)
     self.assertEqual(expected_addstr_call, textbox.win.addstr.call_args)





More information about the tor-commits mailing list