summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2012-12-04 21:20:09 +0100
committerhut <hut@lavabit.com>2012-12-04 21:20:09 +0100
commit972da7babcecbe47bd56a3d2d19157b4aba61e99 (patch)
tree4d3b5a9ecb992a80dd54e511bf00dd3bc3670a3d
parent6f7e47d6a91627fab3e08f42df5114db3c22841a (diff)
downloadranger-972da7babcecbe47bd56a3d2d19157b4aba61e99.tar.gz
removed options.py, improved plugins. *UPDATE YOUR COMMANDS.PY*
Previously, you could change settings in both rc.conf and options.py.
With this commit, options.py is deprecated and you are encouraged to use
rc.conf to change settings.  I chose to do this because it is more
elegant to use a simple list of ranger commands for configuration
rather than a python file with lots of magic around it and potential
syntax errors for inexperienced users.

The existing "set" command doesn't evaluate python objects anymore,
instead it always takes strings and converts to the proper type
automatically.  This means that the old set command will not work
anymore and you have to update your commands.py if it still uses the old
definition of the "set" command.

This is how to convert your options.py:

old way, in options.py     | new way, in rc.conf
---------------------------+------------------------
show_hidden = False        | set show_hidden false
sort = 'basename'          | set sort basename
column_ratios = (1, 5, 3)  | set column_ratios 1,5,3

For backward compatibility, you still can use options.py, but you get a
warning when you start ranger.  You can pipe stderr to /dev/null to
silence the warning, or just move your stuff from options.py to rc.conf
and plugins and delete the options.py.

Finally, to extend ranger, which you previously could do through
monkey-patching in options.py, you should now use the plugin system.
This was an experimental, undocumented feature of ranger for some time,
but this and the following commits will imrpove and document it.
You can simply move all the monkey-patching code from options.py to a
*.py file in ~/.config/ranger/plugins/.
-rw-r--r--examples/README2
-rw-r--r--examples/plugin_chmod_keybindings.py18
-rw-r--r--examples/plugin_file_filter.py17
-rw-r--r--examples/plugin_new_macro.py17
-rw-r--r--examples/plugin_new_sorting_method.py7
-rw-r--r--examples/plugin_skip_default_rc.py9
-rw-r--r--ranger/config/commands.py8
-rw-r--r--ranger/config/options.py216
-rw-r--r--ranger/config/rc.conf119
-rw-r--r--ranger/container/history.py2
-rw-r--r--ranger/container/settingobject.py32
-rw-r--r--ranger/core/actions.py29
-rw-r--r--ranger/core/fm.py11
-rw-r--r--ranger/core/main.py31
-rw-r--r--ranger/core/shared.py16
-rw-r--r--ranger/gui/colorscheme.py29
16 files changed, 286 insertions, 277 deletions
diff --git a/examples/README b/examples/README
index 60f29ac6..8606a89d 100644
--- a/examples/README
+++ b/examples/README
@@ -1,2 +1,2 @@
-Thes files in this directory contain applications or extensions of ranger which
+The files in this directory contain applications or extensions of ranger which
 are put here for your inspiration and as references.
