summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/container/environment.py4
-rw-r--r--ranger/container/keybuffer.py57
-rw-r--r--ranger/defaults/keys.py39
-rw-r--r--ranger/gui/ui.py9
-rw-r--r--ranger/gui/widgets/console.py2
5 files changed, 92 insertions, 19 deletions
diff --git a/ranger/container/environment.py b/ranger/container/environment.py
index b766a4c9..1b26d48e 100644
--- a/ranger/container/environment.py
+++ b/ranger/container/environment.py
@@ -36,11 +36,11 @@ class Environment(SettingsAware):
 	def key_append(self, key):
 		"""Append a key to the keybuffer"""
 		from ranger import log
-		self.keybuffer = KeyBuffer(self.keybuffer + (key, ))
+		self.keybuffer.append(key)
 
 	def key_clear(self):
 		"""Clear the keybuffer"""
-		self.keybuffer = KeyBuffer()
+		self.keybuffer.clear()
 	
 	def at_level(self, level):
 		"""Returns the FileSystemObject at the given level.
diff --git a/ranger/container/keybuffer.py b/ranger/container/keybuffer.py
index 10c9c40c..048a5083 100644
--- a/ranger/container/keybuffer.py
+++ b/ranger/container/keybuffer.py
@@ -1,11 +1,56 @@
-class KeyBuffer(tuple):
-	"""Extension of tuple suited to be used as a keybuffer"""
-	def __str__(self):
-		"""returns a concatenation of all characters"""
-		return "".join( map( to_string, self ) )
-
 def to_string(i):
 	try:
 		return chr(i)
 	except ValueError:
 		return '?'
+
+from collections import deque
+from curses.ascii import ascii
+
+ZERO = ord('0')
+NINE = ord('9')
+
+class KeyBuffer(object):
+	def __init__(self):
+		self.number = None
+		self.queue = deque()
+		self.queue_with_numbers = deque()
+	
+	def clear(self):
+		"""Clear the keybuffer and restore the initial state"""
+		self.number = None
+		self.queue.clear()
+		self.queue_with_numbers.clear()
+	
+	def append(self, key):
+		"""
+		Append a key to the keybuffer, or initial numbers to
+		the number attribute.
+		"""
+		self.queue_with_numbers.append(key)
+
+		if not self.queue and key >= ZERO and key <= NINE:
+			if self.number is None:
+				self.number = 0
+			try:
+				self.number = self.number * 10 + int(chr(key))
+			except ValueError:
+				return
+		else:
+			self.queue.append(key)
+	
+	def tuple_with_numbers(self):
+		"""Get a tuple of ascii codes."""
+		return tuple(self.queue_with_numbers)
+
+	def tuple_without_numbers(self):
+		"""
+		Get a tuple of ascii codes.
+		If the keybuffer starts with numbers, those will
+		be left out. To access them, use keybuffer.number
+		"""
+		return tuple(self.queue)
+
+	def __str__(self):
+		"""returns a concatenation of all characters"""
+		return "".join( map( to_string, self.queue_with_numbers ) )
diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py
index 98ecd6c1..e3be795d 100644
--- a/ranger/defaults/keys.py
+++ b/ranger/defaults/keys.py
@@ -1,12 +1,10 @@
 import curses
 from curses.ascii import *
 from ranger import RANGERDIR
+from ranger import log
 from ranger.gui.widgets.console import Console
 from ranger.container.bookmarks import ALLOWED_KEYS as ALLOWED_BOOKMARK_KEYS
 
-def do(method, *args, **kw):
-	return lambda fm: getattr(fm, method)(*args, **kw)
-
 # syntax for binding keys: bind(*keys, fnc)
 # fnc is a function which is called with the FM instance,
 # keys are one or more key-combinations which are either:
@@ -20,6 +18,9 @@ def do(method, *args, **kw):
 def initialize_commands(command_list):
 	"""Initialize the commands for the main user interface"""
 
+	def do(method, *args, **kw):
+		return lambda fm, n: getattr(fm, method)(*args, **kw)
+
 	def bind(*args):
 		command_list.bind(args[-1], *args[:-1])
 
@@ -28,15 +29,12 @@ def initialize_commands(command_list):
 	bind(curses.KEY_ENTER, ctrl('j'), do('move_right', mode=1))
 	bind('H', do('history_go', -1))
 	bind('L', do('history_go',  1))
-	bind('j', do('move_pointer', relative = 1))
 	bind('J', do('move_pointer_by_pages', 0.5))
-	bind('k', do('move_pointer', relative = -1))
 	bind('K', do('move_pointer_by_pages', -0.5))
-	bind('gg', do('move_pointer', absolute = 0))
-	bind('G', do('move_pointer', absolute = -1))
 	bind('E', do('edit_file'))
 	bind('o', do('force_load_preview'))
 
+
 	bind('yy', 'cp', do('copy'))
 	bind('cut', do('cut'))
 	bind('p', do('paste'))
@@ -85,11 +83,33 @@ def initialize_commands(command_list):
 	bind('!', do('open_console', '!'))
 	bind('r', do('open_console', '@'))
 
-	def test(fm):
+
+	# definitions which require their own function:
+	def test(fm, n):
 		from ranger import log
 		log(fm.bookmarks.dct)
 	bind('x', test)
 
+	def ggG(default):
+		# moves to an absolute point, or to a predefined default
+		# if no number is specified.
+		return lambda fm, n: \
+				fm.move_pointer(absolute=(n or default))
+
+	bind('gg', ggG(0))
+	bind('G', ggG(-1))
+
+	bind('%', lambda fm, n: fm.move_pointer_by_percentage(absolute=n or 0))
+
+	def jk(direction):
+		# moves up or down by the specified number or one, in
+		# the predefined direction
+		return lambda fm, n: \
+				fm.move_pointer(relative=(n or 1) * direction)
+
+	bind('j', jk(1))
+	bind('k', jk(-1))
+
 	command_list.rebuild_paths()
 
 
@@ -99,6 +119,9 @@ def initialize_console_commands(command_list):
 	def bind(*args):
 		command_list.bind(args[-1], *args[:-1])
 
+	def do(method, *args, **kw):
+		return lambda fm: getattr(fm, method)(*args, **kw)
+
 	def do_fm(method, *args, **kw):
 		return lambda con: getattr(con.fm, method)(*args, **kw)
 
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index da633698..cdb58ad5 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -111,7 +111,12 @@ class UI(DisplayableContainer):
 			return
 
 		try:
-			cmd = self.commandlist[tuple(self.env.keybuffer)]
+			tup = self.env.keybuffer.tuple_without_numbers()
+
+			if tup:
+				cmd = self.commandlist[tup]
+			else:
+				return
 		except KeyError:
 			self.env.key_clear()
 			return
@@ -119,7 +124,7 @@ class UI(DisplayableContainer):
 		if cmd == self.commandlist.dummy_object:
 			return
 
-		cmd.execute(self.fm)
+		cmd.execute(self.fm, self.env.keybuffer.number)
 		self.env.key_clear()
 
 	def get_next_key(self):
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index bed9f031..f2c15426 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -79,7 +79,7 @@ class Console(Widget):
 		from curses.ascii import ctrl, ESC
 
 		try:
-			cmd = self.commandlist[self.env.keybuffer]
+			cmd = self.commandlist[self.env.keybuffer.tuple_with_numbers()]
 		except KeyError:
 			self.env.key_clear()
 			return