about 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