Make the config parsing code more re-useable

This commit is contained in:
Kovid Goyal 2018-01-11 12:17:18 +05:30
parent 9184e9a28f
commit 8da426039b
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 85 additions and 53 deletions

View File

@ -12,13 +12,16 @@ import tempfile
from collections import namedtuple from collections import namedtuple
from . import fast_data_types as defines from . import fast_data_types as defines
from .config_utils import (
init_config, parse_config_base, positive_float, positive_int, to_bool,
unit_float
)
from .constants import config_dir from .constants import config_dir
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
from .layout import all_layouts from .layout import all_layouts
from .rgb import to_color from .rgb import to_color
from .utils import safe_print from .utils import safe_print
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
MINIMUM_FONT_SIZE = 4 MINIMUM_FONT_SIZE = 4
@ -44,10 +47,6 @@ def to_cursor_shape(x):
) )
def to_bool(x):
return x.lower() in 'y yes true'.split()
def parse_mods(parts): def parse_mods(parts):
def map_mod(m): def map_mod(m):
@ -209,18 +208,6 @@ def to_layout_names(raw):
return parts return parts
def positive_int(x):
return max(0, int(x))
def positive_float(x):
return max(0, float(x))
def unit_float(x):
return max(0, min(float(x), 1))
def adjust_line_height(x): def adjust_line_height(x):
if x.endswith('%'): if x.endswith('%'):
return float(x[:-1].strip()) / 100.0 return float(x[:-1].strip()) / 100.0
@ -309,50 +296,33 @@ for a in ('active', 'inactive'):
type_map['%s_tab_%s' % (a, b)] = lambda x: to_color(x, validate=True) type_map['%s_tab_%s' % (a, b)] = lambda x: to_color(x, validate=True)
def special_handling(key, val, ans):
if key == 'map':
parse_key(val, ans['keymap'])
return True
if key == 'symbol_map':
ans['symbol_map'].update(parse_symbol_map(val))
return True
if key == 'send_text':
# For legacy compatibility
parse_send_text(val, ans['keymap'])
return True
defaults = None
default_config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'kitty.conf')
def parse_config(lines, check_keys=True): def parse_config(lines, check_keys=True):
ans = { ans = {
'keymap': {}, 'keymap': {},
'symbol_map': {}, 'symbol_map': {},
} }
if check_keys: parse_config_base(lines, defaults, type_map, special_handling, ans, check_keys=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 key == 'map':
parse_key(val, ans['keymap'])
continue
if key == 'symbol_map':
ans['symbol_map'].update(parse_symbol_map(val))
continue
if key == 'send_text':
# For legacy compatibility
parse_send_text(val, ans['keymap'])
continue
if check_keys:
if key not in all_keys:
safe_print(
'Ignoring unknown config key: {}'.format(key),
file=sys.stderr
)
continue
tm = type_map.get(key)
if tm is not None:
val = tm(val)
ans[key] = val
return ans return ans
with open( Options, defaults = init_config(default_config_path, parse_config)
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'kitty.conf'), 'rb'
) as f:
defaults = parse_config(f.read().decode('utf-8').splitlines(), check_keys=False)
Options = namedtuple('Defaults', ','.join(defaults.keys()))
defaults = Options(**defaults)
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset( actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset(
'combine send_text goto_tab new_tab_with_cwd new_window_with_cwd new_os_window_with_cwd'.split() 'combine send_text goto_tab new_tab_with_cwd new_window_with_cwd new_os_window_with_cwd'.split()
) )

62
kitty/config_utils.py Normal file
View File

@ -0,0 +1,62 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import re
import sys
from collections import namedtuple
from .utils import safe_print
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
def positive_int(x):
return max(0, int(x))
def positive_float(x):
return max(0, float(x))
def unit_float(x):
return max(0, min(float(x), 1))
def to_bool(x):
return x.lower() in 'y yes true'.split()
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:
safe_print(
'Ignoring unknown config key: {}'.format(key),
file=sys.stderr
)
continue
tm = type_map.get(key)
if tm is not None:
val = tm(val)
ans[key] = val
def init_config(defaults_path, parse_config):
with open(defaults_path, encoding='utf-8') as f:
defaults = parse_config(f.read().splitlines(), check_keys=False)
Options = namedtuple('Defaults', ','.join(defaults.keys()))
defaults = Options(**defaults)
return Options, defaults