summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2010-10-02 05:51:17 +0200
committerhut <hut@lavabit.com>2010-10-02 05:51:17 +0200
commita457053815d72ef5d7ccfedbfda02101665bdec6 (patch)
tree5ea00e015b6488f0874c626e61bc64c62e514b9c
parentba16a2e43a71f3ee1a66ffaf1613bb1cce1665fc (diff)
downloadranger-a457053815d72ef5d7ccfedbfda02101665bdec6.tar.gz
a little restructuration
-rw-r--r--ranger/__init__.py49
-rw-r--r--ranger/api/apps.py2
-rw-r--r--ranger/api/commands.py2
-rw-r--r--ranger/container/settingobject.py (renamed from ranger/shared/settings.py)40
-rw-r--r--ranger/core/actions.py3
-rw-r--r--ranger/core/environment.py2
-rw-r--r--ranger/core/fm.py21
-rw-r--r--ranger/core/helper.py (renamed from ranger/__main__.py)155
-rw-r--r--ranger/core/loader.py2
-rw-r--r--ranger/core/main.py98
-rw-r--r--ranger/core/shared.py73
-rw-r--r--ranger/fsobject/directory.py2
-rw-r--r--ranger/fsobject/fsobject.py8
-rw-r--r--ranger/gui/colorscheme.py12
-rw-r--r--ranger/gui/curses_shortcuts.py2
-rw-r--r--ranger/gui/displayable.py2
-rw-r--r--ranger/gui/widgets/console.py3
-rw-r--r--ranger/help/console.py1
-rw-r--r--ranger/help/invocation.py1
-rw-r--r--ranger/shared/__init__.py35
-rw-r--r--ranger/shared/mimetype.py26
-rwxr-xr-xsetup.py4
-rw-r--r--test/tc_directory.py8
-rw-r--r--test/tc_loader.py2
24 files changed, 276 insertions, 277 deletions
diff --git a/ranger/__init__.py b/ranger/__init__.py
index 6e96b779..0245988e 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -13,13 +13,21 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-"""Ranger - file browser for the unix terminal"""
+"""
+Console-based visual file manager.
+
+Ranger is a file manager with an ncurses frontend written in Python.
+It is designed to give you a broader overview of the file system by
+displaying previews and backviews, dividing the screen into columns.
+
+The keybindings are similar to those of other console programs like
+vim, mutt or ncmpcpp so the usage will be intuitive and efficient.
+"""
 
 from os import path, environ
-from os.path import join as _join
 from ranger.ext.openstruct import OpenStruct
 from sys import argv
-from .__main__ import main
+from ranger.core.main import main
 
 # Information
 __license__ = 'GPL3'
@@ -40,40 +48,9 @@ DEBUG = ('-d' in argv or '--debug' in argv) and ('--' not in argv or
 	('--debug' in argv and argv.index('--debug') < argv.index('--'))))
 
 # Get some valid arguments before actually parsing them in main()
-arg = OpenStruct(debug=DEBUG, clean=False, confdir=DEFAULT_CONFDIR,
-		mode=0, flags='', targets=[])
-
-# Debugging features.  These will be activated when run with --debug.
-# Example usage in the code:
-# import ranger; ranger.log("hello world")
-def log(*objects, **keywords):
-	"""
-	Writes objects to a logfile (for the purpose of debugging only.)
-	Has the same arguments as print() in python3.
-	"""
-	if LOGFILE is None or not arg.debug or arg.clean: return
-	start = 'start' in keywords and keywords['start'] or 'ranger:'
-	sep   =   'sep' in keywords and keywords['sep']   or ' '
-	_file =  'file' in keywords and keywords['file']  or open(LOGFILE, 'a')
-	end   =   'end' in keywords and keywords['end']   or '\n'
-	_file.write(sep.join(map(str, (start, ) + objects)) + end)
-
-def log_traceback():
-	if LOGFILE is None or not arg.debug or arg.clean: return
-	import traceback
-	traceback.print_stack(file=open(LOGFILE, 'a'))
-
-# Handy functions
-def relpath_conf(*paths):
-	"""returns the path relative to rangers configuration directory"""
-	if arg.clean:
-		assert 0, "Should not access relpath_conf in clean mode!"
-	else:
-		return _join(arg.confdir, *paths)
+#arg = OpenStruct(debug=DEBUG, clean=False, confdir=DEFAULT_CONFDIR,
+#		mode=0, flags='', targets=[])
 