diff --git a/examples/plugin_chmod_keybindings.py b/examples/plugin_chmod_keybindings.py
new file mode 100644
index 00000000..c04cc492
--- /dev/null
+++ b/examples/plugin_chmod_keybindings.py
@@ -0,0 +1,18 @@
+# This plugin serves as an example for adding key bindings through a plugin.
+# It could replace the ten lines in the rc.conf that create the key bindings
+# for the "chmod" command.
+
+import ranger.core.fm
+old_init_hook = ranger.core.fm.init_hook
+
+def init_hook(fm):
+	old_init_hook(fm)
+
+	# Generate key bindings for the chmod command
+	command = "map {0}{1}{2} shell -d chmod {1}{0}{2} %s"
+	for	mode in list('ugoa') + '':
+		for	perm in "rwxXst":
+			fm.execute_console(command.format('-', mode, perm))
+			fm.execute_console(command.format('+', mode, perm))
+
+ranger.core.fm.init_hook = init_hook
diff --git a/examples/plugin_file_filter.py b/examples/plugin_file_filter.py
new file mode 100644
index 00000000..99d026bb
--- /dev/null
+++ b/examples/plugin_file_filter.py
@@ -0,0 +1,17 @@
+# This plugin hides the directories "boot", "sbin", "proc" and "sys" in the
+# root directory.
+
+# Save the original filter function
+import ranger.fsobject.directory
+old_accept_file = ranger.fsobject.directory.accept_file
+
+# Define a new one
+def custom_accept_file(fname, mypath, hidden_filter, name_filter):
+       if hidden_filter and mypath == '/' and fname in ('boot', 'sbin', 'proc', 'sys'):
+               return False
+       else:
+               return old_accept_file(fname, mypath, hidden_filter, name_filter)
+
+# Overwrite the old function
+import ranger.fsobject.directory
+ranger.fsobject.directory.accept_file = custom_accept_file
diff --git a/examples/plugin_new_macro.py b/examples/plugin_new_macro.py
new file mode 100644
index 00000000..ec0c487c
--- /dev/null
+++ b/examples/plugin_new_macro.py
@@ -0,0 +1,17 @@
+# This plugin adds the new macro %date which is substituted with the current
+# date in commands that allow macros.  You can test it with the command
+# ":shell echo %date; read"
+
+# Save the original macro function
+import ranger.core.actions
+old_get_macros = ranger.core.actions.Actions._get_macros
+
+# Define a new macro function
+import time
+def get_macros_with_date(self):
+       macros = old_get_macros(self)
+       macros['date'] = time.strftime('%m/%d/%Y')
+       return macros
+
+# Overwrite the old one
+ranger.core.actions.Actions._get_macros = get_macros_with_date
diff --git a/examples/plugin_new_sorting_method.py b/examples/plugin_new_sorting_method.py
new file mode 100644
index 00000000..2500c1c1
--- /dev/null
+++ b/examples/plugin_new_sorting_method.py
@@ -0,0 +1,7 @@
+# This plugin adds the sorting algorithm called 'random'.  To enable it, type
+# ":set sort=random" or create a key binding with ":map oz set sort=random"
+
+from ranger.fsobject.directory import Directory
+from random import random
+Directory.sort_dict['random'] = lambda path: random()
+
diff --git a/examples/plugin_skip_default_rc.py b/examples/plugin_skip_default_rc.py
new file mode 100644
index 00000000..6a657a99
--- /dev/null
+++ b/examples/plugin_skip_default_rc.py
@@ -0,0 +1,9 @@
+# This plugin inhibits the loading of the default rc.conf.  This serves to
+# speed up starting time by avoiding to load rc.conf twice if you have a full
+# copy of it in ~/.config/ranger.
+#
+# Don't use this if you have a supplementary rc.conf or no rc.conf at all, or
+# you will end up without key bindings and options.
+
+import ranger.core.main
+ranger.core.main.load_default_config = False
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 962b9fd1..4a2bb912 100644
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -387,13 +387,7 @@ class set_(Command):
 	def execute(self):
 		name = self.arg(1)
 		name, value, _ = self.parse_setting_line()
-		if name and value:
-			from re import compile as regexp
-			try:
-				value = eval(value)
-			except:
-				pass
-			self.fm.settings[name] = value
+		self.fm.set_option_from_string(name, value)
 
 	def tab(self):
 		name, value, name_done = self.parse_setting_line()
