diff options
-rw-r--r-- | ranger/container/keymap.py | 62 | ||||
-rw-r--r-- | ranger/defaults/keys.py | 16 | ||||
-rw-r--r-- | ranger/ext/tree.py | 1 | ||||
-rw-r--r-- | test/tc_newkeys.py | 54 |
4 files changed, 72 insertions, 61 deletions
diff --git a/ranger/container/keymap.py b/ranger/container/keymap.py index 930800ff..29d6e629 100644 --- a/ranger/container/keymap.py +++ b/ranger/container/keymap.py @@ -14,6 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import curses.ascii +from collections import deque from string import ascii_lowercase from inspect import isfunction, getargspec from ranger.ext.tree import Tree @@ -155,27 +156,28 @@ class KeyBuffer(object): self.direction_keys = direction_keys def add(self, key): - if self.failure: - return None assert isinstance(key, int) assert key >= 0 self.all_keys.append(key) + self.key_queue.append(key) + while self.key_queue: + key = self.key_queue.popleft() - # evaluate quantifiers - if self.eval_quantifier and self._do_eval_quantifier(key): - return + # evaluate quantifiers + if self.eval_quantifier and self._do_eval_quantifier(key): + return - # evaluate the command - if self.eval_command and self._do_eval_command(key): - return + # evaluate the command + if self.eval_command and self._do_eval_command(key): + return - # evaluate (the first number of) the direction-quantifier - if self.eval_quantifier and self._do_eval_quantifier(key): - return + # evaluate (the first number of) the direction-quantifier + if self.eval_quantifier and self._do_eval_quantifier(key): + return - # evaluate direction keys {j,k,gg,pagedown,...} - if not self.eval_command: - self._do_eval_direction(key) + # evaluate direction keys {j,k,gg,pagedown,...} + if not self.eval_command: + self._do_eval_direction(key) def _do_eval_direction(self, key): try: @@ -186,8 +188,8 @@ class KeyBuffer(object): else: self._direction_try_to_finish() - def _direction_try_to_finish(self, rec=MAX_ALIAS_RECURSION): - if rec <= 0: + def _direction_try_to_finish(self): + if self.max_alias_recursion <= 0: self.failure = True return None match = self.dir_tree_pointer @@ -197,12 +199,9 @@ class KeyBuffer(object): match = self.dir_tree_pointer if isinstance(self.dir_tree_pointer, Binding): if match.alias: - try: - self.dir_tree_pointer = self.direction_keys[match.alias] - self._direction_try_to_finish(rec - 1) - except KeyError: - self.failure = True - return None + self.key_queue.extend(translate_keys(match.alias)) + self.dir_tree_pointer = self.direction_keys._tree + self.max_alias_recursion -= 1 else: direction = match.actions['dir'].copy() if self.direction_quant is not None: @@ -232,11 +231,11 @@ class KeyBuffer(object): try: self.tree_pointer = self.tree_pointer[key] except TypeError: - print(self.tree_pointer) self.failure = True return None except KeyError: try: + is_ascii_digit(key) or self.direction_keys._tree[key] self.tree_pointer = self.tree_pointer[DIRKEY] except KeyError: try: @@ -261,8 +260,8 @@ class KeyBuffer(object): self.command = None self._try_to_finish() - def _try_to_finish(self, rec=MAX_ALIAS_RECURSION): - if rec <= 0: + def _try_to_finish(self): + if self.max_alias_recursion <= 0: self.failure = True return None assert isinstance(self.tree_pointer, (Binding, dict, KeyMap)) @@ -270,17 +269,15 @@ class KeyBuffer(object): self.tree_pointer = self.tree_pointer._tree if isinstance(self.tree_pointer, Binding): if self.tree_pointer.alias: - try: - self.tree_pointer = self.keymap[self.tree_pointer.alias] - self._try_to_finish(rec - 1) - except KeyError: - self.failure = True - return None + self.key_queue.extend(translate_keys(self.tree_pointer.alias)) + self.tree_pointer = self.keymap._tree + self.max_alias_recursion -= 1 else: self.command = self.tree_pointer self.done = True def clear(self): + self.max_alias_recursion = MAX_ALIAS_RECURSION self.failure = False self.done = False self.quant = None @@ -292,6 +289,8 @@ class KeyBuffer(object): self.tree_pointer = self.keymap._tree self.dir_tree_pointer = self.direction_keys._tree + self.key_queue = deque() + self.eval_quantifier = True self.eval_command = True @@ -318,6 +317,7 @@ special_keys = { 'cr': ord("\n"), 'enter': ord("\n"), 'space': ord(" "), + 'esc': curses.ascii.ESC, 'down': curses.KEY_DOWN, 'up': curses.KEY_UP, 'left': curses.KEY_LEFT, diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py index 70521e1e..57a0d415 100644 --- a/ranger/defaults/keys.py +++ b/ranger/defaults/keys.py @@ -265,8 +265,6 @@ map('w', 'q', ESC, ctrl('d'), ctrl('c'), map = keymanager.get_context('console') map.merge(global_keys) map.merge(readline_aliases) -map.unmap('Q') # don't quit with Q in console, so we can type it -map.unmap('<dir>') # define my own direction keys map('<up>', wdg.history_move(-1)) map('<down>', wdg.history_move(1)) @@ -274,7 +272,7 @@ map('<home>', wdg.move(right=0, absolute=True)) map('<end>', wdg.move(right=-1, absolute=True)) map('<tab>', wdg.tab()) map('<s-tab>', wdg.tab(-1)) -map('<c-c>', wdg.close()) +map('<c-c>', '<esc>', wdg.close()) map('<CR>', '<c-j>', wdg.execute()) map('<F1>', lambda arg: arg.fm.display_command_help(arg.wdg)) @@ -285,14 +283,24 @@ map('<C-K>', wdg.delete_rest(1)) map('<C-U>', wdg.delete_rest(-1)) map('<C-Y>', wdg.paste()) -map('<any>') +# Any key which is still undefined will simply be typed in. +@map('<any>') def type_key(arg): arg.wdg.type_key(arg.match) +# Override some global keys so we can type them: +override = ('Q', '%') +for key in override: + map(key, wdg.type_key(key)) + # =================================================================== # == Define direction keys # =================================================================== +# Note that direction keys point to no functions, but Direction objects. +# Direction keys are completely independent and can not be merged into +# other keymaps. You can't define or unmap direction keys on +# a per-context-basis, instead use aliases. map = keymanager.get_context('directions') map('<down>', dir=Direction(down=1)) map('<up>', dir=Direction(down=-1)) diff --git a/ranger/ext/tree.py b/ranger/ext/tree.py index 6d841c2a..a954136b 100644 --- a/ranger/ext/tree.py +++ b/ranger/ext/tree.py @@ -81,6 +81,7 @@ class Tree(object): if first or isinstance(subtree, Tree) and subtree.empty(): top = chars.pop() subtree = self.traverse(chars) + assert top in subtree._tree, "no such key: " + chr(top) del subtree._tree[top] else: break diff --git a/test/tc_newkeys.py b/test/tc_newkeys.py index fc17aeda..9a7f10c7 100644 --- a/test/tc_newkeys.py +++ b/test/tc_newkeys.py @@ -83,31 +83,6 @@ class Test(PressTestCase): self.assert_(match.function) self.assertEqual(8, match.function(args)) - def test_map_collision(self): - def add_dirs(arg): - return sum(dir.down() for dir in arg.directions) - def return5(_): - return 5 - - - directions = KeyMap() - directions.map('gg', dir=Direction(down=1)) - - - km = KeyMap() - km.map('gh', return5) - km.map('agh', return5) - km.map('a<dir>', add_dirs) - - kb = KeyBuffer(km, directions) - press = self._mkpress(kb, km) - - self.assertEqual(5, press('gh')) - self.assertEqual(5, press('agh')) -# self.assertPressFails(kb, 'agh') - self.assertEqual(1, press('agg')) - - def test_translate_keys(self): def test(string, *args): if not args: @@ -187,7 +162,7 @@ class Test(PressTestCase): self.assertEqual(press('c<CR>'), press('c@')) self.assertEqual(press('c<CR>'), press('c@')) - for n in range(1, 50): + for n in range(1, 10): self.assertPressIncomplete(kb, 'y' * n) for n in range(1, 5): @@ -540,11 +515,13 @@ class Test(PressTestCase): press = self._mkpress(kb) km.map('<dir>', func) + km.map('d<dir>', func) directions.map('j', dir=Direction(down=42)) self.assertEqual(42, press('j')) km.map('o', alias='j') self.assertEqual(42, press('o')) + self.assertEqual(42, press('do')) def test_both_directory_and_any_key(self): def func(arg): @@ -571,4 +548,29 @@ class Test(PressTestCase): km.map('abc<any>', func2) self.assertEqual("yay", press('abcd')) + def test_map_collision(self): + def add_dirs(arg): + return sum(dir.down() for dir in arg.directions) + def return5(_): + return 5 + + + directions = KeyMap() + directions.map('gg', dir=Direction(down=1)) + + + km = KeyMap() + km.map('gh', return5) + km.map('agh', return5) + km.map('a<dir>', add_dirs) + + kb = KeyBuffer(km, directions) + press = self._mkpress(kb, km) + + self.assertEqual(5, press('gh')) + self.assertEqual(5, press('agh')) +# self.assertPressFails(kb, 'agh') + self.assertEqual(1, press('agg')) + + if __name__ == '__main__': main() |