about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--TODO1
-rw-r--r--ranger/__init__.py22
-rw-r--r--ranger/applications.py40
-rw-r--r--ranger/colorschemes/__init__.py6
-rw-r--r--ranger/colorschemes/jungle.py4
-rw-r--r--ranger/container/__init__.py4
-rw-r--r--ranger/container/bookmarks.py (renamed from ranger/bookmark.py)0
-rw-r--r--ranger/container/commandlist.py (renamed from ranger/command.py)0
-rw-r--r--ranger/container/history.py (renamed from ranger/history.py)0
-rw-r--r--ranger/container/keybuffer.py9
-rwxr-xr-xranger/data/generate.py (renamed from data/generate.py)0
-rw-r--r--ranger/data/mime.dat (renamed from data/mime.dat)0
-rw-r--r--ranger/data/mime.types (renamed from data/mime.types)0
-rw-r--r--ranger/defaults/apps.py10
-rw-r--r--ranger/defaults/keys.py2
-rw-r--r--ranger/defaults/options.py1
-rw-r--r--ranger/directory.py9
-rw-r--r--ranger/environment.py26
-rw-r--r--ranger/ext/__init__.py3
-rw-r--r--ranger/ext/human_readable.py21
-rw-r--r--ranger/ext/openstruct.py16
-rw-r--r--ranger/ext/waitpid_no_intr.py12
-rw-r--r--ranger/fm.py31
-rw-r--r--ranger/fsobject.py21
-rw-r--r--ranger/gui/colorscheme.py5
-rw-r--r--ranger/gui/ui.py13
-rw-r--r--ranger/gui/wconsole.py5
-rw-r--r--ranger/gui/wdisplay.py1
-rw-r--r--ranger/gui/widget.py6
-rw-r--r--ranger/gui/wtitlebar.py11
-rw-r--r--ranger/helper.py111
-rw-r--r--ranger/main.py25
-rw-r--r--ranger/mimetype.py14
-rw-r--r--ranger/shared/__init__.py11
-rw-r--r--ranger/shared/mimetype.py13
-rw-r--r--ranger/shared/settings.py (renamed from ranger/conf/__init__.py)22
-rw-r--r--test5.py26
37 files changed, 302 insertions, 199 deletions
diff --git a/TODO b/TODO
index 44ebe6e9..206df5bb 100644
--- a/TODO
+++ b/TODO
@@ -11,3 +11,4 @@ General
 
    ( ) #5   09/12/06  move code from fm into objects
    ( ) #6   09/12/06  move main to fm
+   ( ) #7   09/12/06  cooler titlebar
diff --git a/ranger/__init__.py b/ranger/__init__.py
index d2716895..f5a1c480 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -6,3 +6,25 @@ rangerdir = os.path.dirname(__file__)
 
 sys.path.append(confdir)
 
+
+def relpath(*args):
+	return os.path.join(rangerdir, *args)
+
+LOGFILE = '/tmp/errorlog'
+
+def log(txt):
+	f = open(LOGFILE, 'a')
+	f.write("r1: ")
+	f.write(str(txt))
+	f.write("\n")
+	f.close()
+
+# used to get all colorschemes in ~/.ranger/colorschemes
+# and ranger/colorschemes
+def get_all(dirname):
+	import os
+	result = []
+	for filename in os.listdir(dirname):
+		if filename.endswith('.py') and not filename.startswith('_'):
+			result.append(filename[0:filename.index('.')])
+	return result
diff --git a/ranger/applications.py b/ranger/applications.py
index fd977c43..ca934920 100644
--- a/ranger/applications.py
+++ b/ranger/applications.py
@@ -13,3 +13,43 @@ class Applications(object):
 	def all(self):
 		return [x for x in self.__dict__ if x.startswith('app_')]
 