diff --git a/ranger/config/options.py b/ranger/config/options.py
deleted file mode 100644
index a401abc5..00000000
--- a/ranger/config/options.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2009, 2010, 2011  Roman Zimbelmann <romanz@lavabit.com>
-# This configuration file is licensed under the same terms as ranger.
-# ===================================================================
-# This is the main configuration file of ranger.  It consists of python
-# code, but fear not, you don't need any python knowledge for changing
-# the settings.
-#
-# Lines beginning with # are comments.  To enable a line, remove the #.
-#
-# You can customize ranger in the file ~/.config/ranger/options.py.
-# It has the same syntax as this file.  In fact, you can just copy this
-# file there with `ranger --copy-config=options' and make your modifications.
-# But make sure you update your configs when you update ranger.
-# ===================================================================
-
-# Load the deault rc.conf file?  If you've copied it to your configuration
-# direcory, then you should deactivate this option.
-load_default_rc = True
-
-# How many columns are there, and what are their relative widths?
-column_ratios = (1, 3, 4)
-
-# Which files should be hidden?  Toggle this by typing `zh' or
-# changing the setting `show_hidden'
-hidden_filter = r'^\.|\.(?:pyc|pyo|bak|swp)$|^lost\+found$|^__(py)?cache__$'
-show_hidden = False
-
-# Which script is used to generate file previews?
-# ranger ships with scope.sh, a script that calls external programs (see
-# README for dependencies) to preview images, archives, etc.
-preview_script = '~/.config/ranger/scope.sh'
-
-# Use that external preview script or display internal plain text previews?
-use_preview_script = True
-
-# Use a unicode "..." character to mark cut-off filenames?
-unicode_ellipsis = False
-
-# Show dotfiles in the bookmark preview box?
-show_hidden_bookmarks = True
-
-# Which colorscheme to use?  These colorschemes are available by default:
-# default, default88, jungle, snow
-# Snow is monochrome and default88 uses 88 colors.
-colorscheme = 'default'
-
-# Preview files on the rightmost column?
-# And collapse (shrink) the last column if there is nothing to preview?
-preview_files = True
-preview_directories = True
-collapse_preview = True
-
-# Save the console history on exit?
-save_console_history = True
-
-# Draw a progress bar in the status bar which displays the average state of all
-# currently running tasks which support progress bars?
-draw_progress_bar_in_status_bar = True
-
-# Draw borders around columns?
-draw_borders = False
-draw_bookmark_borders = True
-
-# Display the directory name in tabs?
-dirname_in_tabs = False
-
-# Enable the mouse support?
-mouse_enabled = True
-
-# Display the file size in the main column or status bar?
-display_size_in_main_column = True
-display_size_in_status_bar = False
-
-# Display files tags in all columns or only in main column?
-display_tags_in_all_columns = True
-
-# Set a title for the window?
-update_title = True
-
-# Shorten the title if it gets long?  The number defines how many
-# directories are displayed at once, False turns off this feature.
-shorten_title = 3
-
-# Abbreviate $HOME with ~ in the titlebar (first line) of ranger?
-tilde_in_titlebar = True
-
-# How many directory-changes or console-commands should be kept in history?
-max_history_size = 20
-max_console_history_size = 50
-
-# Try to keep so much space between the top/bottom border when scrolling:
-scroll_offset = 8
-
-# Flush the input after each key hit?  (Noticable when ranger lags)
-flushinput = True
-
-# Padding on the right when there's no preview?
-# This allows you to click into the space to run the file.
-padding_right = True
-
-# Save bookmarks (used with mX and `X) instantly?
-# This helps to synchronize bookmarks between multiple ranger
-# instances but leads to *slight* performance loss.
-# When false, bookmarks are saved when ranger is exited.
-autosave_bookmarks = True
-
-# You can display the "real" cumulative size of directories by using the
-# command :get_cumulative_size or typing "dc".  The size is expensive to
-# calculate and will not be updated automatically.  You can choose
-# to update it automatically though by turning on this option:
-autoupdate_cumulative_size = False
-
-# Makes sense for screen readers:
-show_cursor = False
-
-# One of: size, basename, mtime, type
-sort = 'natural'
-sort_reverse = False
-sort_case_insensitive = True
-sort_directories_first = True
-
-# Enable this if key combinations with the Alt Key don't work for you.
-# (Especially on xterm)
-xterm_alt_key = False
-
-# A function that is called when the user interface is being set up.
-init_function = None
-
-# You can use it to initialize some custom functionality or bind singals
-#def init_function(fm):
-#	fm.notify("Hello :)")
-#	def on_tab_change(signal):
-#		signal.origin.notify("Changing tab! Yay!")
-#	fm.signal_bind("tab.change", on_tab_change)
-
-# The color scheme overlay.  Explained below.
-colorscheme_overlay = None
-
-## Apply an overlay function to the colorscheme.  It will be called with
-## 4 arguments: the context and the 3 values (fg, bg, attr) returned by
-## the original use() function of your colorscheme.  The return value
-## must be a 3-tuple of (fg, bg, attr).
-## Note: Here, the colors/attributes aren't directly imported into
-## the namespace but have to be accessed with color.xyz.
-
-#from ranger.gui import color
-#def colorscheme_overlay(context, fg, bg, attr):
-#	if context.directory and attr & color.bold and \
-#			not any((context.marked, context.selected)):
-#		attr ^= color.bold  # I don't like bold directories!
-#
-#	if context.main_column and context.selected:
-#		fg, bg = color.red, color.default  # To highlight the main column!
-#
-#	return fg, bg, attr
-
-
-# ===================================================================
-# Beware: from here on, you are on your own.  This part requires python
-# knowledge.
-#
-# Since python is a dynamic language, it gives you the power to replace any
-# part of ranger without touching the code.  This is commonly referred to as
-# Monkey Patching and can be helpful if you, for some reason, don't want to
-# modify rangers code directly.  Just remember: the more you mess around, the
-# more likely it is to break when you switch to another version.
-#
-# Here are some practical examples of monkey patching.
-#
-# Technical information:  This file is imported as a python module.  If a
-# variable has the name of a setting, ranger will attempt to use it to change
-# that setting.  You can write "del <variable-name>" to avoid that.
-# ===================================================================
-# Add a new sorting algorithm: Random sort.
-# Enable this with :set sort=random
-
-#from ranger.fsobject.directory import Directory
-#from random import random
-#Directory.sort_dict['random'] = lambda path: random()
-
-# ===================================================================
-# A function that changes which files are displayed.  This is more powerful
-# than the hidden_filter setting since this function has more information.
-
-## Save the original filter function
-#import ranger.fsobject.directory
-#old_accept_file = ranger.fsobject.directory.accept_file
-#
-## Define a new one
-#def accept_file_MOD(fname, mypath, hidden_filter, name_filter):
-#	if hidden_filter and mypath == '/' and fname in ('boot', 'sbin', 'proc', 'sys'):
-#		return False
-#	else:
-#		return old_accept_file(fname, mypath, hidden_filter, name_filter)
-#
-## Overwrite the old function
-#import ranger.fsobject.directory
-#ranger.fsobject.directory.accept_file = accept_file_MOD
-
-# ===================================================================
-# A function that adds an additional macro.  Test this with :shell -p echo %date
-
-## Save the original macro function
-#import ranger.core.actions
-#old_get_macros = ranger.core.actions.Actions._get_macros
-#
-## Define a new macro function
-#import time
-#def get_macros_MOD(self):
-#	macros = old_get_macros(self)
-#	macros['date'] = time.strftime('%m/%d/%Y')
-#	return macros
-#
-## Overwrite the old one
-#ranger.core.actions.Actions._get_macros = get_macros_MOD
diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf
index 1b344465..2a6be5d8 100644
--- a/ranger/config/rc.conf
+++ b/ranger/config/rc.conf
@@ -8,9 +8,9 @@
 #
 #     load_default_rc = False
 #
