summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/container/keymap.py62
-rw-r--r--ranger/defaults/keys.py16
-rw-r--r--ranger/ext/tree.py1
-rw-r--r--test/tc_newkeys.py54
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()
dlers.go?h=v0.2.1&id=474ffad421eee04a50cbdd5cfbc2b396c24dc521'>^
b9d16fb ^
d4c05d2 ^
fc49c57 ^
d4c05d2 ^

fc49c57 ^

d4c05d2 ^
fc49c57 ^

b9d16fb ^
d3d9df2 ^

b9d16fb ^
747f4fb ^
b6e7bb3 ^
fc49c57 ^

efa99ed ^
fc49c57 ^








b6e7bb3 ^
efa99ed ^

d4c05d2 ^
b6e7bb3 ^
efa99ed ^
d4c05d2 ^
fc49c57 ^

d4c05d2 ^
fc49c57 ^

b9d16fb ^
d3d9df2 ^
d2680fb ^

fc49c57 ^
d2680fb ^




fc49c57 ^




d2680fb ^

fc49c57 ^
d2680fb ^

d3d9df2 ^
b9d16fb ^
fc49c57 ^
d4c05d2 ^



fc49c57 ^
d4c05d2 ^

fc49c57 ^

d4c05d2 ^
b9d16fb ^
fc49c57 ^
b9d16fb ^
d3d9df2 ^

b9d16fb ^
fc49c57 ^
d4c05d2 ^
d4c05d2 ^

fc49c57 ^




747f4fb ^
fc49c57 ^






d4c05d2 ^
b9d16fb ^
fc49c57 ^
b9d16fb ^
d6fbc25 ^


747f4fb ^
747f4fb ^
d6fbc25 ^



fc49c57 ^
d6fbc25 ^

fc49c57 ^
d6fbc25 ^













fc49c57 ^
d6fbc25 ^

fc49c57 ^

d6fbc25 ^
fc49c57 ^

d6fbc25 ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209