diff options
Diffstat (limited to 'ranger/shared/settings.py')
-rw-r--r-- | ranger/shared/settings.py | 176 |
1 files changed, 96 insertions, 80 deletions
diff --git a/ranger/shared/settings.py b/ranger/shared/settings.py index cdddd623..a4a58e6e 100644 --- a/ranger/shared/settings.py +++ b/ranger/shared/settings.py @@ -13,22 +13,25 @@ # 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 os -import types -from inspect import isclass, ismodule import ranger +from ranger.ext.signal_dispatcher import SignalDispatcher from ranger.ext.openstruct import OpenStruct -from ranger.gui.colorscheme import ColorScheme ALLOWED_SETTINGS = { 'show_hidden': bool, 'show_cursor': bool, 'autosave_bookmarks': bool, + 'save_console_history': bool, 'collapse_preview': bool, + 'column_ratios': (tuple, list, set), + 'display_size_in_main_column': bool, + 'display_size_in_status_bar': bool, 'draw_borders': bool, + 'draw_bookmark_borders': bool, 'sort': str, - 'reverse': bool, - 'directories_first': bool, + 'sort_reverse': bool, + 'sort_case_insensitive': bool, + 'sort_directories_first': bool, 'update_title': bool, 'shorten_title': int, # Note: False is an instance of int 'max_filesize_for_preview': (int, type(None)), @@ -38,26 +41,88 @@ ALLOWED_SETTINGS = { 'preview_directories': bool, 'flushinput': bool, 'colorscheme': str, + 'colorscheme_overlay': (type(None), type(lambda:0)), 'hidden_filter': lambda x: isinstance(x, str) or hasattr(x, 'match'), } + +COMPAT_MAP = { + 'sort_reverse': 'reverse', + 'sort_directories_first': 'directories_first', +} + + +class SettingObject(SignalDispatcher): + def __init__(self): + SignalDispatcher.__init__(self) + self.__dict__['_settings'] = dict() + self.__dict__['_setting_sources'] = list() + + def __setattr__(self, name, value): + if name[0] == '_': + self.__dict__[name] = value + else: + assert name in self._settings, "No such setting: {0}!".format(name) + assert self._check_type(name, value) + kws = dict(setting=name, value=value, + previous=self._settings[name]) + self.signal_bind('setopt.'+name, + self._raw_set_with_signal, priority=0.2) + self.signal_emit('setopt', **kws) + self.signal_emit('setopt.'+name, **kws) + + def __getattr__(self, name): + assert name in ALLOWED_SETTINGS or name in self._settings, \ + "No such setting: {0}!".format(name) + 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) + self._raw_set(name, value) + self.__setattr__(name, value) + return self._settings[name] + + def _check_type(self, name, value): + from inspect import isfunction + typ = ALLOWED_SETTINGS[name] + if isfunction(typ): + assert typ(value), \ + "The option `" + name + "' has an incorrect type!" + else: + assert isinstance(value, typ), \ + "The option `" + name + "' has an incorrect type!"\ + " Got " + str(type(value)) + ", expected " + str(typ) + "!" + return True + + __getitem__ = __getattr__ + __setitem__ = __setattr__ + + def _raw_set(self, name, value): + self._settings[name] = value + + 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 = OpenStruct() + settings = SettingObject() - from ranger.defaults import options - for setting in ALLOWED_SETTINGS: - try: - settings[setting] = getattr(options, setting) - except AttributeError: - raise Exception("The option `{0}' was not defined" \ - " in the defaults!".format(setting)) + from ranger.gui.colorscheme import _colorscheme_name_to_class + settings.signal_bind('setopt.colorscheme', + _colorscheme_name_to_class, priority=1) - import sys if not ranger.arg.clean: # overwrite single default options with custom options try: @@ -65,83 +130,34 @@ class SettingsAware(object): except ImportError: pass else: - for setting in ALLOWED_SETTINGS: + settings._setting_sources.append(my_options) + + # For backward compatibility: + for new, old in COMPAT_MAP.items(): try: - settings[setting] = getattr(my_options, setting) + setattr(my_options, new, getattr(my_options, old)) + print("Warning: the option `{0}'"\ + " was renamed to `{1}'\nPlease update"\ + " your configuration file soon." \ + .format(old, new)) except AttributeError: pass - assert check_option_types(settings) - - # Find the colorscheme. First look for it at ~/.ranger/colorschemes, - # then at RANGERDIR/colorschemes. If the file contains a class - # named Scheme, it is used. Otherwise, an arbitrary other class - # is picked. - - scheme_name = settings.colorscheme - - def exists(colorscheme): - return os.path.exists(colorscheme + '.py') - - def is_scheme(x): - return isclass(x) and issubclass(x, ColorScheme) - - # create ~/.ranger/colorschemes/__init__.py if it doesn't exist - if os.path.exists(ranger.relpath_conf('colorschemes')): - initpy = ranger.relpath_conf('colorschemes', '__init__.py') - if not os.path.exists(initpy): - open(initpy, 'a').close() - - if exists(ranger.relpath_conf('colorschemes', scheme_name)): - scheme_supermodule = 'colorschemes' - elif exists(ranger.relpath('colorschemes', scheme_name)): - scheme_supermodule = 'ranger.colorschemes' - else: - scheme_supermodule = None # found no matching file. - - if scheme_supermodule is None: - print("ERROR: colorscheme not found, fall back to builtin scheme") - if ranger.arg.debug: - raise Exception("Cannot locate colorscheme!") - settings.colorscheme = ColorScheme() - else: - scheme_module = getattr(__import__(scheme_supermodule, - globals(), locals(), [scheme_name], 0), scheme_name) - assert ismodule(scheme_module) - if hasattr(scheme_module, 'Scheme') \ - and is_scheme(scheme_module.Scheme): - settings.colorscheme = scheme_module.Scheme() - else: - for name, var in scheme_module.__dict__.items(): - if var != ColorScheme and is_scheme(var): - settings.colorscheme = var() - break - else: - raise Exception("The module contains no " \ - "valid colorscheme!") + 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!" try: import apps except ImportError: from ranger.defaults import apps - settings.apps = apps + settings._raw_set('apps', apps) try: import keys except ImportError: from ranger.defaults import keys - settings.keys = keys + settings._raw_set('keys', keys) SettingsAware.settings = settings - -def check_option_types(opt): - import inspect - for name, typ in ALLOWED_SETTINGS.items(): - optvalue = getattr(opt, name) - if inspect.isfunction(typ): - assert typ(optvalue), \ - "The option `" + name + "' has an incorrect type!" - else: - assert isinstance(optvalue, typ), \ - "The option `" + name + "' has an incorrect type!"\ - " Got " + str(type(optvalue)) + ", expected " + str(typ) + "!" - return True |