summary refs log tree commit diff stats
path: root/ranger/keyapi.py
diff options
context:
space:
mode:
Diffstat (limited to 'ranger/keyapi.py')
-rw-r--r--ranger/keyapi.py94
1 files changed, 65 insertions, 29 deletions
diff --git a/ranger/keyapi.py b/ranger/keyapi.py
index 82f1495d..e5d6f367 100644
--- a/ranger/keyapi.py
+++ b/ranger/keyapi.py
@@ -1,5 +1,7 @@
 from curses import *
 from curses.ascii import *
+from inspect import getargspec, ismethod
+
 from ranger import RANGERDIR
 from ranger.gui.widgets import console_mode as cmode
 from ranger.container.bookmarks import ALLOWED_KEYS as ALLOWED_BOOKMARK_KEYS
@@ -18,18 +20,18 @@ class Wrapper(object):
 		self.__firstattr__ = firstattr
 
 	def __getattr__(self, attr):
-		def wrapper(*args, **keywords):
-			def bla(command_argument):
+		def wrapper(*real_args, **real_keywords):
+			def function(command_argument):
+				args, kws = real_args, real_keywords
+				number = command_argument.n
 				obj = getattr(command_argument, self.__firstattr__)
-				if obj is None:
-					return
-				return getattr(obj, attr)(*args, **keywords)
-			return bla
+				fnc = getattr(obj, attr)
+				if number is not None:
+					args, kws = replace_narg(number, fnc, args, kws)
+				return fnc(*args, **kws)
+			return function
 		return wrapper
 
-fm = Wrapper('fm')
-wdg = Wrapper('wdg')
-
 # fm.enter_dir('~') is translated into lambda arg: arg.fm.enter_dir('~')
 # this makes things like this possible:
 # bind('gh', fm.enter_dir('~'))
@@ -39,25 +41,59 @@ wdg = Wrapper('wdg')
 #
 # for something like that, use the long version:
 # bind('H', lambda arg: arg.fm.history.go(-1))
+#
+# If the method has an argument named "narg", pressing a number before
+# the key will pass that number as the narg argument. If you want the
+# same behaviour in a custom lambda function, you can write:
+# bind('gg', fm.move_pointer(absolute=0))
+# as:
+# bind('gg', lambda arg: narg(arg.n, arg.fm.move_pointer, absolute=0))
+
+fm = Wrapper('fm')
+wdg = Wrapper('wdg')
+
+
+NARG_KEYWORD = 'narg'
+
+def narg(number_, function_, *args_, **keywords_):
+	"""
+	This applies the replace_narg function to the arguments and keywords
+	and directly runs this function.
+
+	Example:
+	def foo(xyz, narg): return hash((xyz, narg))
+
+	narg(50, foo, 123) == foo(123, narg=50)
+	"""
+	args, keywords = replace_narg(number_, function_, args_, keywords_)
+	print(args, keywords)
+	return function_(*args, **keywords)
+
+def replace_narg(number, function, args, keywords):
+	"""
+	This function returns (args, keywords) with one little change:
+	if <function> has a named argument called "narg", args and keywords
+	will be modified so that the value of "narg" will be <number>.
+
+	def foo(xyz, narg): pass
+
+	replace_narg(666, foo, (), {'narg': 10, 'xyz': 5})
+	=> (), {'narg': 666, 'xyz': 5}
 
+	replace_narg(666, foo, (1, 2), {})
+	=> (1, 666), {}
+	"""
+	argspec = getargspec(function).args
+	if NARG_KEYWORD in argspec:
+		try:
+			# is narg in args?
+			args = list(args)
+			index = argspec.index(NARG_KEYWORD)
+			if ismethod(function):
+				index -= 1  # because of 'self'
+			args[index] = number
+		except (ValueError, IndexError):
+			# is narg in keywords?
+			keywords[NARG_KEYWORD] = number
+	return args, keywords
 
-# Another wrapper for common actions which use a numerical argument:
-class nwrap(object):
-	@staticmethod
-	def move(relative=0, absolute=None, pages=False):
-		if absolute is None:
-			def fnc(arg):
-				if arg.n is not None:
-					if relative >= 0:
-						arg.wdg.move(relative=arg.n, pages=pages)
-					else:
-						arg.wdg.move(relative=-arg.n, pages=pages)
-				else:
-					arg.wdg.move(relative=relative, pages=pages)
-		else:
-			def fnc(arg):
-				if arg.n is not None:
-					arg.wdg.move(absolute=arg.n, relative=relative, pages=pages)
-				else:
-					arg.wdg.move(absolute=absolute, relative=relative, pages=pages)
-		return fnc