diff options
Diffstat (limited to 'ranger/api/keys.py')
-rw-r--r-- | ranger/api/keys.py | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/ranger/api/keys.py b/ranger/api/keys.py new file mode 100644 index 00000000..308fab2b --- /dev/null +++ b/ranger/api/keys.py @@ -0,0 +1,132 @@ +# Copyright (c) 2009, 2010 hut <hut@lavabit.com> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import os +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 + +def make_abbreviations(command_list): + def bind(*args): + lastarg = args[-1] + if hasattr(lastarg, '__call__'): + # do the binding + command_list.bind(lastarg, *args[:-1]) + else: + # act as a decorator. eg: + # @bind('a') + # def do_stuff(arg): + # arg.fm.ui.do_stuff() + # + # is equivalent to: + # bind('a', lambda arg: arg.fm.ui.do_stuff()) + return lambda fnc: command_list.bind(fnc, *args) + + def hint(*args): + command_list.hint(args[-1], *args[:-1]) + + def alias(*args): + command_list.alias(*args) + + return bind, hint, alias + +class Wrapper(object): + def __init__(self, firstattr): + self.__firstattr__ = firstattr + + def __getattr__(self, attr): + if attr.startswith('_'): + raise AttributeError + 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__) + 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.enter_dir('~') is translated into lambda arg: arg.fm.enter_dir('~') +# this makes things like this possible: +# bind('gh', fm.enter_dir('~')) +# +# but NOT: (note the 2 dots) +# bind('H', fm.history.go(-1)) +# +# 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 = dict(keywords) + keywords[NARG_KEYWORD] = number + return args, keywords + |