-def relpath(*paths):
-	"""returns the path relative to rangers library directory"""
-	return _join(RANGERDIR, *paths)
 
 # Clean up
 del environ, OpenStruct, argv
diff --git a/ranger/api/apps.py b/ranger/api/apps.py
index 91aae357..45432705 100644
--- a/ranger/api/apps.py
+++ b/ranger/api/apps.py
@@ -17,7 +17,7 @@ import os, sys, re
 from ranger.api import *
 from ranger.ext.iter_tools import flatten
 from ranger.ext.get_executables import get_executables
-from ranger.shared import FileManagerAware
+from ranger.core.shared import FileManagerAware
 
 
 class Applications(FileManagerAware):
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index f4e2ca76..08751b70 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -16,7 +16,7 @@
 import os
 from collections import deque
 from ranger.api import *
-from ranger.shared import FileManagerAware
+from ranger.core.shared import FileManagerAware
 from ranger.ext.command_parser import LazyParser as parse
 
 
diff --git a/ranger/shared/settings.py b/ranger/container/settingobject.py
index 7604af12..008b846d 100644
--- a/ranger/shared/settings.py
+++ b/ranger/container/settingobject.py
@@ -13,11 +13,9 @@
 # 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 sys
 from inspect import isfunction
-import ranger
 from ranger.ext.signal_dispatcher import SignalDispatcher
-from ranger.ext.openstruct import OpenStruct
+from ranger.core.shared import FileManagerAware
 
 ALLOWED_SETTINGS = {
 	'autosave_bookmarks': bool,
@@ -53,7 +51,7 @@ ALLOWED_SETTINGS = {
 }
 
 
-class SettingObject(SignalDispatcher):
+class SettingObject(SignalDispatcher, FileManagerAware):
 	def __init__(self):
 		SignalDispatcher.__init__(self)
 		self.__dict__['_settings'] = dict()
@@ -71,7 +69,7 @@ class SettingObject(SignalDispatcher):
 				getattr(self, name)
 			assert self._check_type(name, value)
 			kws = dict(setting=name, value=value,
-					previous=self._settings[name])
+					previous=self._settings[name], fm=self.fm)
 			self.signal_emit('setopt', **kws)
 			self.signal_emit('setopt.'+name, **kws)
 
@@ -128,35 +126,3 @@ class SettingObject(SignalDispatcher):
 
 	def _raw_set_with_signal(self, signal):
 		self._settings[signal.setting] = signal.value
-
-
-# -- globalize the settings --
-class SettingsAware(object):
-	settings = OpenStruct()
-
-	@staticmethod
-	def _setup():
-		settings = SettingObject()
-
-		from ranger.gui.colorscheme import _colorscheme_name_to_class
-		settings.signal_bind('setopt.colorscheme',
-				_colorscheme_name_to_class, priority=1)
-
-		if not ranger.arg.clean:
-			# overwrite single default options with custom options
-			sys.path[0:0] = [ranger.arg.confdir]
-			try:
-				import options as my_options
-			except ImportError:
-				pass
-			else:
-				settings._setting_sources.append(my_options)
-			del sys.path[0]
-
-		from ranger.defaults import options as default_options
-		settings._setting_sources.append(default_options)
-		assert all(hasattr(default_options, setting) \
-				for setting in ALLOWED_SETTINGS), \
-				"Ensure that all options are defined in the defaults!"
-
-		SettingsAware.settings = settings
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index a19927a4..59902bab 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -26,7 +26,8 @@ from ranger.ext.direction import Direction
 from ranger.ext.relative_symlink import relative_symlink
 from ranger.ext.shell_escape import shell_quote
 from ranger import fsobject
-from ranger.shared import FileManagerAware, EnvironmentAware, SettingsAware
+from ranger.core.shared import FileManagerAware, EnvironmentAware, \
+		SettingsAware
 from ranger.fsobject import File
 from ranger.ext import shutil_generatorized as shutil_g
 from ranger.core.loader import LoadableObject
diff --git a/ranger/core/environment.py b/ranger/core/environment.py
index 8d4c60df..655054d7 100644
--- a/ranger/core/environment.py
+++ b/ranger/core/environment.py
@@ -22,7 +22,7 @@ from os.path import abspath, normpath, join, expanduser, isdir
 from ranger.fsobject import Directory
 from ranger.container import KeyBuffer, KeyManager, History
 from ranger.ext.signal_dispatcher import SignalDispatcher
