diff --git a/alot/commands/globals.py b/alot/commands/globals.py index aa1fd4368..429b314e3 100644 --- a/alot/commands/globals.py +++ b/alot/commands/globals.py @@ -35,6 +35,7 @@ from ..settings.const import settings from ..settings.errors import ConfigError, NoMatchingAccount from ..utils import argparse as cargparse +from ..settings.theme import Theme MODE = 'global' @@ -1088,6 +1089,42 @@ def apply(self, ui): ui.notify('Error when reloading config files:\n {}'.format(e), priority='error') +@registerCommand(MODE, 'theme', arguments=[ + (['theme_name'], {'help': 'Name of the theme'})], help='Select your own them') +class ThemeCommand(Command): + + """move in widget""" + def __init__(self, theme_name=None, **kwargs): + self.theme = theme_name + # if movement is None: + # self.movement = '' + # else: + # self.movement = ' '.join(movement) + Command.__init__(self, **kwargs) + + """Reload configuration.""" + def apply(self, ui): + # theme = matt + + try: + themes_dir = settings._config.get('themes_dir') + + theme_path = Theme.find(self.theme, themes_dir) + if theme_path is None: + # theme.find_theme() + raise ConfigError('Could not find theme {}, see log for more ' + 'information'.format(self.theme)) + + settings._theme = Theme(theme_path) + logging.info("Applied theme %s", theme_path) + ui.current_buffer.rebuild() + + ui.update() + + except ConfigError as e: + ui.notify('Error when loading theme:\n {}'.format(e), + priority='error') + @registerCommand( MODE, 'savequery', diff --git a/alot/helper.py b/alot/helper.py index fca49ec6c..772cd3d95 100644 --- a/alot/helper.py +++ b/alot/helper.py @@ -22,7 +22,6 @@ import urwid import magic - def split_commandline(s): """ splits semi-colon separated commandlines, ignoring quoted separators @@ -616,3 +615,11 @@ def get_notmuch_config_path(): if profile: profile = '.' + profile return os.path.expanduser('~/.notmuch-config' + profile) + +# DATA_DIRS = get_xdg_env('XDG_DATA_DIRS', +# '/usr/local/share:/usr/share').split(':') + +def get_xdg_data_dirs(): + return get_xdg_env('XDG_DATA_DIRS', + '/usr/local/share:/usr/share').split(':') + diff --git a/alot/settings/manager.py b/alot/settings/manager.py index d9fa724db..664c5ea59 100644 --- a/alot/settings/manager.py +++ b/alot/settings/manager.py @@ -13,7 +13,7 @@ from ..account import SendmailAccount from ..addressbook.abook import AbookAddressBook from ..addressbook.external import ExternalAddressbook -from ..helper import pretty_datetime, string_decode, get_xdg_env +from ..helper import pretty_datetime, string_decode, get_xdg_env, get_xdg_data_dirs from ..utils import configobj as checks from .errors import ConfigError, NoMatchingAccount @@ -23,8 +23,6 @@ DEFAULTSPATH = os.path.join(os.path.dirname(__file__), '..', 'defaults') -DATA_DIRS = get_xdg_env('XDG_DATA_DIRS', - '/usr/local/share:/usr/share').split(':') class SettingsManager: @@ -96,28 +94,17 @@ def read_config(self, path): logging.debug('themes directory: `%s`' % themes_dir) # if config contains theme string use that - data_dirs = [os.path.join(d, 'alot/themes') for d in DATA_DIRS] if themestring: - # This is a python for/else loop - # https://docs.python.org/3/reference/compound_stmts.html#for - # - # tl/dr; If the loop loads a theme it breaks. If it doesn't break, - # then it raises a ConfigError. - for dir_ in itertools.chain([themes_dir], data_dirs): - theme_path = os.path.join(dir_, themestring) - if not os.path.exists(os.path.expanduser(theme_path)): - logging.warning('Theme `%s` does not exist.', theme_path) - else: - try: - self._theme = Theme(theme_path) - except ConfigError as e: - raise ConfigError('Theme file `%s` failed ' - 'validation:\n%s' % (theme_path, e)) - else: - break - else: - raise ConfigError('Could not find theme {}, see log for more ' - 'information'.format(themestring)) + try: + theme_path = Theme.find(themestring, themes_dir) + self._theme = Theme(theme_path) + except ConfigError as e: + raise ConfigError('Theme file `%s` failed ' + 'validation:\n%s' % (path, e)) + + # else: + # raise ConfigError('Could not find theme {}, see log for more ' + # 'information'.format(themestring)) # if still no theme is set, resort to default if self._theme is None: diff --git a/alot/settings/theme.py b/alot/settings/theme.py index 2794be2c4..51f1d34b3 100644 --- a/alot/settings/theme.py +++ b/alot/settings/theme.py @@ -2,14 +2,19 @@ # This file is released under the GNU GPL, version 3 or a later revision. # For further details see the COPYING file import os +import logging +import itertools from ..utils import configobj as checks from .utils import read_config from .errors import ConfigError +from ..helper import get_xdg_data_dirs DEFAULTSPATH = os.path.join(os.path.dirname(__file__), '..', 'defaults') DUMMYDEFAULT = ('default',) * 6 +# TODO share this one from utils maybe ? + class Theme: """Colour theme""" @@ -20,11 +25,45 @@ def __init__(self, path): :raises: :class:`~alot.settings.errors.ConfigError` """ self._spec = os.path.join(DEFAULTSPATH, 'theme.spec') + logging.debug("Loading theme spec %s", self._spec) + + self._colours = [1, 16, 256] + + # path = self.find(theme_name) + # if path is not None: + # return Theme(theme_path) + self._load_theme(path) + # else: + # raise ConfigError('Could not find theme {}, see log for more ' + # 'information'.format(theme_name)) + + + """Returns (Boolean, abspath)""" + @staticmethod + # def exists(themestring): + def find(themestring: str, themes_dir=None): + # This is a python for/else loop + # https://docs.python.org/3/reference/compound_stmts.html#for + # + # tl/dr; If the loop loads a theme it breaks. If it doesn't break, + # then it raises a ConfigError. + + data_dirs = [os.path.join(d, 'alot/themes') for d in get_xdg_data_dirs()] + + for dir_ in itertools.chain([themes_dir] if themes_dir else [], data_dirs): + theme_path = os.path.join(dir_, themestring) + if not os.path.exists(os.path.expanduser(theme_path)): + logging.warning('Theme `%s` does not exist.', theme_path) + else: + return theme_path + + def _load_theme(self, path): self._config = read_config(path, self._spec, report_extra=True, checks={'align': checks.align_mode, 'widthtuple': checks.width_tuple, 'force_list': checks.force_list, 'attrtriple': checks.attr_triple}) + logging.info("TOTO", self._config) self._colours = [1, 16, 256] # make sure every entry in 'order' lists have their own subsections threadline = self._config['search']['threadline'] diff --git a/alot/settings/utils.py b/alot/settings/utils.py index 65942aff6..43d66335c 100644 --- a/alot/settings/utils.py +++ b/alot/settings/utils.py @@ -32,14 +32,16 @@ def read_config(configpath=None, specpath=None, checks=None, try: config = ConfigObj(infile=configpath, configspec=specpath, - file_error=True, encoding='UTF8') + raise_errors = True, + file_error=True, encoding='UTF8') except ConfigObjError as e: msg = 'Error when parsing `%s`:\n%s' % (configpath, e) logging.error(msg) raise ConfigError(msg) - except IOError: - raise ConfigError('Could not read %s and/or %s' - % (configpath, specpath)) + except IOError as e: + raise e + # print(e) + # raise ConfigError('Could not read %s and/or %s' % (configpath, specpath)) except UnboundLocalError: # this works around a bug in configobj msg = '%s is malformed. Check for sections without parents..'