-# The purpose of this file is mainly to define keybindings.  For
-# changing settings or running more complex python code, use the
-# configuation file "options.py" or define commands in "commands.py".
+# The purpose of this file is mainly to define keybindings and settings.
+# For running more complex python code, please create a plugin in "plugins/" or
+# a command in "commands.py".
 #
 # Each line is a command that will be run before the user interface
 # is initialized.  As a result, you can not use commands which rely
@@ -18,6 +18,119 @@
 # ===================================================================
 
 # ===================================================================
+# == Options
+# ===================================================================
+
+# How many columns are there, and what are their relative widths?
+set column_ratios 1,3,4
+
+# Which files should be hidden? (regular expression)
+set hidden_filter ^\.|\.(?:pyc|pyo|bak|swp)$|^lost\+found$|^__(py)?cache__$
+
+# Show hidden files? You can toggle this by typing 'zh'
+set show_hidden false
+
+# Which script is used to generate file previews?
+# ranger ships with scope.sh, a script that calls external programs (see
+# README for dependencies) to preview images, archives, etc.
+set preview_script ~/.config/ranger/scope.sh
+
+# Use the external preview script or display simple plain text previews?
+set use_preview_script true
+
+# Use a unicode "..." character to mark cut-off filenames?
+set unicode_ellipsis false
+
+# Show dotfiles in the bookmark preview box?
+set show_hidden_bookmarks true
+
+# Which colorscheme to use?  These colorschemes are available by default:
+# default, default88, jungle, snow
+# Snow is monochrome and default88 uses 88 colors.
+set colorscheme default
+
+# Preview files on the rightmost column?
+# And collapse (shrink) the last column if there is nothing to preview?
+set preview_files true
+set preview_directories true
+set collapse_preview true
+
+# Save the console history on exit?
+set save_console_history true
+
+# Draw a progress bar in the status bar which displays the average state of all
+# currently running tasks which support progress bars?
+set draw_progress_bar_in_status_bar True
+
+# Draw borders around columns?
+set draw_borders false
+
+# Display the directory name in tabs?
+set dirname_in_tabs false
+
+# Enable the mouse support?
+set mouse_enabled true
+
+# Display the file size in the main column or status bar?
+set display_size_in_main_column true
+set display_size_in_status_bar true
+
+# Display files tags in all columns or only in main column?
+set display_tags_in_all_columns true
+
+# Set a title for the window?
+set update_title false
+
+# Shorten the title if it gets long?  The number defines how many
+# directories are displayed at once, False turns off this feature.
+set shorten_title 3
+
+# Abbreviate $HOME with ~ in the titlebar (first line) of ranger?
+set tilde_in_titlebar false
+
+# How many directory-changes or console-commands should be kept in history?
+set max_history_size 20
+set max_console_history_size 50
+
+# Try to keep so much space between the top/bottom border when scrolling:
+set scroll_offset 8
+
+# Flush the input after each key hit?  (Noticable when ranger lags)
+set flushinput true
+
+# Padding on the right when there's no preview?
+# This allows you to click into the space to run the file.
+set padding_right true
+
+# Save bookmarks (used with mX and `X) instantly?
+# This helps to synchronize bookmarks between multiple ranger
+# instances but leads to *slight* performance loss.
+# When false, bookmarks are saved when ranger is exited.
+set autosave_bookmarks true
+
+# You can display the "real" cumulative size of directories by using the
+# command :get_cumulative_size or typing "dc".  The size is expensive to
+# calculate and will not be updated automatically.  You can choose
+# to update it automatically though by turning on this option:
+set autoupdate_cumulative_size false
+
+# Turning this on makes sense for screen readers:
+set show_cursor false
+
+# One of: size, basename, mtime, type
+set sort natural
+
+# Additional sorting options
+set sort_reverse false
+set sort_case_insensitive true
+set sort_directories_first true
+
+# Enable this if key combinations with the Alt Key don't work for you.
+# (Especially on xterm)
+set xterm_alt_key true
+
+
+# ===================================================================
 # == Command Aliases in the Console
 # ===================================================================
 
