summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/__main__.py25
-rw-r--r--ranger/api/commands.py182
-rw-r--r--ranger/defaults/commands.py171
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)
-