diff options
-rw-r--r-- | ranger/applications.py | 2 | ||||
-rw-r--r-- | ranger/commands.py | 75 | ||||
-rw-r--r-- | ranger/gui/widgets/console.py | 67 |
3 files changed, 122 insertions, 22 deletions
diff --git a/ranger/applications.py b/ranger/applications.py index d5c0f5fb..ed5f282e 100644 --- a/ranger/applications.py +++ b/ranger/applications.py @@ -22,7 +22,7 @@ class Applications(object): def all(self): """Returns a list with all application functions""" - return [x for x in self.__dict__ if x.startswith('app_')] + return [x[4:] for x in self.__class__.__dict__ if x.startswith('app_')] import os, sys null = open(os.devnull, 'a') diff --git a/ranger/commands.py b/ranger/commands.py index 2c0593a3..07fa1679 100644 --- a/ranger/commands.py +++ b/ranger/commands.py @@ -19,7 +19,7 @@ class Command(FileManagerAware): def quick_open(self): """Override this""" - def _tab_through_directories(self): + def _tab_only_directories(self): from os.path import dirname, basename, expanduser, join, isdir line = parse(self.line) @@ -30,33 +30,94 @@ class Command(FileManagerAware): except IndexError: rel_dest = '' + # expand the tilde into the user directory if rel_dest.startswith('~'): return line + expanduser(rel_dest) + '/' + # define some shortcuts abs_dest = join(pwd, rel_dest) abs_dirname = dirname(abs_dest) rel_basename = basename(rel_dest) rel_dirname = dirname(rel_dest) try: + # are we after a directory? if rel_dest.endswith('/') or rel_dest == '': _, dirnames, _ = os.walk(abs_dest).next() + + # are we in the middle of the filename? else: _, dirnames, _ = os.walk(abs_dirname).next() dirnames = [dn for dn in dirnames \ if dn.startswith(rel_basename)] except (OSError, StopIteration): + # os.walk found nothing pass else: dirnames.sort() + # no results, return None if len(dirnames) == 0: return + # one result. since it must be a directory, append a slash. if len(dirnames) == 1: return line + join(rel_dirname, dirnames[0]) + '/' + # more than one result. append no slash, so the user can + # manually type in the slash to advance into that directory return (line + join(rel_dirname, dirname) for dirname in dirnames) + + def _tab_directory_content(self): + from os.path import dirname, basename, expanduser, join, isdir + + line = parse(self.line) + pwd = self.fm.env.pwd.path + + try: + rel_dest = line.rest(1) + except IndexError: + rel_dest = '' + + # expand the tilde into the user directory + if rel_dest.startswith('~'): + return line + expanduser(rel_dest) + '/' + + # define some shortcuts + abs_dest = join(pwd, rel_dest) + abs_dirname = dirname(abs_dest) + rel_basename = basename(rel_dest) + rel_dirname = dirname(rel_dest) + + try: + # are we after a directory? + if rel_dest.endswith('/') or rel_dest == '': + _, dirnames, filenames = os.walk(abs_dest).next() + names = dirnames + filenames + + # are we in the middle of the filename? + else: + _, dirnames, filenames = os.walk(abs_dirname).next() + names = [name for name in (dirnames + filenames) \ + if name.startswith(rel_basename)] + except (OSError, StopIteration): + # os.walk found nothing + pass + else: + names.sort() + + # no results, return None + if len(names) == 0: + return + + # one result. since it must be a directory, append a slash. + if len(names) == 1: + return line + join(rel_dirname, names[0]) + '/' + + # more than one result. append no slash, so the user can + # manually type in the slash to advance into that directory + return (line + join(rel_dirname, name) for name in names) + # -------------------------------- definitions @@ -81,7 +142,7 @@ class cd(Command): self.fm.enter_dir(destination) def tab(self): - return self._tab_through_directories() + return self._tab_only_directories() def quick_open(self): from os.path import isdir, join, normpath @@ -120,6 +181,9 @@ class find(Command): self.fm.block_input(0.5) return True + def tab(self): + return self._tab_directory_content() + def _search(self): self.count = 0 line = parse(self.line) @@ -168,6 +232,9 @@ class rename(Command): def execute(self): line = parse(self.line) self.fm.rename(self.fm.env.cf, line.rest(1)) + + def tab(self): + return self._tab_directory_content() # -------------------------------- rest @@ -185,3 +252,7 @@ def alias(**kw): by_name[key] = value alias(q=quit) + +def command_generator(start): + return (cmd + ' ' for cmd in by_name if cmd.startswith(start)) + diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py index 75963829..1e0f0b06 100644 --- a/ranger/gui/widgets/console.py +++ b/ranger/gui/widgets/console.py @@ -191,18 +191,7 @@ class Console(Widget): pass -class CommandConsole(Console): - prompt = ':' - - def execute(self, cmd=None): - if cmd is None: - cmd = self._get_cmd() - - if cmd: - cmd.execute() - - Console.execute(self) - +class ConsoleWithTab(Console): def tab(self, n=1): if self.tab_deque is None: tab_result = self._get_tab() @@ -224,11 +213,38 @@ class CommandConsole(Console): self.line = self.tab_deque[0] self.pos = len(self.line) self.on_line_change() + + def _get_tab(self): + """ + Override this function in the subclass! + + It should return either a string, an iterable or None. + If a string is returned, tabbing will result in the line turning + into that string. + If another iterable is returned, each tabbing will cycle through + the elements of the iterable (which have to be strings). + If None is returned, nothing will happen. + """ + + return None + + +class CommandConsole(ConsoleWithTab): + prompt = ':' + + def execute(self, cmd=None): + if cmd is None: + cmd = self._get_cmd() + + if cmd: + cmd.execute() + + Console.execute(self) def _get_cmd(self): try: command_name = self.line.split()[0] - except: + except IndexError: return None try: @@ -239,11 +255,14 @@ class CommandConsole(Console): return command_class(self.line, self.mode) def _get_tab(self): - cmd = self._get_cmd() - if cmd: - return cmd.tab() - else: - return None + if ' ' in self.line: + cmd = self._get_cmd() + if cmd: + return cmd.tab() + else: + return None + + return commands.command_generator(self.line) class QuickCommandConsole(CommandConsole): @@ -338,7 +357,7 @@ class OpenConsole(Console): return "'" + str(string).replace("'","'\"'\"'") + "'" -class QuickOpenConsole(Console): +class QuickOpenConsole(ConsoleWithTab): """ The QuickOpenConsole allows you to open files with pre-defined programs and modes very quickly. By adding flags @@ -434,6 +453,16 @@ class QuickOpenConsole(Console): return app, flags, int(mode) + def _get_tab(self): + if ' ' not in self.line: + all_apps = self.fm.apps.all() + log(all_apps) + if all_apps: + return (app for app in all_apps if app.startswith(self.line)) + + return None + + def _is_app(self, arg): return self.fm.apps.has(arg) |