+import os
+null = open(os.devnull, 'a')
+
+def run(*args, **kw):
+	from subprocess import Popen
+	from subprocess import PIPE
+	from ranger.ext import waitpid_no_intr
+
+	flags, fm = kw['flags'], kw['fm']
+	for flag in flags:
+		if ord(flag) <= 90:
+			bad = flag + flag.lower()
+			flags = ''.join(c for c in flags if c not in bad)
+
+	args = map(str, args)
+	popen_kw = {}
+
+	if kw['stdin'] is not None:
+		popen_kw['stdin'] = kw['stdin']
+
+	if 's' in flags or 'd' in flags:
+		popen_kw['stdout'] = popen_kw['stderr'] = popen_kw['stdin'] = null
+	
+	if 'p' in flags:
+		popen_kw['stdout'] = PIPE
+		process1 = Popen(args, **popen_kw)
+		kw['stdin'] = process1.stdout
+		kw['files'] = ()
+		kw['flags'] = ''.join(f for f in kw['flags'] if f in 'd')
+		process2 = kw['apps'].app_pager(**kw)
+		return process2
+	if 'd' in flags:
+		process = Popen(args, **popen_kw)
+		return process
+	else:
+		fm.ui.exit()
+		p = Popen(args, **popen_kw)
+		waitpid_no_intr(p.pid)
+		fm.ui.initialize()
+		return p
diff --git a/ranger/colorschemes/__init__.py b/ranger/colorschemes/__init__.py
index 6319fa96..2318ba27 100644
--- a/ranger/colorschemes/__init__.py
+++ b/ranger/colorschemes/__init__.py
@@ -1,4 +1,4 @@
-from ranger.helper import get_all, log
+from ranger import get_all, log
 from os.path import expanduser, dirname, exists, join
 
 __all__ = get_all(dirname(__file__))
@@ -9,8 +9,8 @@ confpath = expanduser('~/.ranger')
 if exists(join(confpath, 'colorschemes')):
 	initpy = join(confpath, 'colorschemes/__init__.py')
 	if not exists(initpy):