diff --git a/ranger/container/history.py b/ranger/container/history.py
index 8ba092bc..d0e077aa 100644
--- a/ranger/container/history.py
+++ b/ranger/container/history.py
@@ -33,7 +33,7 @@ class History(object):
 			if self._history and self._history[-1] == item:
 				del self._history[-1]
 		# Remove first if list is too long
-		if len(self._history) > self.maxlen - 1:
+		if len(self._history) > max(self.maxlen - 1, 0):
 			del self._history[0]
 		# Append the item and fast forward
 		self._history.append(item)
diff --git a/ranger/container/settingobject.py b/ranger/container/settingobject.py
index f70361b5..ed9ab1ea 100644
--- a/ranger/container/settingobject.py
+++ b/ranger/container/settingobject.py
@@ -4,12 +4,12 @@
 from inspect import isfunction
 from ranger.ext.signals import SignalDispatcher
 from ranger.core.shared import FileManagerAware
+import re
 
 ALLOWED_SETTINGS = {
 	'autosave_bookmarks': bool,
 	'autoupdate_cumulative_size': bool,
 	'collapse_preview': bool,
-	'colorscheme_overlay': (type(None), type(lambda:0)),
 	'colorscheme': str,
 	'column_ratios': (tuple, list),
 	'dirname_in_tabs': bool,
@@ -20,9 +20,7 @@ ALLOWED_SETTINGS = {
 	'draw_borders': bool,
 	'draw_progress_bar_in_status_bar': bool,
 	'flushinput': bool,
-	'hidden_filter': lambda x: isinstance(x, str) or hasattr(x, 'match'),
-	'init_function': (type(None), type(lambda:0)),
-	'load_default_rc': (bool, type(None)),
+	'hidden_filter': (str, type(re.compile(""))), #XXX
 	'max_console_history_size': (int, type(None)),
 	'max_history_size': (int, type(None)),
 	'mouse_enabled': bool,
@@ -32,7 +30,7 @@ ALLOWED_SETTINGS = {
 	'padding_right': bool,
 	'save_console_history': bool,
 	'scroll_offset': int,
-	'shorten_title': int,  # Note: False is an instance of int
+	'shorten_title': int,  # XXX Note: False is an instance of int
 	'show_cursor': bool,
 	'show_hidden_bookmarks': bool,
 	'show_hidden': bool,
@@ -47,6 +45,13 @@ ALLOWED_SETTINGS = {
 	'xterm_alt_key': bool,
 }
 
+DEFAULT_VALUES = {
+	bool: False,
+	type(None): None,
+	str: "",
+	int: 0,
+	list: [],
+}
 
 class SettingObject(SignalDispatcher, FileManagerAware):
 	def __init__(self):
@@ -63,10 +68,11 @@ class SettingObject(SignalDispatcher, FileManagerAware):
 		else:
 			assert name in ALLOWED_SETTINGS, "No such setting: {0}!".format(name)
 			if name not in self._settings:
-				getattr(self, name)
+				previous = None
+			else:
+				previous=self._settings[name]
 			assert self._check_type(name, value)
-			kws = dict(setting=name, value=value,
-					previous=self._settings[name], fm=self.fm)
+			kws = dict(setting=name, value=value, previous=previous, fm=self.fm)
 			self.signal_emit('setopt', **kws)
 			self.signal_emit('setopt.'+name, **kws)
 
@@ -78,14 +84,8 @@ class SettingObject(SignalDispatcher, FileManagerAware):
 		try:
 			return self._settings[name]
 		except:
-			for struct in self._setting_sources:
-				try: value = getattr(struct, name)
-				except: pass
-				else: break
-			else:
-				raise Exception("The option `{0}' was not defined" \
-						" in the defaults!".format(name))
-			assert self._check_type(name, value)
+			type_ = self.types_of(name)[0]
+			value = DEFAULT_VALUES[type_]
 			self._raw_set(name, value)
 			self.__setattr__(name, value)
 			return self._settings[name]
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index cbe74132..6df73cdf 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -23,6 +23,7 @@ from ranger.core.shared import FileManagerAware, EnvironmentAware, \
 from ranger.core.tab import Tab
 from ranger.fsobject import File
 from ranger.core.loader import CommandLoader, CopyLoader
+from ranger.container.settingobject import ALLOWED_SETTINGS
 
 MACRO_FAIL = "<\x01\x01MACRO_HAS_NO_VALUE\x01\01>"
 
@@ -66,6 +67,34 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		self.mode = mode
 		self.ui.status.request_redraw()
 
+	def set_option_from_string(self, option_name, value):
+		if option_name not in ALLOWED_SETTINGS:
+			raise ValueError("The option named `%s' does not exist" %
+					option_name)
+		if not isinstance(value, str):
+			raise ValueError("The value for an option needs to be a string.")
+		self.settings[option_name] = self._parse_option_value(option_name, value)
+
+	def _parse_option_value(self, name, value):
+		types = self.fm.settings.types_of(name)
+		if bool in types:
+			if value.lower() in ('false', 'off', '0'):
+				return False
+			elif value.lower() in ('true', 'on', '1'):
+				return True
+		if type(None) in types and value.lower() == 'none':
+			return None
+		if int in types:
+			try:
+				return int(value)
+			except ValueError:
+				pass
+		if str in types:
+			return value
+		if list in types:
+			return value.split(',')
+		raise ValueError("Invalid value `%s' for option `%s'!" % (name, value))
+
 	def toggle_visual_mode(self, reverse=False):
 		if self.mode == 'normal':
 			self._visual_reverse = reverse
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index f554ab1b..b32e5730 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -28,6 +28,9 @@ from ranger.ext.signals import SignalDispatcher
 from ranger import __version__
 from ranger.core.loader import Loader
 
+def init_hook():
+	pass
+
 class FM(Actions, SignalDispatcher):
 	input_blocked = False
 	input_blocked_until = 0
@@ -123,8 +126,7 @@ class FM(Actions, SignalDispatcher):
 			self.notify(text, bad=True)
 		self.run = Runner(ui=self.ui, logfunc=mylogfunc, fm=self)
 
-		if self.settings.init_function:
-			self.settings.init_function(self)
+		init_hook()
 
 	def destroy(self):
 		debug = ranger.arg.debug
@@ -185,14 +187,11 @@ class FM(Actions, SignalDispatcher):
 			copy('config/commands.py', 'commands.py')
 		if which == 'rc' or which == 'all':
 			copy('config/rc.conf', 'rc.conf')
-		if which == 'options' or which == 'all':
-			copy('config/options.py', 'options.py')
 		if which == 'scope' or which == 'all':
 			copy('data/scope.sh', 'scope.sh')
 			os.chmod(self.confpath('scope.sh'),
 				os.stat(self.confpath('scope.sh')).st_mode | stat.S_IXUSR)
-		if which not in \
-				('all', 'rifle', 'scope', 'commands', 'rc', 'options'):
+		if which not in ('all', 'rifle', 'scope', 'commands', 'rc'):
 			sys.stderr.write("Unknown config file `%s'\n" % which)
 
 	def confpath(self, *paths):
diff --git a/ranger/core/main.py b/ranger/core/main.py
index c3a3d76b..df2a922e 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -6,12 +6,14 @@ The main function responsible to initialize the FM object and stuff.
 """
 
 import os.path
+import sys
+
+load_default_config = True
 
 def main():
 	"""initialize objects and run the filemanager"""
 	import locale
 	import ranger
-	import sys
 	from ranger.core.shared import FileManagerAware, SettingsAware
 	from ranger.core.fm import FM
 
@@ -181,7 +183,7 @@ def parse_arguments():
 			help="don't touch/require any config files. ")
 	parser.add_option('--copy-config', type='string', metavar='which',
 			help="copy the default configs to the local config directory. "
-			"Possible values: all, rc, rifle, commands, options, scope")
+			"Possible values: all, rc, rifle, commands, scope")
 	parser.add_option('--fail-unless-cd', action='store_true',
 			help="experimental: return the exit code 1 if ranger is" \
 					"used to run a file (with `ranger filename`)")
@@ -225,6 +227,7 @@ def parse_arguments():
 
 
 def load_settings(fm, clean):
+	global load_default_config
 	from ranger.core.actions import Actions
 	import ranger.core.shared
 	import ranger.api.commands
@@ -250,9 +253,8 @@ def load_settings(fm, clean):
 		# Load rc.conf
 		custom_conf = fm.confpath('rc.conf')
 		default_conf = fm.relpath('config', 'rc.conf')
-		load_default_rc = fm.settings.load_default_rc
 
-		if load_default_rc:
+		if load_default_config:
 			fm.source(default_conf)
 		if os.access(custom_conf, os.R_OK):
 			fm.source(custom_conf)
@@ -281,6 +283,27 @@ def load_settings(fm, clean):
 						fm.log.append(line)
 			ranger.fm = None
 
+		# COMPAT: Load the outdated options.py
+		# options.py[oc] are deliberately ignored
+		if os.path.exists(fm.confpath("options.py")):  
+			module = __import__('options')
+			from ranger.container.settingobject import ALLOWED_SETTINGS
+			for setting in ALLOWED_SETTINGS:
+				if hasattr(module, setting):
+					fm.settings[setting] = getattr(module, setting)
+
+			sys.stderr.write(
+"""******************************
+Warning: The configuration file 'options.py' is deprecated.
+Please move all settings to the file 'rc.conf', converting lines like
+    "preview_files = False"
+to
+    "set preview_files false"
+If you had python code in the options.py that you'd like to keep, simply
+copy & paste it to a .py file in ~/.config/ranger/plugins/.
+Remove the options.py or discard stderr to get rid of this warning.
+******************************\n""")
+
 		allow_access_to_confdir(ranger.arg.confdir, False)
 	else:
 		fm.source(fm.relpath('config', 'rc.conf'))
diff --git a/ranger/core/shared.py b/ranger/core/shared.py
index 26023e43..ec791f22 100644
--- a/ranger/core/shared.py
+++ b/ranger/core/shared.py
@@ -43,6 +43,9 @@ class SettingsAware(Awareness):
 		settings.signal_bind('setopt.colorscheme',
 				_colorscheme_name_to_class, priority=1)
 
+		settings.signal_bind('setopt.column_ratios',
+				_sanitize_setting_column_ratios, priority=1)
+
 		def after_setting_preview_script(signal):
 			if isinstance(signal.value, str):
 				signal.value = os.path.expanduser(signal.value)
@@ -71,9 +74,12 @@ class SettingsAware(Awareness):
 				settings._setting_sources.append(my_options)
 			del sys.path[0]
 
-		from ranger.config 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
+
+def _sanitize_setting_column_ratios(signal):
+	if isinstance(signal.value, tuple):
+		signal.value = list(signal.value)
+	if not isinstance(signal.value, list) or len(signal.value) < 2:
+		signal.value = [1,1]
+	else:
+		signal.value = [int(i) if str(i).isdigit() else 1 for i in signal.value]
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index b36048e2..34e59f55 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -33,23 +33,18 @@ import ranger
 from ranger.gui.color import get_color
 from ranger.gui.context import Context
 from ranger.core.main import allow_access_to_confdir
-from ranger.core.shared import SettingsAware
 from ranger.ext.cached_function import cached_function
 from ranger.ext.iter_tools import flatten
 
-# ColorScheme is not SettingsAware but it will gain access
-# to the settings during the initialization.  We can't import
-# SettingsAware here because of circular imports.
-
-class ColorScheme(SettingsAware):
+class ColorScheme(object):
 	"""
 	This is the class that colorschemes must inherit from.
 
-	it defines get() 
 	it defines the get() method, which returns the color tuple
 	which fits to the given keys.
 	"""
 
+	@cached_function
 	def get(self, *keys):
 		"""
 		Returns the (fg, bg, attr) for the given keys.
@@ -58,17 +53,11 @@ class ColorScheme(SettingsAware):
 		colors for faster access.
 		"""
 		context = Context(keys)
-
-		# add custom error messages for broken colorschemes
 		color = self.use(context)
-		if self.settings.colorscheme_overlay:
-			result = self.settings.colorscheme_overlay(context, *color)
-			assert isinstance(result, (tuple, list)), \
-					"Your colorscheme overlay doesn't return a tuple!"
-			assert all(isinstance(val, int) for val in result), \
-					"Your colorscheme overlay doesn't return a tuple"\
-					" containing 3 integers!"
-			color = result
+		if len(color) != 3 or not all(isinstance(value, int) \
+				for value in color):
+			raise ValueError("Bad Value from colorscheme.  Need "
+				"a tuple of (foreground_color, background_color, attribute).")
 		return color
 
 	@cached_function
@@ -82,7 +71,8 @@ class ColorScheme(SettingsAware):
 		return attr | color_pair(get_color(fg, bg))
 
 	def use(self, context):
-		"""Use the colorscheme to determine the (fg, bg, attr) tuple.
+		"""
+		Use the colorscheme to determine the (fg, bg, attr) tuple.
 
 		Override this method in your own colorscheme.
 		"""
@@ -95,6 +85,9 @@ def _colorscheme_name_to_class(signal):
 	# is picked.
 	if isinstance(signal.value, ColorScheme): return
 
+	if not signal.value:
+		signal.value = 'default'
+
 	scheme_name = signal.value
 	usecustom = not ranger.arg.clean