-from ranger.shared import SettingsAware
+from ranger.core.shared import SettingsAware
 
 ALLOWED_CONTEXTS = ('browser', 'pager', 'embedded_pager', 'taskview',
 		'console')
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 05b3e52b..7f655aa6 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -19,6 +19,7 @@ The File Manager, putting the pieces together
 
 from time import time
 from collections import deque
+import mimetypes
 import os
 import sys
 
@@ -28,7 +29,6 @@ from ranger.container.tags import Tags
 from ranger.gui.defaultui import DefaultUI
 from ranger.container import Bookmarks
 from ranger.core.runner import Runner
-from ranger import relpath_conf
 from ranger.ext.get_executables import get_executables
 from ranger.fsobject import Directory
 from ranger.ext.signal_dispatcher import SignalDispatcher
@@ -69,7 +69,7 @@ class FM(Actions, SignalDispatcher):
 			if ranger.arg.clean:
 				bookmarkfile = None
 			else:
-				bookmarkfile = relpath_conf('bookmarks')
+				bookmarkfile = self.confpath('bookmarks')
 			self.bookmarks = Bookmarks(
 					bookmarkfile=bookmarkfile,
 					bookmarktype=Directory,
@@ -80,7 +80,7 @@ class FM(Actions, SignalDispatcher):
 			self.bookmarks = bookmarks
 
 		if not ranger.arg.clean and self.tags is None:
-			self.tags = Tags(relpath_conf('tagged'))
+			self.tags = Tags(self.confpath('tagged'))
 
 		if self.ui is None:
 			self.ui = DefaultUI()
@@ -93,6 +93,10 @@ class FM(Actions, SignalDispatcher):
 
 		self.env.signal_bind('cd', self._update_current_tab)
 
+		mimetypes.knownfiles.append(os.path.expanduser('~/.mime.types'))
+		mimetypes.knownfiles.append(self.relpath('data/mime.types'))
+		self.mimetypes = mimetypes.MimeTypes()
+
 	def block_input(self, sec=0):
 		self.input_blocked = sec != 0
 		self.input_blocked_until = time() + sec
@@ -102,6 +106,17 @@ class FM(Actions, SignalDispatcher):
 			self.input_blocked = False
 		return self.input_blocked
 
+	def confpath(self, *paths):
+		"""returns the path relative to rangers configuration directory"""
+		if ranger.arg.clean:
+			assert 0, "Should not access relpath_conf in clean mode!"
+		else:
+			return os.path.join(ranger.arg.confdir, *paths)
+
+	def relpath(self, *paths):
+		"""returns the path relative to rangers library directory"""
+		return os.path.join(ranger.RANGERDIR, *paths)
+
 	def loop(self):
 		"""
 		The main loop consists of:
diff --git a/ranger/__main__.py b/ranger/core/helper.py
index 2efec4df..c7ac3702 100644
--- a/ranger/__main__.py
+++ b/ranger/core/helper.py
@@ -13,19 +13,18 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Most import statements in this module are inside the functions.
-# This enables more convenient exception handling in ranger.py
-# (ImportError will imply that this module can't be found)
+"""Helper functions"""
 
-import locale
 import os.path
 import sys
+from ranger import *
 
 def parse_arguments():
 	"""Parse the program arguments"""
 	from optparse import OptionParser, SUPPRESS_HELP
 	from ranger import __version__, USAGE, DEFAULT_CONFDIR
 	from ranger.ext.openstruct import OpenStruct
+	from os.path import expanduser
 
 	minor_version = __version__[2:]  # assumes major version number is <10
 	if '.' in minor_version:
@@ -58,7 +57,7 @@ def parse_arguments():
 
 	options, positional = parser.parse_args()
 	arg = OpenStruct(options.__dict__, targets=positional)
-	arg.confdir = os.path.expanduser(arg.confdir)
+	arg.confdir = expanduser(arg.confdir)
 	if arg.fail_if_run:
 		arg.fail_unless_cd = arg.fail_if_run
 		del arg['fail_if_run']
@@ -66,26 +65,8 @@ def parse_arguments():
 	return arg
 
 
-def allow_access_to_confdir(confdir, allow):
-	if allow:
-		try:
-			os.makedirs(confdir)
-		except OSError as err:
-			if err.errno != 17:  # 17 means it already exists
-				print("This configuration directory could not be created:")
-				print(confdir)
-				print("To run ranger without the need for configuration")
-				print("files, use the --clean option.")
-				raise SystemExit()
-		if not confdir in sys.path:
-			sys.path[0:0] = [confdir]
-	else:
-		if sys.path[0] == confdir:
-			del sys.path[0]
-
-
 def load_settings(fm, clean):
-	import ranger.shared
+	import ranger.core.shared
 	import ranger.api.commands
 	import ranger.api.keys
 	if not clean:
@@ -110,24 +91,19 @@ def load_settings(fm, clean):
 			from ranger.defaults import apps
 
 		# Load keys
-		keymanager = ranger.shared.EnvironmentAware.env.keymanager
+		keymanager = ranger.core.shared.EnvironmentAware.env.keymanager
 		ranger.api.keys.keymanager = keymanager
 		from ranger.defaults import keys
 		try:
 			import keys
 		except ImportError:
 			pass
-		# COMPAT WARNING
-		if hasattr(keys, 'initialize_commands'):
-			print("Warning: the syntax for ~/.config/ranger/keys.py has changed.")
-			print("Your custom keys are not loaded."\
-					"  Please update your configuration.")
 		allow_access_to_confdir(ranger.arg.confdir, False)
 	else:
 		comcont = ranger.api.commands.CommandContainer()
 		ranger.api.commands.alias = comcont.alias
 		from ranger.api import keys
-		keymanager = ranger.shared.EnvironmentAware.env.keymanager
+		keymanager = ranger.core.shared.EnvironmentAware.env.keymanager
 		ranger.api.keys.keymanager = keymanager
 		from ranger.defaults import commands, keys, apps
 		comcont.load_commands_from_module(commands)
@@ -151,86 +127,41 @@ def load_apps(fm, clean):
 	fm.apps = apps.CustomApplications()
 
 
-def main():
-	"""initialize objects and run the filemanager"""
-	try:
-		import curses
-	except ImportError as errormessage:
-		print(errormessage)
-		print('ranger requires the python curses module. Aborting.')
-		sys.exit(1)
-
-	try: locale.setlocale(locale.LC_ALL, '')
-	except: print("Warning: Unable to set locale.  Expect encoding problems.")
-
-	if not 'SHELL' in os.environ:
-		os.environ['SHELL'] = 'bash'
+def allow_access_to_confdir(confdir, allow):
+	if allow:
+		try:
+			os.makedirs(confdir)
+		except OSError as err:
+			if err.errno != 17:  # 17 means it already exists
+				print("This configuration directory could not be created:")
+				print(confdir)
+				print("To run ranger without the need for configuration")
+				print("files, use the --clean option.")
+				raise SystemExit()
+		if not confdir in sys.path:
+			sys.path[0:0] = [confdir]
+	else:
+		if sys.path[0] == confdir:
+			del sys.path[0]
 
-	arg = parse_arguments()
 
-	import ranger
-	from ranger.ext import curses_interrupt_handler
-	from ranger.core.runner import Runner
-	from ranger.core.fm import FM
-	from ranger.core.environment import Environment
-	from ranger.gui.defaultui import DefaultUI as UI
-	from ranger.fsobject import File
-	from ranger.shared import (EnvironmentAware, FileManagerAware,
-			SettingsAware)
-
-	if not arg.debug:
-		curses_interrupt_handler.install_interrupt_handler()
-	ranger.arg = arg
-
-	SettingsAware._setup()
-
-	targets = arg.targets or ['.']
-	target = targets[0]
-	if arg.targets:
-		if target.startswith('file://'):
-			target = target[7:]
-		if not os.access(target, os.F_OK):
-			print("File or directory doesn't exist: %s" % target)
-			sys.exit(1)
-		elif os.path.isfile(target):
-			def print_function(string):
-				print(string)
-			runner = Runner(logfunc=print_function)
-			load_apps(runner, ranger.arg.clean)
-			runner(files=[File(target)], mode=arg.mode, flags=arg.flags)
-			sys.exit(1 if arg.fail_unless_cd else 0)
-
-	crash_traceback = None
-	try:
-		# Initialize objects
-		EnvironmentAware._assign(Environment(target))
-		fm = FM()
-		fm.tabs = dict((n+1, os.path.abspath(path)) for n, path \
-				in enumerate(targets[:9]))
-		load_settings(fm, ranger.arg.clean)
-		if fm.env.username == 'root':
-			fm.settings.preview_files = False
-		FileManagerAware._assign(fm)
-		fm.ui = UI()
-
-		# Run the file manager
-		fm.initialize()
-		fm.ui.initialize()
-		fm.loop()
-	except Exception:
-		import traceback
-		crash_traceback = traceback.format_exc()
-	except SystemExit as error:
-		return error.args[0]
-	finally:
-		try:
-			fm.ui.destroy()
-		except (AttributeError, NameError):
-			pass
-		if crash_traceback:
-			print(crash_traceback)
-			print("Ranger crashed.  " \
-					"Please report this (including the traceback) at:")
-			print("http://savannah.nongnu.org/bugs/?group=ranger&func=additem")
-			return 1
-		return 0
+# Debugging functions.  These will be activated when run with --debug.
+# Example usage in the code:
+# import ranger; ranger.log("hello world")
+def log(*objects, **keywords):
+	"""
+	Writes objects to a logfile (for the purpose of debugging only.)
+	Has the same arguments as print() in python3.
+	"""
+	if LOGFILE is None or not arg.debug or arg.clean: return
+	start = 'start' in keywords and keywords['start'] or 'ranger:'
+	sep   =   'sep' in keywords and keywords['sep']   or ' '
+	_file =  'file' in keywords and keywords['file']  or open(LOGFILE, 'a')
+	end   =   'end' in keywords and keywords['end']   or '\n'
+	_file.write(sep.join(map(str, (start, ) + objects)) + end)
+
+
+def log_traceback():
+	if LOGFILE is None or not arg.debug or arg.clean: return
+	import traceback
+	traceback.print_stack(file=open(LOGFILE, 'a'))
diff --git a/ranger/core/loader.py b/ranger/core/loader.py
index 4f4424e4..ae6436a1 100644
--- a/ranger/core/loader.py
+++ b/ranger/core/loader.py
@@ -15,7 +15,7 @@
 
 from collections import deque
 from time import time
-from ranger.shared import FileManagerAware
+from ranger.core.shared import FileManagerAware
 import math
 
 def status_generator():
diff --git a/ranger/core/main.py b/ranger/core/main.py
new file mode 100644
index 00000000..42118516
--- /dev/null
+++ b/ranger/core/main.py
@@ -0,0 +1,98 @@
+# 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/>.
+
+"""
+The main function responsible to initialize the FM object and stuff.
+"""
+
+from ranger.core.helper import *
+
+def main():
+	"""initialize objects and run the filemanager"""
+	import locale
+	import os.path
+	import ranger
+	from ranger.ext import curses_interrupt_handler
+	from ranger.core.runner import Runner
+	from ranger.core.fm import FM
+	from ranger.core.environment import Environment
+	from ranger.gui.defaultui import DefaultUI as UI
+	from ranger.fsobject import File
+	from ranger.core.shared import (EnvironmentAware, FileManagerAware,
+			SettingsAware)
+
+	try:
+		locale.setlocale(locale.LC_ALL, '')
+	except:
+		print("Warning: Unable to set locale.  Expect encoding problems.")
+
+	if not 'SHELL' in os.environ:
+		os.environ['SHELL'] = 'bash'
+
+	ranger.arg = arg = parse_arguments()
+	SettingsAware._setup(clean=arg.clean)
+
+	targets = arg.targets or ['.']
+	target = targets[0]
+	if arg.targets:
+		if target.startswith('file://'):
+			target = target[7:]
+		if not os.access(target, os.F_OK):
+			print("File or directory doesn't exist: %s" % target)
+			sys.exit(1)
+		elif os.path.isfile(target):
+			def print_function(string):
+				print(string)
+			runner = Runner(logfunc=print_function)
+			load_apps(runner, arg.clean)
+			runner(files=[File(target)], mode=arg.mode, flags=arg.flags)
+			sys.exit(1 if arg.fail_unless_cd else 0)
+
+	crash_traceback = None
+	try:
+		# Initialize objects
+		EnvironmentAware.env = Environment(target)
+		fm = FM()
+		fm.tabs = dict((n+1, os.path.abspath(path)) for n, path \
+				in enumerate(targets[:9]))
+		load_settings(fm, arg.clean)
+		if fm.env.username == 'root':
+			fm.settings.preview_files = False
+		FileManagerAware.fm = fm
+		fm.ui = UI()
+		if not arg.debug:
+			curses_interrupt_handler.install_interrupt_handler()
+
+		# Run the file manager
+		fm.initialize()
+		fm.ui.initialize()
+		fm.loop()
+	except Exception:
+		import traceback
+		crash_traceback = traceback.format_exc()
+	except SystemExit as error:
+		return error.args[0]
+	finally:
+		try:
+			fm.ui.destroy()
+		except (AttributeError, NameError):
+			pass
+		if crash_traceback:
+			print(crash_traceback)
+			print("Ranger crashed.  " \
+					"Please report this (including the traceback) at:")
+			print("http://savannah.nongnu.org/bugs/?group=ranger&func=additem")
+			return 1
+		return 0
diff --git a/ranger/core/shared.py b/ranger/core/shared.py
new file mode 100644
index 00000000..b91445a3
--- /dev/null
+++ b/ranger/core/shared.py
@@ -0,0 +1,73 @@
+# 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/>.
+
+"""Shared objects contain singleton variables which can be
+inherited, essentially acting like global variables."""
+
+from ranger.ext.lazy_property import lazy_property
+
+class Awareness(object):
+	pass
+
+class EnvironmentAware(Awareness):
+	# This creates an instance implicitly, mainly for unit tests
+	@lazy_property
+	def env(self):
+		from ranger.core.environment import Environment
+		return Environment(".")
+
+class FileManagerAware(Awareness):
+	# This creates an instance implicitly, mainly for unit tests
+	@lazy_property
+	def fm(self):
+		from ranger.core.fm import FM
+		return FM()
+
+class SettingsAware(Awareness):
+	# This creates an instance implicitly, mainly for unit tests
+	@lazy_property
+	def settings(self):
+		from ranger.ext.openstruct import OpenStruct
+		return OpenStruct()
+
+	@staticmethod
+	def _setup(clean=True):
+		from ranger.container.settingobject import SettingObject, \
+				ALLOWED_SETTINGS
+		import ranger
+		import sys
+		settings = SettingObject()
+
+		from ranger.gui.colorscheme import _colorscheme_name_to_class
+		settings.signal_bind('setopt.colorscheme',
+				_colorscheme_name_to_class, priority=1)
+
+		if not clean:
+			# add the custom options to the list of setting sources
+			sys.path[0:0] = [ranger.arg.confdir]
+			try:
+				import options as my_options
+			except ImportError:
+				pass
+			else:
+				settings._setting_sources.append(my_options)
+			del sys.path[0]
+
+		from ranger.defaults import options as default_options
+		settings._setting_sources.append(default_options)
+		assert all(hasattr(default_options, setting) \
+				for setting in ALLOWED_SETTINGS), \
+				"Ensure that all options are defined in the defaults!"
+		SettingsAware.settings = settings
diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py
index ac628ff0..e52b84d7 100644
--- a/ranger/fsobject/directory.py
+++ b/ranger/fsobject/directory.py
@@ -23,7 +23,7 @@ from time import time
 
 from ranger.ext.mount_path import mount_path
 from ranger.fsobject import BAD_INFO, File, FileSystemObject
-from ranger.shared import SettingsAware
+from ranger.core.shared import SettingsAware
 from ranger.ext.accumulator import Accumulator
 import ranger.fsobject
 
diff --git a/ranger/fsobject/fsobject.py b/ranger/fsobject/fsobject.py
index a52dac91..fd886275 100644
--- a/ranger/fsobject/fsobject.py
+++ b/ranger/fsobject/fsobject.py
@@ -22,7 +22,7 @@ from os import access, listdir, lstat, readlink, stat
 from time import time
 from os.path import abspath, basename, dirname, realpath, splitext, extsep
 from . import BAD_INFO
-from ranger.shared import MimeTypeAware, FileManagerAware
+from ranger.core.shared import FileManagerAware
 from ranger.ext.shell_escape import shell_escape
 from ranger.ext.spawn import spawn
 from ranger.ext.lazy_property import lazy_property
@@ -30,7 +30,7 @@ from ranger.ext.human_readable import human_readable
 
 _extract_number_re = re.compile(r'([^0-9]?)(\d*)')
 
-class FileSystemObject(MimeTypeAware, FileManagerAware):
+class FileSystemObject(FileManagerAware):
 	(basename,
 	basename_lower,
 	dirname,
@@ -70,8 +70,6 @@ class FileSystemObject(MimeTypeAware, FileManagerAware):
 
 
 	def __init__(self, path, preload=None, path_is_abs=False):
-		MimeTypeAware.__init__(self)
-
 		if not path_is_abs:
 			path = abspath(path)
 		self.path = path
@@ -123,7 +121,7 @@ class FileSystemObject(MimeTypeAware, FileManagerAware):
 		basename = self.basename
 		if self.extension == 'part':
 			basename = basename[0:-5]
-		self._mimetype = self.mimetypes.guess_type(basename, False)[0]
+		self._mimetype = self.fm.mimetypes.guess_type(basename, False)[0]
 		if self._mimetype is None:
 			self._mimetype = ''
 
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index 5b317acb..ae6aac0b 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -47,8 +47,8 @@ from curses import color_pair
 import ranger
 from ranger.gui.color import get_color
 from ranger.gui.context import Context
-from ranger.__main__ import allow_access_to_confdir
-from ranger.shared.settings import SettingsAware
+from ranger.core.helper import allow_access_to_confdir
+from ranger.core.shared import SettingsAware
 
 # ColorScheme is not SettingsAware but it will gain access
 # to the settings during the initialization.  We can't import
@@ -141,15 +141,15 @@ def _colorscheme_name_to_class(signal):
 
 	# create ~/.config/ranger/colorschemes/__init__.py if it doesn't exist
 	if usecustom:
-		if os.path.exists(ranger.relpath_conf('colorschemes')):
-			initpy = ranger.relpath_conf('colorschemes', '__init__.py')
+		if os.path.exists(signal.fm.confpath('colorschemes')):
+			initpy = signal.fm.confpath('colorschemes', '__init__.py')
 			if not os.path.exists(initpy):
 				open(initpy, 'a').close()
 
 	if usecustom and \
-			exists(ranger.relpath_conf('colorschemes', scheme_name)):
+			exists(signal.fm.confpath('colorschemes', scheme_name)):
 		scheme_supermodule = 'colorschemes'
-	elif exists(ranger.relpath('colorschemes', scheme_name)):
+	elif exists(signal.fm.relpath('colorschemes', scheme_name)):
 		scheme_supermodule = 'ranger.colorschemes'
 		usecustom = False
 	else:
diff --git a/ranger/gui/curses_shortcuts.py b/ranger/gui/curses_shortcuts.py
index 3df45700..4ed348fd 100644
--- a/ranger/gui/curses_shortcuts.py
+++ b/ranger/gui/curses_shortcuts.py
@@ -16,7 +16,7 @@
 import _curses
 
 from ranger.ext.iter_tools import flatten
-from ranger.shared import SettingsAware
+from ranger.core.shared import SettingsAware
 
 def ascii_only(string):
 	# Some python versions have problems with invalid unicode strings.
diff --git a/ranger/gui/displayable.py b/ranger/gui/displayable.py
index 9ca72b13..70455b35 100644
--- a/ranger/gui/displayable.py
+++ b/ranger/gui/displayable.py
@@ -15,7 +15,7 @@
 
 import _curses
 
-from ranger.shared import FileManagerAware, EnvironmentAware
+from ranger.core.shared import FileManagerAware, EnvironmentAware
 from ranger.gui.curses_shortcuts import CursesShortcuts
 
 class Displayable(EnvironmentAware, FileManagerAware, CursesShortcuts):
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 57264292..9f7d2405 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -23,7 +23,6 @@ import re
 from collections import deque
 
 from . import Widget
-from ranger import log, relpath_conf
 from ranger.container.keymap import CommandArgs
 from ranger.ext.direction import Direction
 from ranger.ext.utfwidth import uwid, uchars
@@ -50,7 +49,7 @@ class Console(Widget):
 		self.history = History(self.settings.max_console_history_size)
 		# load history from files
 		if not ranger.arg.clean:
-			self.historypath = relpath_conf('history')
+			self.historypath = self.fm.confpath('history')
 			try:
 				f = open(self.historypath, 'r')
 			except:
diff --git a/ranger/help/console.py b/ranger/help/console.py
index f03491db..716740b9 100644
--- a/ranger/help/console.py
+++ b/ranger/help/console.py
@@ -12,6 +12,7 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 """
 3. The Console
 
diff --git a/ranger/help/invocation.py b/ranger/help/invocation.py
index 26cffd4a..27ab5a67 100644
--- a/ranger/help/invocation.py
+++ b/ranger/help/invocation.py
@@ -12,6 +12,7 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 """
 5. Ranger invocation
 
diff --git a/ranger/shared/__init__.py b/ranger/shared/__init__.py
deleted file mode 100644
index 048b9e7a..00000000
--- a/ranger/shared/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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/>.
-
-"""Shared objects contain singleton variables which can be
-inherited, essentially acting like global variables."""
-class Awareness(object):
-	pass
-
-class EnvironmentAware(Awareness):
-	env = None
-	@staticmethod
-	def _assign(instance):
-		EnvironmentAware.env = instance
-
-
-class FileManagerAware(Awareness):
-	fm = None
-	@staticmethod
-	def _assign(instance):
-		FileManagerAware.fm = instance
-
-from .mimetype import MimeTypeAware
-from .settings import SettingsAware
diff --git a/ranger/shared/mimetype.py b/ranger/shared/mimetype.py
deleted file mode 100644
index da6fcd10..00000000
--- a/ranger/shared/mimetype.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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/>.
-
-from ranger import relpath
-import mimetypes
-import os.path
-
-class MimeTypeAware(object):
-	mimetypes = {}
-	def __init__(self):
-		MimeTypeAware.__init__ = lambda _: None  # refuse multiple inits
-		mimetypes.knownfiles.append(os.path.expanduser('~/.mime.types'))
-		MimeTypeAware.mimetypes = mimetypes.MimeTypes()
-		MimeTypeAware.mimetypes.read(relpath('data/mime.types'))
diff --git a/setup.py b/setup.py
index 587b52c0..e63e28d2 100755
--- a/setup.py
+++ b/setup.py
@@ -21,6 +21,7 @@ if __name__ == '__main__':
 	distutils.core.setup(
 		name='ranger',
 		description='Vim-like file manager',
+		long_description=ranger.__doc__,
 		version=ranger.__version__,
 		author=ranger.__author__,
 		author_email=ranger.__email__,
@@ -39,5 +40,4 @@ if __name__ == '__main__':
 		          'ranger.fsobject',
 		          'ranger.gui',
 		          'ranger.gui.widgets',
-		          'ranger.help',
-		          'ranger.shared'))
+		          'ranger.help'))
diff --git a/test/tc_directory.py b/test/tc_directory.py
index 754253b3..a43ac89d 100644
--- a/test/tc_directory.py
+++ b/test/tc_directory.py
@@ -24,7 +24,7 @@ from os.path import realpath, join, dirname
 from ranger import fsobject
 from ranger.fsobject.file import File
 from ranger.fsobject.directory import Directory
-from ranger.shared.settings import SettingsAware
+from ranger.core.shared import SettingsAware
 
 SettingsAware._setup()
 
@@ -49,7 +49,7 @@ class Test1(unittest.TestCase):
 		import os
 		# Check whether the directory has the correct list of filenames.
 		dir = Directory(TESTDIR)
-		dir.load_content()
+		dir.load_content(schedule=False)
 
 		self.assertTrue(dir.exists)
 		self.assertEqual(type(dir.filenames), list)
@@ -78,8 +78,8 @@ class Test1(unittest.TestCase):
 
 	def test_nonexistant_dir(self):
 		dir = Directory(NONEXISTANT_DIR)
-		dir.load_content()
-		
+		dir.load_content(schedule=False)
+
 		self.assertTrue(dir.content_loaded)
 		self.assertFalse(dir.exists)
 		self.assertFalse(dir.accessible)
diff --git a/test/tc_loader.py b/test/tc_loader.py
index 5a2e5a68..a679a629 100644
--- a/test/tc_loader.py
+++ b/test/tc_loader.py
@@ -24,7 +24,7 @@ import os
 from os.path import realpath, join, dirname
 
 from testlib import Fake
-from ranger.shared import FileManagerAware, SettingsAware
+from ranger.core.shared import FileManagerAware, SettingsAware
 from ranger.core.loader import Loader
 from ranger.fsobject import Directory, File
 from ranger.ext.openstruct import OpenStruct
ision' href='/danisanti/profani-tty/blame/tests/test_jid.c?id=527e739ac6962627ad6b5c76fa08357e33b6da0e'>^
a2726b6a ^
d239a127 ^
07308673 ^




ae9ef75b ^

94bcf188 ^
e263e00a ^
a2726b6a ^

e263e00a ^
a2726b6a ^
e263e00a ^
a2726b6a ^
e263e00a ^

ae9ef75b ^

e263e00a ^

a2726b6a ^

e263e00a ^
a2726b6a ^
e263e00a ^
a2726b6a ^
e263e00a ^

ae9ef75b ^

1c5efaeb ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239