def load_config(cfg_path, find_config_files, config_loader, loader_callback=None): """Load configuration file and setup watches Watches are only set up if loader_callback is not None. :param str cfg_path: Path for configuration file that should be loaded. :param function find_config_files: Function that finds configuration file. Check out the description of the return value of ``generate_config_finder`` function. :param ConfigLoader config_loader: Configuration file loader class instance. :param function loader_callback: Function that will be called by config_loader when change to configuration file is detected. :return: Configuration file contents. """ found_files = find_config_files(cfg_path, config_loader, loader_callback) ret = None for path in found_files: if loader_callback: config_loader.register(loader_callback, path) if ret is None: ret = config_loader.load(path) else: mergedicts(ret, config_loader.load(path)) return ret
def mergeargs(argvalue): if not argvalue: return None r = dict([argvalue[0]]) for subval in argvalue[1:]: mergedicts(r, dict([subval])) return r
def _override_from(config, override_varname): try: overrides = vim_getvar(override_varname) except KeyError: return config mergedicts(config, overrides) return config
def mergeargs(argvalue): if not argvalue: return None r = {} for subval in argvalue: mergedicts(r, dict([subval])) return r
def load_config(cfg_path, find_config_files, config_loader, loader_callback=None): '''Load configuration file and setup watches Watches are only set up if loader_callback is not None. :param str cfg_path: Path for configuration file that should be loaded. :param function find_config_files: Function that finds configuration file. Check out the description of the return value of ``generate_config_finder`` function. :param ConfigLoader config_loader: Configuration file loader class instance. :param function loader_callback: Function that will be called by config_loader when change to configuration file is detected. :return: Configuration file contents. ''' found_files = find_config_files(cfg_path, config_loader, loader_callback) ret = None for path in found_files: if loader_callback: config_loader.register(loader_callback, path) if ret is None: ret = config_loader.load(path) else: mergedicts(ret, config_loader.load(path)) return ret
def mergeargs(argvalue): if not argvalue: return None argvalue = iter(argvalue) r = dict([next(argvalue)]) for subval in argvalue: mergedicts(r, dict([subval])) return r
def _override_from(config, override_varname): if vim_exists(override_varname): # FIXME vim.eval has problem with numeric types, vim.bindeval may be # absent (and requires converting values to python built-in types), # vim.eval with typed call like the one I implemented in frawor is slow. # Maybe eval(vime.eval('string({0})'.format(override_varname)))? overrides = vim.eval(override_varname) mergedicts(config, overrides) return config
def test_mergedicts(self): d = {} mergedicts(d, {'abc': {'def': 'ghi'}}) self.assertEqual(d, {'abc': {'def': 'ghi'}}) mergedicts(d, {'abc': {'def': {'ghi': 'jkl'}}}) self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}}}) mergedicts(d, {}) self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}}}) mergedicts(d, {'abc': {'mno': 'pqr'}}) self.assertEqual(d, {'abc': {'def': {'ghi': 'jkl'}, 'mno': 'pqr'}}) mergedicts(d, {'abc': {'def': REMOVE_THIS_KEY}}) self.assertEqual(d, {'abc': {'mno': 'pqr'}})
def test_mergedicts(self): d = {} mergedicts(d, {"abc": {"def": "ghi"}}) self.assertEqual(d, {"abc": {"def": "ghi"}}) mergedicts(d, {"abc": {"def": {"ghi": "jkl"}}}) self.assertEqual(d, {"abc": {"def": {"ghi": "jkl"}}}) mergedicts(d, {}) self.assertEqual(d, {"abc": {"def": {"ghi": "jkl"}}}) mergedicts(d, {"abc": {"mno": "pqr"}}) self.assertEqual(d, {"abc": {"def": {"ghi": "jkl"}, "mno": "pqr"}})
def add_local_theme(self, key, config): '''Add local themes at runtime (during vim session). :param str key: Matcher name (in format ``{matcher_module}.{module_attribute}`` or ``{module_attribute}`` if ``{matcher_module}`` is ``powerline.matchers.vim``). Function pointed by ``{module_attribute}`` should be hashable and accept a dictionary with information about current buffer and return boolean value indicating whether current window matched conditions. See also :ref:`local_themes key description <config-ext-local_themes>`. :param dict config: :ref:`Theme <config-themes>` dictionary. :return: ``True`` if theme was added successfully and ``False`` if theme with the same matcher already exists. ''' self.update_renderer() matcher = self.get_matcher(key) theme_config = {} for cfg_path in self.theme_levels: try: lvl_config = self.load_config(cfg_path, 'theme') except IOError: pass else: mergedicts(theme_config, lvl_config) mergedicts(theme_config, config) try: self.renderer.add_local_theme(matcher, {'config': theme_config}) except KeyError: return False else: # Hack for local themes support: when reloading modules it is not # guaranteed that .add_local_theme will be called once again, so # this function arguments will be saved here for calling from # .do_setup(). self.setup_kwargs.setdefault('_local_themes', []).append( (key, config)) return True
def load_colorscheme_config(self, name): '''Get colorscheme. :param str name: Name of the colorscheme to load. :return: dictionary with :ref:`colorscheme configuration <config-colorschemes>`. ''' # TODO Make sure no colorscheme name ends with __ (do it in # powerline-lint) levels = ( os.path.join('colorschemes', name), os.path.join('colorschemes', self.ext, '__main__'), os.path.join('colorschemes', self.ext, name), ) config = {} loaded = 0 exceptions = [] for cfg_path in levels: try: lvl_config = self._load_config(cfg_path, 'colorscheme') except IOError as e: if sys.version_info < (3,): tb = sys.exc_info()[2] exceptions.append((e, tb)) else: exceptions.append(e) else: if not cfg_path.endswith('__'): loaded += 1 # TODO Either make sure `attr` list is always present or make # mergedicts not merge group definitions. mergedicts(config, lvl_config) if not loaded: for exception in exceptions: if type(exception) is tuple: e = exception[0] else: e = exception self.exception('Failed to load colorscheme: {0}', e, exception=exception) raise e return config
def _load_hierarhical_config(self, cfg_type, levels, ignore_levels): '''Load and merge multiple configuration files :param str cfg_type: Type of the loaded configuration files (e.g. ``colorscheme``, ``theme``). :param list levels: Configuration names resembling levels in hierarchy, sorted by priority. Configuration file names with higher priority should go last. :param set ignore_levels: If only files listed in this variable are present then configuration file is considered not loaded: at least one file on the level not listed in this variable must be present. ''' config = {} loaded = 0 exceptions = [] for i, cfg_path in enumerate(levels): try: lvl_config = self.load_config(cfg_path, cfg_type) except IOError as e: if sys.version_info < (3, ): tb = sys.exc_info()[2] exceptions.append((e, tb)) else: exceptions.append(e) else: if i not in ignore_levels: loaded += 1 mergedicts(config, lvl_config) if not loaded: for exception in exceptions: if type(exception) is tuple: e = exception[0] else: e = exception self.exception('Failed to load %s: {0}' % cfg_type, e, exception=exception) raise e return config
def add_local_theme(self, key, config): """Add local themes at runtime (during vim session). :param str key: Matcher name (in format ``{matcher_module}.{module_attribute}`` or ``{module_attribute}`` if ``{matcher_module}`` is ``powerline.matchers.vim``). Function pointed by ``{module_attribute}`` should be hashable and accept a dictionary with information about current buffer and return boolean value indicating whether current window matched conditions. See also :ref:`local_themes key description <config-ext-local_themes>`. :param dict config: :ref:`Theme <config-themes>` dictionary. :return: ``True`` if theme was added successfully and ``False`` if theme with the same matcher already exists. """ self.update_renderer() matcher = self.get_matcher(key) theme_config = {} for cfg_path in self.theme_levels: try: lvl_config = self.load_config(cfg_path, "theme") except IOError: pass else: mergedicts(theme_config, lvl_config) mergedicts(theme_config, config) try: self.renderer.add_local_theme(matcher, {"config": theme_config}) except KeyError: return False else: # Hack for local themes support: when reloading modules it is not # guaranteed that .add_local_theme will be called once again, so # this function arguments will be saved here for calling from # .do_setup(). self.setup_kwargs.setdefault("_local_themes", []).append((key, config)) return True
def _load_hierarhical_config(self, cfg_type, levels, ignore_levels): """Load and merge multiple configuration files :param str cfg_type: Type of the loaded configuration files (e.g. ``colorscheme``, ``theme``). :param list levels: Configuration names resembling levels in hierarchy, sorted by priority. Configuration file names with higher priority should go last. :param set ignore_levels: If only files listed in this variable are present then configuration file is considered not loaded: at least one file on the level not listed in this variable must be present. """ config = {} loaded = 0 exceptions = [] for i, cfg_path in enumerate(levels): try: lvl_config = self.load_config(cfg_path, cfg_type) except IOError as e: if sys.version_info < (3,): tb = sys.exc_info()[2] exceptions.append((e, tb)) else: exceptions.append(e) else: if i not in ignore_levels: loaded += 1 mergedicts(config, lvl_config) if not loaded: for exception in exceptions: if type(exception) is tuple: e = exception[0] else: e = exception self.exception("Failed to load %s: {0}" % cfg_type, e, exception=exception) raise e return config
def load_theme_config(self, name): r = super(ShellPowerline, self).load_theme_config(name) if name in self.theme_option: mergedicts(r, self.theme_option[name]) return r
def load_theme_config(self, name): r = super(ShellPowerline, self).load_theme_config(name) if self.theme_option and name in self.theme_option: mergedicts(r, self.theme_option[name]) return r
def load_main_config(self): r = super(ShellPowerline, self).load_main_config() if self.args.config: mergedicts(r, self.args.config) return r
def load_theme_config(self, name): r = super(IPythonPowerline, self).load_theme_config(name) if name in self.theme_overrides: mergedicts(r, self.theme_overrides[name]) return r
def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False): '''(Re)create renderer object. Can be used after Powerline object was successfully initialized. If any of the below parameters except ``load_main`` is True renderer object will be recreated. :param bool load_main: Determines whether main configuration file (:file:`config.json`) should be loaded. If appropriate configuration changes implies ``load_colorscheme`` and ``load_theme`` and recreation of renderer object. Won’t trigger recreation if only unrelated configuration changed. :param bool load_colors: Determines whether colors configuration from :file:`colors.json` should be (re)loaded. :param bool load_colorscheme: Determines whether colorscheme configuration should be (re)loaded. :param bool load_theme: Determines whether theme configuration should be reloaded. ''' common_config_differs = False ext_config_differs = False if load_main: self._purge_configs('main') config = self.load_main_config() self.common_config = finish_common_config(self.get_encoding(), config['common']) if self.common_config != self.prev_common_config: common_config_differs = True load_theme = (load_theme or not self.prev_common_config or self.prev_common_config['default_top_theme'] != self.common_config['default_top_theme']) self.prev_common_config = self.common_config self.import_paths = self.common_config['paths'] if not self.logger: self.logger = create_logger(self.common_config, self.default_log_stream) if not self.pl: self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext) self.config_loader.pl = self.pl if not self.run_once: self.config_loader.set_watcher( self.common_config['watcher']) self.get_module_attr = gen_module_attr_getter( self.pl, self.import_paths, self.imported_modules) mergedicts( self.renderer_options, dict( pl=self.pl, term_truecolor=self.common_config['term_truecolor'], term_escape_style=self. common_config['term_escape_style'], ambiwidth=self.common_config['ambiwidth'], tmux_escape=self.common_config['additional_escapes'] == 'tmux', screen_escape=self.common_config['additional_escapes'] == 'screen', theme_kwargs={ 'ext': self.ext, 'common_config': self.common_config, 'run_once': self.run_once, 'shutdown_event': self.shutdown_event, 'get_module_attr': self.get_module_attr, }, )) if not self.run_once and self.common_config['reload_config']: interval = self.common_config['interval'] self.config_loader.set_interval(interval) self.run_loader_update = (interval is None) if interval is not None and not self.config_loader.is_alive( ): self.config_loader.start() self.ext_config = config['ext'][self.ext] top_theme = (self.ext_config.get('top_theme') or self.common_config['default_top_theme']) self.theme_levels = ( os.path.join('themes', top_theme), os.path.join('themes', self.ext, '__main__'), ) self.renderer_options['theme_kwargs']['top_theme'] = top_theme if self.ext_config != self.prev_ext_config: ext_config_differs = True if (not self.prev_ext_config or self.ext_config.get('components') != self.prev_ext_config.get('components')): self.setup_components(self.ext_config.get('components')) if (not self.prev_ext_config or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes')): self.renderer_options[ 'local_themes'] = self.get_local_themes( self.ext_config.get('local_themes')) load_colorscheme = (load_colorscheme or not self.prev_ext_config or self.prev_ext_config['colorscheme'] != self.ext_config['colorscheme']) load_theme = (load_theme or not self.prev_ext_config or self.prev_ext_config['theme'] != self.ext_config['theme']) self.prev_ext_config = self.ext_config create_renderer = load_colors or load_colorscheme or load_theme or common_config_differs or ext_config_differs if load_colors: self._purge_configs('colors') self.colors_config = self.load_colors_config() if load_colorscheme or load_colors: self._purge_configs('colorscheme') if load_colorscheme: self.colorscheme_config = self.load_colorscheme_config( self.ext_config['colorscheme']) self.renderer_options['theme_kwargs']['colorscheme'] = ( Colorscheme(self.colorscheme_config, self.colors_config)) if load_theme: self._purge_configs('theme') self.renderer_options['theme_config'] = self.load_theme_config( self.ext_config.get('theme', 'default')) if create_renderer: Renderer = self.get_module_attr(self.renderer_module, 'renderer') if not Renderer: if hasattr(self, 'renderer'): return else: raise ImportError('Failed to obtain renderer') # Renderer updates configuration file via segments’ .startup thus it # should be locked to prevent state when configuration was updated, # but .render still uses old renderer. try: renderer = Renderer(**self.renderer_options) except Exception as e: self.exception('Failed to construct renderer object: {0}', str(e)) if not hasattr(self, 'renderer'): raise else: self.renderer = renderer
def load_main_config(self): r = super(IPythonPowerline, self).load_main_config() if self.config_overrides: mergedicts(r, self.config_overrides) return r
def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False): """(Re)create renderer object. Can be used after Powerline object was successfully initialized. If any of the below parameters except ``load_main`` is True renderer object will be recreated. :param bool load_main: Determines whether main configuration file (:file:`config.json`) should be loaded. If appropriate configuration changes implies ``load_colorscheme`` and ``load_theme`` and recreation of renderer object. Won’t trigger recreation if only unrelated configuration changed. :param bool load_colors: Determines whether colors configuration from :file:`colors.json` should be (re)loaded. :param bool load_colorscheme: Determines whether colorscheme configuration should be (re)loaded. :param bool load_theme: Determines whether theme configuration should be reloaded. """ common_config_differs = False ext_config_differs = False if load_main: self._purge_configs("main") config = self.load_main_config() self.common_config = finish_common_config(self.get_encoding(), config["common"]) if self.common_config != self.prev_common_config: common_config_differs = True load_theme = ( load_theme or not self.prev_common_config or self.prev_common_config["default_top_theme"] != self.common_config["default_top_theme"] ) self.prev_common_config = self.common_config self.import_paths = self.common_config["paths"] if not self.logger: self.logger = create_logger(self.common_config, self.default_log_stream) if not self.pl: self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext) self.config_loader.pl = self.pl if not self.run_once: self.config_loader.set_watcher(self.common_config["watcher"]) self.get_module_attr = gen_module_attr_getter(self.pl, self.import_paths, self.imported_modules) mergedicts( self.renderer_options, dict( pl=self.pl, term_truecolor=self.common_config["term_truecolor"], ambiwidth=self.common_config["ambiwidth"], tmux_escape=self.common_config["additional_escapes"] == "tmux", screen_escape=self.common_config["additional_escapes"] == "screen", theme_kwargs={ "ext": self.ext, "common_config": self.common_config, "run_once": self.run_once, "shutdown_event": self.shutdown_event, "get_module_attr": self.get_module_attr, }, ), ) if not self.run_once and self.common_config["reload_config"]: interval = self.common_config["interval"] self.config_loader.set_interval(interval) self.run_loader_update = interval is None if interval is not None and not self.config_loader.is_alive(): self.config_loader.start() self.ext_config = config["ext"][self.ext] top_theme = self.ext_config.get("top_theme") or self.common_config["default_top_theme"] self.theme_levels = (os.path.join("themes", top_theme), os.path.join("themes", self.ext, "__main__")) self.renderer_options["theme_kwargs"]["top_theme"] = top_theme if self.ext_config != self.prev_ext_config: ext_config_differs = True if not self.prev_ext_config or self.ext_config.get("components") != self.prev_ext_config.get( "components" ): self.setup_components(self.ext_config.get("components")) if not self.prev_ext_config or self.ext_config.get("local_themes") != self.prev_ext_config.get( "local_themes" ): self.renderer_options["local_themes"] = self.get_local_themes(self.ext_config.get("local_themes")) load_colorscheme = ( load_colorscheme or not self.prev_ext_config or self.prev_ext_config["colorscheme"] != self.ext_config["colorscheme"] ) load_theme = ( load_theme or not self.prev_ext_config or self.prev_ext_config["theme"] != self.ext_config["theme"] ) self.prev_ext_config = self.ext_config create_renderer = load_colors or load_colorscheme or load_theme or common_config_differs or ext_config_differs if load_colors: self._purge_configs("colors") self.colors_config = self.load_colors_config() if load_colorscheme or load_colors: self._purge_configs("colorscheme") if load_colorscheme: self.colorscheme_config = self.load_colorscheme_config(self.ext_config["colorscheme"]) self.renderer_options["theme_kwargs"]["colorscheme"] = Colorscheme( self.colorscheme_config, self.colors_config ) if load_theme: self._purge_configs("theme") self.renderer_options["theme_config"] = self.load_theme_config(self.ext_config.get("theme", "default")) if create_renderer: Renderer = self.get_module_attr(self.renderer_module, "renderer") if not Renderer: if hasattr(self, "renderer"): return else: raise ImportError("Failed to obtain renderer") # Renderer updates configuration file via segments’ .startup thus it # should be locked to prevent state when configuration was updated, # but .render still uses old renderer. try: renderer = Renderer(**self.renderer_options) except Exception as e: self.exception("Failed to construct renderer object: {0}", str(e)) if not hasattr(self, "renderer"): raise else: self.renderer = renderer
def load_main_config(self): r = super(ShellPowerline, self).load_main_config() if self.args.config: mergedicts(r, mergeargs(self.args.config)) return r
def create_renderer(self, load_main=False, load_colors=False, load_colorscheme=False, load_theme=False): '''(Re)create renderer object. Can be used after Powerline object was successfully initialized. If any of the below parameters except ``load_main`` is True renderer object will be recreated. :param bool load_main: Determines whether main configuration file (:file:`config.json`) should be loaded. If appropriate configuration changes implies ``load_colorscheme`` and ``load_theme`` and recreation of renderer object. Won’t trigger recreation if only unrelated configuration changed. :param bool load_colors: Determines whether colors configuration from :file:`colors.json` should be (re)loaded. :param bool load_colorscheme: Determines whether colorscheme configuration should be (re)loaded. :param bool load_theme: Determines whether theme configuration should be reloaded. ''' common_config_differs = False ext_config_differs = False if load_main: self._purge_configs('main') config = self.load_main_config() self.common_config = finish_common_config(self.get_encoding(), config['common']) if self.common_config != self.prev_common_config: common_config_differs = True load_theme = (load_theme or not self.prev_common_config or self.prev_common_config['default_top_theme'] != self.common_config['default_top_theme']) self.prev_common_config = self.common_config self.import_paths = self.common_config['paths'] if not self.logger: self.logger = create_logger(self.common_config, self.default_log_stream) if not self.pl: self.pl = PowerlineLogger(self.use_daemon_threads, self.logger, self.ext) self.config_loader.pl = self.pl if not self.run_once: self.config_loader.set_watcher(self.common_config['watcher']) self.get_module_attr = gen_module_attr_getter(self.pl, self.import_paths, self.imported_modules) mergedicts(self.renderer_options, dict( pl=self.pl, term_truecolor=self.common_config['term_truecolor'], ambiwidth=self.common_config['ambiwidth'], tmux_escape=self.common_config['additional_escapes'] == 'tmux', screen_escape=self.common_config['additional_escapes'] == 'screen', theme_kwargs={ 'ext': self.ext, 'common_config': self.common_config, 'run_once': self.run_once, 'shutdown_event': self.shutdown_event, 'get_module_attr': self.get_module_attr, }, )) if not self.run_once and self.common_config['reload_config']: interval = self.common_config['interval'] self.config_loader.set_interval(interval) self.run_loader_update = (interval is None) if interval is not None and not self.config_loader.is_alive(): self.config_loader.start() self.ext_config = config['ext'][self.ext] top_theme = ( self.ext_config.get('top_theme') or self.common_config['default_top_theme'] ) self.theme_levels = ( os.path.join('themes', top_theme), os.path.join('themes', self.ext, '__main__'), ) self.renderer_options['theme_kwargs']['top_theme'] = top_theme if self.ext_config != self.prev_ext_config: ext_config_differs = True if ( not self.prev_ext_config or self.ext_config.get('components') != self.prev_ext_config.get('components') ): self.setup_components(self.ext_config.get('components')) if ( not self.prev_ext_config or self.ext_config.get('local_themes') != self.prev_ext_config.get('local_themes') ): self.renderer_options['local_themes'] = self.get_local_themes(self.ext_config.get('local_themes')) load_colorscheme = ( load_colorscheme or not self.prev_ext_config or self.prev_ext_config['colorscheme'] != self.ext_config['colorscheme'] ) load_theme = ( load_theme or not self.prev_ext_config or self.prev_ext_config['theme'] != self.ext_config['theme'] ) self.prev_ext_config = self.ext_config create_renderer = load_colors or load_colorscheme or load_theme or common_config_differs or ext_config_differs if load_colors: self._purge_configs('colors') self.colors_config = self.load_colors_config() if load_colorscheme or load_colors: self._purge_configs('colorscheme') if load_colorscheme: self.colorscheme_config = self.load_colorscheme_config(self.ext_config['colorscheme']) self.renderer_options['theme_kwargs']['colorscheme'] = ( Colorscheme(self.colorscheme_config, self.colors_config)) if load_theme: self._purge_configs('theme') self.renderer_options['theme_config'] = self.load_theme_config(self.ext_config.get('theme', 'default')) if create_renderer: Renderer = self.get_module_attr(self.renderer_module, 'renderer') if not Renderer: if hasattr(self, 'renderer'): return else: raise ImportError('Failed to obtain renderer') # Renderer updates configuration file via segments’ .startup thus it # should be locked to prevent state when configuration was updated, # but .render still uses old renderer. try: renderer = Renderer(**self.renderer_options) except Exception as e: self.exception('Failed to construct renderer object: {0}', str(e)) if not hasattr(self, 'renderer'): raise else: self.renderer = renderer