-		open(initpy, 'w').write("""import ranger.helper, os.path
-__all__ = ranger.helper.get_all( os.path.dirname( __file__ ) )
+		open(initpy, 'w').write("""import ranger, os.path
+__all__ = ranger.get_all( os.path.dirname( __file__ ) )
 """)
 
 	try:
diff --git a/ranger/colorschemes/jungle.py b/ranger/colorschemes/jungle.py
index 5f575238..eb70e5aa 100644
--- a/ranger/colorschemes/jungle.py
+++ b/ranger/colorschemes/jungle.py
@@ -47,4 +47,8 @@ class Default(ColorScheme):
 			elif context.link:
 				fg = cyan
 
+			elif context.keybuffer:
+				fg = yellow
+				attr = normal
+
 		return fg, bg, attr
diff --git a/ranger/container/__init__.py b/ranger/container/__init__.py
new file mode 100644
index 00000000..fe8228e9
--- /dev/null
+++ b/ranger/container/__init__.py
@@ -0,0 +1,4 @@
+from ranger.container.history import History
+from ranger.container.keybuffer import KeyBuffer
+from .commandlist import CommandList
+from .bookmarks import Bookmarks
diff --git a/ranger/bookmark.py b/ranger/container/bookmarks.py
index da54e8eb..da54e8eb 100644
--- a/ranger/bookmark.py
+++ b/ranger/container/bookmarks.py
diff --git a/ranger/command.py b/ranger/container/commandlist.py
index a252fea2..a252fea2 100644
--- a/ranger/command.py
+++ b/ranger/container/commandlist.py
diff --git a/ranger/history.py b/ranger/container/history.py
index bd9a575f..bd9a575f 100644
--- a/ranger/history.py
+++ b/ranger/container/history.py
diff --git a/ranger/container/keybuffer.py b/ranger/container/keybuffer.py
new file mode 100644
index 00000000..1f6471d8
--- /dev/null
+++ b/ranger/container/keybuffer.py
@@ -0,0 +1,9 @@
+class KeyBuffer(tuple):
+	def __str__(self):
+		return "".join( map( to_string, self ) )
+
+def to_string(i):
+	try:
+		return chr(i)
+	except ValueError:
+		return '?'
diff --git a/data/generate.py b/ranger/data/generate.py
index 61309259..61309259 100755
--- a/data/generate.py
+++ b/ranger/data/generate.py
diff --git a/data/mime.dat b/ranger/data/mime.dat
index ddfca976..ddfca976 100644
--- a/data/mime.dat
+++ b/ranger/data/mime.dat
diff --git a/data/mime.types b/ranger/data/mime.types
index 866db2c2..866db2c2 100644
--- a/data/mime.types
+++ b/ranger/data/mime.types
diff --git a/ranger/defaults/apps.py b/ranger/defaults/apps.py
index 23b95537..b2dc36c6 100644
--- a/ranger/defaults/apps.py
+++ b/ranger/defaults/apps.py
@@ -1,7 +1,6 @@
-from ranger.applications import Applications as SuperClass
-from ranger.helper import popen as run
+from ranger.applications import Applications, run
 
-class CustomApplications(SuperClass):
+class CustomApplications(Applications):
 	# How to determine the default application? {{{
 	def app_default(self, **kw):
 		f = kw['mainfile']
@@ -43,6 +42,11 @@ class CustomApplications(SuperClass):
 					'-lavdopts', 'lowres=1:fast:skiploopfilter=all:threads=8',
 					*kw['files'], **kw)
 
+		elif kw['mode'] == 3:
+			return run('mplayer',
+					'-mixer', 'software',
+					*kw['files'], **kw)
+
 		else:
 			return run('mplayer', '-fs', *kw['files'], **kw)
 
diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py
index dc7362cf..de58681a 100644
--- a/ranger/defaults/keys.py
+++ b/ranger/defaults/keys.py
@@ -1,7 +1,7 @@
 def initialize_commands(cl):
 	from ranger.fm import FM
 	from curses.ascii import ctrl
-	from ranger.bookmark import ALLOWED_KEYS as ALLOWED_BOOKMARK_KEYS
+	from ranger.container.bookmarks import ALLOWED_KEYS as ALLOWED_BOOKMARK_KEYS
 	import curses
 
 	# syntax for binding keys: cl.bind(fnc, *keys)
diff --git a/ranger/defaults/options.py b/ranger/defaults/options.py
index d3eeef84..f78d0a81 100644
--- a/ranger/defaults/options.py
+++ b/ranger/defaults/options.py
@@ -1,3 +1,4 @@
+from ranger.defaults import apps, keys
 from ranger import colorschemes
 
 colorscheme = colorschemes.default
diff --git a/ranger/directory.py b/ranger/directory.py
index 6a619537..258266c0 100644
--- a/ranger/directory.py
+++ b/ranger/directory.py
@@ -4,7 +4,7 @@ from ranger.file import File
 
 from ranger.fsobject import BAD_INFO
 from ranger.fsobject import FileSystemObject as SuperClass
-from ranger.conf import SettingsAware
+from ranger.shared import SettingsAware
 
 def sort_by_basename(path):
 	return path.basename
@@ -37,7 +37,7 @@ class Directory(SuperClass, SettingsAware):
 		# to find out if something has changed:
 		self.old_show_hidden = self.settings.show_hidden
 		self.old_directories_first = self.settings.directories_first
-	
+
 	def load_content(self):
 		from os.path import join, isdir, basename
 		from os import listdir
@@ -211,3 +211,8 @@ class Directory(SuperClass, SettingsAware):
 		if not self.accessible: raise ranger.fsobject.NotLoadedYet()
 		return self.files[key]
 
+	def __eq__(self, other):
+		return isinstance(other, Directory) and self.path == other.path
+
+	def __neq__(self, other):
+		return not self.__eq__(other)
diff --git a/ranger/environment.py b/ranger/environment.py
index a5e54414..8e45516b 100644
--- a/ranger/environment.py
+++ b/ranger/environment.py
@@ -1,28 +1,31 @@
 from os.path import abspath, normpath, join, expanduser
 from ranger.directory import Directory, NoDirectoryGiven
-from ranger.conf import SettingsAware
+from ranger.container import KeyBuffer, History
+from ranger.shared import SettingsAware
 
 class Environment(SettingsAware):
 	# A collection of data which is relevant for more than
 	# one class.
 	def __init__(self, path):
-		from ranger.history import History
 		self.path = abspath(expanduser(path))
 		self.pathway = ()
 		self.last_search = None
 		self.directories = {}
 		self.pwd = None # current directory
 		self.cf = None # current file
-		self.keybuffer = ()
+		self.keybuffer = KeyBuffer()
 		self.copy = None
 		self.termsize = (24, 80)
 		self.history = History(self.settings.max_history_size)
 
+		from ranger.shared import EnvironmentAware
+		EnvironmentAware.env = self
+
 	def key_append(self, key):
-		self.keybuffer += (key, )
+		self.keybuffer = KeyBuffer(self.keybuffer + (key, ))
 
 	def key_clear(self):
-		self.keybuffer = ()
+		self.keybuffer = KeyBuffer()
 	
 	def at_level(self, level):
 		if level <= 0:
@@ -37,6 +40,14 @@ class Environment(SettingsAware):
 				return None
 			except KeyError:
 				return self.cf
+
+	def garbage_collect(self):
+		from ranger.fsobject import FileSystemObject
+		for key in tuple(self.directories.keys()):
+			value = self.directories[key]
+			if isinstance(value, FileSystemObject):
+				if value.is_older_than(1):
+					del self.directories[key]
 	
 	def get_directory(self, path):
 		path = abspath(path)
@@ -59,7 +70,8 @@ class Environment(SettingsAware):
 	
 	def history_go(self, relative):
 		if self.history:
-			self.enter_dir(self.history.move(relative))
+#			self.enter_dir(self.history.move(relative))
+			self.history.move(relative).go()
 
 	def enter_dir(self, path, history = True):
 		if path is None: return
@@ -98,7 +110,7 @@ class Environment(SettingsAware):
 		self.cf = self.pwd.pointed_file
 
 		if history:
-			self.history.add(path)
+			self.history.add(new_pwd)
 
 		return True
 
diff --git a/ranger/ext/__init__.py b/ranger/ext/__init__.py
new file mode 100644
index 00000000..f09324b7
--- /dev/null
+++ b/ranger/ext/__init__.py
@@ -0,0 +1,3 @@
+from .openstruct import OpenStruct
+from .human_readable import human_readable
+from .waitpid_no_intr import waitpid_no_intr
diff --git a/ranger/ext/human_readable.py b/ranger/ext/human_readable.py
new file mode 100644
index 00000000..4afa03cb
--- /dev/null
+++ b/ranger/ext/human_readable.py
@@ -0,0 +1,21 @@
+ONE_KB = 1024
+UNITS = 'BKMGTP'
+MAX_EXPONENT = len(UNITS) - 1
+
+def human_readable(byte):
+	import math
+
+	if not byte:
+		return '0 B'
+
+	exponent = int(math.log(byte, 2) / 10)
+	flt = float(byte) / (1 << (10 * exponent))
+	
+	if exponent > MAX_EXPONENT:
+		return '>9000' # off scale
+
+	if int(flt) == flt:
+		return '%.0f %s' % (flt, UNITS[exponent])
+
+	else:
+		return '%.2f %s' % (flt, UNITS[exponent])
diff --git a/ranger/ext/openstruct.py b/ranger/ext/openstruct.py
new file mode 100644
index 00000000..0a899de6
--- /dev/null
+++ b/ranger/ext/openstruct.py
@@ -0,0 +1,16 @@
+class OpenStruct(object):
+	def __init__(self, __dictionary=None, **__keywords):
+		if __dictionary:
+			self.__dict__.update(__dictionary)
+		if __keywords:
+			self.__dict__.update(__keywords)
+
+	def __getitem__(self, key):
+		return self.__dict__[key]
+	
+	def __setitem__(self, key, value):
+		self.__dict__[key] = value
+		return value
+
+	def __contains__(self, key):
+		return key in self.__dict__
diff --git a/ranger/ext/waitpid_no_intr.py b/ranger/ext/waitpid_no_intr.py
new file mode 100644
index 00000000..38df44ee
--- /dev/null
+++ b/ranger/ext/waitpid_no_intr.py
@@ -0,0 +1,12 @@
+def waitpid_no_intr(pid):
+	""" catch interrupts which occur while using os.waitpid """
+	import os, errno
+
+	while True:
+		try:
+			return os.waitpid(pid, 0)
+		except OSError as e:
+			if e.errno == errno.EINTR:
+				continue
+			else:
+				raise
diff --git a/ranger/fm.py b/ranger/fm.py
index 3fcfb92f..2bfecffb 100644
--- a/ranger/fm.py
+++ b/ranger/fm.py
@@ -1,29 +1,34 @@
-from os import devnull
-#from ranger.conf.apps import CustomApplications as Applications
-from ranger.conf import apps
-null = open(devnull, 'a')
-
-class FM(object):
-	def __init__(self, environment, ui, bookmarks):
-		self.env = environment
+from ranger.shared import EnvironmentAware
+
+class FM(EnvironmentAware):
+	def __init__(self, ui, bookmarks):
 		self.ui = ui
-		self.apps = apps.CustomApplications()
+		self.apps = self.env.settings.apps.CustomApplications()
 		self.bookmarks = bookmarks
 		self.bookmarks.enter_dir_function = self.enter_dir
 
-	def run(self):
+		from ranger.shared import FileManagerAware
+		FileManagerAware.fm = self
+
+	def loop(self):
 		self.env.enter_dir(self.env.path)
 
+		gc_tick = 0
+
 		while True:
 			try:
 				self.bookmarks.reload_if_outdated()
 				self.ui.draw()
 				key = self.ui.get_next_key()
 				self.ui.press(key, self)
+
+				gc_tick += 1
+				if gc_tick > 10:
+					gc_tick = 0
+					self.env.garbage_collect()
+
 			except KeyboardInterrupt:
 				self.ui.press(3, self)
-			except:
-				raise
 	
 	def interrupt(self):
 		import time
@@ -53,7 +58,7 @@ class FM(object):
 		self.env.enter_dir(path)
 
 	def enter_bookmark(self, key):
-		from ranger.bookmark import NonexistantBookmark
+		from ranger.container.bookmarks import NonexistantBookmark
 		try:
 			destination = self.bookmarks[key]
 			current_path = self.env.pwd.path
diff --git a/ranger/fsobject.py b/ranger/fsobject.py
index 35a6465a..35d0d5b3 100644
--- a/ranger/fsobject.py
+++ b/ranger/fsobject.py
@@ -12,9 +12,11 @@ CONTAINER_EXTENSIONS = 'rar zip tar gz bz bz2 tgz 7z iso cab'.split()
 DOCUMENT_EXTENSIONS = 'pdf doc ppt odt'.split()
 DOCUMENT_BASENAMES = 'README TODO LICENSE'.split()
 
-class FileSystemObject(object):
+from ranger.shared import MimeTypeAware, FileManagerAware
+class FileSystemObject(MimeTypeAware, FileManagerAware):
 
 	def __init__(self, path):
+		MimeTypeAware.__init__(self)
 		if type(self) == FileSystemObject:
 			raise TypeError("FileSystemObject is an abstract class and cannot be initialized.")
 
@@ -42,14 +44,22 @@ class FileSystemObject(object):
 		self.type = T_UNKNOWN
 
 		self.set_mimetype()
+		self.use()
 	
 	def __str__(self):
 		return str(self.path)
 
+	def use(self):
+		import time
+		self.last_used = time.time()
+	
+	def is_older_than(self, seconds):
+		import time
+		return self.last_used + seconds < time.time()
+	
 	def set_mimetype(self):
-		import ranger.mimetype as mimetype
 		try:
-			self.mimetype = mimetype.get() [self.extension]
+			self.mimetype = self.mimetypes[self.extension]
 		except KeyError:
 			self.mimetype = ''
 
@@ -70,7 +80,7 @@ class FileSystemObject(object):
 	# and caches it in instance attributes.
 	def load(self):
 		import os
-		from ranger.helper import human_readable
+		from ranger.ext import human_readable
 
 		self.loaded = True
 
@@ -113,6 +123,9 @@ class FileSystemObject(object):
 			return True
 		return False
 
+	def go(self):
+		self.fm.enter_dir(self.path)
+
 	def load_if_outdated(self):
 		if self.load_once(): return True
 
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index 6f3ef01f..281396a5 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -3,7 +3,8 @@ CONTEXT_KEYS = [ 'reset', 'error',
 		'directory', 'file', 'hostname',
 		'executable', 'media', 'link',
 		'video', 'audio', 'image', 'media', 'document', 'container',
-		'broken', 'selected', 'empty', 'maindisplay']
+		'broken', 'selected', 'empty', 'maindisplay',
+		'keybuffer']
 
 # colorscheme specification:
 #
@@ -27,7 +28,7 @@ CONTEXT_KEYS = [ 'reset', 'error',
 # If your colorscheme-file contains more than one colorscheme, specify it with:
 # colorscheme = colorschemes.filename.classname
 
-from ranger.helper import OpenStruct
+from ranger.ext import OpenStruct
 
 class ColorScheme(object):
 	def __init__(self):
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index b5ae78dc..beedea09 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -17,14 +17,15 @@ class MouseEvent(object):
 		except:
 			return False
 
-class UI(object):
-	def __init__(self, env, commandlist, colorscheme):
+from ranger.shared import EnvironmentAware
+
+class UI(EnvironmentAware):
+	def __init__(self, commandlist):
 		import os
 		os.environ['ESCDELAY'] = '25' # don't know a cleaner way
 
-		self.env = env
 		self.commandlist = commandlist
-		self.colorscheme = colorscheme
+		self.colorscheme = self.env.settings.colorscheme
 		self.is_set_up = False
 		self.win = curses.initscr()
 
@@ -52,7 +53,7 @@ class UI(object):
 		self.resize()
 
 	def exit(self):
-		from ranger.helper import log
+		from ranger import log
 		log("exiting ui!")
 		self.win.keypad(0)
 		curses.nocbreak()
@@ -108,7 +109,7 @@ class UI(object):
 				return
 
 		try:
-			cmd = self.commandlist.paths[self.env.keybuffer]
+			cmd = self.commandlist.paths[tuple(self.env.keybuffer)]
 		except KeyError:
 			self.env.key_clear()
 			return
diff --git a/ranger/gui/wconsole.py b/ranger/gui/wconsole.py
index a0322c42..581745b4 100644
--- a/ranger/gui/wconsole.py
+++ b/ranger/gui/wconsole.py
@@ -6,13 +6,12 @@ CONSOLE_MODES_DICTIONARY = { '@': 'open with: ' }
 
 class WConsole(SuperClass):
 	def __init__(self, win, colorscheme):
-		from ranger.command import CommandList
-		from ranger.conf import keys
+		from ranger.container import CommandList
 		SuperClass.__init__(self, win, colorscheme)
 		self.mode = None
 		self.visible = False
 		self.commandlist = CommandList()
-		keys.initialize_console_commands(self.commandlist)
+		self.settings.keys.initialize_console_commands(self.commandlist)
 		self.last_cursor_mode = 1
 		self.clear()
 		self.prompt = None
diff --git a/ranger/gui/wdisplay.py b/ranger/gui/wdisplay.py
index fd4f7dec..5e5e80d6 100644
--- a/ranger/gui/wdisplay.py
+++ b/ranger/gui/wdisplay.py
@@ -70,6 +70,7 @@ class WDisplay(SuperClass):
 		import curses
 		import stat
 
+		self.target.use()
 		self.target.load_content_if_outdated()
 		self.target.sort_if_outdated()
 
diff --git a/ranger/gui/widget.py b/ranger/gui/widget.py
index 071b88bc..093eee14 100644
--- a/ranger/gui/widget.py
+++ b/ranger/gui/widget.py
@@ -8,12 +8,12 @@ def combine(keylist, keys):
 	else:
 		return tuple((keylist, ) + keys)
 
-from ranger.conf import SettingsAware
+from ranger.shared import SettingsAware
 class Widget(SettingsAware):
-	def __init__(self, win, colorscheme):
+	def __init__(self, win, _):
 		self.win = win
 		self.focused = False
-		self.colorscheme = colorscheme
+		self.colorscheme = self.settings.colorscheme
 		self.visible = True
 		self.setdim(0, 0, 0, 0)
 
diff --git a/ranger/gui/wtitlebar.py b/ranger/gui/wtitlebar.py
index af8ab0d7..65ed2e33 100644
--- a/ranger/gui/wtitlebar.py
+++ b/ranger/gui/wtitlebar.py
@@ -4,6 +4,7 @@ class WTitleBar(SuperClass):
 	def feed_env(self, env):
 		self.pathway = env.pathway
 		self.cf = env.cf
+		self.keybuffer = env.keybuffer
 
 	def draw(self):
 		import curses, socket, os
@@ -30,5 +31,15 @@ class WTitleBar(SuperClass):
 			currentx = self.win.getyx()[1]
 			self.color('in_titlebar', 'file')
 			self.win.addnstr(self.cf.basename, max(self.wid - currentx, 0))
+
+		self.color('in_titlebar', 'keybuffer')
+
+		kb = str(self.keybuffer)
+		if self.wid + self.x - currentx > len(kb):
+			self.win.addstr(
+					self.y,
+					self.x + self.wid - len(kb) - 2,
+					kb)
+
 		self.color_reset()
 
diff --git a/ranger/helper.py b/ranger/helper.py
deleted file mode 100644
index d9f6270d..00000000
--- a/ranger/helper.py
+++ /dev/null
@@ -1,111 +0,0 @@
-
-LOGFILE = '/tmp/errorlog'
-
-def log(txt):
-	f = open(LOGFILE, 'a')
-	f.write("r1: ")
-	f.write(str(txt))
-	f.write("\n")
-	f.close()
-
-class OpenStruct(object):
-	def __init__(self, __dictionary=None, **__keywords):
-		if __dictionary:
-			self.__dict__.update(__dictionary)
-		if __keywords:
-			self.__dict__.update(__keywords)
-
-	def __getitem__(self, key):
-		return self.__dict__[key]
-	
-	def __setitem__(self, key, value):
-		self.__dict__[key] = value
-		return value
-
-	def __contains__(self, key):
-		return key in self.__dict__
-
-# used to get all colorschemes in ~/.ranger/colorschemes and ranger/colorschemes
-def get_all(dirname):
-	import os
-	result = []
-	for filename in os.listdir(dirname):
-		if filename.endswith('.py') and not filename.startswith('_'):
-			result.append(filename[0:filename.index('.')])
-	return result
-
-
-ONE_KB = 1024
-UNITS = 'BKMGTP'
-MAX_EXPONENT = len(UNITS) - 1
-
-def human_readable(byte):
-	import math
-
-	if not byte:
-		return '0 B'
-
-	exponent = int(math.log(byte, 2) / 10)
-	flt = float(byte) / (1 << (10 * exponent))
-	
-	if exponent > MAX_EXPONENT:
-		return '>9000' # off scale
-
-	if int(flt) == flt:
-		return '%.0f %s' % (flt, UNITS[exponent])
-
-	else:
-		return '%.2f %s' % (flt, UNITS[exponent])
-
-def waitpid_no_intr(pid):
-	""" catch interrupts which occur while using os.waitpid """
-	import os, errno
-
-	while True:
-		try:
-			return os.waitpid(pid, 0)
-		except OSError as e:
-			if e.errno == errno.EINTR:
-				continue
-			else:
-				raise
-
-import os
-null = open(os.devnull, 'a')
-
-def popen(*args, **kw):
-	from subprocess import Popen
-	from subprocess import PIPE
-
-	flags, fm = kw['flags'], kw['fm']
-	for flag in flags:
-		if ord(flag) <= 90:
-			bad = flag + flag.lower()
-			flags = ''.join(c for c in flags if c not in bad)
-
-	args = map(str, args)
-	popen_kw = {}
-
-	if kw['stdin'] is not None:
-		popen_kw['stdin'] = kw['stdin']
-
-	if 's' in flags or 'd' in flags:
-		popen_kw['stdout'] = popen_kw['stderr'] = popen_kw['stdin'] = null
-	
-	if 'p' in flags:
-		popen_kw['stdout'] = PIPE
-		process1 = Popen(args, **popen_kw)
-		kw['stdin'] = process1.stdout
-		kw['files'] = ()
-		kw['flags'] = ''.join(f for f in kw['flags'] if f in 'd')
-		process2 = kw['apps'].app_pager(**kw)
-		return process2
-	if 'd' in flags:
-		process = Popen(args, **popen_kw)
-		return process
-	else:
-		fm.ui.exit()
-		p = Popen(args, **popen_kw)
-		waitpid_no_intr(p.pid)
-		fm.ui.initialize()
-		return p
diff --git a/ranger/main.py b/ranger/main.py
index 9faf069f..f5453187 100644
--- a/ranger/main.py
+++ b/ranger/main.py
@@ -4,12 +4,11 @@ from locale import setlocale, LC_ALL
 from optparse import OptionParser, SUPPRESS_HELP
 
 from ranger.fm import FM
+from ranger.container import CommandList, Bookmarks
 from ranger.environment import Environment
-from ranger.command import CommandList
-from ranger.bookmark import Bookmarks
-from ranger.conf import keys, options
+from ranger.shared import SettingsAware, EnvironmentAware, FileManagerAware
 from ranger.gui.defaultui import DefaultUI as UI
-from ranger.gui.colorscheme import ColorScheme
+from ranger.file import File
 
 VERSION = '1.0.0'
 
@@ -53,7 +52,8 @@ def main():
 			print("File or directory doesn't exist: %s" % target)
 			sys.exit(1)
 		elif os.path.isfile(target):
-			FM.execute_file(FM(0, 0), target)
+			thefile = File(target)
+			FM(0, 0, sys).execute_file(thefile)
 			sys.exit(0)
 		else:
 			path = target
@@ -61,23 +61,26 @@ def main():
 	else:
 		path = '.'
 
-	env = Environment(path)
+	Environment(path)
 	commandlist = CommandList()
-	keys.initialize_commands(commandlist)
+	SettingsAware.settings.keys.initialize_commands(commandlist)
 	bookmarks = Bookmarks()
 	bookmarks.load()
 
-	my_ui = UI(env, commandlist, options.colorscheme())
-	my_fm = FM(env, my_ui, bookmarks)
+	my_ui = None
 
 	try:
+		my_ui = UI(commandlist)
+		my_fm = FM(my_ui, bookmarks)
+
 		# Run the file manager
 		my_ui.initialize()
-		my_fm.run()
+		my_fm.loop()
 
 	finally:
 		# Finish, clean up
-		my_ui.exit()
+		if my_ui:
+			my_ui.exit()
 
 		if args.cd_after_exit:
 			try: sys.__stderr__.write(env.pwd.path)
diff --git a/ranger/mimetype.py b/ranger/mimetype.py
deleted file mode 100644
index 5e70f2e7..00000000
--- a/ranger/mimetype.py
+++ /dev/null
@@ -1,14 +0,0 @@
-types = {'not loaded': True}
-
-def load():
-	import sys, os, pickle
-	types.clear()
-
-	f = open(os.path.join(os.path.dirname(__file__), '../data/mime.dat'), 'rb')
-	types.update(pickle.load(f))
-	f.close()
-
-def get():
-	if 'not loaded' in types:
-		load()
-	return types
diff --git a/ranger/shared/__init__.py b/ranger/shared/__init__.py
new file mode 100644
index 00000000..eed206d6
--- /dev/null
+++ b/ranger/shared/__init__.py
@@ -0,0 +1,11 @@
+class Awareness(object):
+	pass
+
+from .mimetype import MimeTypeAware
+from .settings import SettingsAware
+
+class EnvironmentAware(Awareness):
+   env = None
+
+class FileManagerAware(Awareness):
+   fm = None
diff --git a/ranger/shared/mimetype.py b/ranger/shared/mimetype.py
new file mode 100644
index 00000000..ac4ff629
--- /dev/null
+++ b/ranger/shared/mimetype.py
@@ -0,0 +1,13 @@
+from ranger import relpath
+class MimeTypeAware(object):
+	mimetypes = {}
+	__initialized = False
+	def __init__(self):
+		if not MimeTypeAware.__initialized:
+			MimeTypeAware.__initialized = True
+			import os, sys, pickle
+			MimeTypeAware.mimetypes.clear()
+
+			f = open(relpath('data/mime.dat'), 'rb')
+			MimeTypeAware.mimetypes.update(pickle.load(f))
+			f.close()
diff --git a/ranger/conf/__init__.py b/ranger/shared/settings.py
index 626fe98e..def09c4e 100644
--- a/ranger/conf/__init__.py
+++ b/ranger/shared/settings.py
@@ -1,24 +1,13 @@
 from inspect import isclass, ismodule
-from ranger.helper import OpenStruct
+from ranger.ext.openstruct import OpenStruct
 from ranger.gui.colorscheme import ColorScheme
 
 ALLOWED_SETTINGS = """
 show_hidden scroll_offset directories_first
 preview_files max_history_size colorscheme
+apps keys
 """.split()
 
-# -- import the options --
-# either use the custom file or the default file
-try:
-	import keys
-except ImportError:
-	from ranger.defaults import keys
-
-try:
-	import apps
-except ImportError:
-	from ranger.defaults import apps
-
 # overwrite single default options with custom options
 from ranger.defaults import options
 try:
@@ -34,14 +23,15 @@ except ImportError:
 # If a module is specified as the colorscheme, replace it with one
 # valid colorscheme inside that module.
 
-if isclass(options.colorscheme) and issubclass(options.colorscheme, ColorScheme):
-	pass # everything ok
+if isclass(options.colorscheme) and \
+		issubclass(options.colorscheme, ColorScheme):
+	options.colorscheme = options.colorscheme()
 
 elif ismodule(options.colorscheme):
 	for var_name in dir(options.colorscheme):
 		var = getattr(options.colorscheme, var_name)
 		if var != ColorScheme and isclass(var) and issubclass(var, ColorScheme):
-			options.colorscheme = var
+			options.colorscheme = var()
 			break
 	else:
 		raise Exception("The given colorscheme module contains no valid colorscheme!")
diff --git a/test5.py b/test5.py
new file mode 100644
index 00000000..682a716f
--- /dev/null
+++ b/test5.py
@@ -0,0 +1,26 @@
+class A:
+	def foo(self, x):
+		y = x + 1
+		print(y)
+		return y
+
+	@staticmethod
+	def zar():
+		print("l o l")
+
+class B(A):
+	def bar(self, x):
+		y = self.foo(x) + 3
+		print(y)
+		return y
+
+class C():
+	def foo(self, x):
+		y = x - 1
+		print(y)
+		return y
+
+a = C()
+A.foo(a, 5)
+
+B.zar()