diff options
-rw-r--r-- | ranger/actions.py | 15 | ||||
-rw-r--r-- | ranger/defaults/keys.py | 60 | ||||
-rw-r--r-- | ranger/ext/accumulator.py | 15 | ||||
-rw-r--r-- | ranger/gui/widgets/pager.py | 15 | ||||
-rw-r--r-- | ranger/keyapi.py | 94 |
5 files changed, 116 insertions, 83 deletions
diff --git a/ranger/actions.py b/ranger/actions.py index bc6da7b8..8209c9ab 100644 --- a/ranger/actions.py +++ b/ranger/actions.py @@ -137,10 +137,10 @@ class Actions(EnvironmentAware, SettingsAware): """Delete the bookmark with the name <key>""" self.bookmarks.delete(key) - def move_left(self, n=1): + def move_left(self, narg=1): """Enter the parent directory""" try: - directory = os.path.join(*(['..'] * n)) + directory = os.path.join(*(['..'] * narg)) except: return self.env.enter_dir(directory) @@ -237,20 +237,25 @@ class Actions(EnvironmentAware, SettingsAware): if hasattr(self.ui, 'open_console'): self.ui.open_console(mode, string) - def move_pointer(self, relative = 0, absolute = None): + def move_pointer(self, relative = 0, absolute = None, narg=None): """Move the pointer down by <relative> or to <absolute>""" - self.env.pwd.move(relative, absolute) + self.env.pwd.move(relative=relative, + absolute=absolute, narg=narg) def move_pointer_by_pages(self, relative): """Move the pointer down by <relative> pages""" self.env.pwd.move(relative=int(relative * self.env.termsize[0])) - def move_pointer_by_percentage(self, relative=0, absolute=None): + def move_pointer_by_percentage(self, relative=0, absolute=None, narg=None): """Move the pointer down by <relative>% or to <absolute>%""" try: factor = len(self.env.pwd) / 100.0 except: return + + if narg is not None: + absolute = narg + self.env.pwd.move( relative=int(relative * factor), absolute=int(absolute * factor)) diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py index 5f7691e2..02438cbc 100644 --- a/ranger/defaults/keys.py +++ b/ranger/defaults/keys.py @@ -26,6 +26,7 @@ def system_functions(command_list): bind(KEY_RESIZE, fm.resize()) bind(KEY_MOUSE, fm.handle_mouse()) + bind('Q', fm.exit()) bind(ctrl('L'), fm.redraw_window()) def initialize_commands(command_list): @@ -33,7 +34,15 @@ def initialize_commands(command_list): bind, hint = make_abbreviations(command_list) + bind('j', KEY_DOWN, fm.move_pointer(relative=1)) + bind('k', KEY_UP, fm.move_pointer(relative=-1)) bind('l', KEY_RIGHT, fm.move_right()) + bind('h', KEY_LEFT, KEY_BACKSPACE, DEL, fm.move_left(1)) + + bind('gg', fm.move_pointer(absolute=0)) + bind('G', fm.move_pointer(absolute=-1)) + bind('%', fm.move_pointer_by_percentage(absolute=50)) + bind(KEY_END, fm.move_pointer(absolute=-1)) bind(KEY_HOME, fm.move_pointer(absolute=0)) bind(KEY_ENTER, ctrl('j'), fm.move_right(mode=1)) @@ -132,7 +141,7 @@ def initialize_commands(command_list): # system functions system_functions(command_list) - bind('Q', 'ZZ', fm.exit()) + bind('ZZ', fm.exit()) bind(ctrl('R'), fm.reset()) bind(ctrl('C'), fm.interrupt()) bind(':', ';', fm.open_console(cmode.COMMAND)) @@ -143,29 +152,6 @@ def initialize_commands(command_list): bind('r', fm.open_console(cmode.OPEN_QUICK)) # definitions which require their own function: - def ggG(default): - # moves to an absolute point, or to a predefined default - # if no number is specified. - return lambda arg: \ - arg.fm.move_pointer(absolute=(arg.n or default)-1) - - bind('gg', ggG(1)) - bind('G', ggG(0)) - - bind('%', lambda arg: \ - arg.fm.move_pointer_by_percentage(absolute=arg.n or 50)) - - def jk(direction): - # moves up or down by the specified number or one, in - # the predefined direction - return lambda arg: \ - arg.fm.move_pointer(relative=(arg.n or 1) * direction) - - bind('j', KEY_DOWN, jk(1)) - bind('k', KEY_UP, jk(-1)) - - bind('h', KEY_LEFT, KEY_BACKSPACE, DEL, lambda arg: \ - arg.fm.move_left(arg.n or 1)) bind('w', lambda arg: arg.fm.ui.open_taskview()) @@ -214,15 +200,15 @@ def initialize_taskview_commands(command_list): system_functions(command_list) bind, hint = make_abbreviations(command_list) - bind('j', KEY_DOWN, nwrap.move(relative=1)) - bind('k', KEY_UP, nwrap.move(relative=-1)) - bind('gg', nwrap.move(absolute=0)) - bind('G', nwrap.move(absolute=-1)) + bind('j', KEY_DOWN, wdg.move(relative=1)) + bind('k', KEY_UP, wdg.move(relative=-1)) + bind('gg', wdg.move(absolute=0)) + bind('G', wdg.move(absolute=-1)) bind('K', wdg.task_move(0)) bind('J', wdg.task_move(-1)) bind('dd', wdg.task_remove()) - bind('w', ESC, ctrl('d'), ctrl('c'), + bind('w', 'q', ESC, ctrl('d'), ctrl('c'), lambda arg: arg.fm.ui.close_taskview()) command_list.rebuild_paths() @@ -238,14 +224,14 @@ def initialize_embedded_pager_commands(command_list): system_functions(command_list) bind, hint = make_abbreviations(command_list) - bind('j', KEY_DOWN, nwrap.move(relative=1)) - bind('k', KEY_UP, nwrap.move(relative=-1)) - bind('gg', KEY_HOME, nwrap.move(absolute=0)) - bind('G', KEY_END, nwrap.move(absolute=-1)) - bind('J', ctrl('d'), nwrap.move(relative=0.5, pages=True)) - bind('K', ctrl('u'), nwrap.move(relative=-0.5, pages=True)) - bind(KEY_NPAGE, ctrl('f'), nwrap.move(relative=1, pages=True)) - bind(KEY_PPAGE, ctrl('b'), nwrap.move(relative=-1, pages=True)) + bind('j', KEY_DOWN, wdg.move(relative=1)) + bind('k', KEY_UP, wdg.move(relative=-1)) + bind('gg', KEY_HOME, wdg.move(absolute=0)) + bind('G', KEY_END, wdg.move(absolute=-1)) + bind('J', ctrl('d'), wdg.move(relative=0.5, pages=True)) + bind('K', ctrl('u'), wdg.move(relative=-0.5, pages=True)) + bind(KEY_NPAGE, ctrl('f'), wdg.move(relative=1, pages=True)) + bind(KEY_PPAGE, ctrl('b'), wdg.move(relative=-1, pages=True)) bind('E', fm.edit_file()) bind('h', wdg.move_horizontal(relative=-4)) diff --git a/ranger/ext/accumulator.py b/ranger/ext/accumulator.py index 6513bee2..5aee54de 100644 --- a/ranger/ext/accumulator.py +++ b/ranger/ext/accumulator.py @@ -3,7 +3,7 @@ class Accumulator(object): self.pointer = 0 self.pointed_obj = None - def move(self, relative=0, absolute=None, pages=False): + def move(self, relative=0, absolute=None, pages=None, narg=None): i = self.pointer lst = self.get_list() if not lst: @@ -11,16 +11,19 @@ class Accumulator(object): length = len(lst) if isinstance(absolute, int): + if isinstance(narg, int): + absolute = narg if absolute < 0: # wrap i = absolute + length else: i = absolute - if pages: - i += relative * self.get_height() - else: - i += relative - i = int(i) + if relative != 0: + if isinstance(pages, int): + relative *= pages * self.get_height() + if isinstance(narg, int): + relative *= narg + i = int(i + relative) if i >= length: i = length - 1 diff --git a/ranger/gui/widgets/pager.py b/ranger/gui/widgets/pager.py index 0e13ecbd..5e9ef3c8 100644 --- a/ranger/gui/widgets/pager.py +++ b/ranger/gui/widgets/pager.py @@ -60,19 +60,22 @@ class Pager(Widget): pass self.need_redraw = False - def move(self, relative=0, absolute=None, pages=False): + def move(self, relative=0, absolute=None, pages=None, narg=None): i = self.scroll_begin if isinstance(absolute, int): + if isinstance(narg, int): + absolute = narg if absolute < 0: i = absolute + len(self.lines) else: i = absolute - if pages: - i += relative * self.hei - else: - i += relative - i = int(i) + if relative != 0: + if isinstance(pages, int): + relative *= pages * self.hei + if isinstance(narg, int): + relative *= narg + i = int(i + relative) length = len(self.lines) - self.hei if i >= length: 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 |