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()
3df56e0a6302b8'>^
c5ffb6e1 ^
76755b28 ^
c5ffb6e1 ^

76755b28 ^

90560d71 ^
65361948 ^
76755b28 ^
65361948 ^

90560d71 ^
65361948 ^
76755b28 ^
65361948 ^
90560d71 ^
65361948 ^


672e3e50 ^

c5ffb6e1 ^





90560d71 ^
c5ffb6e1 ^
90560d71 ^


76755b28 ^
c5ffb6e1 ^




90560d71 ^
c5ffb6e1 ^
90560d71 ^

c5ffb6e1 ^




90560d71 ^
c5ffb6e1 ^
90560d71 ^

c5ffb6e1 ^



90560d71 ^



c5ffb6e1 ^

90560d71 ^
c5ffb6e1 ^
90560d71 ^
672e3e50 ^

65361948 ^



76755b28 ^




65361948 ^
90560d71 ^
65361948 ^




90560d71 ^
76755b28 ^






65361948 ^
90560d71 ^
76755b28 ^

90560d71 ^

62a52ffb ^
90560d71 ^
76755b28 ^

90560d71 ^
dbe12410 ^
4bbd3ded ^
65361948 ^
62a52ffb ^
65361948 ^

672e3e50 ^



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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394