diff options
-rw-r--r-- | ranger/__main__.py | 25 | ||||
-rw-r--r-- | ranger/api/commands.py | 182 | ||||
-rw-r--r-- | ranger/defaults/commands.py | 171 |
3 files changed, 207 insertions, 171 deletions
diff --git a/ranger/__main__.py b/ranger/__main__.py index 4da9bb73..4b652824 100644 --- a/ranger/__main__.py +++ b/ranger/__main__.py @@ -49,8 +49,9 @@ def parse_arguments(): return arg -def load_settings(fm): - if not ranger.arg.clean: +def load_settings(fm, clean): + import ranger.api.commands + if not clean: try: os.makedirs(ranger.arg.confdir) except OSError as err: @@ -63,15 +64,25 @@ def load_settings(fm): sys.path[0:0] = [ranger.arg.confdir] + # Load commands + comcont = ranger.api.commands.CommandContainer() + ranger.api.commands.alias = comcont.alias try: import commands + comcont.load_commands_from_module(commands) except ImportError: - from ranger.defaults import commands + pass + from ranger.defaults import commands + comcont.load_commands_from_module(commands) + commands = comcont + + # Load apps try: import apps except ImportError: from ranger.defaults import apps + # Load keys from ranger import shared, api from ranger.api import keys keymanager = shared.EnvironmentAware.env.keymanager @@ -83,7 +94,11 @@ def load_settings(fm): pass del sys.path[0] else: + comcont = ranger.api.commands.CommandContainer() + ranger.api.commands.alias = comcont.alias from ranger.defaults import commands, keys, apps + comcont.load_commands_from_module(commands) + commands = comcont fm.commands = commands fm.keys = keys fm.apps = apps.CustomApplications() @@ -134,7 +149,7 @@ def main(): elif os.path.isfile(target): thefile = File(target) fm = FM() - load_settings(fm) + load_settings(fm, ranger.arg.clean) fm.execute_file(thefile, mode=arg.mode, flags=arg.flags) sys.exit(0) else: @@ -146,7 +161,7 @@ def main(): # Initialize objects EnvironmentAware._assign(Environment(path)) fm = FM() - load_settings(fm) + load_settings(fm, ranger.arg.clean) FileManagerAware._assign(fm) fm.ui = UI() diff --git a/ranger/api/commands.py b/ranger/api/commands.py new file mode 100644 index 00000000..db6c1a3c --- /dev/null +++ b/ranger/api/commands.py @@ -0,0 +1,182 @@ +# Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +from collections import deque +from ranger.shared import FileManagerAware +from ranger.gui.widgets import console_mode as cmode +from ranger.ext.command_parser import LazyParser as parse + + +class CommandContainer(object): + def __init__(self): + self.aliases = {} + self.commands = {} + + def __getitem__(self, key): + return self.commands[key] + + def alias(self, new, old): + self.aliases[new] = old + + def load_commands_from_module(self, module): + for varname, var in vars(module).items(): + try: + if issubclass(var, Command) and var != Command: + self.commands[var.name or varname] = var + except TypeError: + pass + for new, old in self.aliases.items(): + try: + self.commands[new] = self.commands[old] + except: + pass + + def get_command(self, name, abbrev=True): + if abbrev: + lst = [cls for cmd, cls in self.commands.items() \ + if cmd.startswith(name) \ + and cls.allow_abbrev \ + or cmd == name] + if len(lst) == 0: + raise KeyError + if len(lst) == 1 or self.commands[name] in lst: + return lst[0] + raise ValueError("Ambiguous command") + else: + try: + return self.commands[name] + except KeyError: + return None + + def command_generator(self, start): + return (cmd + ' ' for cmd in self.commands if cmd.startswith(start)) + + +class Command(FileManagerAware): + """Abstract command class""" + name = None + allow_abbrev = True + def __init__(self, line, mode): + self.line = line + self.mode = mode + + def execute(self): + """Override this""" + + def tab(self): + """Override this""" + + def quick_open(self): + """Override this""" + + def _tab_only_directories(self): + from os.path import dirname, basename, expanduser, join, isdir + + line = parse(self.line) + cwd = self.fm.env.cwd.path + + try: + rel_dest = line.rest(1) + except IndexError: + rel_dest = '' + + # expand the tilde into the user directory + if rel_dest.startswith('~'): + rel_dest = expanduser(rel_dest) + + # define some shortcuts + abs_dest = join(cwd, rel_dest) + abs_dirname = dirname(abs_dest) + rel_basename = basename(rel_dest) + rel_dirname = dirname(rel_dest) + + try: + # are we at the end of 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.start(1) + 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.start(1) + 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) + cwd = self.fm.env.cwd.path + + try: + rel_dest = line.rest(1) + except IndexError: + rel_dest = '' + + # expand the tilde into the user directory + if rel_dest.startswith('~'): + rel_dest = expanduser(rel_dest) + + # define some shortcuts + abs_dest = join(cwd, rel_dest) + abs_dirname = dirname(abs_dest) + rel_basename = basename(rel_dest) + rel_dirname = dirname(rel_dest) + + try: + # are we at the end of 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.start(1) + 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.start(1) + join(rel_dirname, name) for name in names) diff --git a/ranger/defaults/commands.py b/ranger/defaults/commands.py index f04c4889..bf8830c7 100644 --- a/ranger/defaults/commands.py +++ b/ranger/defaults/commands.py @@ -13,130 +13,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import os -from collections import deque -from ranger.shared import FileManagerAware -from ranger.gui.widgets import console_mode as cmode -from ranger.ext.command_parser import LazyParser as parse - -class Command(FileManagerAware): - """Abstract command class""" - name = None - allow_abbrev = True - def __init__(self, line, mode): - self.line = line - self.mode = mode +from ranger.api.commands import * - def execute(self): - """Override this""" - - def tab(self): - """Override this""" - - def quick_open(self): - """Override this""" - - def _tab_only_directories(self): - from os.path import dirname, basename, expanduser, join, isdir - - line = parse(self.line) - cwd = self.fm.env.cwd.path - - try: - rel_dest = line.rest(1) - except IndexError: - rel_dest = '' - - # expand the tilde into the user directory - if rel_dest.startswith('~'): - rel_dest = expanduser(rel_dest) - - # define some shortcuts - abs_dest = join(cwd, rel_dest) - abs_dirname = dirname(abs_dest) - rel_basename = basename(rel_dest) - rel_dirname = dirname(rel_dest) - - try: - # are we at the end of 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.start(1) + 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.start(1) + 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) - cwd = self.fm.env.cwd.path - - try: - rel_dest = line.rest(1) - except IndexError: - rel_dest = '' - - # expand the tilde into the user directory - if rel_dest.startswith('~'): - rel_dest = expanduser(rel_dest) - - # define some shortcuts - abs_dest = join(cwd, rel_dest) - abs_dirname = dirname(abs_dest) - rel_basename = basename(rel_dest) - rel_dirname = dirname(rel_dest) - - try: - # are we at the end of 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.start(1) + 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.start(1) + join(rel_dirname, name) for name in names) - - -# -------------------------------- definitions +alias('e', 'edit') +alias('q', 'quit') +alias('q!', 'quit!') +alias('qall', 'quit!') class cd(Command): """ @@ -511,46 +393,3 @@ class grep(Command): action.extend(['-e', line.rest(1), '-r']) action.extend(f.path for f in self.fm.env.get_selection()) self.fm.execute_command(action, flags='p') - - -# -------------------------------- rest - -by_name = {} -for varname, var in vars().copy().items(): - try: - if issubclass(var, Command) and var != Command: - by_name[var.name or varname] = var - except TypeError: - pass -del varname -del var - -def alias(**kw): - """Create an alias for commands, eg: alias(quit=exit)""" - for key, value in kw.items(): - by_name[key] = value - -def get_command(name, abbrev=True): - if abbrev: - lst = [cls for cmd, cls in by_name.items() \ - if cmd.startswith(name) \ - and cls.allow_abbrev \ - or cmd == name] - if len(lst) == 0: - raise KeyError - if len(lst) == 1 or by_name[name] in lst: - return lst[0] - raise ValueError("Ambiguous command") - else: - try: - return by_name[name] - except KeyError: - return None - -def command_generator(start): - return (cmd + ' ' for cmd in by_name if cmd.startswith(start)) - -alias(e=edit, q=quit) # for unambiguity -alias(**{'q!':quit_now}) -alias(qall=quit_now) - |