def merge_configs(defaults: Dict, vals: Dict) -> Dict: ans = {} for k, v in defaults.items(): if isinstance(v, dict): newvals = vals.get(k, {}) ans[k] = merge_dicts(v, newvals) else: ans[k] = vals.get(k, v) return ans def parse_defaults(lines: Iterable[str], check_keys: bool = False) -> Dict[str, Any]: return parse_config(lines, check_keys) x = _init_config(config_lines(all_options), parse_defaults) Options: Type[DiffOptions] = x[0] defaults = x[1] def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> DiffOptions: return _load_config(Options, defaults, parse_config, merge_configs, *paths, overrides=overrides) SYSTEM_CONF = '/etc/xdg/kitty/diff.conf' defconf = os.path.join(config_dir, 'diff.conf') def init_config(args: DiffCLIOptions) -> DiffOptions: config = tuple(resolve_config(SYSTEM_CONF, defconf, args.config)) overrides = (a.replace('=', ' ', 1) for a in args.override or ())
def parse_opts() -> Options: all_options = {} # type: OptionDefs o, k, g, _all_groups = option_func( all_options, { 'shortcuts': ['Keyboard shortcuts'], 'colors': ['Colors'], 'behavior': ['Behavior'] }) g('shortcuts') k('quit', 'q', 'quit') k('quit', 'esc', 'quit') k('confirm', 'enter', 'confirm') k('left', 'left', 'move left') k('right', 'right', 'move right') k('up', 'up', 'move up') k('down', 'down', 'move down') k('page up', 'page_up', 'move page up') k('page down', 'page_down', 'move page down') k('start of line', 'home', 'move first') k('first non-whitespace', 'a', 'move first nonwhite') k('last non-whitespace', 'end', 'move last nonwhite') k('end of line', 'e', 'move last') k('start of buffer', 'ctrl+home', 'move top') k('end of buffer', 'ctrl+end', 'move bottom') k('word left', 'ctrl+left', 'move word left') k('word right', 'ctrl+right', 'move word right') k('scroll up', 'ctrl+up', 'scroll up') k('scroll down', 'ctrl+down', 'scroll down') k('select left', 'shift+left', 'select stream left') k('select right', 'shift+right', 'select stream right') k('select up', 'shift+up', 'select stream up') k('select down', 'shift+down', 'select stream down') k('select page up', 'shift+page_up', 'select stream page up') k('select page down', 'shift+page_down', 'select stream page down') k('select to start of line', 'shift+home', 'select stream first') k('select to first non-whitespace', 'A', 'select stream first nonwhite') k('select to last non-whitespace', 'shift+end', 'select stream last nonwhite') k('select to end of line', 'E', 'select stream last') k('select to start of buffer', 'shift+ctrl+home', 'select stream top') k('select to end of buffer', 'shift+ctrl+end', 'select stream bottom') k('select word left', 'shift+ctrl+left', 'select stream word left') k('select word right', 'shift+ctrl+right', 'select stream word right') k('column select left', 'alt+left', 'select columnar left') k('column select right', 'alt+right', 'select columnar right') k('column select up', 'alt+up', 'select columnar up') k('column select down', 'alt+down', 'select columnar down') k('column select page up', 'alt+page_up', 'select columnar page up') k('column select page down', 'alt+page_down', 'select columnar page down') k('column select to start of line', 'alt+home', 'select columnar first') k('column select to first non-whitespace', 'alt+A', 'select columnar first nonwhite') k('column select to last non-whitespace', 'alt+end', 'select columnar last nonwhite') k('column select to end of line', 'alt+E', 'select columnar last') k('column select to start of buffer', 'alt+ctrl+home', 'select columnar top') k('column select to end of buffer', 'alt+ctrl+end', 'select columnar bottom') k('column select word left', 'alt+ctrl+left', 'select columnar word left') k('column select word right', 'alt+ctrl+right', 'select columnar word right') g('colors') o('selection_foreground', '#FFFFFF', option_type=to_color) o('selection_background', '#5294E2', option_type=to_color) g('behavior') o('select_by_word_characters', json.loads(os.getenv('KITTY_COMMON_OPTS'))['select_by_word_characters'], option_type=str) type_map = TypeConvert({ o.name: o.option_type for o in all_options.values() if hasattr(o, 'option_type') }) defaults = None # Parsers/validators for key binding directives func_with_args, args_funcs = key_func() def parse_region_type(region_type: str) -> str: result = region_type.lower() assert result in ['stream', 'columnar'] return result def parse_direction(direction: str) -> str: direction_lc = direction.lower() assert direction_lc in [ 'left', 'right', 'up', 'down', 'page up', 'page down', 'first', 'first nonwhite', 'last nonwhite', 'last', 'top', 'bottom', 'word left', 'word right' ] return direction_lc.replace(' ', '_') def parse_scroll_direction(direction: str) -> str: result = direction.lower() assert result in ['up', 'down'] return result @func_with_args('move') def move(func: Callable, direction: str) -> Tuple[Callable, str]: return func, parse_direction(direction) @func_with_args('scroll') def scroll(func: Callable, direction: str) -> Tuple[Callable, str]: return func, parse_scroll_direction(direction) @func_with_args('select') def select(func: Callable, args: str) -> Tuple[Callable, Tuple[str, str]]: region_type, direction = args.split(' ', 1) return func, (parse_region_type(region_type), parse_direction(direction)) def parse_kittens_key( val: str, args_funcs: Dict[str, Callable] ) -> Optional[Tuple[Tuple[ActionName, ActionArgs], KeyName, ShortcutMods, bool]]: parsed_key = _parse_kittens_key(val, args_funcs) if parsed_key is None: return None if len(parsed_key) == 2: # kitty ≥ 0.17.0 action, (key, mods, is_text) = parsed_key else: # kitty < 0.17.0 action, key, mods, is_text = parsed_key return (action, key, mods, is_text and (0 == (mods or 0) & (kk.CTRL | kk.ALT | kk.SUPER))) # Configuration reader helpers def special_handling(key: OptionName, val: str, result: OptionValues) -> bool: if key == 'map': action, *key_def = parse_kittens_key(val, args_funcs) result['key_definitions'][tuple(key_def)] = action return True return False def parse_config(lines: List[str], check_keys: bool = True) -> OptionValues: result = {'key_definitions': {}} # type: OptionValues parse_config_base(lines, defaults, type_map, special_handling, result, check_keys=check_keys) return result def merge_configs(defaults: OptionValues, vals: OptionValues) -> OptionValues: return { k: (merge_dicts(v, vals.get(k, {})) if isinstance(v, dict) else vals.get(k, v)) for k, v in defaults.items() } Options, defaults = init_config(config_lines(all_options), parse_config) configs = list( resolve_config('/etc/xdg/kitty/grab.conf', os.path.join(config_dir, 'grab.conf'), config_files_on_cmd_line=None)) return load_config(Options, defaults, parse_config, merge_configs, *configs)