From 1c78633d1a45d9f15d6365566328353d265b6467 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 1 Apr 2018 10:19:21 +0530 Subject: [PATCH] Add an "include" directive for the config files to read multiple config files. --- kitty/config_utils.py | 67 +++++++++++++++++++++++++++++-------------- kitty/kitty.conf | 5 ++++ 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/kitty/config_utils.py b/kitty/config_utils.py index 6e8d8976c..e95edfbf8 100644 --- a/kitty/config_utils.py +++ b/kitty/config_utils.py @@ -2,11 +2,12 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2018, Kovid Goyal +import os import re from collections import namedtuple -from .utils import log_error from .rgb import to_color as as_color +from .utils import log_error key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$') @@ -31,33 +32,57 @@ def to_bool(x): return x.lower() in 'y yes true'.split() +def parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_includes): + line = line.strip() + if not line or line.startswith('#'): + return + m = key_pat.match(line) + if m is not None: + key, val = m.groups() + if special_handling(key, val, ans): + return + if key == 'include': + val = val.strip() + if not os.path.isabs(val): + val = os.path.join(base_path_for_includes, val) + try: + with open(val, encoding='utf-8', errors='replace') as include: + _parse(include, type_map, special_handling, ans, all_keys) + except FileNotFoundError: + log_error('Could not find included config file: {}, ignoring'.format(val)) + except EnvironmentError: + log_error('Could not read from included config file: {}, ignoring'.format(val)) + return + if all_keys is not None and key not in all_keys: + log_error('Ignoring unknown config key: {}'.format(key)) + return + tm = type_map.get(key) + if tm is not None: + val = tm(val) + ans[key] = val + + +def _parse(lines, type_map, special_handling, ans, all_keys): + name = getattr(lines, 'name', None) + if name: + base_path_for_includes = os.path.dirname(os.path.abspath(name)) + else: + from .constants import config_dir + base_path_for_includes = config_dir + for line in lines: + parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_includes) + + def parse_config_base( lines, defaults, type_map, special_handling, ans, check_keys=True ): - if check_keys: - all_keys = defaults._asdict() - for line in lines: - line = line.strip() - if not line or line.startswith('#'): - continue - m = key_pat.match(line) - if m is not None: - key, val = m.groups() - if special_handling(key, val, ans): - continue - if check_keys: - if key not in all_keys: - log_error('Ignoring unknown config key: {}'.format(key)) - continue - tm = type_map.get(key) - if tm is not None: - val = tm(val) - ans[key] = val + all_keys = defaults._asdict() if check_keys else None + _parse(lines, type_map, special_handling, ans, all_keys) def init_config(defaults_path, parse_config): with open(defaults_path, encoding='utf-8', errors='replace') as f: - defaults = parse_config(f.read().splitlines(), check_keys=False) + defaults = parse_config(f, check_keys=False) Options = namedtuple('Defaults', ','.join(defaults.keys())) defaults = Options(**defaults) return Options, defaults diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 072465c43..49eee41d2 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -1,5 +1,10 @@ # vim:fileencoding=utf-8:ft=conf +# You can include secondary config files via the "include" directive. +# If you use a relative path for include, it is resolved with respect to the +# location od the current config file. For example: +# include other.conf + # Fonts {{{ # Font family. You can also specify different fonts for the # bold/italic/bold-italic variants. By default they are derived automatically,