diff --git a/.gitattributes b/.gitattributes index 77e4acc1d..eab950d60 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,10 @@ kitty/rgb.py linguist-generated=true kitty/gl-wrapper.* linguist-generated=true kitty/glfw-wrapper.* linguist-generated=true kitty/parse-graphics-command.h linguist-generated=true +kitty/options/types.py linguist-generated=true +kitty/options/parse.py linguist-generated=true +kittens/diff/options/types.py linguist-generated=true +kittens/diff/options/parse.py linguist-generated=true glfw/*.c linguist-vendored=true glfw/*.h linguist-vendored=true kittens/unicode_input/names.h linguist-generated=true diff --git a/count-lines-of-code b/count-lines-of-code index 841a2fbe0..0d0919737 100755 --- a/count-lines-of-code +++ b/count-lines-of-code @@ -16,6 +16,10 @@ kitty/glfw-wrapper.c kitty/emoji.h kittens/unicode_input/names.h kitty/parse-graphics-command.h +kitty/options/types.py +kitty/options/parse.py +kittens/diff/options/types.py +kittens/diff/options/parse.py ''' p = subprocess.Popen([ diff --git a/gen-config.py b/gen-config.py new file mode 100755 index 000000000..a36acc3a9 --- /dev/null +++ b/gen-config.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2021, Kovid Goyal + +import inspect +import os +import pprint +import re +import textwrap +from typing import ( + Any, Callable, Dict, List, Set, Tuple, Union, get_type_hints +) + +from kitty.conf.types import Definition, MultiOption, Option, unset + + +def atoi(text: str) -> str: + return f'{int(text):08d}' if text.isdigit() else text + + +def natural_keys(text: str) -> Tuple[str, ...]: + return tuple(atoi(c) for c in re.split(r'(\d+)', text)) + + +def generate_class(defn: Definition, loc: str) -> Tuple[str, str]: + class_lines: List[str] = [] + tc_lines: List[str] = [] + a = class_lines.append + t = tc_lines.append + a('class Options:') + t('class Parser:') + choices = {} + imports: Set[Tuple[str, str]] = set() + tc_imports: Set[Tuple[str, str]] = set() + + def type_name(x: type) -> str: + ans = x.__name__ + if x.__module__ and x.__module__ != 'builtins': + imports.add((x.__module__, x.__name__)) + return ans + + def option_type_as_str(x: Any) -> str: + if hasattr(x, '__name__'): + return type_name(x) + ans = repr(x) + ans = ans.replace('NoneType', 'None') + return ans + + def option_type_data(option: Union[Option, MultiOption]) -> Tuple[Callable, str]: + func = option.parser_func + if func.__module__ == 'builtins': + return func, func.__name__ + th = get_type_hints(func) + rettype = th['return'] + typ = option_type_as_str(rettype) + if isinstance(option, MultiOption): + typ = typ[typ.index('[') + 1:-1] + typ = typ.replace('Tuple', 'Dict', 1) + return func, typ + + is_mutiple_vars = {} + option_names = set() + + def parser_function_declaration(option_name: str) -> None: + t('') + t(f' def {option_name}(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:') + + for option in sorted(defn.iter_all_options(), key=lambda a: natural_keys(a.name)): + option_names.add(option.name) + parser_function_declaration(option.name) + if isinstance(option, MultiOption): + mval: Dict[str, Dict[str, Any]] = {'macos': {}, 'linux': {}, '': {}} + func, typ = option_type_data(option) + for val in option: + if val.add_to_default: + gr = mval[val.only] + for k, v in func(val.defval_as_str): + gr[k] = v + is_mutiple_vars[option.name] = typ, mval + sig = inspect.signature(func) + tc_imports.add((func.__module__, func.__name__)) + if len(sig.parameters) == 1: + t(f' for k, v in {func.__name__}(val):') + t(f' ans["{option.name}"][k] = v') + else: + t(f' for k, v in {func.__name__}(val, ans["{option.name}"]):') + t(f' ans["{option.name}"][k] = v') + continue + + if option.choices: + typ = 'typing.Literal[{}]'.format(', '.join(repr(x) for x in option.choices)) + ename = f'choices_for_{option.name}' + choices[ename] = typ + typ = ename + func = str + else: + func, typ = option_type_data(option) + try: + params = inspect.signature(func).parameters + except Exception: + params = {} + if 'dict_with_parse_results' in params: + t(f' {func.__name__}(val, ans)') + else: + t(f' ans[{option.name!r}] = {func.__name__}(val)') + if func.__module__ != 'builtins': + tc_imports.add((func.__module__, func.__name__)) + + defval = repr(func(option.defval_as_string)) + if option.macos_defval is not unset: + md = repr(func(option.macos_defval)) + defval = f'{md} if is_macos else {defval}' + imports.add(('kitty.constants', 'is_macos')) + a(f' {option.name}: {typ} = {defval}') + if option.choices: + t(' val = val.lower()') + t(f' if val not in self.choices_for_{option.name}:') + t(f' raise ValueError(f"The value {{val}} is not a valid choice for {option.name}")') + t(f' ans["{option.name}"] = val') + t('') + t(f' choices_for_{option.name} = frozenset({option.choices!r})') + + for option_name, (typ, mval) in is_mutiple_vars.items(): + a(f' {option_name}: {typ} = ' '{}') + + for parser, aliases in defn.deprecations.items(): + for alias in aliases: + parser_function_declaration(alias) + tc_imports.add((parser.__module__, parser.__name__)) + t(f' {parser.__name__}({alias!r}, val, ans)') + + action_parsers = {} + + def resolve_import(ftype: str) -> str: + if '.' in ftype: + fmod, ftype = ftype.rpartition('.')[::2] + else: + fmod = f'{loc}.options.utils' + imports.add((fmod, ftype)) + return ftype + + for aname, action in defn.actions.items(): + option_names.add(aname) + action_parsers[aname] = func = action.parser_func + th = get_type_hints(func) + rettype = th['return'] + typ = option_type_as_str(rettype) + typ = typ[typ.index('[') + 1:-1] + a(f' {aname}: typing.List[{typ}] = []') + for imp in action.imports: + resolve_import(imp) + for fname, ftype in action.fields.items(): + ftype = resolve_import(ftype) + a(f' {fname}: {ftype} = ' '{}') + parser_function_declaration(aname) + t(f' for k in {func.__name__}(val):') + t(f' ans[{aname!r}].append(k)') + tc_imports.add((func.__module__, func.__name__)) + + a('') + a(' def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None:') + a(' if options_dict is not None:') + a(' for key in option_names:') + a(' setattr(self, key, options_dict[key])') + + a('') + a(' @property') + a(' def _fields(self) -> typing.Tuple[str, ...]:') + a(' return option_names') + + a('') + a(' def __iter__(self) -> typing.Iterator[str]:') + a(' return iter(self._fields)') + + a('') + a(' def __len__(self) -> int:') + a(' return len(self._fields)') + + a('') + a(' def _copy_of_val(self, name: str) -> typing.Any:') + a(' ans = getattr(self, name)') + a(' if isinstance(ans, dict):\n ans = ans.copy()') + a(' elif isinstance(ans, list):\n ans = ans[:]') + a(' return ans') + + a('') + a(' def _asdict(self) -> typing.Dict[str, typing.Any]:') + a(' return {k: self._copy_of_val(k) for k in self}') + + a('') + a(' def _replace(self, **kw: typing.Any) -> "Options":') + a(' ans = Options()') + a(' for name in self:') + a(' setattr(ans, name, self._copy_of_val(name))') + a(' for name, val in kw.items():') + a(' setattr(ans, name, val)') + a(' return ans') + + a('') + a(' def __getitem__(self, key: typing.Union[int, str]) -> typing.Any:') + a(' k = option_names[key] if isinstance(key, int) else key') + a(' try:') + a(' return getattr(self, k)') + a(' except AttributeError:') + a(' pass') + a(' raise KeyError(f"No option named: {k}")') + + a('') + a('') + a('defaults = Options()') + for option_name, (typ, mval) in is_mutiple_vars.items(): + a(f'defaults.{option_name} = {mval[""]!r}') + if mval['macos']: + imports.add(('kitty.constants', 'is_macos')) + a('if is_macos:') + a(f' defaults.{option_name}.update({mval["macos"]!r}') + if mval['macos']: + imports.add(('kitty.constants', 'is_macos')) + a('if not is_macos:') + a(f' defaults.{option_name}.update({mval["linux"]!r}') + + for aname, func in action_parsers.items(): + a(f'defaults.{aname} = [') + only: Dict[str, List[Tuple[str, Callable]]] = {} + for sc in defn.iter_all_maps(aname): + if not sc.add_to_default: + continue + text = sc.parseable_text + if sc.only: + only.setdefault(sc.only, []).append((text, func)) + for val in func(text): + a(f' {val!r},') + a(']') + if only: + imports.add(('kitty.constants', 'is_macos')) + for cond, items in only.items(): + cond = 'is_macos' if cond == 'macos' else 'not is_macos' + a(f'if {cond}:') + for (text, func) in items: + for val in func(text): + a(f' defaults.{aname}.append({val!r})') + + t('') + t('') + t('def create_result_dict() -> typing.Dict[str, typing.Any]:') + t(' return {') + for oname in is_mutiple_vars: + t(f' {oname!r}: {{}},') + for aname in defn.actions: + t(f' {aname!r}: [],') + t(' }') + + t('') + t('') + t(f'actions = frozenset({tuple(defn.actions)!r})') + t('') + t('') + t('def merge_result_dicts(defaults: typing.Dict[str, typing.Any], vals: typing.Dict[str, typing.Any]) -> typing.Dict[str, typing.Any]:') + t(' ans = {}') + t(' for k, v in defaults.items():') + t(' if isinstance(v, dict):') + t(' ans[k] = merge_dicts(v, vals.get(k, {}))') + t(' elif k in actions:') + t(' ans[k] = v + vals.get(k, [])') + t(' else:') + t(' ans[k] = vals.get(k, v)') + t(' return ans') + tc_imports.add(('kitty.conf.utils', 'merge_dicts')) + + t('') + t('') + t('parser = Parser()') + t('') + t('') + t('def parse_conf_item(key: str, val: str, ans: typing.Dict[str, typing.Any]) -> bool:') + t(' func = getattr(parser, key, None)') + t(' if func is not None:') + t(' func(val, ans)') + t(' return True') + t(' return False') + + preamble = ['# generated by gen-config.py DO NOT edit', '# vim:fileencoding=utf-8', ''] + a = preamble.append + + def output_imports(imports: Set, add_module_imports: bool = True) -> None: + a('import typing') + seen_mods = {'typing'} + mmap: Dict[str, List[str]] = {} + for mod, name in imports: + mmap.setdefault(mod, []).append(name) + for mod, names in mmap.items(): + names = sorted(names) + lines = textwrap.wrap(', '.join(names), 100) + if len(lines) == 1: + s = lines[0] + else: + s = '\n '.join(lines) + s = f'(\n {s}\n)' + a(f'from {mod} import {s}') + if add_module_imports and mod not in seen_mods: + a(f'import {mod}') + seen_mods.add(mod) + + output_imports(imports) + a('') + if choices: + a('if typing.TYPE_CHECKING:') + for name, cdefn in choices.items(): + a(f' {name} = {cdefn}') + a('else:') + for name in choices: + a(f' {name} = str') + + a('') + a('option_names = ( # {{''{') + a(' ' + pprint.pformat(tuple(sorted(option_names, key=natural_keys)))[1:] + ' # }}''}') + class_def = '\n'.join(preamble + ['', ''] + class_lines) + + preamble = ['# generated by gen-config.py DO NOT edit', '# vim:fileencoding=utf-8', ''] + a = preamble.append + output_imports(tc_imports, False) + + return class_def, '\n'.join(preamble + ['', ''] + tc_lines) + + +def write_output(loc: str, defn: Definition) -> None: + cls, tc = generate_class(defn, loc) + with open(os.path.join(*loc.split('.'), 'options', 'types.py'), 'w') as f: + f.write(cls) + with open(os.path.join(*loc.split('.'), 'options', 'parse.py'), 'w') as f: + f.write(tc) + + +def main() -> None: + from kitty.options.definition import definition + write_output('kitty', definition) + from kittens.diff.options.definition import definition as kd + write_output('kittens.diff', kd) + + +if __name__ == '__main__': + main() diff --git a/kittens/diff/config.py b/kittens/diff/config.py index 053dfbcfd..62b2232de 100644 --- a/kittens/diff/config.py +++ b/kittens/diff/config.py @@ -3,21 +3,16 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal import os -from typing import Any, Dict, FrozenSet, Iterable, Optional, Tuple, Type, Union +from typing import Any, Dict, Iterable, Optional from kitty.cli_stub import DiffCLIOptions -from kitty.conf.definition import config_lines from kitty.conf.utils import ( - init_config as _init_config, key_func, load_config as _load_config, - merge_dicts, parse_config_base, parse_kittens_key, resolve_config + load_config as _load_config, parse_config_base, resolve_config ) from kitty.constants import config_dir -from kitty.options_stub import DiffOptions from kitty.rgb import color_as_sgr -from .config_data import all_options - -defaults: Optional[DiffOptions] = None +from .options.types import Options as DiffOptions, defaults formats: Dict[str, str] = { 'title': '', @@ -42,97 +37,27 @@ def set_formats(opts: DiffOptions) -> None: formats['added_highlight'] = '48' + color_as_sgr(opts.highlight_added_bg) -func_with_args, args_funcs = key_func() - - -@func_with_args('scroll_by') -def parse_scroll_by(func: str, rest: str) -> Tuple[str, int]: - try: - return func, int(rest) - except Exception: - return func, 1 - - -@func_with_args('scroll_to') -def parse_scroll_to(func: str, rest: str) -> Tuple[str, str]: - rest = rest.lower() - if rest not in {'start', 'end', 'next-change', 'prev-change', 'next-page', 'prev-page', 'next-match', 'prev-match'}: - rest = 'start' - return func, rest - - -@func_with_args('change_context') -def parse_change_context(func: str, rest: str) -> Tuple[str, Union[int, str]]: - rest = rest.lower() - if rest in {'all', 'default'}: - return func, rest - try: - amount = int(rest) - except Exception: - amount = 5 - return func, amount - - -@func_with_args('start_search') -def parse_start_search(func: str, rest: str) -> Tuple[str, Tuple[bool, bool]]: - rest_ = rest.lower().split() - is_regex = bool(rest_ and rest_[0] == 'regex') - is_backward = bool(len(rest_) > 1 and rest_[1] == 'backward') - return func, (is_regex, is_backward) - - -def special_handling(key: str, val: str, ans: Dict) -> bool: - if key == 'map': - x = parse_kittens_key(val, args_funcs) - if x is not None: - action, key_def = x - ans['key_definitions'][key_def] = action - return True - return False - - -def parse_config(lines: Iterable[str], check_keys: bool = True) -> Dict[str, Any]: - ans: Dict[str, Any] = {'key_definitions': {}} - defs: Optional[FrozenSet] = None - if check_keys: - defs = frozenset(defaults._fields) # type: ignore - - parse_config_base( - lines, - defs, - all_options, - special_handling, - ans, - ) - return ans - - -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] +SYSTEM_CONF = '/etc/xdg/kitty/diff.conf' +defconf = os.path.join(config_dir, 'diff.conf') def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> DiffOptions: - return _load_config(Options, defaults, parse_config, merge_configs, *paths, overrides=overrides) + from .options.parse import ( + create_result_dict, merge_result_dicts, parse_conf_item + ) + def parse_config(lines: Iterable[str]) -> Dict[str, Any]: + ans: Dict[str, Any] = create_result_dict() + parse_config_base( + lines, + parse_conf_item, + ans, + ) + return ans -SYSTEM_CONF = '/etc/xdg/kitty/diff.conf' -defconf = os.path.join(config_dir, 'diff.conf') + opts_dict = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides) + opts = DiffOptions(opts_dict) + return opts def init_config(args: DiffCLIOptions) -> DiffOptions: @@ -140,4 +65,6 @@ def init_config(args: DiffCLIOptions) -> DiffOptions: overrides = (a.replace('=', ' ', 1) for a in args.override or ()) opts = load_config(*config, overrides=overrides) set_formats(opts) + for (sc, action) in opts.map: + opts.key_definitions[sc] = action return opts diff --git a/kittens/diff/config_data.py b/kittens/diff/config_data.py deleted file mode 100644 index f1ec80fba..000000000 --- a/kittens/diff/config_data.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python3 -# vim:fileencoding=utf-8 -# License: GPL v3 Copyright: 2018, Kovid Goyal - - -# Utils {{{ -from functools import partial -from gettext import gettext as _ -from typing import Dict - -from kitty.conf.definition import OptionOrAction, option_func -from kitty.conf.utils import ( - positive_int, python_string, to_color, to_color_or_none -) - -# }}} - -all_options: Dict[str, OptionOrAction] = {} -o, k, m, g, all_groups = option_func(all_options, { - 'colors': [_('Colors')], - 'diff': [_('Diffing'), ], - 'shortcuts': [_('Keyboard shortcuts')], -}) - - -g('diff') - - -def syntax_aliases(raw: str) -> Dict[str, str]: - ans = {} - for x in raw.split(): - a, b = x.partition(':')[::2] - if a and b: - ans[a.lower()] = b - return ans - - -o('syntax_aliases', 'pyj:py pyi:py recipe:py', option_type=syntax_aliases, long_text=_(''' -File extension aliases for syntax highlight -For example, to syntax highlight :file:`file.xyz` as -:file:`file.abc` use a setting of :code:`xyz:abc` -''')) - -o('num_context_lines', 3, option_type=positive_int, long_text=_(''' -The number of lines of context to show around each change.''')) - -o('diff_cmd', 'auto', long_text=_(''' -The diff command to use. Must contain the placeholder :code:`_CONTEXT_` -which will be replaced by the number of lines of context. The default -is to search the system for either git or diff and use that, if found. -''')) - -o('replace_tab_by', r'\x20\x20\x20\x20', option_type=python_string, long_text=_(''' -The string to replace tabs with. Default is to use four spaces.''')) - - -g('colors') - -o('pygments_style', 'default', long_text=_(''' -The pygments color scheme to use for syntax highlighting. -See :link:`pygments colors schemes ` for a list of schemes.''')) - - -c = partial(o, option_type=to_color) -c('foreground', 'black', long_text=_('Basic colors')) -c('background', 'white') - -c('title_fg', 'black', long_text=_('Title colors')) -c('title_bg', 'white') - -c('margin_bg', '#fafbfc', long_text=_('Margin colors')) -c('margin_fg', '#aaaaaa') - -c('removed_bg', '#ffeef0', long_text=_('Removed text backgrounds')) -c('highlight_removed_bg', '#fdb8c0') -c('removed_margin_bg', '#ffdce0') - -c('added_bg', '#e6ffed', long_text=_('Added text backgrounds')) -c('highlight_added_bg', '#acf2bd') -c('added_margin_bg', '#cdffd8') - -c('filler_bg', '#fafbfc', long_text=_('Filler (empty) line background')) -c('margin_filler_bg', 'none', option_type=to_color_or_none, long_text=_( - 'Filler (empty) line background in margins, defaults to the filler background')) - -c('hunk_margin_bg', '#dbedff', long_text=_('Hunk header colors')) -c('hunk_bg', '#f1f8ff') - -c('search_bg', '#444', long_text=_('Highlighting')) -c('search_fg', 'white') -c('select_bg', '#b4d5fe') -o('select_fg', 'black', option_type=to_color_or_none) - -g('shortcuts') -k('quit', 'q', 'quit', _('Quit')) -k('quit', 'esc', 'quit', _('Quit')) - -k('scroll_down', 'j', 'scroll_by 1', _('Scroll down')) -k('scroll_down', 'down', 'scroll_by 1', _('Scroll down')) -k('scroll_up', 'k', 'scroll_by -1', _('Scroll up')) -k('scroll_up', 'up', 'scroll_by -1', _('Scroll up')) - -k('scroll_top', 'home', 'scroll_to start', _('Scroll to top')) -k('scroll_bottom', 'end', 'scroll_to end', _('Scroll to bottom')) - -k('scroll_page_down', 'page_down', 'scroll_to next-page', _('Scroll to next page')) -k('scroll_page_down', 'space', 'scroll_to next-page', _('Scroll to next page')) -k('scroll_page_up', 'page_up', 'scroll_to prev-page', _('Scroll to previous page')) - -k('next_change', 'n', 'scroll_to next-change', _('Scroll to next change')) -k('prev_change', 'p', 'scroll_to prev-change', _('Scroll to previous change')) - -k('all_context', 'a', 'change_context all', _('Show all context')) -k('default_context', '=', 'change_context default', _('Show default context')) -k('increase_context', '+', 'change_context 5', _('Increase context')) -k('decrease_context', '-', 'change_context -5', _('Decrease context')) - -k('search_forward', '/', 'start_search regex forward', _('Search forward')) -k('search_backward', '?', 'start_search regex backward', _('Search backward')) -k('next_match', '.', 'scroll_to next-match', _('Scroll to next search match')) -k('prev_match', ',', 'scroll_to prev-match', _('Scroll to previous search match')) -k('next_match', '>', 'scroll_to next-match', _('Scroll to next search match')) -k('prev_match', '<', 'scroll_to prev-match', _('Scroll to previous search match')) -k('search_forward_simple', 'f', 'start_search substring forward', _('Search forward (no regex)')) -k('search_backward_simple', 'b', 'start_search substring backward', _('Search backward (no regex)')) diff --git a/kittens/diff/highlight.py b/kittens/diff/highlight.py index 55d852ded..f81bbeb65 100644 --- a/kittens/diff/highlight.py +++ b/kittens/diff/highlight.py @@ -159,13 +159,12 @@ def highlight_collection(collection: Collection, aliases: Optional[Dict[str, str def main() -> None: - from .config import defaults # kitty +runpy "from kittens.diff.highlight import main; main()" file + from .options.types import defaults import sys initialize_highlighter() - if defaults is not None: - with open(sys.argv[-1]) as f: - highlighted = highlight_data(f.read(), f.name, defaults.syntax_aliases) - if highlighted is None: - raise SystemExit('Unknown filetype: {}'.format(sys.argv[-1])) - print(highlighted) + with open(sys.argv[-1]) as f: + highlighted = highlight_data(f.read(), f.name, defaults.syntax_aliases) + if highlighted is None: + raise SystemExit('Unknown filetype: {}'.format(sys.argv[-1])) + print(highlighted) diff --git a/kittens/diff/main.py b/kittens/diff/main.py index 416c9352d..dd77bd6b5 100644 --- a/kittens/diff/main.py +++ b/kittens/diff/main.py @@ -19,11 +19,10 @@ from typing import ( from kitty.cli import CONFIG_HELP, parse_args from kitty.cli_stub import DiffCLIOptions -from kitty.conf.utils import KittensKeyAction +from kitty.conf.utils import KeyAction from kitty.constants import appname from kitty.fast_data_types import wcswidth from kitty.key_encoding import EventType, KeyEvent -from kitty.options_stub import DiffOptions from kitty.utils import ScreenSize from ..tui.handler import Handler @@ -33,10 +32,11 @@ from ..tui.loop import Loop from ..tui.operations import styled from . import global_data from .collect import ( - Collection, create_collection, data_for_path, lines_for_path, sanitize, - set_highlight_data, add_remote_dir + Collection, add_remote_dir, create_collection, data_for_path, + lines_for_path, sanitize, set_highlight_data ) from .config import init_config +from .options.types import Options as DiffOptions from .patch import Differ, Patch, set_diff_command, worker_processes from .render import ( ImagePlacement, ImageSupportWarning, Line, LineRef, Reference, render_diff @@ -95,14 +95,14 @@ class DiffHandler(Handler): for key_def, action in self.opts.key_definitions.items(): self.add_shortcut(action, key_def) - def perform_action(self, action: KittensKeyAction) -> None: + def perform_action(self, action: KeyAction) -> None: func, args = action if func == 'quit': self.quit_loop(0) return if self.state <= DIFFED: if func == 'scroll_by': - return self.scroll_lines(int(args[0])) + return self.scroll_lines(int(args[0] or 0)) if func == 'scroll_to': where = str(args[0]) if 'change' in where: @@ -122,7 +122,7 @@ class DiffHandler(Handler): elif to == 'default': new_ctx = self.original_context_count else: - new_ctx += int(to) + new_ctx += int(to or 0) return self.change_context_count(new_ctx) if func == 'start_search': self.start_search(bool(args[0]), bool(args[1])) @@ -658,5 +658,5 @@ elif __name__ == '__doc__': cd['options'] = OPTIONS cd['help_text'] = help_text elif __name__ == '__conf__': - from .config_data import all_options - sys.all_options = all_options # type: ignore + from .options.definition import definition + sys.options_definition = definition # type: ignore diff --git a/kittens/diff/options/__init__.py b/kittens/diff/options/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/kittens/diff/options/definition.py b/kittens/diff/options/definition.py new file mode 100644 index 000000000..359631705 --- /dev/null +++ b/kittens/diff/options/definition.py @@ -0,0 +1,241 @@ +from kitty.conf.types import Action, Definition + + +definition = Definition( + 'kittens.diff', + Action('map', 'parse_map', {'key_definitions': 'kitty.conf.utils.KittensKeyMap'}, ['kitty.types.ParsedShortcut', 'kitty.conf.utils.KeyAction']), +) + +agr = definition.add_group +egr = definition.end_group +opt = definition.add_option +map = definition.add_map +mma = definition.add_mouse_map + +# diff {{{ +agr('diff', 'Diffing') + +opt('syntax_aliases', 'pyj:py pyi:py recipe:py', + option_type='syntax_aliases', + long_text=''' +File extension aliases for syntax highlight For example, to syntax highlight +:file:`file.xyz` as :file:`file.abc` use a setting of :code:`xyz:abc` +''' + ) + +opt('num_context_lines', '3', + option_type='positive_int', + long_text='The number of lines of context to show around each change.' + ) + +opt('diff_cmd', 'auto', + long_text=''' +The diff command to use. Must contain the placeholder :code:`_CONTEXT_` which +will be replaced by the number of lines of context. The default is to search the +system for either git or diff and use that, if found. +''' + ) + +opt('replace_tab_by', '\\x20\\x20\\x20\\x20', + option_type='python_string', + long_text='The string to replace tabs with. Default is to use four spaces.' + ) +egr() # }}} + +# colors {{{ +agr('colors', 'Colors') + +opt('pygments_style', 'default', + long_text=''' +The pygments color scheme to use for syntax highlighting. See :link:`pygments +colors schemes ` for a list of schemes. +''' + ) + +opt('foreground', 'black', + option_type='to_color', + long_text='Basic colors' + ) + +opt('background', 'white', + option_type='to_color', + ) + +opt('title_fg', 'black', + option_type='to_color', + long_text='Title colors' + ) + +opt('title_bg', 'white', + option_type='to_color', + ) + +opt('margin_bg', '#fafbfc', + option_type='to_color', + long_text='Margin colors' + ) + +opt('margin_fg', '#aaaaaa', + option_type='to_color', + ) + +opt('removed_bg', '#ffeef0', + option_type='to_color', + long_text='Removed text backgrounds' + ) + +opt('highlight_removed_bg', '#fdb8c0', + option_type='to_color', + ) + +opt('removed_margin_bg', '#ffdce0', + option_type='to_color', + ) + +opt('added_bg', '#e6ffed', + option_type='to_color', + long_text='Added text backgrounds' + ) + +opt('highlight_added_bg', '#acf2bd', + option_type='to_color', + ) + +opt('added_margin_bg', '#cdffd8', + option_type='to_color', + ) + +opt('filler_bg', '#fafbfc', + option_type='to_color', + long_text='Filler (empty) line background' + ) + +opt('margin_filler_bg', 'none', + option_type='to_color_or_none', + long_text='Filler (empty) line background in margins, defaults to the filler background' + ) + +opt('hunk_margin_bg', '#dbedff', + option_type='to_color', + long_text='Hunk header colors' + ) + +opt('hunk_bg', '#f1f8ff', + option_type='to_color', + ) + +opt('search_bg', '#444', + option_type='to_color', + long_text='Highlighting' + ) + +opt('search_fg', 'white', + option_type='to_color', + ) + +opt('select_bg', '#b4d5fe', + option_type='to_color', + ) + +opt('select_fg', 'black', + option_type='to_color_or_none', + ) +egr() # }}} + +# shortcuts {{{ +agr('shortcuts', 'Keyboard shortcuts') + +map('Quit', + 'quit q quit', + ) +map('Quit', + 'quit esc quit', + ) + +map('Scroll down', + 'scroll_down j scroll_by 1', + ) +map('Scroll down', + 'scroll_down down scroll_by 1', + ) + +map('Scroll up', + 'scroll_up k scroll_by -1', + ) +map('Scroll up', + 'scroll_up up scroll_by -1', + ) + +map('Scroll to top', + 'scroll_top home scroll_to start', + ) + +map('Scroll to bottom', + 'scroll_bottom end scroll_to end', + ) + +map('Scroll to next page', + 'scroll_page_down page_down scroll_to next-page', + ) +map('Scroll to next page', + 'scroll_page_down space scroll_to next-page', + ) + +map('Scroll to previous page', + 'scroll_page_up page_up scroll_to prev-page', + ) + +map('Scroll to next change', + 'next_change n scroll_to next-change', + ) + +map('Scroll to previous change', + 'prev_change p scroll_to prev-change', + ) + +map('Show all context', + 'all_context a change_context all', + ) + +map('Show default context', + 'default_context = change_context default', + ) + +map('Increase context', + 'increase_context + change_context 5', + ) + +map('Decrease context', + 'decrease_context - change_context -5', + ) + +map('Search forward', + 'search_forward / start_search regex forward', + ) + +map('Search backward', + 'search_backward ? start_search regex backward', + ) + +map('Scroll to next search match', + 'next_match . scroll_to next-match', + ) +map('Scroll to next search match', + 'next_match > scroll_to next-match', + ) + +map('Scroll to previous search match', + 'prev_match , scroll_to prev-match', + ) +map('Scroll to previous search match', + 'prev_match < scroll_to prev-match', + ) + +map('Search forward (no regex)', + 'search_forward_simple f start_search substring forward', + ) + +map('Search backward (no regex)', + 'search_backward_simple b start_search substring backward', + ) +egr() # }}} diff --git a/kittens/diff/options/parse.py b/kittens/diff/options/parse.py new file mode 100644 index 000000000..822cffbaf --- /dev/null +++ b/kittens/diff/options/parse.py @@ -0,0 +1,120 @@ +# generated by gen-config.py DO NOT edit +# vim:fileencoding=utf-8 + +import typing +from kitty.conf.utils import merge_dicts, positive_int, python_string, to_color, to_color_or_none +from kittens.diff.options.utils import parse_map, syntax_aliases + + +class Parser: + + def added_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['added_bg'] = to_color(val) + + def added_margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['added_margin_bg'] = to_color(val) + + def background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['background'] = to_color(val) + + def diff_cmd(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['diff_cmd'] = str(val) + + def filler_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['filler_bg'] = to_color(val) + + def foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['foreground'] = to_color(val) + + def highlight_added_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['highlight_added_bg'] = to_color(val) + + def highlight_removed_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['highlight_removed_bg'] = to_color(val) + + def hunk_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['hunk_bg'] = to_color(val) + + def hunk_margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['hunk_margin_bg'] = to_color(val) + + def margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['margin_bg'] = to_color(val) + + def margin_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['margin_fg'] = to_color(val) + + def margin_filler_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['margin_filler_bg'] = to_color_or_none(val) + + def num_context_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['num_context_lines'] = positive_int(val) + + def pygments_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['pygments_style'] = str(val) + + def removed_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['removed_bg'] = to_color(val) + + def removed_margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['removed_margin_bg'] = to_color(val) + + def replace_tab_by(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['replace_tab_by'] = python_string(val) + + def search_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['search_bg'] = to_color(val) + + def search_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['search_fg'] = to_color(val) + + def select_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['select_bg'] = to_color(val) + + def select_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['select_fg'] = to_color_or_none(val) + + def syntax_aliases(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['syntax_aliases'] = syntax_aliases(val) + + def title_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['title_bg'] = to_color(val) + + def title_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['title_fg'] = to_color(val) + + def map(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k in parse_map(val): + ans['map'].append(k) + + +def create_result_dict() -> typing.Dict[str, typing.Any]: + return { + 'map': [], + } + + +actions = frozenset(('map',)) + + +def merge_result_dicts(defaults: typing.Dict[str, typing.Any], vals: typing.Dict[str, typing.Any]) -> typing.Dict[str, typing.Any]: + ans = {} + for k, v in defaults.items(): + if isinstance(v, dict): + ans[k] = merge_dicts(v, vals.get(k, {})) + elif k in actions: + ans[k] = v + vals.get(k, []) + else: + ans[k] = vals.get(k, v) + return ans + + +parser = Parser() + + +def parse_conf_item(key: str, val: str, ans: typing.Dict[str, typing.Any]) -> bool: + func = getattr(parser, key, None) + if func is not None: + func(val, ans) + return True + return False \ No newline at end of file diff --git a/kittens/diff/options/types.py b/kittens/diff/options/types.py new file mode 100644 index 000000000..9890e6f61 --- /dev/null +++ b/kittens/diff/options/types.py @@ -0,0 +1,141 @@ +# generated by gen-config.py DO NOT edit +# vim:fileencoding=utf-8 + +import typing +from kitty.types import ParsedShortcut +import kitty.types +from kitty.conf.utils import KeyAction, KittensKeyMap +import kitty.conf.utils +from kitty.rgb import Color +import kitty.rgb + + +option_names = ( # {{{ + 'added_bg', + 'added_margin_bg', + 'background', + 'diff_cmd', + 'filler_bg', + 'foreground', + 'highlight_added_bg', + 'highlight_removed_bg', + 'hunk_bg', + 'hunk_margin_bg', + 'map', + 'margin_bg', + 'margin_fg', + 'margin_filler_bg', + 'num_context_lines', + 'pygments_style', + 'removed_bg', + 'removed_margin_bg', + 'replace_tab_by', + 'search_bg', + 'search_fg', + 'select_bg', + 'select_fg', + 'syntax_aliases', + 'title_bg', + 'title_fg') # }}} + + +class Options: + added_bg: Color = Color(red=230, green=255, blue=237) + added_margin_bg: Color = Color(red=205, green=255, blue=216) + background: Color = Color(red=255, green=255, blue=255) + diff_cmd: str = 'auto' + filler_bg: Color = Color(red=250, green=251, blue=252) + foreground: Color = Color(red=0, green=0, blue=0) + highlight_added_bg: Color = Color(red=172, green=242, blue=189) + highlight_removed_bg: Color = Color(red=253, green=184, blue=192) + hunk_bg: Color = Color(red=241, green=248, blue=255) + hunk_margin_bg: Color = Color(red=219, green=237, blue=255) + margin_bg: Color = Color(red=250, green=251, blue=252) + margin_fg: Color = Color(red=170, green=170, blue=170) + margin_filler_bg: typing.Optional[kitty.rgb.Color] = None + num_context_lines: int = 3 + pygments_style: str = 'default' + removed_bg: Color = Color(red=255, green=238, blue=240) + removed_margin_bg: Color = Color(red=255, green=220, blue=224) + replace_tab_by: str = ' ' + search_bg: Color = Color(red=68, green=68, blue=68) + search_fg: Color = Color(red=255, green=255, blue=255) + select_bg: Color = Color(red=180, green=213, blue=254) + select_fg: typing.Optional[kitty.rgb.Color] = Color(red=0, green=0, blue=0) + syntax_aliases: typing.Dict[str, str] = {'pyj': 'py', 'pyi': 'py', 'recipe': 'py'} + title_bg: Color = Color(red=255, green=255, blue=255) + title_fg: Color = Color(red=0, green=0, blue=0) + map: typing.List[typing.Tuple[kitty.types.ParsedShortcut, kitty.conf.utils.KeyAction]] = [] + key_definitions: KittensKeyMap = {} + + def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + if options_dict is not None: + for key in option_names: + setattr(self, key, options_dict[key]) + + @property + def _fields(self) -> typing.Tuple[str, ...]: + return option_names + + def __iter__(self) -> typing.Iterator[str]: + return iter(self._fields) + + def __len__(self) -> int: + return len(self._fields) + + def _copy_of_val(self, name: str) -> typing.Any: + ans = getattr(self, name) + if isinstance(ans, dict): + ans = ans.copy() + elif isinstance(ans, list): + ans = ans[:] + return ans + + def _asdict(self) -> typing.Dict[str, typing.Any]: + return {k: self._copy_of_val(k) for k in self} + + def _replace(self, **kw: typing.Any) -> "Options": + ans = Options() + for name in self: + setattr(ans, name, self._copy_of_val(name)) + for name, val in kw.items(): + setattr(ans, name, val) + return ans + + def __getitem__(self, key: typing.Union[int, str]) -> typing.Any: + k = option_names[key] if isinstance(key, int) else key + try: + return getattr(self, k) + except AttributeError: + pass + raise KeyError(f"No option named: {k}") + + +defaults = Options() +defaults.map = [ + (ParsedShortcut(mods=0, key_name='q'), KeyAction('quit')), + (ParsedShortcut(mods=0, key_name='ESCAPE'), KeyAction('quit')), + (ParsedShortcut(mods=0, key_name='j'), KeyAction('scroll_by', (1,))), + (ParsedShortcut(mods=0, key_name='DOWN'), KeyAction('scroll_by', (1,))), + (ParsedShortcut(mods=0, key_name='k'), KeyAction('scroll_by', (-1,))), + (ParsedShortcut(mods=0, key_name='UP'), KeyAction('scroll_by', (-1,))), + (ParsedShortcut(mods=0, key_name='HOME'), KeyAction('scroll_to', ('start',))), + (ParsedShortcut(mods=0, key_name='END'), KeyAction('scroll_to', ('end',))), + (ParsedShortcut(mods=0, key_name='PAGE_DOWN'), KeyAction('scroll_to', ('next-page',))), + (ParsedShortcut(mods=0, key_name=' '), KeyAction('scroll_to', ('next-page',))), + (ParsedShortcut(mods=0, key_name='PAGE_UP'), KeyAction('scroll_to', ('prev-page',))), + (ParsedShortcut(mods=0, key_name='n'), KeyAction('scroll_to', ('next-change',))), + (ParsedShortcut(mods=0, key_name='p'), KeyAction('scroll_to', ('prev-change',))), + (ParsedShortcut(mods=0, key_name='a'), KeyAction('change_context', ('all',))), + (ParsedShortcut(mods=0, key_name='='), KeyAction('change_context', ('default',))), + (ParsedShortcut(mods=0, key_name='+'), KeyAction('change_context', (5,))), + (ParsedShortcut(mods=0, key_name='-'), KeyAction('change_context', (-5,))), + (ParsedShortcut(mods=0, key_name='/'), KeyAction('start_search', (True, False))), + (ParsedShortcut(mods=0, key_name='?'), KeyAction('start_search', (True, True))), + (ParsedShortcut(mods=0, key_name='.'), KeyAction('scroll_to', ('next-match',))), + (ParsedShortcut(mods=0, key_name='>'), KeyAction('scroll_to', ('next-match',))), + (ParsedShortcut(mods=0, key_name=','), KeyAction('scroll_to', ('prev-match',))), + (ParsedShortcut(mods=0, key_name='<'), KeyAction('scroll_to', ('prev-match',))), + (ParsedShortcut(mods=0, key_name='f'), KeyAction('start_search', (False, False))), + (ParsedShortcut(mods=0, key_name='b'), KeyAction('start_search', (False, True))), +] \ No newline at end of file diff --git a/kittens/diff/options/utils.py b/kittens/diff/options/utils.py new file mode 100644 index 000000000..3036f5d3e --- /dev/null +++ b/kittens/diff/options/utils.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2021, Kovid Goyal + + +from typing import Any, Dict, Iterable, Sequence, Tuple, Union + +from kitty.conf.utils import KittensKeyDefinition, key_func, parse_kittens_key + +func_with_args, args_funcs = key_func() +FuncArgsType = Tuple[str, Sequence[Any]] + + +@func_with_args('scroll_by') +def parse_scroll_by(func: str, rest: str) -> Tuple[str, int]: + try: + return func, int(rest) + except Exception: + return func, 1 + + +@func_with_args('scroll_to') +def parse_scroll_to(func: str, rest: str) -> Tuple[str, str]: + rest = rest.lower() + if rest not in {'start', 'end', 'next-change', 'prev-change', 'next-page', 'prev-page', 'next-match', 'prev-match'}: + rest = 'start' + return func, rest + + +@func_with_args('change_context') +def parse_change_context(func: str, rest: str) -> Tuple[str, Union[int, str]]: + rest = rest.lower() + if rest in {'all', 'default'}: + return func, rest + try: + amount = int(rest) + except Exception: + amount = 5 + return func, amount + + +@func_with_args('start_search') +def parse_start_search(func: str, rest: str) -> Tuple[str, Tuple[bool, bool]]: + rest_ = rest.lower().split() + is_regex = bool(rest_ and rest_[0] == 'regex') + is_backward = bool(len(rest_) > 1 and rest_[1] == 'backward') + return func, (is_regex, is_backward) + + +def syntax_aliases(raw: str) -> Dict[str, str]: + ans = {} + for x in raw.split(): + a, b = x.partition(':')[::2] + if a and b: + ans[a.lower()] = b + return ans + + +def parse_map(val: str) -> Iterable[KittensKeyDefinition]: + x = parse_kittens_key(val, args_funcs) + if x is not None: + yield x diff --git a/kittens/diff/search.py b/kittens/diff/search.py index 85432d6c5..7aba9fb0b 100644 --- a/kittens/diff/search.py +++ b/kittens/diff/search.py @@ -6,7 +6,7 @@ import re from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Tuple from kitty.fast_data_types import wcswidth -from kitty.options_stub import DiffOptions +from .options.types import Options as DiffOptions from ..tui.operations import styled diff --git a/kittens/tui/handler.py b/kittens/tui/handler.py index 8c850877e..12ebc5dbb 100644 --- a/kittens/tui/handler.py +++ b/kittens/tui/handler.py @@ -11,7 +11,7 @@ from typing import ( from kitty.types import ParsedShortcut from kitty.typing import ( AbstractEventLoop, BossType, Debug, ImageManagerType, KeyEventType, - KittensKeyActionType, LoopType, MouseEvent, ScreenSize, TermManagerType + KeyActionType, LoopType, MouseEvent, ScreenSize, TermManagerType ) @@ -46,15 +46,15 @@ class Handler: def asyncio_loop(self) -> AbstractEventLoop: return self._tui_loop.asycio_loop - def add_shortcut(self, action: KittensKeyActionType, spec: Union[str, ParsedShortcut]) -> None: + def add_shortcut(self, action: KeyActionType, spec: Union[str, ParsedShortcut]) -> None: if not hasattr(self, '_key_shortcuts'): - self._key_shortcuts: Dict[ParsedShortcut, KittensKeyActionType] = {} + self._key_shortcuts: Dict[ParsedShortcut, KeyActionType] = {} if isinstance(spec, str): from kitty.key_encoding import parse_shortcut spec = parse_shortcut(spec) self._key_shortcuts[spec] = action - def shortcut_action(self, key_event: KeyEventType) -> Optional[KittensKeyActionType]: + def shortcut_action(self, key_event: KeyEventType) -> Optional[KeyActionType]: for sc, action in self._key_shortcuts.items(): if key_event.matches(sc): return action diff --git a/kittens/tui/operations_stub.py b/kittens/tui/operations_stub.py index 81d9ff8d9..70860a37a 100644 --- a/kittens/tui/operations_stub.py +++ b/kittens/tui/operations_stub.py @@ -9,6 +9,6 @@ class CMD: def generate_stub() -> None: from kittens.tui.operations import as_type_stub - from kitty.conf.definition import save_type_stub + from kitty.conf.utils import save_type_stub text = as_type_stub() save_type_stub(text, __file__) diff --git a/kitty/boss.py b/kitty/boss.py index 5f7398dde..baba94c5c 100755 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -18,7 +18,7 @@ from weakref import WeakValueDictionary from .child import cached_process_data, cwd_of_process, default_env from .cli import create_opts, parse_args from .cli_stub import CLIOptions -from .conf.utils import BadLine, to_cmdline +from .conf.utils import BadLine, KeyAction, to_cmdline from .config import common_opts_as_dict, prepare_config_file_for_editing from .constants import ( appname, config_dir, is_macos, kitty_exe, supports_primary_selection @@ -37,8 +37,8 @@ from .fast_data_types import ( from .keys import get_shortcut, shortcut_matches from .layout.base import set_layout_options from .notify import notification_activated -from .options_stub import Options -from .options.utils import MINIMUM_FONT_SIZE, KeyAction, SubSequenceMap +from .options.types import Options +from .options.utils import MINIMUM_FONT_SIZE, SubSequenceMap from .os_window_size import initial_window_size_func from .rgb import Color, color_from_int from .session import Session, create_sessions, get_os_window_sizing_data diff --git a/kitty/cli.py b/kitty/cli.py index e62e69b1a..c63c59af7 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -12,10 +12,10 @@ from typing import ( ) from .cli_stub import CLIOptions -from .conf.utils import resolve_config -from .options.utils import KeyAction, MouseMap +from .conf.utils import KeyAction, resolve_config from .constants import appname, defconf, is_macos, is_wayland, str_version -from .options_stub import Options as OptionsStub +from .options.types import Options as KittyOpts, defaults +from .options.utils import MouseMap from .types import MouseEvent, SingleKey from .typing import BadLineType, SequenceMap, TypedDict @@ -836,13 +836,13 @@ def compare_mousemaps(final: MouseMap, initial: MouseMap) -> None: print_changes(final, changed, 'Changed mouse actions:') -def compare_opts(opts: OptionsStub) -> None: - from .config import defaults, load_config +def compare_opts(opts: KittyOpts) -> None: + from .config import load_config print('\nConfig options different from defaults:') default_opts = load_config() ignored = ('keymap', 'sequence_map', 'mousemap', 'map', 'mouse_map') changed_opts = [ - f for f in sorted(defaults._fields) # type: ignore + f for f in sorted(defaults._fields) if f not in ignored and getattr(opts, f) != getattr(defaults, f) ] field_len = max(map(len, changed_opts)) if changed_opts else 20 @@ -860,7 +860,7 @@ def compare_opts(opts: OptionsStub) -> None: compare_keymaps(final, initial) -def create_opts(args: CLIOptions, debug_config: bool = False, accumulate_bad_lines: Optional[List[BadLineType]] = None) -> OptionsStub: +def create_opts(args: CLIOptions, debug_config: bool = False, accumulate_bad_lines: Optional[List[BadLineType]] = None) -> KittyOpts: from .config import load_config config = tuple(resolve_config(SYSTEM_CONF, defconf, args.config)) if debug_config: @@ -887,7 +887,7 @@ def create_opts(args: CLIOptions, debug_config: bool = False, accumulate_bad_lin return opts -def create_default_opts() -> OptionsStub: +def create_default_opts() -> KittyOpts: from .config import load_config config = tuple(resolve_config(SYSTEM_CONF, defconf, ())) opts = load_config(*config) diff --git a/kitty/cli_stub.py b/kitty/cli_stub.py index bf27545e8..8e2ace661 100644 --- a/kitty/cli_stub.py +++ b/kitty/cli_stub.py @@ -18,7 +18,7 @@ QueryTerminalCLIOptions = BroadcastCLIOptions = ShowKeyCLIOptions = CLIOptions def generate_stub() -> None: from .cli import parse_option_spec, as_type_stub - from .conf.definition import save_type_stub + from .conf.utils import save_type_stub text = 'import typing\n\n\n' def do(otext=None, cls: str = 'CLIOptions', extra_fields: Sequence[str] = ()): diff --git a/kitty/conf/definition.py b/kitty/conf/definition.py deleted file mode 100644 index 68b6863e1..000000000 --- a/kitty/conf/definition.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python3 -# vim:fileencoding=utf-8 -# License: GPL v3 Copyright: 2018, Kovid Goyal - -import re -from functools import partial -from typing import ( - Any, Callable, Dict, Generator, Iterable, List, Match, Optional, Sequence, - Set, Tuple, Union, get_type_hints -) - -from .utils import Choice, to_bool - - -class Group: - - __slots__ = 'name', 'short_text', 'start_text', 'end_text' - - def __init__(self, name: str, short_text: str, start_text: str = '', end_text: str = '') -> None: - self.name, self.short_text = name, short_text.strip() - self.start_text, self.end_text = start_text.strip(), end_text.strip() - - -class Option: - - __slots__ = 'name', 'group', 'long_text', 'option_type', 'defval_as_string', 'add_to_default', 'add_to_docs', 'line', 'is_multiple' - - def __init__(self, name: str, group: Group, defval: str, option_type: Any, long_text: str, add_to_default: bool, add_to_docs: bool, is_multiple: bool): - self.name, self.group = name, group - self.long_text, self.option_type = long_text.strip(), option_type - self.defval_as_string = defval - self.add_to_default = add_to_default - self.add_to_docs = add_to_docs - self.is_multiple = is_multiple - self.line = self.name + ' ' + self.defval_as_string - - def type_definition(self, imports: Set[Tuple[str, str]]) -> str: - - def type_name(x: type) -> str: - ans = x.__name__ - if x.__module__ and x.__module__ != 'builtins': - imports.add((x.__module__, x.__name__)) - return ans - - def option_type_as_str(x: Any) -> str: - if hasattr(x, '__name__'): - return type_name(x) - ans = repr(x) - ans = ans.replace('NoneType', 'None') - if self.is_multiple: - ans = ans[ans.index('[') + 1:-1] - ans = ans.replace('Tuple', 'Dict', 1) - return ans - - if type(self.option_type) is type: - return type_name(self.option_type) - if isinstance(self.option_type, Choice): - return 'typing.Literal[{}]'.format(','.join(f'{x!r}' for x in self.option_type.all_choices)) - th = get_type_hints(self.option_type) - try: - rettype = th['return'] - except KeyError: - raise ValueError('The Option {} has an unknown option_type: {}'.format(self.name, self.option_type)) - return option_type_as_str(rettype) - - -class Shortcut: - - __slots__ = 'name', 'group', 'key', 'action_def', 'short_text', 'long_text', 'add_to_default', 'add_to_docs', 'line' - - def __init__(self, name: str, group: Group, key: str, action_def: str, short_text: str, long_text: str, add_to_default: bool, add_to_docs: bool): - self.name, self.group, self.key, self.action_def = name, group, key, action_def - self.short_text, self.long_text = short_text, long_text - self.add_to_default = add_to_default - self.add_to_docs = add_to_docs - self.line = 'map ' + self.key + ' ' + self.action_def - - -class MouseAction: - - __slots__ = 'name', 'group', 'button', 'event', 'modes', 'action_def', 'short_text', 'long_text', 'add_to_default', 'add_to_docs', 'line' - - def __init__( - self, name: str, group: Group, - button: str, event: str, modes: str, action_def: str, - short_text: str, long_text: str, add_to_default: bool, add_to_docs: bool - ): - self.name, self.group, self.button, self.event, self.action_def = name, group, button, event, action_def - self.modes, self.short_text, self.long_text = modes, short_text, long_text - self.add_to_default = add_to_default - self.add_to_docs = add_to_docs - self.line = f'mouse_map {self.button} {self.event} {self.modes} {self.action_def}' - - @property - def key(self) -> str: - return self.button - - -def option( - all_options: Dict[str, Option], - group: Sequence[Group], - name: str, - defval: Any, - long_text: str = '', - option_type: Callable[[str], Any] = str, - add_to_default: bool = True, - add_to_docs: bool = True -) -> Option: - is_multiple = name.startswith('+') - if is_multiple: - name = name[1:] - defval_type = type(defval) - if defval_type is not str: - if option_type is str: - if defval_type is bool: - option_type = to_bool - else: - option_type = defval_type - if defval_type is bool: - defval = 'yes' if defval else 'no' - else: - defval = str(defval) - - ans = Option(name, group[0], defval, option_type, long_text, add_to_default, add_to_docs, is_multiple) - all_options[name] = ans - return ans - - -def shortcut( - all_options: Dict[str, List[Shortcut]], - group: Sequence[Group], - action_name: str, - key: str, - action_def: str, - short_text: str = '', - long_text: str = '', - add_to_default: bool = True, - add_to_docs: bool = True, -) -> Shortcut: - ans = Shortcut(action_name, group[0], key, action_def, short_text, long_text, add_to_default, add_to_docs) - key = 'sc-' + action_name - all_options.setdefault(key, []).append(ans) - return ans - - -def mouse_action( - all_options: Dict[str, List[MouseAction]], - group: Sequence[Group], - action_name: str, - button: str, - event: str, - modes: str, - action_def: str, - short_text: str = '', - long_text: str = '', - add_to_default: bool = True, - add_to_docs: bool = True, -) -> MouseAction: - ans = MouseAction(action_name, group[0], button, event, modes, action_def, short_text, long_text, add_to_default, add_to_docs) - key = 'ma-' + action_name - all_options.setdefault(key, []).append(ans) - return ans - - -def option_func(all_options: Dict[str, Any], all_groups: Dict[str, Sequence[str]]) -> Tuple[ - Callable, Callable, Callable, Callable[[str], None], Dict[str, Group]]: - all_groups_ = {k: Group(k, *v) for k, v in all_groups.items()} - group: List[Optional[Group]] = [None] - - def change_group(name: str) -> None: - group[0] = all_groups_[name] - - return partial(option, all_options, group), partial(shortcut, all_options, group), partial(mouse_action, all_options, group), change_group, all_groups_ - - -OptionOrAction = Union[Option, List[Union[Shortcut, MouseAction]]] - - -def merged_opts(all_options: Sequence[OptionOrAction], opt: Option, i: int) -> Generator[Option, None, None]: - yield opt - for k in range(i + 1, len(all_options)): - q = all_options[k] - if not isinstance(q, Option): - break - if not q.long_text and q.add_to_docs: - yield q - else: - break - - -def remove_markup(text: str) -> str: - - def sub(m: Match) -> str: - if m.group(1) == 'ref': - return { - 'layouts': 'https://sw.kovidgoyal.net/kitty/index.html#layouts', - 'sessions': 'https://sw.kovidgoyal.net/kitty/index.html#sessions', - 'functional': 'https://sw.kovidgoyal.net/kitty/keyboard-protocol.html#functional-key-definitions', - }[m.group(2)] - return str(m.group(2)) - - return re.sub(r':([a-zA-Z0-9]+):`(.+?)`', sub, text, flags=re.DOTALL) - - -def iter_blocks(lines: Iterable[str]) -> Generator[Tuple[List[str], int], None, None]: - current_block: List[str] = [] - prev_indent = 0 - for line in lines: - indent_size = len(line) - len(line.lstrip()) - if indent_size != prev_indent or not line: - if current_block: - yield current_block, prev_indent - current_block = [] - prev_indent = indent_size - if not line: - yield [''], 100 - else: - current_block.append(line) - if current_block: - yield current_block, indent_size - - -def wrapped_block(lines: Iterable[str]) -> Generator[str, None, None]: - wrapper = getattr(wrapped_block, 'wrapper', None) - if wrapper is None: - import textwrap - wrapper = textwrap.TextWrapper( - initial_indent='#: ', subsequent_indent='#: ', width=70, break_long_words=False - ) - setattr(wrapped_block, 'wrapper', wrapper) - for block, indent_size in iter_blocks(lines): - if indent_size > 0: - for line in block: - if not line: - yield line - else: - yield '#: ' + line - else: - for line in wrapper.wrap('\n'.join(block)): - yield line - - -def render_block(text: str) -> str: - text = remove_markup(text) - lines = text.splitlines() - return '\n'.join(wrapped_block(lines)) - - -def as_conf_file(all_options: Iterable[OptionOrAction]) -> List[str]: - ans = ['# vim:fileencoding=utf-8:ft=conf:foldmethod=marker', ''] - a = ans.append - current_group: Optional[Group] = None - group_folds = [] - all_options_ = list(all_options) - - def render_group(group: Group, is_shortcut: bool) -> None: - a('#: ' + group.short_text + ' {{''{') - group_folds.append(group.name) - a('') - if group.start_text: - a(render_block(group.start_text)) - a('') - - def handle_group_end(group: Group, new_group_name: str = '', new_group_is_shortcut: bool = False) -> None: - if group.end_text: - a(''), a(render_block(group.end_text)) - is_subgroup = new_group_name.startswith(group.name + '.') - while group_folds: - is_subgroup = new_group_name.startswith(group_folds[-1] + '.') - if is_subgroup: - break - a('#: }}''}'), a('') - del group_folds[-1] - - def handle_group(new_group: Group, is_shortcut: bool = False) -> None: - nonlocal current_group - if new_group is not current_group: - if current_group: - handle_group_end(current_group, new_group.name, is_shortcut) - current_group = new_group - render_group(current_group, is_shortcut) - - def handle_shortcut(shortcuts: Sequence[Union[Shortcut, MouseAction]]) -> None: - handle_group(shortcuts[0].group, True) - for sc in shortcuts: - if sc.add_to_default: - a(sc.line) - if sc.long_text: - a(''), a(render_block(sc.long_text.strip())), a('') - - def handle_option(opt: Option) -> None: - if not opt.long_text or not opt.add_to_docs: - return - handle_group(opt.group) - mopts = list(merged_opts(all_options_, opt, i)) - sz = max(len(x.name) for x in mopts) - for mo in mopts: - prefix = '' if mo.add_to_default else '# ' - a('{}{} {}'.format(prefix, mo.name.ljust(sz), mo.defval_as_string)) - a('') - a(render_block(opt.long_text)) - a('') - - for i, opt in enumerate(all_options_): - if isinstance(opt, Option): - handle_option(opt) - else: - handle_shortcut(opt) - - if current_group: - handle_group_end(current_group) - while group_folds: - a('# }}''}') - del group_folds[-1] - - map_groups = [] - start: Optional[int] = None - count: Optional[int] = None - for i, line in enumerate(ans): - if line.startswith('map ') or line.startswith('mouse_map '): - if start is None: - start = i - count = 1 - else: - if count is not None: - count += 1 - else: - if start is not None and count is not None: - map_groups.append((start, count)) - start = count = None - for start, count in map_groups: - r = range(start, start + count) - sz = max(len(ans[i].split(' ', 3)[1]) for i in r) - for i in r: - line = ans[i] - parts = line.split(' ', 3) - parts[1] = parts[1].ljust(sz) - ans[i] = ' '.join(parts) - - return ans - - -def config_lines( - all_options: Dict[str, OptionOrAction], -) -> Generator[str, None, None]: - for opt in all_options.values(): - if isinstance(opt, Option): - if opt.add_to_default: - yield opt.line - else: - for sc in opt: - if sc.add_to_default: - yield sc.line - - -def as_type_stub( - all_options: Dict[str, OptionOrAction], - preamble_lines: Union[Tuple[str, ...], List[str], Iterable[str]] = (), - extra_fields: Union[Tuple[Tuple[str, str], ...], List[Tuple[str, str]], Iterable[Tuple[str, str]]] = (), - class_name: str = 'Options' -) -> str: - ans = ['import typing\n'] + list(preamble_lines) + ['', 'class {}:'.format(class_name)] - imports: Set[Tuple[str, str]] = set() - for name, val in all_options.items(): - if isinstance(val, Option): - field_name = name.partition(' ')[0] - ans.append(' {}: {}'.format(field_name, val.type_definition(imports))) - for mod, name in imports: - ans.insert(0, 'from {} import {}'.format(mod, name)) - ans.insert(0, 'import {}'.format(mod)) - for field_name, type_def in extra_fields: - ans.append(' {}: {}'.format(field_name, type_def)) - ans.append(' def __iter__(self) -> typing.Iterator[str]: pass') - ans.append(' def __len__(self) -> int: pass') - ans.append(' def __getitem__(self, k: typing.Union[int, str]) -> typing.Any: pass') - ans.append(' def _replace(self, **kw: typing.Any) -> {}: pass'.format(class_name)) - return '\n'.join(ans) + '\n\n\n' - - -def save_type_stub(text: str, fpath: str) -> None: - fpath += 'i' - preamble = '# Update this file by running: ./test.py mypy\n\n' - try: - existing = open(fpath).read() - except FileNotFoundError: - existing = '' - current = preamble + text - if existing != current: - open(fpath, 'w').write(current) diff --git a/kitty/conf/types.py b/kitty/conf/types.py new file mode 100644 index 000000000..e2e2141fb --- /dev/null +++ b/kitty/conf/types.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPLv3 Copyright: 2021, Kovid Goyal + +import builtins +import typing +from importlib import import_module +from typing import ( + Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast +) + +import kitty.conf.utils as generic_parsers + +if typing.TYPE_CHECKING: + Only = typing.Literal['macos', 'linux', ''] +else: + Only = str + + +class Unset: + def __bool__(self) -> bool: + return False + + +unset = Unset() + + +class Option: + + def __init__( + self, name: str, defval: str, macos_default: Union[Unset, str], parser_func: Callable, + long_text: str, documented: bool, group: 'Group', choices: Tuple[str, ...] + ): + self.name = name + self.defval_as_string = defval + self.macos_defval = macos_default + self.long_text = long_text + self.documented = documented + self.group = group + self.parser_func = parser_func + self.choices = choices + + +class MultiVal: + + def __init__(self, val_as_str: str, add_to_default: bool, documented: bool, only: Only) -> None: + self.defval_as_str = val_as_str + self.documented = documented + self.only = only + self.add_to_default = add_to_default + + +class MultiOption: + + def __init__(self, name: str, parser_func: Callable, long_text: str, group: 'Group'): + self.name = name + self.parser_func = parser_func + self.long_text = long_text + self.group = group + self.items: List[MultiVal] = [] + + def add_value(self, val_as_str: str, add_to_default: bool, documented: bool, only: Only) -> None: + self.items.append(MultiVal(val_as_str, add_to_default, documented, only)) + + def __iter__(self) -> Iterator[MultiVal]: + yield from self.items + + +class ShortcutMapping: + + def __init__( + self, name: str, key: str, action_def: str, short_text: str, long_text: str, add_to_default: bool, documented: bool, group: 'Group', only: Only + ): + self.name = name + self.only = only + self.key = key + self.action_def = action_def + self.short_text = short_text + self.long_text = long_text + self.documented = documented + self.add_to_default = add_to_default + self.group = group + + @property + def parseable_text(self) -> str: + return f'{self.key} {self.action_def}' + + +class MouseMapping: + + def __init__( + self, name: str, button: str, event: str, modes: str, action_def: str, + short_text: str, long_text: str, add_to_default: bool, documented: bool, group: 'Group', only: Only + ): + self.name = name + self.only = only + self.button = button + self.event = event + self.modes = modes + self.action_def = action_def + self.short_text = short_text + self.long_text = long_text + self.documented = documented + self.add_to_default = add_to_default + self.group = group + + @property + def parseable_text(self) -> str: + return f'{self.button} {self.event} {self.modes} {self.action_def}' + + +NonGroups = Union[Option, MultiOption, ShortcutMapping, MouseMapping] +GroupItem = Union[NonGroups, 'Group'] + + +class Group: + + def __init__(self, name: str, title: str, start_text: str = '', parent: Optional['Group'] = None): + self.name = name + self.title = title + self.start_text = start_text + self.end_text = '' + self.items: List[GroupItem] = [] + self.parent = parent + + def append(self, item: GroupItem) -> None: + self.items.append(item) + + def __iter__(self) -> Iterator[GroupItem]: + return iter(self.items) + + def __len__(self) -> int: + return len(self.items) + + def iter_all_non_groups(self) -> Iterator[NonGroups]: + for x in self: + if isinstance(x, Group): + yield from x.iter_all_non_groups() + else: + yield x + + +def resolve_import(name: str, module: Any = None) -> Callable: + ans = None + if name.count('.') > 1: + m = import_module(name.rpartition('.')[0]) + ans = getattr(m, name.rpartition('.')[2]) + else: + ans = getattr(builtins, name, None) + if not callable(ans): + ans = getattr(generic_parsers, name, None) + if not callable(ans): + ans = getattr(module, name) + if not callable(ans): + raise TypeError(f'{name} is not a function') + return cast(Callable, ans) + + +class Action: + + def __init__(self, name: str, option_type: str, fields: Dict[str, str], imports: Iterable[str]): + self.name = name + self._parser_func = option_type + self.fields = fields + self.imports = frozenset(imports) + + def resolve_imports(self, module: Any) -> 'Action': + self.parser_func = resolve_import(self._parser_func, module) + return self + + +class Definition: + + def __init__(self, package: str, *actions: Action) -> None: + self.module_for_parsers = import_module(f'{package}.options.utils') + self.package = package + self.root_group = Group('', '') + self.current_group = self.root_group + self.option_map: Dict[str, Option] = {} + self.multi_option_map: Dict[str, MultiOption] = {} + self.shortcut_map: Dict[str, List[ShortcutMapping]] = {} + self.mouse_map: Dict[str, List[MouseMapping]] = {} + self.actions = {a.name: a.resolve_imports(self.module_for_parsers) for a in actions} + self.deprecations: Dict[Callable, Tuple[str, ...]] = {} + + def iter_all_non_groups(self) -> Iterator[NonGroups]: + yield from self.root_group.iter_all_non_groups() + + def iter_all_options(self) -> Iterator[Union[Option, MultiOption]]: + for x in self.iter_all_non_groups(): + if isinstance(x, (Option, MultiOption)): + yield x + + def iter_all_maps(self, which: str = 'map') -> Iterator[Union[ShortcutMapping, MouseMapping]]: + for x in self.iter_all_non_groups(): + if isinstance(x, ShortcutMapping) and which == 'map': + yield x + elif isinstance(x, MouseMapping) and which == 'mouse_map': + yield x + + def parser_func(self, name: str) -> Callable: + ans = getattr(builtins, name, None) + if callable(ans): + return cast(Callable, ans) + ans = getattr(generic_parsers, name, None) + if callable(ans): + return cast(Callable, ans) + ans = getattr(self.module_for_parsers, name) + if not callable(ans): + raise TypeError(f'{name} is not a function') + return cast(Callable, ans) + + def add_group(self, name: str, title: str = '', start_text: str = '') -> None: + self.current_group = Group(name, title or name, start_text.strip(), self.current_group) + if self.current_group.parent is not None: + self.current_group.parent.append(self.current_group) + + def end_group(self, end_text: str = '') -> None: + self.current_group.end_text = end_text.strip() + if self.current_group.parent is not None: + self.current_group = self.current_group.parent + + def add_option( + self, name: str, defval: Union[str, float, int, bool], + option_type: str = 'str', long_text: str = '', + documented: bool = True, add_to_default: bool = False, + only: Only = '', macos_default: Union[Unset, str] = unset, + choices: Tuple[str, ...] = () + ) -> None: + if isinstance(defval, bool): + defval = 'yes' if defval else 'no' + else: + defval = str(defval) + is_multiple = name.startswith('+') + long_text = long_text.strip() + if is_multiple: + name = name[1:] + if macos_default is not unset: + raise TypeError(f'Cannot specify macos_default for is_multiple option: {name} use only instead') + is_new = name not in self.multi_option_map + if is_new: + self.multi_option_map[name] = MultiOption(name, self.parser_func(option_type), long_text, self.current_group) + mopt = self.multi_option_map[name] + if is_new: + self.current_group.append(mopt) + mopt.add_value(defval, add_to_default, documented, only) + return + opt = Option(name, defval, macos_default, self.parser_func(option_type), long_text, documented, self.current_group, choices) + self.current_group.append(opt) + self.option_map[name] = opt + + def add_map( + self, short_text: str, defn: str, long_text: str = '', add_to_default: bool = True, documented: bool = True, only: Only = '' + ) -> None: + name, key, action_def = defn.split(maxsplit=2) + sc = ShortcutMapping(name, key, action_def, short_text, long_text.strip(), add_to_default, documented, self.current_group, only) + self.current_group.append(sc) + self.shortcut_map.setdefault(name, []).append(sc) + + def add_mouse_map( + self, short_text: str, defn: str, long_text: str = '', add_to_default: bool = True, documented: bool = True, only: Only = '' + ) -> None: + name, button, event, modes, action_def = defn.split(maxsplit=4) + mm = MouseMapping(name, button, event, modes, action_def, short_text, long_text.strip(), add_to_default, documented, self.current_group, only) + self.current_group.append(mm) + self.mouse_map.setdefault(name, []).append(mm) + + def add_deprecation(self, parser_name: str, *aliases: str) -> None: + self.deprecations[self.parser_func(parser_name)] = aliases + + def as_conf(self, commented: bool = False) -> str: + raise NotImplementedError('TODO:') diff --git a/kitty/conf/utils.py b/kitty/conf/utils.py index 21ddec98c..b2dcaf8c8 100644 --- a/kitty/conf/utils.py +++ b/kitty/conf/utils.py @@ -6,18 +6,26 @@ import os import re import shlex from typing import ( - Any, Callable, Dict, FrozenSet, Generator, Iterable, Iterator, List, - NamedTuple, Optional, Sequence, Tuple, Type, TypeVar, Union, Set + Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional, + Sequence, Set, Tuple, TypeVar, Union ) from ..rgb import Color, to_color as as_color -from ..types import ParsedShortcut, ConvertibleToNumbers +from ..types import ConvertibleToNumbers, ParsedShortcut +from ..typing import Protocol from ..utils import expandvars, log_error key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$') +ItemParser = Callable[[str, str, Dict[str, Any]], bool] T = TypeVar('T') +class OptionsProtocol(Protocol): + + def _asdict(self) -> Dict[str, Any]: + pass + + class BadLine(NamedTuple): number: int line: str @@ -110,23 +118,12 @@ def choices(*choices: str) -> Choice: return Choice(choices) -def create_type_converter(all_options: Dict) -> Callable[[str, Any], Any]: - from .definition import Option - - def type_convert(name: str, val: Any) -> Any: - o = all_options.get(name) - if isinstance(o, Option): - val = o.option_type(val) - return val - return type_convert - - def parse_line( line: str, - type_convert: Callable[[str, Any], Any], - special_handling: Callable, - ans: Dict[str, Any], all_keys: Optional[FrozenSet[str]], - base_path_for_includes: str + parse_conf_item: ItemParser, + ans: Dict[str, Any], + base_path_for_includes: str, + accumulate_bad_lines: Optional[List[BadLine]] = None ) -> None: line = line.strip() if not line or line.startswith('#'): @@ -136,15 +133,13 @@ def parse_line( log_error('Ignoring invalid config line: {}'.format(line)) return key, val = m.groups() - if special_handling(key, val, ans): - return if key == 'include': val = os.path.expandvars(os.path.expanduser(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_convert, special_handling, ans, all_keys) + _parse(include, parse_conf_item, ans, accumulate_bad_lines) except FileNotFoundError: log_error( 'Could not find included config file: {}, ignoring'. @@ -156,18 +151,14 @@ def parse_line( format(val) ) return - if all_keys is not None and key not in all_keys: + if not parse_conf_item(key, val, ans): log_error('Ignoring unknown config key: {}'.format(key)) - return - ans[key] = type_convert(key, val) def _parse( lines: Iterable[str], - type_convert: Callable[[str, Any], Any], - special_handling: Callable, + parse_conf_item: ItemParser, ans: Dict[str, Any], - all_keys: Optional[FrozenSet[str]], accumulate_bad_lines: Optional[List[BadLine]] = None ) -> None: name = getattr(lines, 'name', None) @@ -179,8 +170,7 @@ def _parse( for i, line in enumerate(lines): try: parse_line( - line, type_convert, special_handling, ans, all_keys, - base_path_for_includes + line, parse_conf_item, ans, base_path_for_includes, accumulate_bad_lines ) except Exception as e: if accumulate_bad_lines is None: @@ -190,62 +180,15 @@ def _parse( def parse_config_base( lines: Iterable[str], - all_option_names: Optional[FrozenSet], - all_options: Dict[str, Any], - special_handling: Callable, + parse_conf_item: ItemParser, ans: Dict[str, Any], accumulate_bad_lines: Optional[List[BadLine]] = None ) -> None: _parse( - lines, create_type_converter(all_options), special_handling, ans, all_option_names, accumulate_bad_lines + lines, parse_conf_item, ans, accumulate_bad_lines ) -def create_options_class(all_keys: Iterable[str]) -> Type: - keys = tuple(sorted(all_keys)) - slots = keys + ('_fields', ) - - def __init__(self: Any, kw: Dict[str, Any]) -> None: - for k, v in kw.items(): - setattr(self, k, v) - - def __iter__(self: Any) -> Iterator[str]: - return iter(keys) - - def __len__(self: Any) -> int: - return len(keys) - - def __getitem__(self: Any, i: Union[int, str]) -> Any: - if isinstance(i, int): - i = keys[i] - try: - return getattr(self, i) - except AttributeError: - raise KeyError('No option named: {}'.format(i)) - - def _asdict(self: Any) -> Dict[str, Any]: - return {k: getattr(self, k) for k in self._fields} - - def _replace(self: Any, **kw: Dict) -> Any: - ans = self._asdict() - ans.update(kw) - return self.__class__(ans) - - ans = type( - 'Options', (), { - '__slots__': slots, - '__init__': __init__, - '_asdict': _asdict, - '_replace': _replace, - '__iter__': __iter__, - '__len__': __len__, - '__getitem__': __getitem__ - } - ) - ans._fields = keys # type: ignore - return ans - - def merge_dicts(defaults: Dict, newvals: Dict) -> Dict: ans = defaults.copy() ans.update(newvals) @@ -264,14 +207,13 @@ def resolve_config(SYSTEM_CONF: str, defconf: str, config_files_on_cmd_line: Seq def load_config( - Options: Type[T], - defaults: Any, - parse_config: Callable[[Iterable[str]], Dict[str, Any]], - merge_configs: Callable[[Dict, Dict], Dict], - *paths: str, - overrides: Optional[Iterable[str]] = None -) -> T: - ans: Dict = defaults._asdict() + defaults: OptionsProtocol, + parse_config: Callable[[Iterable[str]], Dict[str, Any]], + merge_configs: Callable[[Dict, Dict], Dict], + *paths: str, + overrides: Optional[Iterable[str]] = None +) -> Dict[str, Any]: + ans = defaults._asdict() for path in paths: if not path: continue @@ -284,14 +226,7 @@ def load_config( if overrides is not None: vals = parse_config(overrides) ans = merge_configs(ans, vals) - return Options(ans) # type: ignore - - -def init_config(default_config_lines: Iterable[str], parse_config: Callable) -> Tuple[Type, Any]: - defaults = parse_config(default_config_lines, check_keys=False) - Options = create_options_class(defaults.keys()) - defaults = Options(defaults) - return Options, defaults + return ans def key_func() -> Tuple[Callable[..., Callable], Dict[str, Callable]]: @@ -312,14 +247,21 @@ def key_func() -> Tuple[Callable[..., Callable], Dict[str, Callable]]: return func_with_args, ans -KittensKeyAction = Tuple[str, Tuple[str, ...]] +class KeyAction(NamedTuple): + func: str + args: Tuple[Union[str, float, bool, int, None], ...] = () + + def __repr__(self) -> str: + if self.args: + return f'KeyAction({self.func!r}, {self.args!r})' + return f'KeyAction({self.func!r})' -def parse_kittens_func_args(action: str, args_funcs: Dict[str, Callable]) -> KittensKeyAction: +def parse_kittens_func_args(action: str, args_funcs: Dict[str, Callable]) -> KeyAction: parts = action.strip().split(' ', 1) func = parts[0] if len(parts) == 1: - return func, () + return KeyAction(func, ()) rest = parts[1] try: @@ -338,21 +280,38 @@ def parse_kittens_func_args(action: str, args_funcs: Dict[str, Callable]) -> Kit if not isinstance(args, (list, tuple)): args = (args, ) - return func, tuple(args) + return KeyAction(func, tuple(args)) + + +KittensKeyDefinition = Tuple[ParsedShortcut, KeyAction] +KittensKeyMap = Dict[ParsedShortcut, KeyAction] def parse_kittens_key( val: str, funcs_with_args: Dict[str, Callable] -) -> Optional[Tuple[KittensKeyAction, ParsedShortcut]]: +) -> Optional[KittensKeyDefinition]: from ..key_encoding import parse_shortcut sc, action = val.partition(' ')[::2] if not sc or not action: return None ans = parse_kittens_func_args(action, funcs_with_args) - return ans, parse_shortcut(sc) + return parse_shortcut(sc), ans def uniq(vals: Iterable[T]) -> List[T]: seen: Set[T] = set() seen_add = seen.add return [x for x in vals if x not in seen and not seen_add(x)] + + +def save_type_stub(text: str, fpath: str) -> None: + fpath += 'i' + preamble = '# Update this file by running: ./test.py mypy\n\n' + try: + existing = open(fpath).read() + except FileNotFoundError: + existing = '' + current = preamble + text + if existing != current: + with open(fpath, 'w') as f: + f.write(current) diff --git a/kitty/config.py b/kitty/config.py index c424f824e..2d9fa7752 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -6,160 +6,28 @@ import json import os from contextlib import contextmanager, suppress from functools import partial -from typing import ( - Any, Callable, Dict, FrozenSet, Generator, Iterable, List, Optional, Tuple, - Type -) +from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple -from .conf.definition import as_conf_file, config_lines -from .conf.utils import ( - BadLine, init_config, load_config as _load_config, merge_dicts, - parse_config_base, to_bool -) -from .config_data import all_options +from .conf.utils import BadLine, load_config as _load_config, parse_config_base from .constants import cache_dir, defconf +from .options.types import Options, defaults, option_names from .options.utils import ( - KeyDefinition, KeyMap, MouseMap, MouseMapping, SequenceMap, - deprecated_hide_window_decorations_aliases, - deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, - env, font_features, kitten_alias, parse_map, parse_mouse_map, symbol_map + KeyDefinition, KeyMap, MouseMap, MouseMapping, SequenceMap ) -from .options_stub import Options as OptionsStub from .typing import TypedDict from .utils import log_error -SpecialHandlerFunc = Callable[[str, str, Dict[str, Any]], None] -special_handlers: Dict[str, SpecialHandlerFunc] = {} + +def option_names_for_completion() -> Tuple[str, ...]: + return option_names -def special_handler(func: SpecialHandlerFunc) -> SpecialHandlerFunc: - special_handlers[func.__name__.partition('_')[2]] = func - return func - - -def deprecated_handler(*names: str) -> Callable[[SpecialHandlerFunc], SpecialHandlerFunc]: - def special_handler(func: SpecialHandlerFunc) -> SpecialHandlerFunc: - for name in names: - special_handlers[name] = func - return func - return special_handler - - -@special_handler -def handle_map(key: str, val: str, ans: Dict[str, Any]) -> None: - for k in parse_map(val): - ans['map'].append(k) - - -@special_handler -def handle_mouse_map(key: str, val: str, ans: Dict[str, Any]) -> None: - for ma in parse_mouse_map(val): - ans['mouse_map'].append(ma) - - -@special_handler -def handle_symbol_map(key: str, val: str, ans: Dict[str, Any]) -> None: - for k, v in symbol_map(val): - ans['symbol_map'][k] = v - - -@special_handler -def handle_font_features(key: str, val: str, ans: Dict[str, Any]) -> None: - for key, features in font_features(val): - ans['font_features'][key] = features - - -@special_handler -def handle_kitten_alias(key: str, val: str, ans: Dict[str, Any]) -> None: - for k, v in kitten_alias(val): - ans['kitten_alias'][k] = v - - -@special_handler -def handle_send_text(key: str, val: str, ans: Dict[str, Any]) -> None: - # For legacy compatibility - deprecated_send_text(key, val, ans) - - -@special_handler -def handle_clear_all_shortcuts(key: str, val: str, ans: Dict[str, Any]) -> None: - if to_bool(val): - ans['map'] = [None] - - -@deprecated_handler('x11_hide_window_decorations', 'macos_hide_titlebar') -def handle_deprecated_hide_window_decorations_aliases(key: str, val: str, ans: Dict[str, Any]) -> None: - deprecated_hide_window_decorations_aliases(key, val, ans) - - -@deprecated_handler('macos_show_window_title_in_menubar') -def handle_deprecated_macos_show_window_title_in_menubar_alias(key: str, val: str, ans: Dict[str, Any]) -> None: - deprecated_macos_show_window_title_in_menubar_alias(key, val, ans) - - -@special_handler -def handle_env(key: str, val: str, ans: Dict[str, Any]) -> None: - for key, val in env(val, ans['env']): - ans['env'][key] = val - - -def special_handling(key: str, val: str, ans: Dict[str, Any]) -> bool: - func = special_handlers.get(key) - if func is not None: - func(key, val, ans) - return True - - -def option_names_for_completion() -> Generator[str, None, None]: - yield from defaults - yield from special_handlers - - -def parse_config(lines: Iterable[str], check_keys: bool = True, accumulate_bad_lines: Optional[List[BadLine]] = None) -> Dict[str, Any]: - ans: Dict[str, Any] = { - 'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'map': [], - 'env': {}, 'kitten_alias': {}, 'font_features': {}, 'mouse_map': [], - 'mousemap': {} - } - defs: Optional[FrozenSet] = None - if check_keys: - defs = frozenset(defaults._fields) # type: ignore - - parse_config_base( - lines, - defs, - all_options, - special_handling, - ans, - accumulate_bad_lines=accumulate_bad_lines - ) - return ans - - -def parse_defaults(lines: Iterable[str], check_keys: bool = False) -> Dict[str, Any]: - return parse_config(lines, check_keys) - - -xc = init_config(config_lines(all_options), parse_defaults) -Options: Type[OptionsStub] = xc[0] -defaults: OptionsStub = xc[1] no_op_actions = frozenset({'noop', 'no-op', 'no_op'}) -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) - elif k in ('map', 'mouse_map'): - ans[k] = v + vals.get(k, []) - else: - ans[k] = vals.get(k, v) - return ans - - -def build_ansi_color_table(opts: OptionsStub = defaults) -> List[int]: +def build_ansi_color_table(opts: Optional[Options] = None) -> List[int]: + if opts is None: + opts = defaults def as_int(x: Tuple[int, int, int]) -> int: return (x[0] << 16) | (x[1] << 8) | x[2] @@ -211,12 +79,8 @@ def cached_values_for(name: str) -> Generator[Dict, None, None]: def commented_out_default_config() -> str: - ans = [] - for line in as_conf_file(all_options.values()): - if line and line[0] != '#': - line = '# ' + line - ans.append(line) - return '\n'.join(ans) + from .options.definition import definition + return definition.as_conf(commented=True) def prepare_config_file_for_editing() -> str: @@ -229,11 +93,11 @@ def prepare_config_file_for_editing() -> str: return defconf -def finalize_keys(opts: OptionsStub) -> None: +def finalize_keys(opts: Options) -> None: defns: List[KeyDefinition] = [] - for d in getattr(opts, 'map'): + for d in opts.map: if d is None: # clear_all_shortcuts - defns = [] + defns = [] # type: ignore else: defns.append(d.resolve_and_copy(opts.kitty_mod, opts.kitten_alias)) keymap: KeyMap = {} @@ -260,13 +124,10 @@ def finalize_keys(opts: OptionsStub) -> None: opts.sequence_map = sequence_map -def finalize_mouse_mappings(opts: OptionsStub) -> None: +def finalize_mouse_mappings(opts: Options) -> None: defns: List[MouseMapping] = [] - for d in getattr(opts, 'mouse_map'): - if d is None: # clear_all_shortcuts - defns = [] - else: - defns.append(d.resolve_and_copy(opts.kitty_mod, opts.kitten_alias)) + for d in opts.mouse_map: + defns.append(d.resolve_and_copy(opts.kitty_mod, opts.kitten_alias)) mousemap: MouseMap = {} for defn in defns: @@ -278,17 +139,30 @@ def finalize_mouse_mappings(opts: OptionsStub) -> None: opts.mousemap = mousemap -def load_config(*paths: str, overrides: Optional[Iterable[str]] = None, accumulate_bad_lines: Optional[List[BadLine]] = None) -> OptionsStub: - parser = parse_config - if accumulate_bad_lines is not None: - parser = partial(parse_config, accumulate_bad_lines=accumulate_bad_lines) - opts = _load_config(Options, defaults, parser, merge_configs, *paths, overrides=overrides) +def parse_config(lines: Iterable[str], accumulate_bad_lines: Optional[List[BadLine]] = None) -> Dict[str, Any]: + from .options.parse import create_result_dict, parse_conf_item + ans: Dict[str, Any] = create_result_dict() + parse_config_base( + lines, + parse_conf_item, + ans, + accumulate_bad_lines=accumulate_bad_lines + ) + return ans + + +def load_config(*paths: str, overrides: Optional[Iterable[str]] = None, accumulate_bad_lines: Optional[List[BadLine]] = None) -> Options: + from .options.parse import merge_result_dicts + + opts_dict = _load_config(defaults, partial(parse_config, accumulate_bad_lines=accumulate_bad_lines), merge_result_dicts, *paths, overrides=overrides) + opts = Options(opts_dict) + finalize_keys(opts) finalize_mouse_mappings(opts) # delete no longer needed definitions, replacing with empty placeholders - setattr(opts, 'kitten_alias', {}) - setattr(opts, 'mouse_map', []) - setattr(opts, 'map', []) + opts.kitten_alias = {} + opts.mouse_map = [] + opts.map = [] if opts.background_opacity < 1.0 and opts.macos_titlebar_color: log_error('Cannot use both macos_titlebar_color and background_opacity') opts.macos_titlebar_color = 0 @@ -301,7 +175,7 @@ class KittyCommonOpts(TypedDict): url_prefixes: Tuple[str, ...] -def common_opts_as_dict(opts: Optional[OptionsStub] = None) -> KittyCommonOpts: +def common_opts_as_dict(opts: Optional[Options] = None) -> KittyCommonOpts: if opts is None: opts = defaults return { diff --git a/kitty/config_data.py b/kitty/config_data.py deleted file mode 100644 index e02f0e2ae..000000000 --- a/kitty/config_data.py +++ /dev/null @@ -1,1349 +0,0 @@ -#!/usr/bin/env python3 -# vim:fileencoding=utf-8 -# License: GPL v3 Copyright: 2018, Kovid Goyal - -# Utils {{{ -from gettext import gettext as _ -from typing import Dict - -from . import fast_data_types as defines -from .conf.definition import OptionOrAction, option_func -from .conf.utils import ( - choices, positive_float, positive_int, to_cmdline, to_color, - to_color_or_none, unit_float -) -from .constants import is_macos -from .options.utils import ( - active_tab_title_template, adjust_line_height, allow_hyperlinks, - allow_remote_control, box_drawing_scale, clear_all_shortcuts, - clipboard_control, config_or_absolute_path, copy_on_select, - cursor_text_color, default_tab_separator, disable_ligatures, edge_width, - env, font_features, hide_window_decorations, kitten_alias, - macos_option_as_alt, macos_titlebar_color, optional_edge_width, - resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, - symbol_map, tab_activity_symbol, tab_bar_edge, tab_bar_min_tabs, tab_fade, - tab_font_style, tab_separator, tab_title_template, to_cursor_shape, - to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style, - window_border_width, window_size -) -from .rgb import color_as_sharp, color_from_int - -# }}} - -# Groups {{{ - - -all_options: Dict[str, OptionOrAction] = {} - - -o, k, m, g, all_groups = option_func(all_options, { - 'fonts': [ - _('Fonts'), - _('kitty has very powerful font management. You can configure individual\n' - 'font faces and even specify special fonts for particular characters.') - ], - - 'cursor': [_('Cursor customization'), ], - 'scrollback': [_('Scrollback'), ], - 'mouse': [_('Mouse'), ], - 'performance': [_('Performance tuning')], - 'bell': [_('Terminal bell')], - 'window': [_('Window layout')], - 'tabbar': [_('Tab bar')], - 'colors': [_('Color scheme')], - 'colors.table': [ - _('The color table'), - _('''\ -The 256 terminal colors. There are 8 basic colors, each color has a dull and -bright version, for the first 16 colors. You can set the remaining 240 colors -as color16 to color255.''') - ], - 'advanced': [_('Advanced')], - 'os': [_('OS specific tweaks')], - 'mouse.mousemap': [ - _('Mouse actions'), - _('''\ -Mouse buttons can be remapped to perform arbitrary actions. The syntax for -doing so is: - -.. code-block:: none - - mouse_map button-name event-type modes action - -Where ``button-name`` is one of ``left``, ``middle``, ``right`` or ``b1 ... b8`` -with added keyboard modifiers, for example: ``ctrl+shift+left`` refers to holding -the :kbd:`ctrl+shift` keys while clicking with the left mouse button. The -number ``b1 ... b8`` can be used to refer to upto eight buttons on a mouse. - -``event-type`` is one ``press``, ``release``, ``doublepress``, ``triplepress``, -``click`` and ``doubleclick``. ``modes`` indicates whether the action is -performed when the mouse is grabbed by the terminal application or not. It can -have one or more or the values, ``grabbed,ungrabbed``. Note that the click -and double click events have a delay of :opt:`click_interval` to disambiguate -from double and triple presses. - -You can run kitty with the :option:`kitty --debug-input` command line option -to see mouse events. See the builtin actions below to get a sense of what is possible. - -If you want to unmap an action map it to ``no-op``. - -.. note:: - Once a selection is started, releasing the button that started it will - automatically end it and no release event will be dispatched. - -'''), - ], - 'shortcuts': [ - _('Keyboard shortcuts'), - _('''\ -Keys are identified simply by their lowercase unicode characters. For example: -``a`` for the A key, ``[`` for the left square bracket key, etc. For functional -keys, such as ``Enter or Escape`` the names are present at :ref:`functional`. -For a list of modifier names, see: -:link:`GLFW mods ` - -On Linux you can also use XKB key names to bind keys that are not supported by -GLFW. See :link:`XKB keys -` -for a list of key names. The name to use is the part after the :code:`XKB_KEY_` -prefix. Note that you can only use an XKB key name for keys that are not known -as GLFW keys. - -Finally, you can use raw system key codes to map keys, again only for keys that are not -known as GLFW keys. To see the system key code -for a key, start kitty with the :option:`kitty --debug-input` option. Then kitty will -output some debug text for every key event. In that text look for ``native_code`` -the value of that becomes the key name in the shortcut. For example: - -.. code-block:: none - - on_key_input: glfw key: 65 native_code: 0x61 action: PRESS mods: 0x0 text: 'a' - -Here, the key name for the :kbd:`A` key is :kbd:`0x61` and you can use it with:: - - map ctrl+0x61 something - -to map :kbd:`ctrl+a` to something. - -You can use the special action :code:`no_op` to unmap a keyboard shortcut that is -assigned in the default configuration:: - - map kitty_mod+space no_op - -You can combine multiple actions to be triggered by a single shortcut, using the -syntax below:: - - map key combine action1 action2 action3 ... - -For example:: - - map kitty_mod+e combine : new_window : next_layout - -this will create a new window and switch to the next available layout - -You can use multi-key shortcuts using the syntax shown below:: - - map key1>key2>key3 action - -For example:: - - map ctrl+f>2 set_font_size 20 -''') - ], - 'shortcuts.clipboard': [_('Clipboard')], - 'shortcuts.scrolling': [_('Scrolling')], - 'shortcuts.misc': [_('Miscellaneous')], - 'shortcuts.window': [_('Window management')], - 'shortcuts.tab': [ - _('Tab management'), '', - _('''\ -You can also create shortcuts to go to specific tabs, with 1 being the first -tab, 2 the second tab and -1 being the previously active tab, and any number -larger than the last tab being the last tab:: - - map ctrl+alt+1 goto_tab 1 - map ctrl+alt+2 goto_tab 2 - -Just as with :code:`new_window` above, you can also pass the name of arbitrary -commands to run when using new_tab and use :code:`new_tab_with_cwd`. Finally, -if you want the new tab to open next to the current tab rather than at the -end of the tabs list, use:: - - map ctrl+t new_tab !neighbor [optional cmd to run] - -''')], - 'shortcuts.layout': [ - _('Layout management'), '', - _('''\ -You can also create shortcuts to switch to specific layouts:: - - map ctrl+alt+t goto_layout tall - map ctrl+alt+s goto_layout stack - -Similarly, to switch back to the previous layout:: - - map ctrl+alt+p last_used_layout - -''')], - 'shortcuts.fonts': [ - _('Font sizes'), _('''\ -You can change the font size for all top-level kitty OS windows at a time -or only the current one. -'''), _('''\ -To setup shortcuts for specific font sizes:: - - map kitty_mod+f6 change_font_size all 10.0 - -To setup shortcuts to change only the current OS window's font size:: - - map kitty_mod+f6 change_font_size current 10.0 -''')], - 'shortcuts.selection': [ - _('Select and act on visible text'), _('''\ -Use the hints kitten to select text and either pass it to an external program or -insert it into the terminal or copy it to the clipboard. -'''), _(''' -The hints kitten has many more modes of operation that you can map to different -shortcuts. For a full description see :doc:`kittens/hints`.''')], - -}) -# }}} - -g('fonts') # {{{ - -o( - 'font_family', - 'monospace', - long_text=_(''' -You can specify different fonts for the bold/italic/bold-italic variants. -To get a full list of supported fonts use the `kitty list-fonts` command. -By default they are derived automatically, by the OSes font system. Setting -them manually is useful for font families that have many weight variants like -Book, Medium, Thick, etc. For example:: - - font_family Operator Mono Book - bold_font Operator Mono Medium - italic_font Operator Mono Book Italic - bold_italic_font Operator Mono Medium Italic -''') -) -o('bold_font', 'auto') -o('italic_font', 'auto') -o('bold_italic_font', 'auto') - -o('font_size', 11.0, long_text=_('Font size (in pts)'), option_type=to_font_size) - -o('force_ltr', False, long_text=_(""" -kitty does not support BIDI (bidirectional text), however, for RTL scripts, -words are automatically displayed in RTL. That is -to say, in an RTL script, the words "HELLO WORLD" display in kitty as "WORLD -HELLO", and if you try to select a substring of an RTL-shaped string, you will -get the character that would be there had the the string been LTR. For example, -assuming the Hebrew word ירושלים, selecting the character that on the screen -appears to be ם actually writes into the selection buffer the character י. - -kitty's default behavior is useful in conjunction with a filter to reverse the -word order, however, if you wish to manipulate RTL glyphs, it can be very -challenging to work with, so this option is provided to turn it off. -Furthermore, this option can be used with the command line program -:link:`GNU FriBidi ` to get BIDI -support, because it will force kitty to always treat the text as LTR, which -FriBidi expects for terminals.""")) - - -o('adjust_line_height', 0, option_type=adjust_line_height, long_text=_(''' -Change the size of each character cell kitty renders. You can use either numbers, -which are interpreted as pixels or percentages (number followed by %), which -are interpreted as percentages of the unmodified values. You can use negative -pixels or percentages less than 100% to reduce sizes (but this might cause -rendering artifacts).''')) -o('adjust_column_width', 0, option_type=adjust_line_height) - - -o( - '+symbol_map', - 'U+E0A0-U+E0A3,U+E0C0-U+E0C7 PowerlineSymbols', - add_to_default=False, option_type=symbol_map, - long_text=_(''' -Map the specified unicode codepoints to a particular font. Useful if you need -special rendering for some symbols, such as for Powerline. Avoids the need for -patched fonts. Each unicode code point is specified in the form :code:`U+`. You can specify multiple code points, separated by commas and -ranges separated by hyphens. :code:`symbol_map` itself can be specified multiple times. -Syntax is:: - - symbol_map codepoints Font Family Name - -''')) - - -o('disable_ligatures', 'never', option_type=disable_ligatures, long_text=_(''' -Choose how you want to handle multi-character ligatures. The default is to -always render them. You can tell kitty to not render them when the cursor is -over them by using :code:`cursor` to make editing easier, or have kitty never -render them at all by using :code:`always`, if you don't like them. The ligature -strategy can be set per-window either using the kitty remote control facility -or by defining shortcuts for it in kitty.conf, for example:: - - map alt+1 disable_ligatures_in active always - map alt+2 disable_ligatures_in all never - map alt+3 disable_ligatures_in tab cursor - -Note that this refers to programming ligatures, typically implemented using the -:code:`calt` OpenType feature. For disabling general ligatures, use the -:opt:`font_features` setting. -''')) - -o('+font_features', 'none', add_to_default=False, option_type=font_features, long_text=_(''' -Choose exactly which OpenType features to enable or disable. This is useful as -some fonts might have features worthwhile in a terminal. For example, Fira -Code Retina includes a discretionary feature, :code:`zero`, which in that font -changes the appearance of the zero (0), to make it more easily distinguishable -from Ø. Fira Code Retina also includes other discretionary features known as -Stylistic Sets which have the tags :code:`ss01` through :code:`ss20`. - -Note that this code is indexed by PostScript name, and not the font -family. This allows you to define very precise feature settings; e.g. you can -disable a feature in the italic font but not in the regular font. - -On Linux, these are read from the FontConfig database first and then this, -setting is applied, so they can be configured in a single, central place. - -To get the PostScript name for a font, use :code:`kitty + list-fonts --psnames`: - -.. code-block:: sh - - $ kitty + list-fonts --psnames | grep Fira - Fira Code - Fira Code Bold (FiraCode-Bold) - Fira Code Light (FiraCode-Light) - Fira Code Medium (FiraCode-Medium) - Fira Code Regular (FiraCode-Regular) - Fira Code Retina (FiraCode-Retina) - -The part in brackets is the PostScript name. - -Enable alternate zero and oldstyle numerals:: - - font_features FiraCode-Retina +zero +onum - -Enable only alternate zero:: - - font_features FiraCode-Retina +zero - -Disable the normal ligatures, but keep the :code:`calt` feature which (in this -font) breaks up monotony:: - - font_features TT2020StyleB-Regular -liga +calt - -In conjunction with :opt:`force_ltr`, you may want to disable Arabic shaping -entirely, and only look at their isolated forms if they show up in a document. -You can do this with e.g.:: - - font_features UnifontMedium +isol -medi -fina -init -''')) - - -o( - 'box_drawing_scale', - '0.001, 1, 1.5, 2', - option_type=box_drawing_scale, - long_text=_(''' -Change the sizes of the lines used for the box drawing unicode characters -These values are in pts. They will be scaled by the monitor DPI to arrive at -a pixel value. There must be four values corresponding to thin, normal, thick, -and very thick lines. -''')) - -# }}} - -g('cursor') # {{{ - -o('cursor', '#cccccc', _('Default cursor color'), option_type=to_color) -o('cursor_text_color', '#111111', option_type=cursor_text_color, long_text=_(''' -Choose the color of text under the cursor. If you want it rendered with the -background color of the cell underneath instead, use the special keyword: background''')) -o('cursor_shape', 'block', option_type=to_cursor_shape, long_text=_( - 'The cursor shape can be one of (block, beam, underline)')) -o('cursor_beam_thickness', 1.5, option_type=positive_float, long_text=_( - 'Defines the thickness of the beam cursor (in pts)')) -o('cursor_underline_thickness', 2.0, option_type=positive_float, long_text=_( - 'Defines the thickness of the underline cursor (in pts)')) -o('cursor_blink_interval', -1, option_type=float, long_text=_(''' -The interval (in seconds) at which to blink the cursor. Set to zero to disable -blinking. Negative values mean use system default. Note that numbers smaller -than :opt:`repaint_delay` will be limited to :opt:`repaint_delay`. -''')) -o('cursor_stop_blinking_after', 15.0, option_type=positive_float, long_text=_(''' -Stop blinking cursor after the specified number of seconds of keyboard -inactivity. Set to zero to never stop blinking. -''')) - -# }}} - -g('scrollback') # {{{ - - -o('scrollback_lines', 2000, option_type=scrollback_lines, long_text=_(''' -Number of lines of history to keep in memory for scrolling back. Memory is allocated -on demand. Negative numbers are (effectively) infinite scrollback. Note that using -very large scrollback is not recommended as it can slow down performance of the terminal -and also use large amounts of RAM. Instead, consider using :opt:`scrollback_pager_history_size`.''')) - -o('scrollback_pager', 'less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER', option_type=to_cmdline, long_text=_(''' -Program with which to view scrollback in a new window. The scrollback buffer is -passed as STDIN to this program. If you change it, make sure the program you -use can handle ANSI escape sequences for colors and text formatting. -INPUT_LINE_NUMBER in the command line above will be replaced by an integer -representing which line should be at the top of the screen. Similarly CURSOR_LINE and CURSOR_COLUMN -will be replaced by the current cursor position.''')) - -o('scrollback_pager_history_size', 0, option_type=scrollback_pager_history_size, long_text=_(''' -Separate scrollback history size, used only for browsing the scrollback buffer (in MB). -This separate buffer is not available for interactive scrolling but will be -piped to the pager program when viewing scrollback buffer in a separate window. -The current implementation stores the data in UTF-8, so approximatively -10000 lines per megabyte at 100 chars per line, for pure ASCII text, unformatted text. -A value of zero or less disables this feature. The maximum allowed size is 4GB.''')) - -o('scrollback_fill_enlarged_window', False, long_text=_(''' -Fill new space with lines from the scrollback buffer after enlarging a window. -''')) - -o('wheel_scroll_multiplier', 5.0, long_text=_(''' -Modify the amount scrolled by the mouse wheel. Note this is only used for low -precision scrolling devices, not for high precision scrolling on platforms such -as macOS and Wayland. Use negative numbers to change scroll direction.''')) - -o('touch_scroll_multiplier', 1.0, long_text=_(''' -Modify the amount scrolled by a touchpad. Note this is only used for high -precision scrolling devices on platforms such as macOS and Wayland. -Use negative numbers to change scroll direction.''')) - -# }}} - -g('mouse') # {{{ - -o('mouse_hide_wait', 0.0 if is_macos else 3.0, option_type=float, long_text=_(''' -Hide mouse cursor after the specified number of seconds -of the mouse not being used. Set to zero to disable mouse cursor hiding. -Set to a negative value to hide the mouse cursor immediately when typing text. -Disabled by default on macOS as getting it to work robustly with -the ever-changing sea of bugs that is Cocoa is too much effort. -''')) - -o('url_color', '#0087bd', option_type=to_color, long_text=_(''' -The color and style for highlighting URLs on mouse-over. -:code:`url_style` can be one of: none, single, double, curly''')) - -o('url_style', 'curly', option_type=url_style) - -o('open_url_with', 'default', option_type=to_cmdline, long_text=_(''' -The program with which to open URLs that are clicked on. -The special value :code:`default` means to use the -operating system's default URL handler.''')) - - -o('url_prefixes', 'http https file ftp gemini irc gopher mailto news git', option_type=url_prefixes, long_text=_(''' -The set of URL prefixes to look for when detecting a URL under the mouse cursor.''')) - -o('detect_urls', True, long_text=_(''' -Detect URLs under the mouse. Detected URLs are highlighted -with an underline and the mouse cursor becomes a hand over them. -Even if this option is disabled, URLs are still clickable.''')) - - -o('copy_on_select', 'no', option_type=copy_on_select, long_text=_(''' -Copy to clipboard or a private buffer on select. With this set to -:code:`clipboard`, simply selecting text with the mouse will cause the text to -be copied to clipboard. Useful on platforms such as macOS that do not have the -concept of primary selections. You can instead specify a name such as :code:`a1` to -copy to a private kitty buffer instead. Map a shortcut with the -:code:`paste_from_buffer` action to paste from this private buffer. -For example:: - - map cmd+shift+v paste_from_buffer a1 - -Note that copying to the clipboard is a security risk, as all programs, -including websites open in your browser can read the contents of the -system clipboard.''')) - -o('strip_trailing_spaces', 'never', option_type=choices('never', 'smart', 'always'), long_text=_(''' -Remove spaces at the end of lines when copying to clipboard. -A value of :code:`smart` will do it when using normal selections, but not rectangle -selections. :code:`always` will always do it.''')) - -o('select_by_word_characters', '@-./_~?&=%+#', long_text=_(''' -Characters considered part of a word when double clicking. In addition to these characters -any character that is marked as an alphanumeric character in the unicode -database will be matched.''')) - -o('click_interval', -1.0, option_type=float, long_text=_(''' -The interval between successive clicks to detect double/triple clicks (in seconds). -Negative numbers will use the system default instead, if available, or fallback to 0.5.''')) - -o('focus_follows_mouse', False, long_text=_(''' -Set the active window to the window under the mouse when -moving the mouse around''')) - -o('pointer_shape_when_grabbed', 'arrow', option_type=choices('arrow', 'beam', 'hand'), long_text=(''' -The shape of the mouse pointer when the program running in the terminal grabs the mouse. -Valid values are: :code:`arrow`, :code:`beam` and :code:`hand` -''')) - -o('default_pointer_shape', 'beam', option_type=choices('arrow', 'beam', 'hand'), long_text=(''' -The default shape of the mouse pointer. -Valid values are: :code:`arrow`, :code:`beam` and :code:`hand` -''')) - -o('pointer_shape_when_dragging', 'beam', option_type=choices('arrow', 'beam', 'hand'), long_text=(''' -The default shape of the mouse pointer when dragging across text. -Valid values are: :code:`arrow`, :code:`beam` and :code:`hand` -''')) - -g('mouse.mousemap') # {{{ - -m('click_url_or_select', 'left', 'click', 'ungrabbed', 'mouse_click_url_or_select', _('Click the link under the mouse cursor when no selection is created')) -m('click_url_or_select_grabbed', 'shift+left', 'click', 'grabbed,ungrabbed', 'mouse_click_url_or_select', _( - 'Click the link under the mouse cursor when no selection is created even if grabbed')) -m('click_url', 'ctrl+shift+left', 'release', 'grabbed,ungrabbed', 'mouse_click_url', - _('Click the link under the mouse cursor'), _('Variant with :kbd:`ctrl+shift` is present only for legacy compatibility.')) - -for grabbed in (False, True): - modes = 'ungrabbed' + (',grabbed' if grabbed else '') - name_s = '_grabbed' if grabbed else '' - mods_p = 'shift+' if grabbed else '' - ts = _(' even when grabbed') if grabbed else '' - m('paste_selection' + name_s, mods_p + 'middle', 'release', modes, 'paste_selection', _('Paste from the primary selection') + ts) - m('start_simple_selection' + name_s, mods_p + 'left', 'press', modes, 'mouse_selection normal', _('Start selecting text') + ts) - m('start_rectangle_selection' + name_s, mods_p + 'ctrl+alt+left', 'press', modes, 'mouse_selection rectangle', - _('Start selecting text in a rectangle') + ts) - m('select_word' + name_s, mods_p + 'left', 'doublepress', modes, 'mouse_selection word', _('Select a word') + ts) - m('select_line' + name_s, mods_p + 'left', 'triplepress', modes, 'mouse_selection line', _('Select a line') + ts, _('Select the entire line')) - m('select_line_from_point' + name_s, mods_p + 'ctrl+alt+left', 'triplepress', modes, - 'mouse_selection line_from_point', _('Select line from point') + ts, _('Select from the clicked point to the end of the line')) - m('extend_selection' + name_s, mods_p + 'right', 'press', modes, 'mouse_selection extend', _('Extend the current selection') + ts) -# }}} - -# }}} - -g('performance') # {{{ - -o('repaint_delay', 10, option_type=positive_int, long_text=_(''' -Delay (in milliseconds) between screen updates. Decreasing it, increases -frames-per-second (FPS) at the cost of more CPU usage. The default value -yields ~100 FPS which is more than sufficient for most uses. Note that to -actually achieve 100 FPS you have to either set :opt:`sync_to_monitor` to no -or use a monitor with a high refresh rate. Also, to minimize latency -when there is pending input to be processed, repaint_delay is ignored.''')) - -o('input_delay', 3, option_type=positive_int, long_text=_(''' -Delay (in milliseconds) before input from the program running in the terminal -is processed. Note that decreasing it will increase responsiveness, but also -increase CPU usage and might cause flicker in full screen programs that -redraw the entire screen on each loop, because kitty is so fast that partial -screen updates will be drawn.''')) - -o('sync_to_monitor', True, long_text=_(''' -Sync screen updates to the refresh rate of the monitor. This prevents -tearing (https://en.wikipedia.org/wiki/Screen_tearing) when scrolling. However, -it limits the rendering speed to the refresh rate of your monitor. With a -very high speed mouse/high keyboard repeat rate, you may notice some slight input latency. -If so, set this to no.''')) - -# }}} - -g('bell') # {{{ - -o('enable_audio_bell', True, long_text=_(''' -Enable/disable the audio bell. Useful in environments that require silence.''')) - -o('visual_bell_duration', 0.0, option_type=positive_float, long_text=_(''' -Visual bell duration. Flash the screen when a bell occurs for the specified number of -seconds. Set to zero to disable.''')) - -o('window_alert_on_bell', True, long_text=_(''' -Request window attention on bell. -Makes the dock icon bounce on macOS or the taskbar flash on linux.''')) - -o('bell_on_tab', True, long_text=_(''' -Show a bell symbol on the tab if a bell occurs in one of the windows in the -tab and the window is not the currently focused window''')) - -o('command_on_bell', 'none', option_type=to_cmdline, long_text=_(''' -Program to run when a bell occurs. -''')) -# }}} - -g('window') # {{{ -o('remember_window_size', True, long_text=_(''' -If enabled, the window size will be remembered so that new instances of kitty -will have the same size as the previous instance. If disabled, the window will -initially have size configured by initial_window_width/height, in pixels. You -can use a suffix of "c" on the width/height values to have them interpreted as -number of cells instead of pixels. -''')) - - -o('initial_window_width', '640', option_type=window_size) -o('initial_window_height', '400', option_type=window_size) - - -o('enabled_layouts', '*', option_type=to_layout_names, long_text=_(''' -The enabled window layouts. A comma separated list of layout names. The special -value :code:`all` means all layouts. The first listed layout will be used as the -startup layout. Default configuration is all layouts in alphabetical order. -For a list of available layouts, see the :ref:`layouts`. -''')) - -o('window_resize_step_cells', 2, option_type=positive_int, long_text=_(''' -The step size (in units of cell width/cell height) to use when resizing -windows. The cells value is used for horizontal resizing and the lines value -for vertical resizing. -''')) -o('window_resize_step_lines', 2, option_type=positive_int) - - -o('window_border_width', '0.5pt', option_type=window_border_width, long_text=_(''' -The width of window borders. Can be either in pixels (px) or pts (pt). Values -in pts will be rounded to the nearest number of pixels based on screen -resolution. If not specified the unit is assumed to be pts. -Note that borders are displayed only when more than one window -is visible. They are meant to separate multiple windows.''')) - -o('draw_minimal_borders', True, long_text=_(''' -Draw only the minimum borders needed. This means that only the minimum -needed borders for inactive windows are drawn. That is only the borders -that separate the inactive window from a neighbor. Note that setting -a non-zero window margin overrides this and causes all borders to be drawn. -''')) - - -edge_desc = _( - 'A single value sets all four sides. Two values set the vertical and horizontal sides.' - ' Three values set top, horizontal and bottom. Four values set top, right, bottom and left.') - - -o('window_margin_width', '0', option_type=edge_width, long_text=_(''' -The window margin (in pts) (blank area outside the border). ''' + edge_desc)) - -o('single_window_margin_width', '-1', option_type=optional_edge_width, long_text=_(''' -The window margin (in pts) to use when only a single window is visible. -Negative values will cause the value of :opt:`window_margin_width` to be used instead. ''' + edge_desc)) - -o('window_padding_width', '0', option_type=edge_width, long_text=_(''' -The window padding (in pts) (blank area between the text and the window border). ''' + edge_desc)) - -o('placement_strategy', 'center', option_type=choices('center', 'top-left'), long_text=_(''' -When the window size is not an exact multiple of the cell size, the cell area of the terminal -window will have some extra padding on the sides. You can control how that padding is -distributed with this option. Using a value of :code:`center` means the cell area will -be placed centrally. A value of :code:`top-left` means the padding will be on only -the bottom and right edges. -''')) - -o('active_border_color', '#00ff00', option_type=to_color_or_none, long_text=_(''' -The color for the border of the active window. Set this to none to not draw borders -around the active window.''')) - -o('inactive_border_color', '#cccccc', option_type=to_color, long_text=_(''' -The color for the border of inactive windows''')) - -o('bell_border_color', '#ff5a00', option_type=to_color, long_text=_(''' -The color for the border of inactive windows in which a bell has occurred''')) - -o('inactive_text_alpha', 1.0, option_type=unit_float, long_text=_(''' -Fade the text in inactive windows by the specified amount (a number between -zero and one, with zero being fully faded). -''')) - - -o('hide_window_decorations', 'no', option_type=hide_window_decorations, long_text=_(''' -Hide the window decorations (title-bar and window borders) with :code:`yes`. -On macOS, :code:`titlebar-only` can be used to only hide the titlebar. -Whether this works and exactly what effect it has depends on the -window manager/operating system. -''')) - -o('resize_debounce_time', 0.1, option_type=positive_float, long_text=_(''' -The time (in seconds) to wait before redrawing the screen when a -resize event is received. On platforms such as macOS, where the -operating system sends events corresponding to the start and end -of a resize, this number is ignored.''')) - - -o('resize_draw_strategy', 'static', option_type=resize_draw_strategy, long_text=_(''' -Choose how kitty draws a window while a resize is in progress. -A value of :code:`static` means draw the current window contents, mostly unchanged. -A value of :code:`scale` means draw the current window contents scaled. -A value of :code:`blank` means draw a blank window. -A value of :code:`size` means show the window size in cells. -''')) - -o('resize_in_steps', False, long_text=_(''' -Resize the OS window in steps as large as the cells, instead of with the usual pixel accuracy. -Combined with an :opt:`initial_window_width` and :opt:`initial_window_height` in number of cells, -this option can be used to keep the margins as small as possible when resizing the OS window. -Note that this does not currently work on Wayland. -''')) - -o('confirm_os_window_close', 0, option_type=positive_int, long_text=_(''' -Ask for confirmation when closing an OS window or a tab that has at least this -number of kitty windows in it. A value of zero disables confirmation. -This confirmation also applies to requests to quit the entire application (all -OS windows, via the quit action). -''')) -# }}} - -g('tabbar') # {{{ - - -o('tab_bar_edge', 'bottom', option_type=tab_bar_edge, long_text=_(''' -Which edge to show the tab bar on, top or bottom''')) - -o('tab_bar_margin_width', 0.0, option_type=positive_float, long_text=_(''' -The margin to the left and right of the tab bar (in pts)''')) - -o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'powerline', 'hidden'), long_text=_(''' -The tab bar style, can be one of: :code:`fade`, :code:`separator`, :code:`powerline`, or :code:`hidden`. -In the fade style, each tab's edges fade into the background color, in the separator style, tabs are -separated by a configurable separator, and the powerline shows the tabs as a continuous line. -If you use the hidden style, you might want to create a mapping for the :code:`select_tab` action which -presents you with a list of tabs and allows for easy switching to a tab. -''')) - - -o('tab_bar_min_tabs', 2, option_type=tab_bar_min_tabs, long_text=_(''' -The minimum number of tabs that must exist before the tab bar is shown -''')) - -o('tab_switch_strategy', 'previous', option_type=choices('previous', 'left', 'right', 'last'), long_text=_(''' -The algorithm to use when switching to a tab when the current tab is closed. -The default of :code:`previous` will switch to the last used tab. A value of -:code:`left` will switch to the tab to the left of the closed tab. A value -of :code:`right` will switch to the tab to the right of the closed tab. -A value of :code:`last` will switch to the right-most tab. -''')) - - -o('tab_fade', '0.25 0.5 0.75 1', option_type=tab_fade, long_text=_(''' -Control how each tab fades into the background when using :code:`fade` for the -:opt:`tab_bar_style`. Each number is an alpha (between zero and one) that controls -how much the corresponding cell fades into the background, with zero being no fade -and one being full fade. You can change the number of cells used by adding/removing -entries to this list. -''')) - -o('tab_separator', '"{}"'.format(default_tab_separator), option_type=tab_separator, long_text=_(''' -The separator between tabs in the tab bar when using :code:`separator` as the :opt:`tab_bar_style`.''')) - -o('tab_powerline_style', 'angled', option_type=choices('angled', 'slanted', 'round'), long_text=_(''' -The powerline separator style between tabs in the tab bar when using :code:`powerline` -as the :opt:`tab_bar_style`, can be one of: :code:`angled`, :code:`slanted`, or :code:`round`. -''')) - - -o('tab_activity_symbol', 'none', option_type=tab_activity_symbol, long_text=_(''' -Some text or a unicode symbol to show on the tab if a window in the tab that does -not have focus has some activity.''')) - -o('tab_title_template', '"{title}"', option_type=tab_title_template, long_text=_(''' -A template to render the tab title. The default just renders -the title. If you wish to include the tab-index as well, -use something like: :code:`{index}: {title}`. Useful -if you have shortcuts mapped for :code:`goto_tab N`. -In addition you can use :code:`{layout_name}` for the current -layout name and :code:`{num_windows}` for the number of windows -in the tab. Note that formatting is done by Python's string formatting -machinery, so you can use, for instance, :code:`{layout_name[:2].upper()}` to -show only the first two letters of the layout name, upper-cased. -If you want to style the text, you can use styling directives, for example: -:code:`{fmt.fg.red}red{fmt.fg.default}normal{fmt.bg._00FF00}green bg{fmt.bg.normal}`. -Similarly, for bold and italic: -:code:`{fmt.bold}bold{fmt.nobold}normal{fmt.italic}italic{fmt.noitalic}`. -''')) -o('active_tab_title_template', 'none', option_type=active_tab_title_template, long_text=_(''' -Template to use for active tabs, if not specified falls back -to :opt:`tab_title_template`.''')) - -o('active_tab_foreground', '#000', option_type=to_color, long_text=_(''' -Tab bar colors and styles''')) -o('active_tab_background', '#eee', option_type=to_color) -o('active_tab_font_style', 'bold-italic', option_type=tab_font_style) -o('inactive_tab_foreground', '#444', option_type=to_color) -o('inactive_tab_background', '#999', option_type=to_color) -o('inactive_tab_font_style', 'normal', option_type=tab_font_style) -o('tab_bar_background', 'none', option_type=to_color_or_none, long_text=_(''' -Background color for the tab bar. Defaults to using the terminal background color.''')) - -# }}} - -g('colors') # {{{ - -o('foreground', '#dddddd', option_type=to_color, long_text=_(''' -The foreground and background colors''')) -o('background', '#000000', option_type=to_color) - -o('background_opacity', 1.0, option_type=unit_float, long_text=_(''' -The opacity of the background. A number between 0 and 1, where 1 is opaque and -0 is fully transparent. This will only work if supported by the OS (for -instance, when using a compositor under X11). Note that it only sets the -background color's opacity in cells that have the same background color as -the default terminal background. This is so that things like the status bar -in vim, powerline prompts, etc. still look good. But it means that if you use -a color theme with a background color in your editor, it will not be rendered -as transparent. Instead you should change the default background color in your -kitty config and not use a background color in the editor color scheme. Or use -the escape codes to set the terminals default colors in a shell script to -launch your editor. Be aware that using a value less than 1.0 is a (possibly -significant) performance hit. If you want to dynamically change transparency -of windows set :opt:`dynamic_background_opacity` to :code:`yes` (this is off by -default as it has a performance cost) -''')) - - -o('background_image', 'none', option_type=config_or_absolute_path, long_text=_(''' -Path to a background image. Must be in PNG format.''')) - -o('background_image_layout', 'tiled', option_type=choices('tiled', 'scaled', 'mirror-tiled'), long_text=_(''' -Whether to tile or scale the background image.''')) - -o('background_image_linear', False, long_text=_(''' -When background image is scaled, whether linear interpolation should be used.''')) - -o('dynamic_background_opacity', False, long_text=_(''' -Allow changing of the :opt:`background_opacity` dynamically, using either keyboard -shortcuts (:sc:`increase_background_opacity` and :sc:`decrease_background_opacity`) -or the remote control facility. -''')) - -o('background_tint', 0.0, option_type=unit_float, long_text=_(''' -How much to tint the background image by the background color. The tint is applied -only under the text area, not margin/borders. Makes it easier to read the text. -Tinting is done using the current background color for each window. This setting -applies only if :opt:`background_opacity` is set and transparent windows are supported -or :opt:`background_image` is set. -''')) - -o('dim_opacity', 0.75, option_type=unit_float, long_text=_(''' -How much to dim text that has the DIM/FAINT attribute set. One means no dimming and -zero means fully dimmed (i.e. invisible).''')) - -o('selection_foreground', '#000000', option_type=to_color_or_none, long_text=_(''' -The foreground for text selected with the mouse. A value of none means to leave the color unchanged.''')) -o('selection_background', '#fffacd', option_type=to_color, long_text=_(''' -The background for text selected with the mouse.''')) - -g('colors.table') -o('color0', '#000000', long_text=_('black'), option_type=to_color) -o('color8', '#767676', option_type=to_color) - -o('color1', '#cc0403', long_text=_('red'), option_type=to_color) -o('color9', '#f2201f', option_type=to_color) - -o('color2', '#19cb00', long_text=_('green'), option_type=to_color) -o('color10', '#23fd00', option_type=to_color) - -o('color3', '#cecb00', long_text=_('yellow'), option_type=to_color) -o('color11', '#fffd00', option_type=to_color) - -o('color4', '#0d73cc', long_text=_('blue'), option_type=to_color) -o('color12', '#1a8fff', option_type=to_color) - -o('color5', '#cb1ed1', long_text=_('magenta'), option_type=to_color) -o('color13', '#fd28ff', option_type=to_color) - -o('color6', '#0dcdcd', long_text=_('cyan'), option_type=to_color) -o('color14', '#14ffff', option_type=to_color) - -o('color7', '#dddddd', long_text=_('white'), option_type=to_color) -o('color15', '#ffffff', option_type=to_color) - -o('mark1_foreground', 'black', long_text=_('Color for marks of type 1'), option_type=to_color) -o('mark1_background', '#98d3cb', long_text=_('Color for marks of type 1 (light steel blue)'), option_type=to_color) -o('mark2_foreground', 'black', long_text=_('Color for marks of type 2'), option_type=to_color) -o('mark2_background', '#f2dcd3', long_text=_('Color for marks of type 1 (beige)'), option_type=to_color) -o('mark3_foreground', 'black', long_text=_('Color for marks of type 3'), option_type=to_color) -o('mark3_background', '#f274bc', long_text=_('Color for marks of type 1 (violet)'), option_type=to_color) -dfctl = defines.default_color_table() -for i in range(16, 256): - o('color{}'.format(i), color_as_sharp(color_from_int(dfctl[i])), option_type=to_color, add_to_docs=False) - -# }}} - -g('advanced') # {{{ -o('shell', '.', long_text=_(''' -The shell program to execute. The default value of . means -to use whatever shell is set as the default shell for the current user. -Note that on macOS if you change this, you might need to add :code:`--login` to -ensure that the shell starts in interactive mode and reads its startup rc files.''')) - -o('editor', '.', long_text=_(''' -The console editor to use when editing the kitty config file or similar tasks. -A value of . means to use the environment variables VISUAL and EDITOR in that -order. Note that this environment variable has to be set not just in your shell -startup scripts but system-wide, otherwise kitty will not see it. -''')) - -o('close_on_child_death', False, long_text=_(''' -Close the window when the child process (shell) exits. If no (the default), the -terminal will remain open when the child exits as long as there are still -processes outputting to the terminal (for example disowned or backgrounded -processes). If yes, the window will close as soon as the child process exits. -Note that setting it to yes means that any background processes still using the -terminal can fail silently because their stdout/stderr/stdin no longer work. -''')) - - -o('allow_remote_control', 'no', option_type=allow_remote_control, long_text=_(''' -Allow other programs to control kitty. If you turn this on other programs can -control all aspects of kitty, including sending text to kitty windows, opening -new windows, closing windows, reading the content of windows, etc. Note that -this even works over ssh connections. You can chose to either allow any program -running within kitty to control it, with :code:`yes` or only programs that -connect to the socket specified with the :option:`kitty --listen-on` command -line option, if you use the value :code:`socket-only`. The latter is useful if -you want to prevent programs running on a remote computer over ssh from -controlling kitty. -''')) - - -o('listen_on', 'none', long_text=_(''' -Tell kitty to listen to the specified unix/tcp socket for remote control -connections. Note that this will apply to all kitty instances. It can be -overridden by the :option:`kitty --listen-on` command line flag. This -option accepts only UNIX sockets, such as unix:${TEMP}/mykitty or (on Linux) -unix:@mykitty. Environment variables are expanded. If {kitty_pid} is present -then it is replaced by the PID of the kitty process, otherwise the PID of the kitty -process is appended to the value, with a hyphen. This option is ignored unless -you also set :opt:`allow_remote_control` to enable remote control. See the -help for :option:`kitty --listen-on` for more details. -''')) - -o('+env', '', add_to_default=False, option_type=env, long_text=_(''' -Specify environment variables to set in all child processes. Note that -environment variables are expanded recursively, so if you use:: - - env MYVAR1=a - env MYVAR2=${MYVAR1}/${HOME}/b - -The value of MYVAR2 will be :code:`a//b`. -''')) - -o('update_check_interval', 24, option_type=float, long_text=_(''' -Periodically check if an update to kitty is available. If an update is found -a system notification is displayed informing you of the available update. -The default is to check every 24 hrs, set to zero to disable. -''')) - - -o('startup_session', 'none', option_type=config_or_absolute_path, long_text=_(''' -Path to a session file to use for all kitty instances. Can be overridden -by using the :option:`kitty --session` command line option for individual -instances. See :ref:`sessions` in the kitty documentation for details. Note -that relative paths are interpreted with respect to the kitty config directory. -Environment variables in the path are expanded. -''')) - - -o('clipboard_control', 'write-clipboard write-primary', option_type=clipboard_control, long_text=_(''' -Allow programs running in kitty to read and write from the clipboard. You can -control exactly which actions are allowed. The set of possible actions is: -write-clipboard read-clipboard write-primary read-primary. You can -additionally specify no-append to disable kitty's protocol extension -for clipboard concatenation. The default is to allow writing to the -clipboard and primary selection with concatenation enabled. Note -that enabling the read functionality is a security risk as it means that any -program, even one running on a remote server via SSH can read your clipboard. -''')) - - -o('allow_hyperlinks', 'yes', option_type=allow_hyperlinks, long_text=_(''' -Process hyperlink (OSC 8) escape sequences. If disabled OSC 8 escape -sequences are ignored. Otherwise they become clickable links, that you -can click by holding down ctrl+shift and clicking with the mouse. The special -value of ``ask`` means that kitty will ask before opening the link.''')) - - -o('term', 'xterm-kitty', long_text=_(''' -The value of the TERM environment variable to set. Changing this can break many -terminal programs, only change it if you know what you are doing, not because -you read some advice on Stack Overflow to change it. The TERM variable is used -by various programs to get information about the capabilities and behavior of -the terminal. If you change it, depending on what programs you run, and how -different the terminal you are changing it to is, various things from -key-presses, to colors, to various advanced features may not work. -''')) - -# }}} - -g('os') # {{{ - - -o('wayland_titlebar_color', 'system', option_type=macos_titlebar_color, long_text=_(''' -Change the color of the kitty window's titlebar on Wayland systems with client side window decorations such as GNOME. -A value of :code:`system` means to use the default system color, -a value of :code:`background` means to use the background color -of the currently active window and finally you can use -an arbitrary color, such as :code:`#12af59` or :code:`red`. -''')) - -o('macos_titlebar_color', 'system', option_type=macos_titlebar_color, long_text=_(''' -Change the color of the kitty window's titlebar on macOS. A value of :code:`system` -means to use the default system color, a value of :code:`background` means to use -the background color of the currently active window and finally you can use -an arbitrary color, such as :code:`#12af59` or :code:`red`. WARNING: This option works by -using a hack, as there is no proper Cocoa API for it. It sets the background -color of the entire window and makes the titlebar transparent. As such it is -incompatible with :opt:`background_opacity`. If you want to use both, you are -probably better off just hiding the titlebar with :opt:`hide_window_decorations`. -''')) - - -o('macos_option_as_alt', 'no', option_type=macos_option_as_alt, long_text=_(''' -Use the option key as an alt key. With this set to :code:`no`, kitty will use -the macOS native :kbd:`Option+Key` = unicode character behavior. This will -break any :kbd:`Alt+key` keyboard shortcuts in your terminal programs, but you -can use the macOS unicode input technique. You can use the values: -:code:`left`, :code:`right`, or :code:`both` to use only the left, right or -both Option keys as Alt, instead. -''')) - -o('macos_hide_from_tasks', False, long_text=_(''' -Hide the kitty window from running tasks (:kbd:`⌘+Tab`) on macOS. -''')) - -o('macos_quit_when_last_window_closed', False, long_text=_(''' -Have kitty quit when all the top-level windows are closed. By default, -kitty will stay running, even with no open windows, as is the expected -behavior on macOS. -''')) - -o('macos_window_resizable', True, long_text=_(''' -Disable this if you want kitty top-level (OS) windows to not be resizable -on macOS. -''')) - -o('macos_thicken_font', 0, option_type=positive_float, long_text=_(''' -Draw an extra border around the font with the given width, to increase -legibility at small font sizes. For example, a value of 0.75 will -result in rendering that looks similar to sub-pixel antialiasing at -common font sizes. -''')) - -o('macos_traditional_fullscreen', False, long_text=_(''' -Use the traditional full-screen transition, that is faster, but less pretty. -''')) - -o('macos_show_window_title_in', 'all', option_type=choices('all', 'window', 'menubar', 'none'), long_text=_(''' -Show or hide the window title in the macOS window or menu-bar. -A value of :code:`window` will show the title of the currently -active window at the top of the macOS window. A value of -:code:`menubar` will show the title of the currently active window -in the macOS menu-bar, making use of otherwise wasted space. -:code:`all` will show the title everywhere and :code:`none` -hides the title in the window and the menu-bar. -''')) - -# Disabled by default because of https://github.com/kovidgoyal/kitty/issues/794 -o('macos_custom_beam_cursor', False, long_text=_(''' -Enable/disable custom mouse cursor for macOS that is easier to see on both -light and dark backgrounds. WARNING: this might make your mouse cursor -invisible on dual GPU machines.''')) - -o('linux_display_server', 'auto', option_type=choices('auto', 'x11', 'wayland'), long_text=_(''' -Choose between Wayland and X11 backends. By default, an -appropriate backend based on the system state is chosen -automatically. Set it to :code:`x11` or :code:`wayland` -to force the choice.''')) -# }}} - -g('shortcuts') # {{{ - -o('kitty_mod', 'ctrl+shift', option_type=to_modifiers, long_text=_(''' -The value of :code:`kitty_mod` is used as the modifier for all default shortcuts, you -can change it in your kitty.conf to change the modifiers for all the default -shortcuts.''')) - -o('clear_all_shortcuts', False, option_type=clear_all_shortcuts, long_text=_(''' -You can have kitty remove all shortcut definition seen up to this point. Useful, for -instance, to remove the default shortcuts.''')) - -o('+kitten_alias', 'hints hints --hints-offset=0', option_type=kitten_alias, add_to_default=False, long_text=_(''' -You can create aliases for kitten names, this allows overriding the defaults -for kitten options and can also be used to shorten repeated mappings of the same -kitten with a specific group of options. For example, the above alias -changes the default value of :option:`kitty +kitten hints --hints-offset` -to zero for all mappings, including the builtin ones. -''')) - -g('shortcuts.clipboard') # {{{ -k('copy_to_clipboard', 'kitty_mod+c', 'copy_to_clipboard', _('Copy to clipboard'), long_text=_(''' -There is also a :code:`copy_or_interrupt` action that can be optionally mapped to :kbd:`Ctrl+c`. -It will copy only if there is a selection and send an interrupt otherwise. Similarly, :code:`copy_and_clear_or_interrupt` -will copy and clear the selection or send an interrupt if there is no selection.''')) -if is_macos: - k('copy_to_clipboard', 'cmd+c', 'copy_to_clipboard', _('Copy to clipboard'), add_to_docs=False) -k('paste_from_clipboard', 'kitty_mod+v', 'paste_from_clipboard', _('Paste from clipboard')) -if is_macos: - k('paste_from_clipboard', 'cmd+v', 'paste_from_clipboard', _('Paste from clipboard'), add_to_docs=False) -k('paste_from_selection', 'kitty_mod+s', 'paste_from_selection', _('Paste from selection')) -k('paste_from_selection', 'shift+insert', 'paste_from_selection', _('Paste from selection')) -k('pass_selection_to_program', 'kitty_mod+o', 'pass_selection_to_program', _('Pass selection to program'), long_text=_(''' -You can also pass the contents of the current selection to any program using -:code:`pass_selection_to_program`. By default, the system's open program is used, but -you can specify your own, the selection will be passed as a command line argument to the program, -for example:: - - map kitty_mod+o pass_selection_to_program firefox - -You can pass the current selection to a terminal program running in a new kitty -window, by using the @selection placeholder:: - - map kitty_mod+y new_window less @selection -''')) - -# }}} - -g('shortcuts.scrolling') # {{{ -k('scroll_line_up', 'kitty_mod+up', 'scroll_line_up', _('Scroll line up')) -if is_macos: - k('scroll_line_up', 'alt+cmd+page_up', 'scroll_line_up', _('Scroll line up'), add_to_docs=False) - k('scroll_line_up', 'cmd+up', 'scroll_line_up', _('Scroll line up'), add_to_docs=False) -k('scroll_line_up', 'kitty_mod+k', 'scroll_line_up') -k('scroll_line_down', 'kitty_mod+down', 'scroll_line_down', _('Scroll line down')) -k('scroll_line_down', 'kitty_mod+j', 'scroll_line_down') -if is_macos: - k('scroll_line_down', 'alt+cmd+page_down', 'scroll_line_down', _('Scroll line down'), add_to_docs=False) - k('scroll_line_down', 'cmd+down', 'scroll_line_down', _('Scroll line down'), add_to_docs=False) -k('scroll_page_up', 'kitty_mod+page_up', 'scroll_page_up', _('Scroll page up')) -if is_macos: - k('scroll_page_up', 'cmd+page_up', 'scroll_page_up', _('Scroll page up'), add_to_docs=False) -k('scroll_page_down', 'kitty_mod+page_down', 'scroll_page_down', _('Scroll page down')) -if is_macos: - k('scroll_page_down', 'cmd+page_down', 'scroll_page_down', _('Scroll page down'), add_to_docs=False) -k('scroll_home', 'kitty_mod+home', 'scroll_home', _('Scroll to top')) -if is_macos: - k('scroll_home', 'cmd+home', 'scroll_home', _('Scroll to top'), add_to_docs=False) -k('scroll_end', 'kitty_mod+end', 'scroll_end', _('Scroll to bottom')) -if is_macos: - k('scroll_end', 'cmd+end', 'scroll_end', _('Scroll to bottom'), add_to_docs=False) -k('show_scrollback', 'kitty_mod+h', 'show_scrollback', _('Browse scrollback buffer in less'), long_text=_(''' - -You can pipe the contents of the current screen + history buffer as -:file:`STDIN` to an arbitrary program using the ``launch`` function. For example, -the following opens the scrollback buffer in less in an overlay window:: - - map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting --type=overlay less +G -R - -For more details on piping screen and buffer contents to external programs, -see :doc:`launch`. -''')) - - -# }}} - -g('shortcuts.window') # {{{ -k('new_window', 'kitty_mod+enter', 'new_window', _(''), long_text=_(''' -You can open a new window running an arbitrary program, for example:: - - map kitty_mod+y launch mutt - -You can open a new window with the current working directory set to the -working directory of the current window using:: - - map ctrl+alt+enter launch --cwd=current - -You can open a new window that is allowed to control kitty via -the kitty remote control facility by prefixing the command line with @. -Any programs running in that window will be allowed to control kitty. -For example:: - - map ctrl+enter launch --allow-remote-control some_program - -You can open a new window next to the currently active window or as the first window, -with:: - - map ctrl+n launch --location=neighbor some_program - map ctrl+f launch --location=first some_program - -For more details, see :doc:`launch`. -''')) -if is_macos: - k('new_window', 'cmd+enter', 'new_window', _('New window'), add_to_docs=False) -k('new_os_window', 'kitty_mod+n', 'new_os_window', _('New OS window'), _( - 'Works like new_window above, except that it opens a top level OS kitty window.' - ' In particular you can use new_os_window_with_cwd to open a window with the current working directory.')) -if is_macos: - k('new_os_window', 'cmd+n', 'new_os_window', _('New OS window'), add_to_docs=False) -k('close_window', 'kitty_mod+w', 'close_window', _('Close window')) -if is_macos: - k('close_window', 'shift+cmd+d', 'close_window', _('Close window'), add_to_docs=False) -k('next_window', 'kitty_mod+]', 'next_window', _('Next window')) -k('previous_window', 'kitty_mod+[', 'previous_window', _('Previous window')) -k('move_window_forward', 'kitty_mod+f', 'move_window_forward', _('Move window forward')) -k('move_window_backward', 'kitty_mod+b', 'move_window_backward', _('Move window backward')) -k('move_window_to_top', 'kitty_mod+`', 'move_window_to_top', _('Move window to top')) -k('start_resizing_window', 'kitty_mod+r', 'start_resizing_window', _('Start resizing window')) -if is_macos: - k('start_resizing_window', 'cmd+r', 'start_resizing_window', _('Start resizing window'), add_to_docs=False) -k('first_window', 'kitty_mod+1', 'first_window', _('First window')) -k('second_window', 'kitty_mod+2', 'second_window', _('Second window')) -k('third_window', 'kitty_mod+3', 'third_window', _('Third window')) -k('fourth_window', 'kitty_mod+4', 'fourth_window', _('Fourth window')) -k('fifth_window', 'kitty_mod+5', 'fifth_window', _('Fifth window')) -k('sixth_window', 'kitty_mod+6', 'sixth_window', _('Sixth window')) -k('seventh_window', 'kitty_mod+7', 'seventh_window', _('Seventh window')) -k('eighth_window', 'kitty_mod+8', 'eighth_window', _('Eight window')) -k('ninth_window', 'kitty_mod+9', 'ninth_window', _('Ninth window')) -k('tenth_window', 'kitty_mod+0', 'tenth_window', _('Tenth window')) -if is_macos: - k('first_window', 'cmd+1', 'first_window', _('First window'), add_to_docs=False) - k('second_window', 'cmd+2', 'second_window', _('Second window'), add_to_docs=False) - k('third_window', 'cmd+3', 'third_window', _('Third window'), add_to_docs=False) - k('fourth_window', 'cmd+4', 'fourth_window', _('Fourth window'), add_to_docs=False) - k('fifth_window', 'cmd+5', 'fifth_window', _('Fifth window'), add_to_docs=False) - k('sixth_window', 'cmd+6', 'sixth_window', _('Sixth window'), add_to_docs=False) - k('seventh_window', 'cmd+7', 'seventh_window', _('Seventh window'), add_to_docs=False) - k('eighth_window', 'cmd+8', 'eighth_window', _('Eight window'), add_to_docs=False) - k('ninth_window', 'cmd+9', 'ninth_window', _('Ninth window'), add_to_docs=False) -# }}} - -g('shortcuts.tab') # {{{ -k('next_tab', 'kitty_mod+right', 'next_tab', _('Next tab')) -if is_macos: - k('next_tab', 'shift+cmd+]', 'next_tab', _('Next tab'), add_to_docs=False) - k('next_tab', 'ctrl+tab', 'next_tab', _('Next tab'), add_to_docs=False) -k('previous_tab', 'kitty_mod+left', 'previous_tab', _('Previous tab')) -if is_macos: - k('previous_tab', 'shift+cmd+[', 'previous_tab', _('Previous tab'), add_to_docs=False) - k('previous_tab', 'shift+ctrl+tab', 'previous_tab', _('Previous tab'), add_to_docs=False) -k('new_tab', 'kitty_mod+t', 'new_tab', _('New tab')) -if is_macos: - k('new_tab', 'cmd+t', 'new_tab', _('New tab'), add_to_docs=False) -k('close_tab', 'kitty_mod+q', 'close_tab', _('Close tab')) -if is_macos: - k('close_tab', 'cmd+w', 'close_tab', _('Close tab'), add_to_docs=False) - k('close_os_window', 'shift+cmd+w', 'close_os_window', _('Close OS window'), add_to_docs=False) -k('move_tab_forward', 'kitty_mod+.', 'move_tab_forward', _('Move tab forward')) -k('move_tab_backward', 'kitty_mod+,', 'move_tab_backward', _('Move tab backward')) -k('set_tab_title', 'kitty_mod+alt+t', 'set_tab_title', _('Set tab title')) -if is_macos: - k('set_tab_title', 'shift+cmd+i', 'set_tab_title', _('Set tab title'), add_to_docs=False) -# }}} - -g('shortcuts.layout') # {{{ -k('next_layout', 'kitty_mod+l', 'next_layout', _('Next layout')) -# }}} - -g('shortcuts.fonts') # {{{ -k('increase_font_size', 'kitty_mod+equal', 'change_font_size all +2.0', _('Increase font size')) -k('increase_font_size', 'kitty_mod+plus', 'change_font_size all +2.0', _('Increase font size'), add_to_docs=False) -k('increase_font_size', 'kitty_mod+kp_add', 'change_font_size all +2.0', _('Increase font size'), add_to_docs=False) -if is_macos: - k('increase_font_size', 'cmd+plus', 'change_font_size all +2.0', _('Increase font size'), add_to_docs=False) - k('increase_font_size', 'cmd+equal', 'change_font_size all +2.0', _('Increase font size'), add_to_docs=False) - k('increase_font_size', 'cmd+shift+equal', 'change_font_size all +2.0', _('Increase font size'), add_to_docs=False) -k('decrease_font_size', 'kitty_mod+minus', 'change_font_size all -2.0', _('Decrease font size')) -k('decrease_font_size', 'kitty_mod+kp_subtract', 'change_font_size all -2.0', _('Decrease font size')) -if is_macos: - k('decrease_font_size', 'cmd+minus', 'change_font_size all -2.0', _('Decrease font size'), add_to_docs=False) - k('decrease_font_size', 'cmd+shift+minus', 'change_font_size all -2.0', _('Decrease font size'), add_to_docs=False) -k('reset_font_size', 'kitty_mod+backspace', 'change_font_size all 0', _('Reset font size')) -if is_macos: - k('reset_font_size', 'cmd+0', 'change_font_size all 0', _('Reset font size'), add_to_docs=False) -# }}} - -g('shortcuts.selection') # {{{ -k('open_url', 'kitty_mod+e', 'kitten hints', _('Open URL'), _(''' -Open a currently visible URL using the keyboard. The program used to open the -URL is specified in :opt:`open_url_with`.''')) - -k('insert_selected_path', 'kitty_mod+p>f', 'kitten hints --type path --program -', _('Insert selected path'), long_text=_(''' -Select a path/filename and insert it into the terminal. Useful, for instance to -run git commands on a filename output from a previous git command.''')) - -k('open_selected_path', 'kitty_mod+p>shift+f', 'kitten hints --type path', _('Open selected path'), long_text=_(''' -Select a path/filename and open it with the default open program.''')) - -k('insert_selected_line', 'kitty_mod+p>l', 'kitten hints --type line --program -', _('Insert selected line'), long_text=_(''' -Select a line of text and insert it into the terminal. Use for the -output of things like: ls -1''')) - -k('insert_selected_word', 'kitty_mod+p>w', 'kitten hints --type word --program -', _('Insert selected word'), long_text=_(''' -Select words and insert into terminal.''')) - -k('insert_selected_hash', 'kitty_mod+p>h', 'kitten hints --type hash --program -', _('Insert selected hash'), long_text=_(''' -Select something that looks like a hash and insert it into the terminal. -Useful with git, which uses sha1 hashes to identify commits''')) - -k('goto_file_line', 'kitty_mod+p>n', 'kitten hints --type linenum', _('Open the selected file at the selected line'), long_text=_(''' -Select something that looks like :code:`filename:linenum` and open it in vim at -the specified line number.''')) - -k('open_selected_hyperlink', 'kitty_mod+p>y', 'kitten hints --type hyperlink', _('Open the selected hyperlink'), long_text=_(''' -Select a hyperlink (i.e. a URL that has been marked as such by the terminal program, for example, by ls --hyperlink=auto). -''')) - -# }}} - -g('shortcuts.misc') # {{{ -k('toggle_fullscreen', 'kitty_mod+f11', 'toggle_fullscreen', _('Toggle fullscreen')) -k('toggle_maximized', 'kitty_mod+f10', 'toggle_maximized', _('Toggle maximized')) -k('input_unicode_character', 'kitty_mod+u', 'kitten unicode_input', _('Unicode input')) -if is_macos: - k('input_unicode_character', 'cmd+ctrl+space', 'kitten unicode_input', _('Unicode input'), add_to_docs=False) -k('edit_config_file', 'kitty_mod+f2', 'edit_config_file', _('Edit config file')) -if is_macos: - k('edit_config_file', 'cmd+,', 'edit_config_file', _('Edit config file'), add_to_docs=False) -k('kitty_shell', 'kitty_mod+escape', 'kitty_shell window', _('Open the kitty command shell'), long_text=_(''' -Open the kitty shell in a new window/tab/overlay/os_window to control kitty using commands.''')) -k('increase_background_opacity', 'kitty_mod+a>m', 'set_background_opacity +0.1', _('Increase background opacity')) -k('decrease_background_opacity', 'kitty_mod+a>l', 'set_background_opacity -0.1', _('Decrease background opacity')) -k('full_background_opacity', 'kitty_mod+a>1', 'set_background_opacity 1', _('Make background fully opaque')) -k('reset_background_opacity', 'kitty_mod+a>d', 'set_background_opacity default', _('Reset background opacity')) -k('reset_terminal', 'kitty_mod+delete', 'clear_terminal reset active', _('Reset the terminal'), - long_text=_(''' -You can create shortcuts to clear/reset the terminal. For example:: - - # Reset the terminal - map kitty_mod+f9 clear_terminal reset active - # Clear the terminal screen by erasing all contents - map kitty_mod+f10 clear_terminal clear active - # Clear the terminal scrollback by erasing it - map kitty_mod+f11 clear_terminal scrollback active - # Scroll the contents of the screen into the scrollback - map kitty_mod+f12 clear_terminal scroll active - -If you want to operate on all windows instead of just the current one, use :italic:`all` instead of :italic:`active`. - -It is also possible to remap Ctrl+L to both scroll the current screen contents into the scrollback buffer -and clear the screen, instead of just clearing the screen:: - - map ctrl+l combine : clear_terminal scroll active : send_text normal,application \\x0c -''')) -k('send_text', 'ctrl+shift+alt+h', 'send_text all Hello World', _('Send arbitrary text on key presses'), - add_to_default=False, long_text=_(''' -You can tell kitty to send arbitrary (UTF-8) encoded text to -the client program when pressing specified shortcut keys. For example:: - - map ctrl+alt+a send_text all Special text - -This will send "Special text" when you press the :kbd:`ctrl+alt+a` key -combination. The text to be sent is a python string literal so you can use -escapes like :code:`\\x1b` to send control codes or :code:`\\u21fb` to send -unicode characters (or you can just input the unicode characters directly as -UTF-8 text). The first argument to :code:`send_text` is the keyboard modes in which to -activate the shortcut. The possible values are :code:`normal` or :code:`application` or :code:`kitty` -or a comma separated combination of them. The special keyword :code:`all` means all -modes. The modes :code:`normal` and :code:`application` refer to the DECCKM cursor key mode for -terminals, and :code:`kitty` refers to the special kitty extended keyboard protocol. - -Another example, that outputs a word and then moves the cursor to the start of -the line (same as pressing the Home key):: - - map ctrl+alt+a send_text normal Word\\x1b[H - map ctrl+alt+a send_text application Word\\x1bOH -''')) -# }}} -# }}} diff --git a/kitty/constants.py b/kitty/constants.py index ec909e3f0..90f9ea6e1 100644 --- a/kitty/constants.py +++ b/kitty/constants.py @@ -7,11 +7,13 @@ import os import pwd import sys from contextlib import suppress -from typing import NamedTuple, Optional, Set +from typing import NamedTuple, Optional, Set, TYPE_CHECKING -from .options_stub import Options from .types import run_once +if TYPE_CHECKING: + from .options.types import Options + class Version(NamedTuple): major: int @@ -149,7 +151,7 @@ def detect_if_wayland_ok() -> bool: return True -def is_wayland(opts: Optional[Options] = None) -> bool: +def is_wayland(opts: Optional['Options'] = None) -> bool: if is_macos: return False if opts is None: diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 298d55b84..ad96d2803 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -8,7 +8,7 @@ import termios from kitty.boss import Boss from kitty.fonts import FontFeature from kitty.fonts.render import FontObject -from kitty.options_stub import Options +from kitty.options.types import Options # Constants {{{ MOUSE_SELECTION_LINE: int diff --git a/kitty/fonts/core_text.py b/kitty/fonts/core_text.py index f33f2ce17..c9b20108e 100644 --- a/kitty/fonts/core_text.py +++ b/kitty/fonts/core_text.py @@ -7,7 +7,7 @@ from typing import Dict, Generator, Iterable, List, Optional, Tuple from kitty.fast_data_types import coretext_all_fonts from kitty.fonts import FontFeature -from kitty.options_stub import Options +from kitty.options.types import Options from kitty.typing import CoreTextFont from kitty.utils import log_error diff --git a/kitty/fonts/fontconfig.py b/kitty/fonts/fontconfig.py index cd85f514c..fc23972de 100644 --- a/kitty/fonts/fontconfig.py +++ b/kitty/fonts/fontconfig.py @@ -11,7 +11,7 @@ from kitty.fast_data_types import ( FC_WEIGHT_REGULAR, FC_WIDTH_NORMAL, fc_list, fc_match as fc_match_impl, fc_match_postscript_name, parse_font_feature ) -from kitty.options_stub import Options +from kitty.options.types import Options from kitty.typing import FontConfigPattern from kitty.utils import log_error diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 8be9947f5..4cc6ef88f 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -10,7 +10,6 @@ from typing import ( Any, Callable, Dict, Generator, List, Optional, Tuple, Union, cast ) -from kitty.config import defaults from kitty.constants import is_macos from kitty.fast_data_types import ( Screen, create_test_font_group, get_fallback_font, set_font_data, @@ -20,7 +19,7 @@ from kitty.fast_data_types import ( from kitty.fonts.box_drawing import ( BufType, render_box_char, render_missing_glyph ) -from kitty.options_stub import Options as OptionsStub +from kitty.options.types import Options, defaults from kitty.typing import CoreTextFont, FontConfigPattern from kitty.utils import log_error @@ -33,7 +32,7 @@ FontObject = Union[CoreTextFont, FontConfigPattern] current_faces: List[Tuple[FontObject, bool, bool]] = [] -def get_font_files(opts: OptionsStub) -> Dict[str, Any]: +def get_font_files(opts: Options) -> Dict[str, Any]: if is_macos: return get_font_files_coretext(opts) return get_font_files_fontconfig(opts) @@ -136,7 +135,7 @@ def coalesce_symbol_maps(maps: Dict[Tuple[int, int], str]) -> Dict[Tuple[int, in return dict(ans) -def create_symbol_map(opts: OptionsStub) -> Tuple[Tuple[int, int, int], ...]: +def create_symbol_map(opts: Options) -> Tuple[Tuple[int, int, int], ...]: val = coalesce_symbol_maps(opts.symbol_map) family_map: Dict[str, int] = {} count = 0 @@ -174,7 +173,7 @@ def dump_faces(ftypes: List[str], indices: Dict[str, int]) -> None: log_error(face_str(face)) -def set_font_family(opts: Optional[OptionsStub] = None, override_font_size: Optional[float] = None, debug_font_matching: bool = False) -> None: +def set_font_family(opts: Optional[Options] = None, override_font_size: Optional[float] = None, debug_font_matching: bool = False) -> None: global current_faces opts = opts or defaults sz = override_font_size or opts.font_size diff --git a/kitty/keys.py b/kitty/keys.py index be3f4c599..f0adc05cc 100644 --- a/kitty/keys.py +++ b/kitty/keys.py @@ -4,11 +4,12 @@ from typing import Optional, Union +from .conf.utils import KeyAction from .fast_data_types import ( GLFW_MOD_ALT, GLFW_MOD_CAPS_LOCK, GLFW_MOD_CONTROL, GLFW_MOD_HYPER, GLFW_MOD_META, GLFW_MOD_NUM_LOCK, GLFW_MOD_SHIFT, GLFW_MOD_SUPER, KeyEvent ) -from .options.utils import KeyAction, KeyMap, SequenceMap, SubSequenceMap +from .options.utils import KeyMap, SequenceMap, SubSequenceMap from .types import SingleKey from .typing import ScreenType diff --git a/kitty/layout/base.py b/kitty/layout/base.py index 90665f515..2ca8d1e72 100644 --- a/kitty/layout/base.py +++ b/kitty/layout/base.py @@ -13,7 +13,7 @@ from kitty.borders import BorderColor from kitty.fast_data_types import ( Region, set_active_window, viewport_for_window ) -from kitty.options_stub import Options +from kitty.options.types import Options from kitty.types import Edges, WindowGeometry from kitty.typing import TypedDict, WindowType from kitty.window_list import WindowGroup, WindowList diff --git a/kitty/main.py b/kitty/main.py index 528d5a30a..ea180800c 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -27,7 +27,7 @@ from .fast_data_types import ( ) from .fonts.box_drawing import set_scale from .fonts.render import set_font_family -from .options_stub import Options as OptionsStub +from .options.types import Options from .os_window_size import initial_window_size_func from .session import get_os_window_sizing_data from .types import SingleKey @@ -98,13 +98,13 @@ def init_glfw_module(glfw_module: str, debug_keyboard: bool = False, debug_rende raise SystemExit('GLFW initialization failed') -def init_glfw(opts: OptionsStub, debug_keyboard: bool = False, debug_rendering: bool = False) -> str: +def init_glfw(opts: Options, debug_keyboard: bool = False, debug_rendering: bool = False) -> str: glfw_module = 'cocoa' if is_macos else ('wayland' if is_wayland(opts) else 'x11') init_glfw_module(glfw_module, debug_keyboard, debug_rendering) return glfw_module -def get_macos_shortcut_for(opts: OptionsStub, function: str = 'new_os_window') -> Optional[SingleKey]: +def get_macos_shortcut_for(opts: Options, function: str = 'new_os_window') -> Optional[SingleKey]: ans = None candidates = [] for k, v in opts.keymap.items(): @@ -132,7 +132,7 @@ def set_x11_window_icon() -> None: set_default_window_icon(path + '-128' + ext) -def _run_app(opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None: +def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None: global_shortcuts: Dict[str, SingleKey] = {} if is_macos: for ac in ('new_os_window', 'close_os_window', 'close_tab', 'edit_config_file', 'previous_tab', @@ -169,7 +169,7 @@ class AppRunner: self.first_window_callback = lambda window_handle: None self.initial_window_size_func = initial_window_size_func - def __call__(self, opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None: + def __call__(self, opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None: set_scale(opts.box_drawing_scale) set_options(opts, is_wayland(), args.debug_rendering, args.debug_font_fallback) try: @@ -248,7 +248,7 @@ def expand_listen_on(listen_on: str, from_config_file: bool) -> str: return listen_on -def setup_environment(opts: OptionsStub, cli_opts: CLIOptions) -> None: +def setup_environment(opts: Options, cli_opts: CLIOptions) -> None: from_config_file = False if not cli_opts.listen_on and opts.listen_on.startswith('unix:'): cli_opts.listen_on = opts.listen_on diff --git a/kitty/open_actions.py b/kitty/open_actions.py index ff2fd181e..acd144db1 100644 --- a/kitty/open_actions.py +++ b/kitty/open_actions.py @@ -11,10 +11,10 @@ from typing import ( ) from urllib.parse import ParseResult, unquote, urlparse -from .conf.utils import to_cmdline_implementation +from .conf.utils import KeyAction, to_cmdline_implementation from .constants import config_dir from .guess_mime_type import guess_type -from .options.utils import KeyAction, parse_key_action +from .options.utils import parse_key_action from .types import run_once from .typing import MatchType from .utils import expandvars, log_error diff --git a/kitty/options/definition.py b/kitty/options/definition.py new file mode 100644 index 000000000..6a67b36d8 --- /dev/null +++ b/kitty/options/definition.py @@ -0,0 +1,3325 @@ +from kitty.conf.types import Action, Definition + + +definition = Definition( + 'kitty', + Action('map', 'parse_map', {'keymap': 'KeyMap', 'sequence_map': 'SequenceMap'}, + ['KeyDefinition', 'kitty.conf.utils.KeyAction', 'kitty.types.SingleKey']), + Action('mouse_map', 'parse_mouse_map', {'mousemap': 'MouseMap'}, ['MouseMapping', 'kitty.conf.utils.KeyAction']), +) +definition.add_deprecation('deprecated_hide_window_decorations_aliases', 'x11_hide_window_decorations', 'macos_hide_titlebar') +definition.add_deprecation('deprecated_macos_show_window_title_in_menubar_alias', 'macos_show_window_title_in_menubar') +definition.add_deprecation('deprecated_send_text', 'send_text') + +agr = definition.add_group +egr = definition.end_group +opt = definition.add_option +map = definition.add_map +mma = definition.add_mouse_map + +# fonts {{{ +agr('fonts', 'Fonts', ''' +kitty has very powerful font management. You can configure individual font faces +and even specify special fonts for particular characters. +''') + +opt('font_family', 'monospace', + long_text=''' +You can specify different fonts for the bold/italic/bold-italic variants. +To get a full list of supported fonts use the `kitty list-fonts` command. +By default they are derived automatically, by the OSes font system. Setting +them manually is useful for font families that have many weight variants like +Book, Medium, Thick, etc. For example:: + + font_family Operator Mono Book + bold_font Operator Mono Medium + italic_font Operator Mono Book Italic + bold_italic_font Operator Mono Medium Italic +''' + ) + +opt('bold_font', 'auto', + ) + +opt('italic_font', 'auto', + ) + +opt('bold_italic_font', 'auto', + ) + +opt('font_size', '11.0', + option_type='to_font_size', + long_text='Font size (in pts)' + ) + +opt('force_ltr', 'no', + option_type='to_bool', + long_text=''' +kitty does not support BIDI (bidirectional text), however, for RTL scripts, +words are automatically displayed in RTL. That is to say, in an RTL script, the +words "HELLO WORLD" display in kitty as "WORLD HELLO", and if you try to select +a substring of an RTL-shaped string, you will get the character that would be +there had the the string been LTR. For example, assuming the Hebrew word +ירושלים, selecting the character that on the screen appears to be ם actually +writes into the selection buffer the character י. kitty's default behavior is +useful in conjunction with a filter to reverse the word order, however, if you +wish to manipulate RTL glyphs, it can be very challenging to work with, so this +option is provided to turn it off. Furthermore, this option can be used with the +command line program :link:`GNU FriBidi +` to get BIDI support, because it +will force kitty to always treat the text as LTR, which FriBidi expects for +terminals. +''' + ) + +opt('adjust_line_height', '0', + option_type='adjust_line_height', + long_text=''' +Change the size of each character cell kitty renders. You can use either +numbers, which are interpreted as pixels or percentages (number followed by %), +which are interpreted as percentages of the unmodified values. You can use +negative pixels or percentages less than 100% to reduce sizes (but this might +cause rendering artifacts). +''' + ) + +opt('adjust_column_width', '0', + option_type='adjust_line_height', + ) + +opt('+symbol_map', 'U+E0A0-U+E0A3,U+E0C0-U+E0C7 PowerlineSymbols', + option_type='symbol_map', + add_to_default=False, + long_text=''' +Map the specified unicode codepoints to a particular font. Useful if you need +special rendering for some symbols, such as for Powerline. Avoids the need for +patched fonts. Each unicode code point is specified in the form :code:`U+`. You can specify multiple code points, separated by commas and +ranges separated by hyphens. :code:`symbol_map` itself can be specified multiple times. +Syntax is:: + + symbol_map codepoints Font Family Name +''' + ) + +opt('disable_ligatures', 'never', + option_type='disable_ligatures', + long_text=''' +Choose how you want to handle multi-character ligatures. The default is to +always render them. You can tell kitty to not render them when the cursor is +over them by using :code:`cursor` to make editing easier, or have kitty never +render them at all by using :code:`always`, if you don't like them. The ligature +strategy can be set per-window either using the kitty remote control facility +or by defining shortcuts for it in kitty.conf, for example:: + + map alt+1 disable_ligatures_in active always + map alt+2 disable_ligatures_in all never + map alt+3 disable_ligatures_in tab cursor + +Note that this refers to programming ligatures, typically implemented using the +:code:`calt` OpenType feature. For disabling general ligatures, use the +:opt:`font_features` setting. +''' + ) + +opt('+font_features', 'none', + option_type='font_features', + add_to_default=False, + long_text=''' +Choose exactly which OpenType features to enable or disable. This is useful as +some fonts might have features worthwhile in a terminal. For example, Fira +Code Retina includes a discretionary feature, :code:`zero`, which in that font +changes the appearance of the zero (0), to make it more easily distinguishable +from Ø. Fira Code Retina also includes other discretionary features known as +Stylistic Sets which have the tags :code:`ss01` through :code:`ss20`. + +Note that this code is indexed by PostScript name, and not the font +family. This allows you to define very precise feature settings; e.g. you can +disable a feature in the italic font but not in the regular font. + +On Linux, these are read from the FontConfig database first and then this, +setting is applied, so they can be configured in a single, central place. + +To get the PostScript name for a font, use :code:`kitty + list-fonts --psnames`: + +.. code-block:: sh + + $ kitty + list-fonts --psnames | grep Fira + Fira Code + Fira Code Bold (FiraCode-Bold) + Fira Code Light (FiraCode-Light) + Fira Code Medium (FiraCode-Medium) + Fira Code Regular (FiraCode-Regular) + Fira Code Retina (FiraCode-Retina) + +The part in brackets is the PostScript name. + +Enable alternate zero and oldstyle numerals:: + + font_features FiraCode-Retina +zero +onum + +Enable only alternate zero:: + + font_features FiraCode-Retina +zero + +Disable the normal ligatures, but keep the :code:`calt` feature which (in this +font) breaks up monotony:: + + font_features TT2020StyleB-Regular -liga +calt + +In conjunction with :opt:`force_ltr`, you may want to disable Arabic shaping +entirely, and only look at their isolated forms if they show up in a document. +You can do this with e.g.:: + + font_features UnifontMedium +isol -medi -fina -init +''' + ) + +opt('box_drawing_scale', '0.001, 1, 1.5, 2', + option_type='box_drawing_scale', + long_text=''' +Change the sizes of the lines used for the box drawing unicode characters These +values are in pts. They will be scaled by the monitor DPI to arrive at a pixel +value. There must be four values corresponding to thin, normal, thick, and very +thick lines. +''' + ) +egr() # }}} + +# cursor {{{ +agr('cursor', 'Cursor customization') + +opt('cursor', '#cccccc', + option_type='to_color', + long_text='Default cursor color' + ) + +opt('cursor_text_color', '#111111', + option_type='cursor_text_color', + long_text=''' +Choose the color of text under the cursor. If you want it rendered with the +background color of the cell underneath instead, use the special keyword: +background +''' + ) + +opt('cursor_shape', 'block', + option_type='to_cursor_shape', + long_text='The cursor shape can be one of (block, beam, underline)' + ) + +opt('cursor_beam_thickness', '1.5', + option_type='positive_float', + long_text='Defines the thickness of the beam cursor (in pts)' + ) + +opt('cursor_underline_thickness', '2.0', + option_type='positive_float', + long_text='Defines the thickness of the underline cursor (in pts)' + ) + +opt('cursor_blink_interval', '-1', + option_type='float', + long_text=''' +The interval (in seconds) at which to blink the cursor. Set to zero to disable +blinking. Negative values mean use system default. Note that numbers smaller +than :opt:`repaint_delay` will be limited to :opt:`repaint_delay`. +''' + ) + +opt('cursor_stop_blinking_after', '15.0', + option_type='positive_float', + long_text=''' +Stop blinking cursor after the specified number of seconds of keyboard +inactivity. Set to zero to never stop blinking. +''' + ) +egr() # }}} + +# scrollback {{{ +agr('scrollback', 'Scrollback') + +opt('scrollback_lines', '2000', + option_type='scrollback_lines', + long_text=''' +Number of lines of history to keep in memory for scrolling back. Memory is +allocated on demand. Negative numbers are (effectively) infinite scrollback. +Note that using very large scrollback is not recommended as it can slow down +performance of the terminal and also use large amounts of RAM. Instead, consider +using :opt:`scrollback_pager_history_size`. +''' + ) + +opt('scrollback_pager', 'less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER', + option_type='to_cmdline', + long_text=''' +Program with which to view scrollback in a new window. The scrollback buffer is +passed as STDIN to this program. If you change it, make sure the program you use +can handle ANSI escape sequences for colors and text formatting. +INPUT_LINE_NUMBER in the command line above will be replaced by an integer +representing which line should be at the top of the screen. Similarly +CURSOR_LINE and CURSOR_COLUMN will be replaced by the current cursor position. +''' + ) + +opt('scrollback_pager_history_size', '0', + option_type='scrollback_pager_history_size', + long_text=''' +Separate scrollback history size, used only for browsing the scrollback buffer +(in MB). This separate buffer is not available for interactive scrolling but +will be piped to the pager program when viewing scrollback buffer in a separate +window. The current implementation stores the data in UTF-8, so approximatively +10000 lines per megabyte at 100 chars per line, for pure ASCII text, unformatted +text. A value of zero or less disables this feature. The maximum allowed size is +4GB. +''' + ) + +opt('scrollback_fill_enlarged_window', 'no', + option_type='to_bool', + long_text='Fill new space with lines from the scrollback buffer after enlarging a window.' + ) + +opt('wheel_scroll_multiplier', '5.0', + option_type='float', + long_text=''' +Modify the amount scrolled by the mouse wheel. Note this is only used for low +precision scrolling devices, not for high precision scrolling on platforms such +as macOS and Wayland. Use negative numbers to change scroll direction. +''' + ) + +opt('touch_scroll_multiplier', '1.0', + option_type='float', + long_text=''' +Modify the amount scrolled by a touchpad. Note this is only used for high +precision scrolling devices on platforms such as macOS and Wayland. Use negative +numbers to change scroll direction. +''' + ) +egr() # }}} + +# mouse {{{ +agr('mouse', 'Mouse') + +opt('mouse_hide_wait', '3.0', + macos_default="0.0", + option_type='float', + long_text=''' +Hide mouse cursor after the specified number of seconds of the mouse not being +used. Set to zero to disable mouse cursor hiding. Set to a negative value to +hide the mouse cursor immediately when typing text. Disabled by default on macOS +as getting it to work robustly with the ever-changing sea of bugs that is Cocoa +is too much effort. +''' + ) + +opt('url_color', '#0087bd', + option_type='to_color', + long_text=''' +The color and style for highlighting URLs on mouse-over. :code:`url_style` can +be one of: none, single, double, curly +''' + ) + +opt('url_style', 'curly', + option_type='url_style', + ) + +opt('open_url_with', 'default', + option_type='to_cmdline', + long_text=''' +The program with which to open URLs that are clicked on. The special value +:code:`default` means to use the operating system's default URL handler. +''' + ) + +opt('url_prefixes', 'http https file ftp gemini irc gopher mailto news git', + option_type='url_prefixes', + long_text=''' +The set of URL prefixes to look for when detecting a URL under the mouse cursor. +''' + ) + +opt('detect_urls', 'yes', + option_type='to_bool', + long_text=''' +Detect URLs under the mouse. Detected URLs are highlighted with an underline and +the mouse cursor becomes a hand over them. Even if this option is disabled, URLs +are still clickable. +''' + ) + +opt('copy_on_select', 'no', + option_type='copy_on_select', + long_text=''' +Copy to clipboard or a private buffer on select. With this set to +:code:`clipboard`, simply selecting text with the mouse will cause the text to +be copied to clipboard. Useful on platforms such as macOS that do not have the +concept of primary selections. You can instead specify a name such as :code:`a1` to +copy to a private kitty buffer instead. Map a shortcut with the +:code:`paste_from_buffer` action to paste from this private buffer. +For example:: + + map cmd+shift+v paste_from_buffer a1 + +Note that copying to the clipboard is a security risk, as all programs, +including websites open in your browser can read the contents of the +system clipboard. +''' + ) + +opt('strip_trailing_spaces', 'never', + choices=('always', 'never', 'smart'), + long_text=''' +Remove spaces at the end of lines when copying to clipboard. A value of +:code:`smart` will do it when using normal selections, but not rectangle +selections. :code:`always` will always do it. +''' + ) + +opt('select_by_word_characters', '@-./_~?&=%+#', + long_text=''' +Characters considered part of a word when double clicking. In addition to these +characters any character that is marked as an alphanumeric character in the +unicode database will be matched. +''' + ) + +opt('click_interval', '-1.0', + option_type='float', + long_text=''' +The interval between successive clicks to detect double/triple clicks (in +seconds). Negative numbers will use the system default instead, if available, or +fallback to 0.5. +''' + ) + +opt('focus_follows_mouse', 'no', + option_type='to_bool', + long_text=''' +Set the active window to the window under the mouse when moving the mouse around +''' + ) + +opt('pointer_shape_when_grabbed', 'arrow', + choices=('arrow', 'beam', 'hand'), + long_text=''' +The shape of the mouse pointer when the program running in the terminal grabs +the mouse. Valid values are: :code:`arrow`, :code:`beam` and :code:`hand` +''' + ) + +opt('default_pointer_shape', 'beam', + choices=('arrow', 'beam', 'hand'), + long_text=''' +The default shape of the mouse pointer. Valid values are: :code:`arrow`, +:code:`beam` and :code:`hand` +''' + ) + +opt('pointer_shape_when_dragging', 'beam', + choices=('arrow', 'beam', 'hand'), + long_text=''' +The default shape of the mouse pointer when dragging across text. Valid values +are: :code:`arrow`, :code:`beam` and :code:`hand` +''' + ) + + +# mouse.mousemap {{{ +agr('mouse.mousemap', 'Mouse actions', ''' +Mouse buttons can be remapped to perform arbitrary actions. The syntax for +doing so is: + +.. code-block:: none + + mouse_map button-name event-type modes action + +Where ``button-name`` is one of ``left``, ``middle``, ``right`` or ``b1 ... b8`` +with added keyboard modifiers, for example: ``ctrl+shift+left`` refers to holding +the :kbd:`ctrl+shift` keys while clicking with the left mouse button. The +number ``b1 ... b8`` can be used to refer to upto eight buttons on a mouse. + +``event-type`` is one ``press``, ``release``, ``doublepress``, ``triplepress``, +``click`` and ``doubleclick``. ``modes`` indicates whether the action is +performed when the mouse is grabbed by the terminal application or not. It can +have one or more or the values, ``grabbed,ungrabbed``. Note that the click +and double click events have a delay of :opt:`click_interval` to disambiguate +from double and triple presses. + +You can run kitty with the :option:`kitty --debug-input` command line option +to see mouse events. See the builtin actions below to get a sense of what is possible. + +If you want to unmap an action map it to ``no-op``. + +.. note:: + Once a selection is started, releasing the button that started it will + automatically end it and no release event will be dispatched. +''') + +mma('Click the link under the mouse cursor when no selection is created', + 'click_url_or_select left click ungrabbed mouse_click_url_or_select', + ) + +mma('Click the link under the mouse cursor when no selection is created even if grabbed', + 'click_url_or_select_grabbed shift+left click grabbed,ungrabbed mouse_click_url_or_select', + ) + +mma('Click the link under the mouse cursor', + 'click_url ctrl+shift+left release grabbed,ungrabbed mouse_click_url', + long_text='Variant with :kbd:`ctrl+shift` is present only for legacy compatibility.' + ) + +mma('Paste from the primary selection', + 'paste_selection middle release ungrabbed paste_selection', + ) + +mma('Start selecting text', + 'start_simple_selection left press ungrabbed mouse_selection normal', + ) + +mma('Start selecting text in a rectangle', + 'start_rectangle_selection ctrl+alt+left press ungrabbed mouse_selection rectangle', + ) + +mma('Select a word', + 'select_word left doublepress ungrabbed mouse_selection word', + ) + +mma('Select a line', + 'select_line left triplepress ungrabbed mouse_selection line', + long_text='Select the entire line' + ) + +mma('Select line from point', + 'select_line_from_point ctrl+alt+left triplepress ungrabbed mouse_selection line_from_point', + long_text='Select from the clicked point to the end of the line' + ) + +mma('Extend the current selection', + 'extend_selection right press ungrabbed mouse_selection extend', + ) + +mma('Paste from the primary selection even when grabbed', + 'paste_selection_grabbed shift+middle release ungrabbed,grabbed paste_selection', + ) + +mma('Start selecting text even when grabbed', + 'start_simple_selection_grabbed shift+left press ungrabbed,grabbed mouse_selection normal', + ) + +mma('Start selecting text in a rectangle even when grabbed', + 'start_rectangle_selection_grabbed shift+ctrl+alt+left press ungrabbed,grabbed mouse_selection rectangle', + ) + +mma('Select a word even when grabbed', + 'select_word_grabbed shift+left doublepress ungrabbed,grabbed mouse_selection word', + ) + +mma('Select a line even when grabbed', + 'select_line_grabbed shift+left triplepress ungrabbed,grabbed mouse_selection line', + long_text='Select the entire line' + ) + +mma('Select line from point even when grabbed', + 'select_line_from_point_grabbed shift+ctrl+alt+left triplepress ungrabbed,grabbed mouse_selection line_from_point', + long_text='Select from the clicked point to the end of the line' + ) + +mma('Extend the current selection even when grabbed', + 'extend_selection_grabbed shift+right press ungrabbed,grabbed mouse_selection extend', + ) +egr() # }}} +egr() # }}} + +# performance {{{ +agr('performance', 'Performance tuning') + +opt('repaint_delay', '10', + option_type='positive_int', + long_text=''' +Delay (in milliseconds) between screen updates. Decreasing it, increases frames- +per-second (FPS) at the cost of more CPU usage. The default value yields ~100 +FPS which is more than sufficient for most uses. Note that to actually achieve +100 FPS you have to either set :opt:`sync_to_monitor` to no or use a monitor +with a high refresh rate. Also, to minimize latency when there is pending input +to be processed, repaint_delay is ignored. +''' + ) + +opt('input_delay', '3', + option_type='positive_int', + long_text=''' +Delay (in milliseconds) before input from the program running in the terminal is +processed. Note that decreasing it will increase responsiveness, but also +increase CPU usage and might cause flicker in full screen programs that redraw +the entire screen on each loop, because kitty is so fast that partial screen +updates will be drawn. +''' + ) + +opt('sync_to_monitor', 'yes', + option_type='to_bool', + long_text=''' +Sync screen updates to the refresh rate of the monitor. This prevents tearing +(https://en.wikipedia.org/wiki/Screen_tearing) when scrolling. However, it +limits the rendering speed to the refresh rate of your monitor. With a very high +speed mouse/high keyboard repeat rate, you may notice some slight input latency. +If so, set this to no. +''' + ) +egr() # }}} + +# bell {{{ +agr('bell', 'Terminal bell') + +opt('enable_audio_bell', 'yes', + option_type='to_bool', + long_text='Enable/disable the audio bell. Useful in environments that require silence.' + ) + +opt('visual_bell_duration', '0.0', + option_type='positive_float', + long_text=''' +Visual bell duration. Flash the screen when a bell occurs for the specified +number of seconds. Set to zero to disable. +''' + ) + +opt('window_alert_on_bell', 'yes', + option_type='to_bool', + long_text=''' +Request window attention on bell. Makes the dock icon bounce on macOS or the +taskbar flash on linux. +''' + ) + +opt('bell_on_tab', 'yes', + option_type='to_bool', + long_text=''' +Show a bell symbol on the tab if a bell occurs in one of the windows in the tab +and the window is not the currently focused window +''' + ) + +opt('command_on_bell', 'none', + option_type='to_cmdline', + long_text='Program to run when a bell occurs.' + ) +egr() # }}} + +# window {{{ +agr('window', 'Window layout') + +opt('remember_window_size', 'yes', + option_type='to_bool', + long_text=''' +If enabled, the window size will be remembered so that new instances of kitty +will have the same size as the previous instance. If disabled, the window will +initially have size configured by initial_window_width/height, in pixels. You +can use a suffix of "c" on the width/height values to have them interpreted as +number of cells instead of pixels. +''' + ) + +opt('initial_window_width', '640', + option_type='window_size', + ) + +opt('initial_window_height', '400', + option_type='window_size', + ) + +opt('enabled_layouts', '*', + option_type='to_layout_names', + long_text=''' +The enabled window layouts. A comma separated list of layout names. The special +value :code:`all` means all layouts. The first listed layout will be used as the +startup layout. Default configuration is all layouts in alphabetical order. For +a list of available layouts, see the :ref:`layouts`. +''' + ) + +opt('window_resize_step_cells', '2', + option_type='positive_int', + long_text=''' +The step size (in units of cell width/cell height) to use when resizing windows. +The cells value is used for horizontal resizing and the lines value for vertical +resizing. +''' + ) + +opt('window_resize_step_lines', '2', + option_type='positive_int', + ) + +opt('window_border_width', '0.5pt', + option_type='window_border_width', + long_text=''' +The width of window borders. Can be either in pixels (px) or pts (pt). Values in +pts will be rounded to the nearest number of pixels based on screen resolution. +If not specified the unit is assumed to be pts. Note that borders are displayed +only when more than one window is visible. They are meant to separate multiple +windows. +''' + ) + +opt('draw_minimal_borders', 'yes', + option_type='to_bool', + long_text=''' +Draw only the minimum borders needed. This means that only the minimum needed +borders for inactive windows are drawn. That is only the borders that separate +the inactive window from a neighbor. Note that setting a non-zero window margin +overrides this and causes all borders to be drawn. +''' + ) + +opt('window_margin_width', '0', + option_type='edge_width', + long_text=''' +The window margin (in pts) (blank area outside the border). A single value sets +all four sides. Two values set the vertical and horizontal sides. Three values +set top, horizontal and bottom. Four values set top, right, bottom and left. +''' + ) + +opt('single_window_margin_width', '-1', + option_type='optional_edge_width', + long_text=''' +The window margin (in pts) to use when only a single window is visible. Negative +values will cause the value of :opt:`window_margin_width` to be used instead. A +single value sets all four sides. Two values set the vertical and horizontal +sides. Three values set top, horizontal and bottom. Four values set top, right, +bottom and left. +''' + ) + +opt('window_padding_width', '0', + option_type='edge_width', + long_text=''' +The window padding (in pts) (blank area between the text and the window border). +A single value sets all four sides. Two values set the vertical and horizontal +sides. Three values set top, horizontal and bottom. Four values set top, right, +bottom and left. +''' + ) + +opt('placement_strategy', 'center', + choices=('center', 'top-left'), + long_text=''' +When the window size is not an exact multiple of the cell size, the cell area of +the terminal window will have some extra padding on the sides. You can control +how that padding is distributed with this option. Using a value of +:code:`center` means the cell area will be placed centrally. A value of +:code:`top-left` means the padding will be on only the bottom and right edges. +''' + ) + +opt('active_border_color', '#00ff00', + option_type='to_color_or_none', + long_text=''' +The color for the border of the active window. Set this to none to not draw +borders around the active window. +''' + ) + +opt('inactive_border_color', '#cccccc', + option_type='to_color', + long_text='The color for the border of inactive windows' + ) + +opt('bell_border_color', '#ff5a00', + option_type='to_color', + long_text='The color for the border of inactive windows in which a bell has occurred' + ) + +opt('inactive_text_alpha', '1.0', + option_type='unit_float', + long_text=''' +Fade the text in inactive windows by the specified amount (a number between zero +and one, with zero being fully faded). +''' + ) + +opt('hide_window_decorations', 'no', + option_type='hide_window_decorations', + long_text=''' +Hide the window decorations (title-bar and window borders) with :code:`yes`. On +macOS, :code:`titlebar-only` can be used to only hide the titlebar. Whether this +works and exactly what effect it has depends on the window manager/operating +system. +''' + ) + +opt('resize_debounce_time', '0.1', + option_type='positive_float', + long_text=''' +The time (in seconds) to wait before redrawing the screen when a resize event is +received. On platforms such as macOS, where the operating system sends events +corresponding to the start and end of a resize, this number is ignored. +''' + ) + +opt('resize_draw_strategy', 'static', + option_type='resize_draw_strategy', + long_text=''' +Choose how kitty draws a window while a resize is in progress. A value of +:code:`static` means draw the current window contents, mostly unchanged. A value +of :code:`scale` means draw the current window contents scaled. A value of +:code:`blank` means draw a blank window. A value of :code:`size` means show the +window size in cells. +''' + ) + +opt('resize_in_steps', 'no', + option_type='to_bool', + long_text=''' +Resize the OS window in steps as large as the cells, instead of with the usual +pixel accuracy. Combined with an :opt:`initial_window_width` and +:opt:`initial_window_height` in number of cells, this option can be used to keep +the margins as small as possible when resizing the OS window. Note that this +does not currently work on Wayland. +''' + ) + +opt('confirm_os_window_close', '0', + option_type='positive_int', + long_text=''' +Ask for confirmation when closing an OS window or a tab that has at least this +number of kitty windows in it. A value of zero disables confirmation. This +confirmation also applies to requests to quit the entire application (all OS +windows, via the quit action). +''' + ) +egr() # }}} + +# tabbar {{{ +agr('tabbar', 'Tab bar') + +opt('tab_bar_edge', 'bottom', + option_type='tab_bar_edge', + long_text='Which edge to show the tab bar on, top or bottom' + ) + +opt('tab_bar_margin_width', '0.0', + option_type='positive_float', + long_text='The margin to the left and right of the tab bar (in pts)' + ) + +opt('tab_bar_style', 'fade', + choices=('fade', 'hidden', 'powerline', 'separator'), + long_text=''' +The tab bar style, can be one of: :code:`fade`, :code:`separator`, +:code:`powerline`, or :code:`hidden`. In the fade style, each tab's edges fade +into the background color, in the separator style, tabs are separated by a +configurable separator, and the powerline shows the tabs as a continuous line. +If you use the hidden style, you might want to create a mapping for the +:code:`select_tab` action which presents you with a list of tabs and allows for +easy switching to a tab. +''' + ) + +opt('tab_bar_min_tabs', '2', + option_type='tab_bar_min_tabs', + long_text='The minimum number of tabs that must exist before the tab bar is shown' + ) + +opt('tab_switch_strategy', 'previous', + choices=('last', 'left', 'previous', 'right'), + long_text=''' +The algorithm to use when switching to a tab when the current tab is closed. The +default of :code:`previous` will switch to the last used tab. A value of +:code:`left` will switch to the tab to the left of the closed tab. A value of +:code:`right` will switch to the tab to the right of the closed tab. A value of +:code:`last` will switch to the right-most tab. +''' + ) + +opt('tab_fade', '0.25 0.5 0.75 1', + option_type='tab_fade', + long_text=''' +Control how each tab fades into the background when using :code:`fade` for the +:opt:`tab_bar_style`. Each number is an alpha (between zero and one) that +controls how much the corresponding cell fades into the background, with zero +being no fade and one being full fade. You can change the number of cells used +by adding/removing entries to this list. +''' + ) + +opt('tab_separator', '" ┇"', + option_type='tab_separator', + long_text=''' +The separator between tabs in the tab bar when using :code:`separator` as the +:opt:`tab_bar_style`. +''' + ) + +opt('tab_powerline_style', 'angled', + choices=('angled', 'round', 'slanted'), + long_text=''' +The powerline separator style between tabs in the tab bar when using +:code:`powerline` as the :opt:`tab_bar_style`, can be one of: :code:`angled`, +:code:`slanted`, or :code:`round`. +''' + ) + +opt('tab_activity_symbol', 'none', + option_type='tab_activity_symbol', + long_text=''' +Some text or a unicode symbol to show on the tab if a window in the tab that +does not have focus has some activity. +''' + ) + +opt('tab_title_template', '"{title}"', + option_type='tab_title_template', + long_text=''' +A template to render the tab title. The default just renders the title. If you +wish to include the tab-index as well, use something like: :code:`{index}: +{title}`. Useful if you have shortcuts mapped for :code:`goto_tab N`. In +addition you can use :code:`{layout_name}` for the current layout name and +:code:`{num_windows}` for the number of windows in the tab. Note that formatting +is done by Python's string formatting machinery, so you can use, for instance, +:code:`{layout_name[:2].upper()}` to show only the first two letters of the +layout name, upper-cased. If you want to style the text, you can use styling +directives, for example: +:code:`{fmt.fg.red}red{fmt.fg.default}normal{fmt.bg._00FF00}green +bg{fmt.bg.normal}`. Similarly, for bold and italic: +:code:`{fmt.bold}bold{fmt.nobold}normal{fmt.italic}italic{fmt.noitalic}`. +''' + ) + +opt('active_tab_title_template', 'none', + option_type='active_tab_title_template', + long_text=''' +Template to use for active tabs, if not specified falls back to +:opt:`tab_title_template`. +''' + ) + +opt('active_tab_foreground', '#000', + option_type='to_color', + long_text='Tab bar colors and styles' + ) + +opt('active_tab_background', '#eee', + option_type='to_color', + ) + +opt('active_tab_font_style', 'bold-italic', + option_type='tab_font_style', + ) + +opt('inactive_tab_foreground', '#444', + option_type='to_color', + ) + +opt('inactive_tab_background', '#999', + option_type='to_color', + ) + +opt('inactive_tab_font_style', 'normal', + option_type='tab_font_style', + ) + +opt('tab_bar_background', 'none', + option_type='to_color_or_none', + long_text=''' +Background color for the tab bar. Defaults to using the terminal background +color. +''' + ) +egr() # }}} + +# colors {{{ +agr('colors', 'Color scheme') + +opt('foreground', '#dddddd', + option_type='to_color', + long_text='The foreground and background colors' + ) + +opt('background', '#000000', + option_type='to_color', + ) + +opt('background_opacity', '1.0', + option_type='unit_float', + long_text=''' +The opacity of the background. A number between 0 and 1, where 1 is opaque and 0 +is fully transparent. This will only work if supported by the OS (for instance, +when using a compositor under X11). Note that it only sets the background +color's opacity in cells that have the same background color as the default +terminal background. This is so that things like the status bar in vim, +powerline prompts, etc. still look good. But it means that if you use a color +theme with a background color in your editor, it will not be rendered as +transparent. Instead you should change the default background color in your +kitty config and not use a background color in the editor color scheme. Or use +the escape codes to set the terminals default colors in a shell script to launch +your editor. Be aware that using a value less than 1.0 is a (possibly +significant) performance hit. If you want to dynamically change transparency of +windows set :opt:`dynamic_background_opacity` to :code:`yes` (this is off by +default as it has a performance cost) +''' + ) + +opt('background_image', 'none', + option_type='config_or_absolute_path', + long_text='Path to a background image. Must be in PNG format.' + ) + +opt('background_image_layout', 'tiled', + choices=('mirror-tiled', 'scaled', 'tiled'), + long_text='Whether to tile or scale the background image.' + ) + +opt('background_image_linear', 'no', + option_type='to_bool', + long_text='When background image is scaled, whether linear interpolation should be used.' + ) + +opt('dynamic_background_opacity', 'no', + option_type='to_bool', + long_text=''' +Allow changing of the :opt:`background_opacity` dynamically, using either +keyboard shortcuts (:sc:`increase_background_opacity` and +:sc:`decrease_background_opacity`) or the remote control facility. +''' + ) + +opt('background_tint', '0.0', + option_type='unit_float', + long_text=''' +How much to tint the background image by the background color. The tint is +applied only under the text area, not margin/borders. Makes it easier to read +the text. Tinting is done using the current background color for each window. +This setting applies only if :opt:`background_opacity` is set and transparent +windows are supported or :opt:`background_image` is set. +''' + ) + +opt('dim_opacity', '0.75', + option_type='unit_float', + long_text=''' +How much to dim text that has the DIM/FAINT attribute set. One means no dimming +and zero means fully dimmed (i.e. invisible). +''' + ) + +opt('selection_foreground', '#000000', + option_type='to_color_or_none', + long_text=''' +The foreground for text selected with the mouse. A value of none means to leave +the color unchanged. +''' + ) + +opt('selection_background', '#fffacd', + option_type='to_color', + long_text='The background for text selected with the mouse.' + ) + + +# colors.table {{{ +agr('colors.table', 'The color table', ''' +The 256 terminal colors. There are 8 basic colors, each color has a dull and +bright version, for the first 16 colors. You can set the remaining 240 colors as +color16 to color255. +''') + +opt('color0', '#000000', + option_type='to_color', + long_text='black' + ) + +opt('color8', '#767676', + option_type='to_color', + ) + +opt('color1', '#cc0403', + option_type='to_color', + long_text='red' + ) + +opt('color9', '#f2201f', + option_type='to_color', + ) + +opt('color2', '#19cb00', + option_type='to_color', + long_text='green' + ) + +opt('color10', '#23fd00', + option_type='to_color', + ) + +opt('color3', '#cecb00', + option_type='to_color', + long_text='yellow' + ) + +opt('color11', '#fffd00', + option_type='to_color', + ) + +opt('color4', '#0d73cc', + option_type='to_color', + long_text='blue' + ) + +opt('color12', '#1a8fff', + option_type='to_color', + ) + +opt('color5', '#cb1ed1', + option_type='to_color', + long_text='magenta' + ) + +opt('color13', '#fd28ff', + option_type='to_color', + ) + +opt('color6', '#0dcdcd', + option_type='to_color', + long_text='cyan' + ) + +opt('color14', '#14ffff', + option_type='to_color', + ) + +opt('color7', '#dddddd', + option_type='to_color', + long_text='white' + ) + +opt('color15', '#ffffff', + option_type='to_color', + ) + +opt('mark1_foreground', 'black', + option_type='to_color', + long_text='Color for marks of type 1' + ) + +opt('mark1_background', '#98d3cb', + option_type='to_color', + long_text='Color for marks of type 1 (light steel blue)' + ) + +opt('mark2_foreground', 'black', + option_type='to_color', + long_text='Color for marks of type 2' + ) + +opt('mark2_background', '#f2dcd3', + option_type='to_color', + long_text='Color for marks of type 1 (beige)' + ) + +opt('mark3_foreground', 'black', + option_type='to_color', + long_text='Color for marks of type 3' + ) + +opt('mark3_background', '#f274bc', + option_type='to_color', + long_text='Color for marks of type 1 (violet)' + ) + +opt('color16', '#000000', + option_type='to_color', + documented=False, + ) + +opt('color17', '#00005f', + option_type='to_color', + documented=False, + ) + +opt('color18', '#000087', + option_type='to_color', + documented=False, + ) + +opt('color19', '#0000af', + option_type='to_color', + documented=False, + ) + +opt('color20', '#0000d7', + option_type='to_color', + documented=False, + ) + +opt('color21', '#0000ff', + option_type='to_color', + documented=False, + ) + +opt('color22', '#005f00', + option_type='to_color', + documented=False, + ) + +opt('color23', '#005f5f', + option_type='to_color', + documented=False, + ) + +opt('color24', '#005f87', + option_type='to_color', + documented=False, + ) + +opt('color25', '#005faf', + option_type='to_color', + documented=False, + ) + +opt('color26', '#005fd7', + option_type='to_color', + documented=False, + ) + +opt('color27', '#005fff', + option_type='to_color', + documented=False, + ) + +opt('color28', '#008700', + option_type='to_color', + documented=False, + ) + +opt('color29', '#00875f', + option_type='to_color', + documented=False, + ) + +opt('color30', '#008787', + option_type='to_color', + documented=False, + ) + +opt('color31', '#0087af', + option_type='to_color', + documented=False, + ) + +opt('color32', '#0087d7', + option_type='to_color', + documented=False, + ) + +opt('color33', '#0087ff', + option_type='to_color', + documented=False, + ) + +opt('color34', '#00af00', + option_type='to_color', + documented=False, + ) + +opt('color35', '#00af5f', + option_type='to_color', + documented=False, + ) + +opt('color36', '#00af87', + option_type='to_color', + documented=False, + ) + +opt('color37', '#00afaf', + option_type='to_color', + documented=False, + ) + +opt('color38', '#00afd7', + option_type='to_color', + documented=False, + ) + +opt('color39', '#00afff', + option_type='to_color', + documented=False, + ) + +opt('color40', '#00d700', + option_type='to_color', + documented=False, + ) + +opt('color41', '#00d75f', + option_type='to_color', + documented=False, + ) + +opt('color42', '#00d787', + option_type='to_color', + documented=False, + ) + +opt('color43', '#00d7af', + option_type='to_color', + documented=False, + ) + +opt('color44', '#00d7d7', + option_type='to_color', + documented=False, + ) + +opt('color45', '#00d7ff', + option_type='to_color', + documented=False, + ) + +opt('color46', '#00ff00', + option_type='to_color', + documented=False, + ) + +opt('color47', '#00ff5f', + option_type='to_color', + documented=False, + ) + +opt('color48', '#00ff87', + option_type='to_color', + documented=False, + ) + +opt('color49', '#00ffaf', + option_type='to_color', + documented=False, + ) + +opt('color50', '#00ffd7', + option_type='to_color', + documented=False, + ) + +opt('color51', '#00ffff', + option_type='to_color', + documented=False, + ) + +opt('color52', '#5f0000', + option_type='to_color', + documented=False, + ) + +opt('color53', '#5f005f', + option_type='to_color', + documented=False, + ) + +opt('color54', '#5f0087', + option_type='to_color', + documented=False, + ) + +opt('color55', '#5f00af', + option_type='to_color', + documented=False, + ) + +opt('color56', '#5f00d7', + option_type='to_color', + documented=False, + ) + +opt('color57', '#5f00ff', + option_type='to_color', + documented=False, + ) + +opt('color58', '#5f5f00', + option_type='to_color', + documented=False, + ) + +opt('color59', '#5f5f5f', + option_type='to_color', + documented=False, + ) + +opt('color60', '#5f5f87', + option_type='to_color', + documented=False, + ) + +opt('color61', '#5f5faf', + option_type='to_color', + documented=False, + ) + +opt('color62', '#5f5fd7', + option_type='to_color', + documented=False, + ) + +opt('color63', '#5f5fff', + option_type='to_color', + documented=False, + ) + +opt('color64', '#5f8700', + option_type='to_color', + documented=False, + ) + +opt('color65', '#5f875f', + option_type='to_color', + documented=False, + ) + +opt('color66', '#5f8787', + option_type='to_color', + documented=False, + ) + +opt('color67', '#5f87af', + option_type='to_color', + documented=False, + ) + +opt('color68', '#5f87d7', + option_type='to_color', + documented=False, + ) + +opt('color69', '#5f87ff', + option_type='to_color', + documented=False, + ) + +opt('color70', '#5faf00', + option_type='to_color', + documented=False, + ) + +opt('color71', '#5faf5f', + option_type='to_color', + documented=False, + ) + +opt('color72', '#5faf87', + option_type='to_color', + documented=False, + ) + +opt('color73', '#5fafaf', + option_type='to_color', + documented=False, + ) + +opt('color74', '#5fafd7', + option_type='to_color', + documented=False, + ) + +opt('color75', '#5fafff', + option_type='to_color', + documented=False, + ) + +opt('color76', '#5fd700', + option_type='to_color', + documented=False, + ) + +opt('color77', '#5fd75f', + option_type='to_color', + documented=False, + ) + +opt('color78', '#5fd787', + option_type='to_color', + documented=False, + ) + +opt('color79', '#5fd7af', + option_type='to_color', + documented=False, + ) + +opt('color80', '#5fd7d7', + option_type='to_color', + documented=False, + ) + +opt('color81', '#5fd7ff', + option_type='to_color', + documented=False, + ) + +opt('color82', '#5fff00', + option_type='to_color', + documented=False, + ) + +opt('color83', '#5fff5f', + option_type='to_color', + documented=False, + ) + +opt('color84', '#5fff87', + option_type='to_color', + documented=False, + ) + +opt('color85', '#5fffaf', + option_type='to_color', + documented=False, + ) + +opt('color86', '#5fffd7', + option_type='to_color', + documented=False, + ) + +opt('color87', '#5fffff', + option_type='to_color', + documented=False, + ) + +opt('color88', '#870000', + option_type='to_color', + documented=False, + ) + +opt('color89', '#87005f', + option_type='to_color', + documented=False, + ) + +opt('color90', '#870087', + option_type='to_color', + documented=False, + ) + +opt('color91', '#8700af', + option_type='to_color', + documented=False, + ) + +opt('color92', '#8700d7', + option_type='to_color', + documented=False, + ) + +opt('color93', '#8700ff', + option_type='to_color', + documented=False, + ) + +opt('color94', '#875f00', + option_type='to_color', + documented=False, + ) + +opt('color95', '#875f5f', + option_type='to_color', + documented=False, + ) + +opt('color96', '#875f87', + option_type='to_color', + documented=False, + ) + +opt('color97', '#875faf', + option_type='to_color', + documented=False, + ) + +opt('color98', '#875fd7', + option_type='to_color', + documented=False, + ) + +opt('color99', '#875fff', + option_type='to_color', + documented=False, + ) + +opt('color100', '#878700', + option_type='to_color', + documented=False, + ) + +opt('color101', '#87875f', + option_type='to_color', + documented=False, + ) + +opt('color102', '#878787', + option_type='to_color', + documented=False, + ) + +opt('color103', '#8787af', + option_type='to_color', + documented=False, + ) + +opt('color104', '#8787d7', + option_type='to_color', + documented=False, + ) + +opt('color105', '#8787ff', + option_type='to_color', + documented=False, + ) + +opt('color106', '#87af00', + option_type='to_color', + documented=False, + ) + +opt('color107', '#87af5f', + option_type='to_color', + documented=False, + ) + +opt('color108', '#87af87', + option_type='to_color', + documented=False, + ) + +opt('color109', '#87afaf', + option_type='to_color', + documented=False, + ) + +opt('color110', '#87afd7', + option_type='to_color', + documented=False, + ) + +opt('color111', '#87afff', + option_type='to_color', + documented=False, + ) + +opt('color112', '#87d700', + option_type='to_color', + documented=False, + ) + +opt('color113', '#87d75f', + option_type='to_color', + documented=False, + ) + +opt('color114', '#87d787', + option_type='to_color', + documented=False, + ) + +opt('color115', '#87d7af', + option_type='to_color', + documented=False, + ) + +opt('color116', '#87d7d7', + option_type='to_color', + documented=False, + ) + +opt('color117', '#87d7ff', + option_type='to_color', + documented=False, + ) + +opt('color118', '#87ff00', + option_type='to_color', + documented=False, + ) + +opt('color119', '#87ff5f', + option_type='to_color', + documented=False, + ) + +opt('color120', '#87ff87', + option_type='to_color', + documented=False, + ) + +opt('color121', '#87ffaf', + option_type='to_color', + documented=False, + ) + +opt('color122', '#87ffd7', + option_type='to_color', + documented=False, + ) + +opt('color123', '#87ffff', + option_type='to_color', + documented=False, + ) + +opt('color124', '#af0000', + option_type='to_color', + documented=False, + ) + +opt('color125', '#af005f', + option_type='to_color', + documented=False, + ) + +opt('color126', '#af0087', + option_type='to_color', + documented=False, + ) + +opt('color127', '#af00af', + option_type='to_color', + documented=False, + ) + +opt('color128', '#af00d7', + option_type='to_color', + documented=False, + ) + +opt('color129', '#af00ff', + option_type='to_color', + documented=False, + ) + +opt('color130', '#af5f00', + option_type='to_color', + documented=False, + ) + +opt('color131', '#af5f5f', + option_type='to_color', + documented=False, + ) + +opt('color132', '#af5f87', + option_type='to_color', + documented=False, + ) + +opt('color133', '#af5faf', + option_type='to_color', + documented=False, + ) + +opt('color134', '#af5fd7', + option_type='to_color', + documented=False, + ) + +opt('color135', '#af5fff', + option_type='to_color', + documented=False, + ) + +opt('color136', '#af8700', + option_type='to_color', + documented=False, + ) + +opt('color137', '#af875f', + option_type='to_color', + documented=False, + ) + +opt('color138', '#af8787', + option_type='to_color', + documented=False, + ) + +opt('color139', '#af87af', + option_type='to_color', + documented=False, + ) + +opt('color140', '#af87d7', + option_type='to_color', + documented=False, + ) + +opt('color141', '#af87ff', + option_type='to_color', + documented=False, + ) + +opt('color142', '#afaf00', + option_type='to_color', + documented=False, + ) + +opt('color143', '#afaf5f', + option_type='to_color', + documented=False, + ) + +opt('color144', '#afaf87', + option_type='to_color', + documented=False, + ) + +opt('color145', '#afafaf', + option_type='to_color', + documented=False, + ) + +opt('color146', '#afafd7', + option_type='to_color', + documented=False, + ) + +opt('color147', '#afafff', + option_type='to_color', + documented=False, + ) + +opt('color148', '#afd700', + option_type='to_color', + documented=False, + ) + +opt('color149', '#afd75f', + option_type='to_color', + documented=False, + ) + +opt('color150', '#afd787', + option_type='to_color', + documented=False, + ) + +opt('color151', '#afd7af', + option_type='to_color', + documented=False, + ) + +opt('color152', '#afd7d7', + option_type='to_color', + documented=False, + ) + +opt('color153', '#afd7ff', + option_type='to_color', + documented=False, + ) + +opt('color154', '#afff00', + option_type='to_color', + documented=False, + ) + +opt('color155', '#afff5f', + option_type='to_color', + documented=False, + ) + +opt('color156', '#afff87', + option_type='to_color', + documented=False, + ) + +opt('color157', '#afffaf', + option_type='to_color', + documented=False, + ) + +opt('color158', '#afffd7', + option_type='to_color', + documented=False, + ) + +opt('color159', '#afffff', + option_type='to_color', + documented=False, + ) + +opt('color160', '#d70000', + option_type='to_color', + documented=False, + ) + +opt('color161', '#d7005f', + option_type='to_color', + documented=False, + ) + +opt('color162', '#d70087', + option_type='to_color', + documented=False, + ) + +opt('color163', '#d700af', + option_type='to_color', + documented=False, + ) + +opt('color164', '#d700d7', + option_type='to_color', + documented=False, + ) + +opt('color165', '#d700ff', + option_type='to_color', + documented=False, + ) + +opt('color166', '#d75f00', + option_type='to_color', + documented=False, + ) + +opt('color167', '#d75f5f', + option_type='to_color', + documented=False, + ) + +opt('color168', '#d75f87', + option_type='to_color', + documented=False, + ) + +opt('color169', '#d75faf', + option_type='to_color', + documented=False, + ) + +opt('color170', '#d75fd7', + option_type='to_color', + documented=False, + ) + +opt('color171', '#d75fff', + option_type='to_color', + documented=False, + ) + +opt('color172', '#d78700', + option_type='to_color', + documented=False, + ) + +opt('color173', '#d7875f', + option_type='to_color', + documented=False, + ) + +opt('color174', '#d78787', + option_type='to_color', + documented=False, + ) + +opt('color175', '#d787af', + option_type='to_color', + documented=False, + ) + +opt('color176', '#d787d7', + option_type='to_color', + documented=False, + ) + +opt('color177', '#d787ff', + option_type='to_color', + documented=False, + ) + +opt('color178', '#d7af00', + option_type='to_color', + documented=False, + ) + +opt('color179', '#d7af5f', + option_type='to_color', + documented=False, + ) + +opt('color180', '#d7af87', + option_type='to_color', + documented=False, + ) + +opt('color181', '#d7afaf', + option_type='to_color', + documented=False, + ) + +opt('color182', '#d7afd7', + option_type='to_color', + documented=False, + ) + +opt('color183', '#d7afff', + option_type='to_color', + documented=False, + ) + +opt('color184', '#d7d700', + option_type='to_color', + documented=False, + ) + +opt('color185', '#d7d75f', + option_type='to_color', + documented=False, + ) + +opt('color186', '#d7d787', + option_type='to_color', + documented=False, + ) + +opt('color187', '#d7d7af', + option_type='to_color', + documented=False, + ) + +opt('color188', '#d7d7d7', + option_type='to_color', + documented=False, + ) + +opt('color189', '#d7d7ff', + option_type='to_color', + documented=False, + ) + +opt('color190', '#d7ff00', + option_type='to_color', + documented=False, + ) + +opt('color191', '#d7ff5f', + option_type='to_color', + documented=False, + ) + +opt('color192', '#d7ff87', + option_type='to_color', + documented=False, + ) + +opt('color193', '#d7ffaf', + option_type='to_color', + documented=False, + ) + +opt('color194', '#d7ffd7', + option_type='to_color', + documented=False, + ) + +opt('color195', '#d7ffff', + option_type='to_color', + documented=False, + ) + +opt('color196', '#ff0000', + option_type='to_color', + documented=False, + ) + +opt('color197', '#ff005f', + option_type='to_color', + documented=False, + ) + +opt('color198', '#ff0087', + option_type='to_color', + documented=False, + ) + +opt('color199', '#ff00af', + option_type='to_color', + documented=False, + ) + +opt('color200', '#ff00d7', + option_type='to_color', + documented=False, + ) + +opt('color201', '#ff00ff', + option_type='to_color', + documented=False, + ) + +opt('color202', '#ff5f00', + option_type='to_color', + documented=False, + ) + +opt('color203', '#ff5f5f', + option_type='to_color', + documented=False, + ) + +opt('color204', '#ff5f87', + option_type='to_color', + documented=False, + ) + +opt('color205', '#ff5faf', + option_type='to_color', + documented=False, + ) + +opt('color206', '#ff5fd7', + option_type='to_color', + documented=False, + ) + +opt('color207', '#ff5fff', + option_type='to_color', + documented=False, + ) + +opt('color208', '#ff8700', + option_type='to_color', + documented=False, + ) + +opt('color209', '#ff875f', + option_type='to_color', + documented=False, + ) + +opt('color210', '#ff8787', + option_type='to_color', + documented=False, + ) + +opt('color211', '#ff87af', + option_type='to_color', + documented=False, + ) + +opt('color212', '#ff87d7', + option_type='to_color', + documented=False, + ) + +opt('color213', '#ff87ff', + option_type='to_color', + documented=False, + ) + +opt('color214', '#ffaf00', + option_type='to_color', + documented=False, + ) + +opt('color215', '#ffaf5f', + option_type='to_color', + documented=False, + ) + +opt('color216', '#ffaf87', + option_type='to_color', + documented=False, + ) + +opt('color217', '#ffafaf', + option_type='to_color', + documented=False, + ) + +opt('color218', '#ffafd7', + option_type='to_color', + documented=False, + ) + +opt('color219', '#ffafff', + option_type='to_color', + documented=False, + ) + +opt('color220', '#ffd700', + option_type='to_color', + documented=False, + ) + +opt('color221', '#ffd75f', + option_type='to_color', + documented=False, + ) + +opt('color222', '#ffd787', + option_type='to_color', + documented=False, + ) + +opt('color223', '#ffd7af', + option_type='to_color', + documented=False, + ) + +opt('color224', '#ffd7d7', + option_type='to_color', + documented=False, + ) + +opt('color225', '#ffd7ff', + option_type='to_color', + documented=False, + ) + +opt('color226', '#ffff00', + option_type='to_color', + documented=False, + ) + +opt('color227', '#ffff5f', + option_type='to_color', + documented=False, + ) + +opt('color228', '#ffff87', + option_type='to_color', + documented=False, + ) + +opt('color229', '#ffffaf', + option_type='to_color', + documented=False, + ) + +opt('color230', '#ffffd7', + option_type='to_color', + documented=False, + ) + +opt('color231', '#ffffff', + option_type='to_color', + documented=False, + ) + +opt('color232', '#080808', + option_type='to_color', + documented=False, + ) + +opt('color233', '#121212', + option_type='to_color', + documented=False, + ) + +opt('color234', '#1c1c1c', + option_type='to_color', + documented=False, + ) + +opt('color235', '#262626', + option_type='to_color', + documented=False, + ) + +opt('color236', '#303030', + option_type='to_color', + documented=False, + ) + +opt('color237', '#3a3a3a', + option_type='to_color', + documented=False, + ) + +opt('color238', '#444444', + option_type='to_color', + documented=False, + ) + +opt('color239', '#4e4e4e', + option_type='to_color', + documented=False, + ) + +opt('color240', '#585858', + option_type='to_color', + documented=False, + ) + +opt('color241', '#626262', + option_type='to_color', + documented=False, + ) + +opt('color242', '#6c6c6c', + option_type='to_color', + documented=False, + ) + +opt('color243', '#767676', + option_type='to_color', + documented=False, + ) + +opt('color244', '#808080', + option_type='to_color', + documented=False, + ) + +opt('color245', '#8a8a8a', + option_type='to_color', + documented=False, + ) + +opt('color246', '#949494', + option_type='to_color', + documented=False, + ) + +opt('color247', '#9e9e9e', + option_type='to_color', + documented=False, + ) + +opt('color248', '#a8a8a8', + option_type='to_color', + documented=False, + ) + +opt('color249', '#b2b2b2', + option_type='to_color', + documented=False, + ) + +opt('color250', '#bcbcbc', + option_type='to_color', + documented=False, + ) + +opt('color251', '#c6c6c6', + option_type='to_color', + documented=False, + ) + +opt('color252', '#d0d0d0', + option_type='to_color', + documented=False, + ) + +opt('color253', '#dadada', + option_type='to_color', + documented=False, + ) + +opt('color254', '#e4e4e4', + option_type='to_color', + documented=False, + ) + +opt('color255', '#eeeeee', + option_type='to_color', + documented=False, + ) +egr() # }}} +egr() # }}} + +# advanced {{{ +agr('advanced', 'Advanced') + +opt('shell', '.', + long_text=''' +The shell program to execute. The default value of . means to use whatever shell +is set as the default shell for the current user. Note that on macOS if you +change this, you might need to add :code:`--login` to ensure that the shell +starts in interactive mode and reads its startup rc files. +''' + ) + +opt('editor', '.', + long_text=''' +The console editor to use when editing the kitty config file or similar tasks. A +value of . means to use the environment variables VISUAL and EDITOR in that +order. Note that this environment variable has to be set not just in your shell +startup scripts but system-wide, otherwise kitty will not see it. +''' + ) + +opt('close_on_child_death', 'no', + option_type='to_bool', + long_text=''' +Close the window when the child process (shell) exits. If no (the default), the +terminal will remain open when the child exits as long as there are still +processes outputting to the terminal (for example disowned or backgrounded +processes). If yes, the window will close as soon as the child process exits. +Note that setting it to yes means that any background processes still using the +terminal can fail silently because their stdout/stderr/stdin no longer work. +''' + ) + +opt('allow_remote_control', 'no', + option_type='allow_remote_control', + long_text=''' +Allow other programs to control kitty. If you turn this on other programs can +control all aspects of kitty, including sending text to kitty windows, opening +new windows, closing windows, reading the content of windows, etc. Note that +this even works over ssh connections. You can chose to either allow any program +running within kitty to control it, with :code:`yes` or only programs that +connect to the socket specified with the :option:`kitty --listen-on` command +line option, if you use the value :code:`socket-only`. The latter is useful if +you want to prevent programs running on a remote computer over ssh from +controlling kitty. +''' + ) + +opt('listen_on', 'none', + long_text=''' +Tell kitty to listen to the specified unix/tcp socket for remote control +connections. Note that this will apply to all kitty instances. It can be +overridden by the :option:`kitty --listen-on` command line flag. This option +accepts only UNIX sockets, such as unix:${TEMP}/mykitty or (on Linux) +unix:@mykitty. Environment variables are expanded. If {kitty_pid} is present +then it is replaced by the PID of the kitty process, otherwise the PID of the +kitty process is appended to the value, with a hyphen. This option is ignored +unless you also set :opt:`allow_remote_control` to enable remote control. See +the help for :option:`kitty --listen-on` for more details. +''' + ) + +opt('+env', '', + option_type='env', + add_to_default=False, + long_text=''' +Specify environment variables to set in all child processes. Note that +environment variables are expanded recursively, so if you use:: + + env MYVAR1=a + env MYVAR2=${MYVAR1}/${HOME}/b + +The value of MYVAR2 will be :code:`a//b`. +''' + ) + +opt('update_check_interval', '24', + option_type='float', + long_text=''' +Periodically check if an update to kitty is available. If an update is found a +system notification is displayed informing you of the available update. The +default is to check every 24 hrs, set to zero to disable. +''' + ) + +opt('startup_session', 'none', + option_type='config_or_absolute_path', + long_text=''' +Path to a session file to use for all kitty instances. Can be overridden by +using the :option:`kitty --session` command line option for individual +instances. See :ref:`sessions` in the kitty documentation for details. Note that +relative paths are interpreted with respect to the kitty config directory. +Environment variables in the path are expanded. +''' + ) + +opt('clipboard_control', 'write-clipboard write-primary', + option_type='clipboard_control', + long_text=''' +Allow programs running in kitty to read and write from the clipboard. You can +control exactly which actions are allowed. The set of possible actions is: +write-clipboard read-clipboard write-primary read-primary. You can additionally +specify no-append to disable kitty's protocol extension for clipboard +concatenation. The default is to allow writing to the clipboard and primary +selection with concatenation enabled. Note that enabling the read functionality +is a security risk as it means that any program, even one running on a remote +server via SSH can read your clipboard. +''' + ) + +opt('allow_hyperlinks', 'yes', + option_type='allow_hyperlinks', + long_text=''' +Process hyperlink (OSC 8) escape sequences. If disabled OSC 8 escape sequences +are ignored. Otherwise they become clickable links, that you can click by +holding down ctrl+shift and clicking with the mouse. The special value of +``ask`` means that kitty will ask before opening the link. +''' + ) + +opt('term', 'xterm-kitty', + long_text=''' +The value of the TERM environment variable to set. Changing this can break many +terminal programs, only change it if you know what you are doing, not because +you read some advice on Stack Overflow to change it. The TERM variable is used +by various programs to get information about the capabilities and behavior of +the terminal. If you change it, depending on what programs you run, and how +different the terminal you are changing it to is, various things from key- +presses, to colors, to various advanced features may not work. +''' + ) +egr() # }}} + +# os {{{ +agr('os', 'OS specific tweaks') + +opt('wayland_titlebar_color', 'system', + option_type='macos_titlebar_color', + long_text=''' +Change the color of the kitty window's titlebar on Wayland systems with client +side window decorations such as GNOME. A value of :code:`system` means to use +the default system color, a value of :code:`background` means to use the +background color of the currently active window and finally you can use an +arbitrary color, such as :code:`#12af59` or :code:`red`. +''' + ) + +opt('macos_titlebar_color', 'system', + option_type='macos_titlebar_color', + long_text=''' +Change the color of the kitty window's titlebar on macOS. A value of +:code:`system` means to use the default system color, a value of +:code:`background` means to use the background color of the currently active +window and finally you can use an arbitrary color, such as :code:`#12af59` or +:code:`red`. WARNING: This option works by using a hack, as there is no proper +Cocoa API for it. It sets the background color of the entire window and makes +the titlebar transparent. As such it is incompatible with +:opt:`background_opacity`. If you want to use both, you are probably better off +just hiding the titlebar with :opt:`hide_window_decorations`. +''' + ) + +opt('macos_option_as_alt', 'no', + option_type='macos_option_as_alt', + long_text=''' +Use the option key as an alt key. With this set to :code:`no`, kitty will use +the macOS native :kbd:`Option+Key` = unicode character behavior. This will break +any :kbd:`Alt+key` keyboard shortcuts in your terminal programs, but you can use +the macOS unicode input technique. You can use the values: :code:`left`, +:code:`right`, or :code:`both` to use only the left, right or both Option keys +as Alt, instead. +''' + ) + +opt('macos_hide_from_tasks', 'no', + option_type='to_bool', + long_text='Hide the kitty window from running tasks (:kbd:`⌘+Tab`) on macOS.' + ) + +opt('macos_quit_when_last_window_closed', 'no', + option_type='to_bool', + long_text=''' +Have kitty quit when all the top-level windows are closed. By default, kitty +will stay running, even with no open windows, as is the expected behavior on +macOS. +''' + ) + +opt('macos_window_resizable', 'yes', + option_type='to_bool', + long_text=''' +Disable this if you want kitty top-level (OS) windows to not be resizable on +macOS. +''' + ) + +opt('macos_thicken_font', '0', + option_type='positive_float', + long_text=''' +Draw an extra border around the font with the given width, to increase +legibility at small font sizes. For example, a value of 0.75 will result in +rendering that looks similar to sub-pixel antialiasing at common font sizes. +''' + ) + +opt('macos_traditional_fullscreen', 'no', + option_type='to_bool', + long_text='Use the traditional full-screen transition, that is faster, but less pretty.' + ) + +opt('macos_show_window_title_in', 'all', + choices=('all', 'menubar', 'none', 'window'), + long_text=''' +Show or hide the window title in the macOS window or menu-bar. A value of +:code:`window` will show the title of the currently active window at the top of +the macOS window. A value of :code:`menubar` will show the title of the +currently active window in the macOS menu-bar, making use of otherwise wasted +space. :code:`all` will show the title everywhere and :code:`none` hides the +title in the window and the menu-bar. +''' + ) + +opt('macos_custom_beam_cursor', 'no', + option_type='to_bool', + long_text=''' +Enable/disable custom mouse cursor for macOS that is easier to see on both light +and dark backgrounds. WARNING: this might make your mouse cursor invisible on +dual GPU machines. +''' + ) + +opt('linux_display_server', 'auto', + choices=('auto', 'wayland', 'x11'), + long_text=''' +Choose between Wayland and X11 backends. By default, an appropriate backend +based on the system state is chosen automatically. Set it to :code:`x11` or +:code:`wayland` to force the choice. +''' + ) +egr() # }}} + +# shortcuts {{{ +agr('shortcuts', 'Keyboard shortcuts', ''' +Keys are identified simply by their lowercase unicode characters. For example: +``a`` for the A key, ``[`` for the left square bracket key, etc. For functional +keys, such as ``Enter or Escape`` the names are present at :ref:`functional`. +For a list of modifier names, see: +:link:`GLFW mods ` + +On Linux you can also use XKB key names to bind keys that are not supported by +GLFW. See :link:`XKB keys +` +for a list of key names. The name to use is the part after the :code:`XKB_KEY_` +prefix. Note that you can only use an XKB key name for keys that are not known +as GLFW keys. + +Finally, you can use raw system key codes to map keys, again only for keys that are not +known as GLFW keys. To see the system key code +for a key, start kitty with the :option:`kitty --debug-input` option. Then kitty will +output some debug text for every key event. In that text look for ``native_code`` +the value of that becomes the key name in the shortcut. For example: + +.. code-block:: none + + on_key_input: glfw key: 65 native_code: 0x61 action: PRESS mods: 0x0 text: 'a' + +Here, the key name for the :kbd:`A` key is :kbd:`0x61` and you can use it with:: + + map ctrl+0x61 something + +to map :kbd:`ctrl+a` to something. + +You can use the special action :code:`no_op` to unmap a keyboard shortcut that is +assigned in the default configuration:: + + map kitty_mod+space no_op + +You can combine multiple actions to be triggered by a single shortcut, using the +syntax below:: + + map key combine action1 action2 action3 ... + +For example:: + + map kitty_mod+e combine : new_window : next_layout + +this will create a new window and switch to the next available layout + +You can use multi-key shortcuts using the syntax shown below:: + + map key1>key2>key3 action + +For example:: + + map ctrl+f>2 set_font_size 20 +''') + +opt('kitty_mod', 'ctrl+shift', + option_type='to_modifiers', + long_text=''' +The value of :code:`kitty_mod` is used as the modifier for all default +shortcuts, you can change it in your kitty.conf to change the modifiers for all +the default shortcuts. +''' + ) + +opt('clear_all_shortcuts', 'no', + option_type='clear_all_shortcuts', + long_text=''' +You can have kitty remove all shortcut definition seen up to this point. Useful, +for instance, to remove the default shortcuts. +''' + ) + +opt('+kitten_alias', 'hints hints --hints-offset=0', + option_type='kitten_alias', + add_to_default=False, + long_text=''' +You can create aliases for kitten names, this allows overriding the defaults for +kitten options and can also be used to shorten repeated mappings of the same +kitten with a specific group of options. For example, the above alias changes +the default value of :option:`kitty +kitten hints --hints-offset` to zero for +all mappings, including the builtin ones. +''' + ) + + +# shortcuts.clipboard {{{ +agr('shortcuts.clipboard', 'Clipboard') + +map('Copy to clipboard', + 'copy_to_clipboard kitty_mod+c copy_to_clipboard', + long_text=''' +There is also a :code:`copy_or_interrupt` action that can be optionally mapped +to :kbd:`Ctrl+c`. It will copy only if there is a selection and send an +interrupt otherwise. Similarly, :code:`copy_and_clear_or_interrupt` will copy +and clear the selection or send an interrupt if there is no selection. +''' + ) +map('Copy to clipboard', + 'copy_to_clipboard cmd+c copy_to_clipboard', + only="macos", + documented=False, + ) + +map('Paste from clipboard', + 'paste_from_clipboard kitty_mod+v paste_from_clipboard', + ) +map('Paste from clipboard', + 'paste_from_clipboard cmd+v paste_from_clipboard', + only="macos", + documented=False, + ) + +map('Paste from selection', + 'paste_from_selection kitty_mod+s paste_from_selection', + ) +map('Paste from selection', + 'paste_from_selection shift+insert paste_from_selection', + ) + +map('Pass selection to program', + 'pass_selection_to_program kitty_mod+o pass_selection_to_program', + long_text=''' +You can also pass the contents of the current selection to any program using +:code:`pass_selection_to_program`. By default, the system's open program is used, but +you can specify your own, the selection will be passed as a command line argument to the program, +for example:: + + map kitty_mod+o pass_selection_to_program firefox + +You can pass the current selection to a terminal program running in a new kitty +window, by using the @selection placeholder:: + + map kitty_mod+y new_window less @selection +''' + ) +egr() # }}} + + +# shortcuts.scrolling {{{ +agr('shortcuts.scrolling', 'Scrolling') + +map('Scroll line up', + 'scroll_line_up kitty_mod+up scroll_line_up', + ) +map('Scroll line up', + 'scroll_line_up alt+cmd+page_up scroll_line_up', + only="macos", + documented=False, + ) +map('Scroll line up', + 'scroll_line_up cmd+up scroll_line_up', + only="macos", + documented=False, + ) +map('', + 'scroll_line_up kitty_mod+k scroll_line_up', + ) + +map('Scroll line down', + 'scroll_line_down kitty_mod+down scroll_line_down', + ) +map('', + 'scroll_line_down kitty_mod+j scroll_line_down', + ) +map('Scroll line down', + 'scroll_line_down alt+cmd+page_down scroll_line_down', + only="macos", + documented=False, + ) +map('Scroll line down', + 'scroll_line_down cmd+down scroll_line_down', + only="macos", + documented=False, + ) + +map('Scroll page up', + 'scroll_page_up kitty_mod+page_up scroll_page_up', + ) +map('Scroll page up', + 'scroll_page_up cmd+page_up scroll_page_up', + only="macos", + documented=False, + ) + +map('Scroll page down', + 'scroll_page_down kitty_mod+page_down scroll_page_down', + ) +map('Scroll page down', + 'scroll_page_down cmd+page_down scroll_page_down', + only="macos", + documented=False, + ) + +map('Scroll to top', + 'scroll_home kitty_mod+home scroll_home', + ) +map('Scroll to top', + 'scroll_home cmd+home scroll_home', + only="macos", + documented=False, + ) + +map('Scroll to bottom', + 'scroll_end kitty_mod+end scroll_end', + ) +map('Scroll to bottom', + 'scroll_end cmd+end scroll_end', + only="macos", + documented=False, + ) + +map('Browse scrollback buffer in less', + 'show_scrollback kitty_mod+h show_scrollback', + long_text=''' +You can pipe the contents of the current screen + history buffer as +:file:`STDIN` to an arbitrary program using the ``launch`` function. For example, +the following opens the scrollback buffer in less in an overlay window:: + + map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting --type=overlay less +G -R + +For more details on piping screen and buffer contents to external programs, +see :doc:`launch`. +''' + ) +egr() # }}} + + +# shortcuts.window {{{ +agr('shortcuts.window', 'Window management') + +map('', + 'new_window kitty_mod+enter new_window', + long_text=''' +You can open a new window running an arbitrary program, for example:: + + map kitty_mod+y launch mutt + +You can open a new window with the current working directory set to the +working directory of the current window using:: + + map ctrl+alt+enter launch --cwd=current + +You can open a new window that is allowed to control kitty via +the kitty remote control facility by prefixing the command line with @. +Any programs running in that window will be allowed to control kitty. +For example:: + + map ctrl+enter launch --allow-remote-control some_program + +You can open a new window next to the currently active window or as the first window, +with:: + + map ctrl+n launch --location=neighbor some_program + map ctrl+f launch --location=first some_program + +For more details, see :doc:`launch`. +''' + ) +map('New window', + 'new_window cmd+enter new_window', + only="macos", + documented=False, + ) + +map('New OS window', + 'new_os_window kitty_mod+n new_os_window', + long_text=''' +Works like new_window above, except that it opens a top level OS kitty window. +In particular you can use new_os_window_with_cwd to open a window with the +current working directory. +''' + ) +map('New OS window', + 'new_os_window cmd+n new_os_window', + only="macos", + documented=False, + ) + +map('Close window', + 'close_window kitty_mod+w close_window', + ) +map('Close window', + 'close_window shift+cmd+d close_window', + only="macos", + documented=False, + ) + +map('Next window', + 'next_window kitty_mod+] next_window', + ) + +map('Previous window', + 'previous_window kitty_mod+[ previous_window', + ) + +map('Move window forward', + 'move_window_forward kitty_mod+f move_window_forward', + ) + +map('Move window backward', + 'move_window_backward kitty_mod+b move_window_backward', + ) + +map('Move window to top', + 'move_window_to_top kitty_mod+` move_window_to_top', + ) + +map('Start resizing window', + 'start_resizing_window kitty_mod+r start_resizing_window', + ) +map('Start resizing window', + 'start_resizing_window cmd+r start_resizing_window', + only="macos", + documented=False, + ) + +map('First window', + 'first_window kitty_mod+1 first_window', + ) +map('First window', + 'first_window cmd+1 first_window', + only="macos", + documented=False, + ) + +map('Second window', + 'second_window kitty_mod+2 second_window', + ) +map('Second window', + 'second_window cmd+2 second_window', + only="macos", + documented=False, + ) + +map('Third window', + 'third_window kitty_mod+3 third_window', + ) +map('Third window', + 'third_window cmd+3 third_window', + only="macos", + documented=False, + ) + +map('Fourth window', + 'fourth_window kitty_mod+4 fourth_window', + ) +map('Fourth window', + 'fourth_window cmd+4 fourth_window', + only="macos", + documented=False, + ) + +map('Fifth window', + 'fifth_window kitty_mod+5 fifth_window', + ) +map('Fifth window', + 'fifth_window cmd+5 fifth_window', + only="macos", + documented=False, + ) + +map('Sixth window', + 'sixth_window kitty_mod+6 sixth_window', + ) +map('Sixth window', + 'sixth_window cmd+6 sixth_window', + only="macos", + documented=False, + ) + +map('Seventh window', + 'seventh_window kitty_mod+7 seventh_window', + ) +map('Seventh window', + 'seventh_window cmd+7 seventh_window', + only="macos", + documented=False, + ) + +map('Eight window', + 'eighth_window kitty_mod+8 eighth_window', + ) +map('Eight window', + 'eighth_window cmd+8 eighth_window', + only="macos", + documented=False, + ) + +map('Ninth window', + 'ninth_window kitty_mod+9 ninth_window', + ) +map('Ninth window', + 'ninth_window cmd+9 ninth_window', + only="macos", + documented=False, + ) + +map('Tenth window', + 'tenth_window kitty_mod+0 tenth_window', + ) +egr() # }}} + + +# shortcuts.tab {{{ +agr('shortcuts.tab', 'Tab management') + +map('Next tab', + 'next_tab kitty_mod+right next_tab', + ) +map('Next tab', + 'next_tab shift+cmd+] next_tab', + only="macos", + documented=False, + ) +map('Next tab', + 'next_tab ctrl+tab next_tab', + documented=False, + ) + +map('Previous tab', + 'previous_tab kitty_mod+left previous_tab', + ) +map('Previous tab', + 'previous_tab shift+cmd+[ previous_tab', + only="macos", + documented=False, + ) +map('Previous tab', + 'previous_tab shift+ctrl+tab previous_tab', + documented=False, + ) + +map('New tab', + 'new_tab kitty_mod+t new_tab', + ) +map('New tab', + 'new_tab cmd+t new_tab', + only="macos", + documented=False, + ) + +map('Close tab', + 'close_tab kitty_mod+q close_tab', + ) +map('Close tab', + 'close_tab cmd+w close_tab', + only="macos", + documented=False, + ) + +map('Close OS window', + 'close_os_window shift+cmd+w close_os_window', + only="macos", + documented=False, + ) + +map('Move tab forward', + 'move_tab_forward kitty_mod+. move_tab_forward', + ) + +map('Move tab backward', + 'move_tab_backward kitty_mod+, move_tab_backward', + ) + +map('Set tab title', + 'set_tab_title kitty_mod+alt+t set_tab_title', + ) +map('Set tab title', + 'set_tab_title shift+cmd+i set_tab_title', + only="macos", + documented=False, + ) +egr(''' +You can also create shortcuts to go to specific tabs, with 1 being the first +tab, 2 the second tab and -1 being the previously active tab, and any number +larger than the last tab being the last tab:: + + map ctrl+alt+1 goto_tab 1 + map ctrl+alt+2 goto_tab 2 + +Just as with :code:`new_window` above, you can also pass the name of arbitrary +commands to run when using new_tab and use :code:`new_tab_with_cwd`. Finally, +if you want the new tab to open next to the current tab rather than at the +end of the tabs list, use:: + + map ctrl+t new_tab !neighbor [optional cmd to run] +''') # }}} + + +# shortcuts.layout {{{ +agr('shortcuts.layout', 'Layout management') + +map('Next layout', + 'next_layout kitty_mod+l next_layout', + ) +egr(''' +You can also create shortcuts to switch to specific layouts:: + + map ctrl+alt+t goto_layout tall + map ctrl+alt+s goto_layout stack + +Similarly, to switch back to the previous layout:: + + map ctrl+alt+p last_used_layout +''') # }}} + + +# shortcuts.fonts {{{ +agr('shortcuts.fonts', 'Font sizes', ''' +You can change the font size for all top-level kitty OS windows at a time or +only the current one. +''') + +map('Increase font size', + 'increase_font_size kitty_mod+equal change_font_size all +2.0', + ) +map('Increase font size', + 'increase_font_size kitty_mod+plus change_font_size all +2.0', + documented=False, + ) +map('Increase font size', + 'increase_font_size kitty_mod+kp_add change_font_size all +2.0', + documented=False, + ) +map('Increase font size', + 'increase_font_size cmd+plus change_font_size all +2.0', + only="macos", + documented=False, + ) +map('Increase font size', + 'increase_font_size cmd+equal change_font_size all +2.0', + only="macos", + documented=False, + ) +map('Increase font size', + 'increase_font_size cmd+shift+equal change_font_size all +2.0', + only="macos", + documented=False, + ) + +map('Decrease font size', + 'decrease_font_size kitty_mod+minus change_font_size all -2.0', + ) +map('Decrease font size', + 'decrease_font_size kitty_mod+kp_subtract change_font_size all -2.0', + ) +map('Decrease font size', + 'decrease_font_size cmd+minus change_font_size all -2.0', + only="macos", + documented=False, + ) +map('Decrease font size', + 'decrease_font_size cmd+shift+minus change_font_size all -2.0', + only="macos", + documented=False, + ) + +map('Reset font size', + 'reset_font_size kitty_mod+backspace change_font_size all 0', + ) +map('Reset font size', + 'reset_font_size cmd+0 change_font_size all 0', + only="macos", + documented=False, + ) +egr(''' +To setup shortcuts for specific font sizes:: + + map kitty_mod+f6 change_font_size all 10.0 + +To setup shortcuts to change only the current OS window's font size:: + + map kitty_mod+f6 change_font_size current 10.0 +''') # }}} + + +# shortcuts.selection {{{ +agr('shortcuts.selection', 'Select and act on visible text', ''' +Use the hints kitten to select text and either pass it to an external program or +insert it into the terminal or copy it to the clipboard. +''') + +map('Open URL', + 'open_url kitty_mod+e kitten hints', + long_text=''' +Open a currently visible URL using the keyboard. The program used to open the +URL is specified in :opt:`open_url_with`. +''' + ) + +map('Insert selected path', + 'insert_selected_path kitty_mod+p>f kitten hints --type path --program -', + long_text=''' +Select a path/filename and insert it into the terminal. Useful, for instance to +run git commands on a filename output from a previous git command. +''' + ) + +map('Open selected path', + 'open_selected_path kitty_mod+p>shift+f kitten hints --type path', + long_text='Select a path/filename and open it with the default open program.' + ) + +map('Insert selected line', + 'insert_selected_line kitty_mod+p>l kitten hints --type line --program -', + long_text=''' +Select a line of text and insert it into the terminal. Use for the output of +things like: ls -1 +''' + ) + +map('Insert selected word', + 'insert_selected_word kitty_mod+p>w kitten hints --type word --program -', + long_text='Select words and insert into terminal.' + ) + +map('Insert selected hash', + 'insert_selected_hash kitty_mod+p>h kitten hints --type hash --program -', + long_text=''' +Select something that looks like a hash and insert it into the terminal. Useful +with git, which uses sha1 hashes to identify commits +''' + ) + +map('Open the selected file at the selected line', + 'goto_file_line kitty_mod+p>n kitten hints --type linenum', + long_text=''' +Select something that looks like :code:`filename:linenum` and open it in vim at +the specified line number. +''' + ) + +map('Open the selected hyperlink', + 'open_selected_hyperlink kitty_mod+p>y kitten hints --type hyperlink', + long_text=''' +Select a hyperlink (i.e. a URL that has been marked as such by the terminal +program, for example, by ls --hyperlink=auto). +''' + ) +egr(''' +The hints kitten has many more modes of operation that you can map to different +shortcuts. For a full description see :doc:`kittens/hints`. +''') # }}} + + +# shortcuts.misc {{{ +agr('shortcuts.misc', 'Miscellaneous') + +map('Toggle fullscreen', + 'toggle_fullscreen kitty_mod+f11 toggle_fullscreen', + ) + +map('Toggle maximized', + 'toggle_maximized kitty_mod+f10 toggle_maximized', + ) + +map('Unicode input', + 'input_unicode_character kitty_mod+u kitten unicode_input', + ) +map('Unicode input', + 'input_unicode_character cmd+ctrl+space kitten unicode_input', + only="macos", + documented=False, + ) + +map('Edit config file', + 'edit_config_file kitty_mod+f2 edit_config_file', + ) +map('Edit config file', + 'edit_config_file cmd+, edit_config_file', + only="macos", + documented=False, + ) + +map('Open the kitty command shell', + 'kitty_shell kitty_mod+escape kitty_shell window', + long_text=''' +Open the kitty shell in a new window/tab/overlay/os_window to control kitty +using commands. +''' + ) + +map('Increase background opacity', + 'increase_background_opacity kitty_mod+a>m set_background_opacity +0.1', + ) + +map('Decrease background opacity', + 'decrease_background_opacity kitty_mod+a>l set_background_opacity -0.1', + ) + +map('Make background fully opaque', + 'full_background_opacity kitty_mod+a>1 set_background_opacity 1', + ) + +map('Reset background opacity', + 'reset_background_opacity kitty_mod+a>d set_background_opacity default', + ) + +map('Reset the terminal', + 'reset_terminal kitty_mod+delete clear_terminal reset active', + long_text=''' +You can create shortcuts to clear/reset the terminal. For example:: + + # Reset the terminal + map kitty_mod+f9 clear_terminal reset active + # Clear the terminal screen by erasing all contents + map kitty_mod+f10 clear_terminal clear active + # Clear the terminal scrollback by erasing it + map kitty_mod+f11 clear_terminal scrollback active + # Scroll the contents of the screen into the scrollback + map kitty_mod+f12 clear_terminal scroll active + +If you want to operate on all windows instead of just the current one, use :italic:`all` instead of :italic:`active`. + +It is also possible to remap Ctrl+L to both scroll the current screen contents into the scrollback buffer +and clear the screen, instead of just clearing the screen:: + + map ctrl+l combine : clear_terminal scroll active : send_text normal,application \x0c +''' + ) + +map('Send arbitrary text on key presses', + 'send_text ctrl+shift+alt+h send_text all Hello World', + add_to_default=False, + long_text=''' +You can tell kitty to send arbitrary (UTF-8) encoded text to +the client program when pressing specified shortcut keys. For example:: + + map ctrl+alt+a send_text all Special text + +This will send "Special text" when you press the :kbd:`ctrl+alt+a` key +combination. The text to be sent is a python string literal so you can use +escapes like :code:`\x1b` to send control codes or :code:`\u21fb` to send +unicode characters (or you can just input the unicode characters directly as +UTF-8 text). The first argument to :code:`send_text` is the keyboard modes in which to +activate the shortcut. The possible values are :code:`normal` or :code:`application` or :code:`kitty` +or a comma separated combination of them. The special keyword :code:`all` means all +modes. The modes :code:`normal` and :code:`application` refer to the DECCKM cursor key mode for +terminals, and :code:`kitty` refers to the special kitty extended keyboard protocol. + +Another example, that outputs a word and then moves the cursor to the start of +the line (same as pressing the Home key):: + + map ctrl+alt+a send_text normal Word\x1b[H + map ctrl+alt+a send_text application Word\x1bOH +''' + ) +egr() # }}} +egr() # }}} diff --git a/kitty/options/parse.py b/kitty/options/parse.py new file mode 100644 index 000000000..73b11a38c --- /dev/null +++ b/kitty/options/parse.py @@ -0,0 +1,1291 @@ +# generated by gen-config.py DO NOT edit +# vim:fileencoding=utf-8 + +import typing +from kitty.options.utils import ( + active_tab_title_template, adjust_line_height, allow_hyperlinks, allow_remote_control, + box_drawing_scale, clear_all_shortcuts, clipboard_control, config_or_absolute_path, copy_on_select, + cursor_text_color, deprecated_hide_window_decorations_aliases, + deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, disable_ligatures, + edge_width, env, font_features, hide_window_decorations, kitten_alias, macos_option_as_alt, + macos_titlebar_color, optional_edge_width, parse_map, parse_mouse_map, resize_draw_strategy, + scrollback_lines, scrollback_pager_history_size, symbol_map, tab_activity_symbol, tab_bar_edge, + tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_title_template, to_cursor_shape, + to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style, window_border_width, + window_size +) +from kitty.conf.utils import ( + merge_dicts, positive_float, positive_int, to_bool, to_cmdline, to_color, to_color_or_none, + unit_float +) + + +class Parser: + + def active_border_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['active_border_color'] = to_color_or_none(val) + + def active_tab_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['active_tab_background'] = to_color(val) + + def active_tab_font_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['active_tab_font_style'] = tab_font_style(val) + + def active_tab_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['active_tab_foreground'] = to_color(val) + + def active_tab_title_template(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['active_tab_title_template'] = active_tab_title_template(val) + + def adjust_column_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['adjust_column_width'] = adjust_line_height(val) + + def adjust_line_height(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['adjust_line_height'] = adjust_line_height(val) + + def allow_hyperlinks(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['allow_hyperlinks'] = allow_hyperlinks(val) + + def allow_remote_control(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['allow_remote_control'] = allow_remote_control(val) + + def background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['background'] = to_color(val) + + def background_image(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['background_image'] = config_or_absolute_path(val) + + def background_image_layout(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_background_image_layout: + raise ValueError(f"The value {val} is not a valid choice for background_image_layout") + ans["background_image_layout"] = val + + choices_for_background_image_layout = frozenset(('mirror-tiled', 'scaled', 'tiled')) + + def background_image_linear(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['background_image_linear'] = to_bool(val) + + def background_opacity(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['background_opacity'] = unit_float(val) + + def background_tint(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['background_tint'] = unit_float(val) + + def bell_border_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['bell_border_color'] = to_color(val) + + def bell_on_tab(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['bell_on_tab'] = to_bool(val) + + def bold_font(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['bold_font'] = str(val) + + def bold_italic_font(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['bold_italic_font'] = str(val) + + def box_drawing_scale(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['box_drawing_scale'] = box_drawing_scale(val) + + def clear_all_shortcuts(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + clear_all_shortcuts(val, ans) + + def click_interval(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['click_interval'] = float(val) + + def clipboard_control(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['clipboard_control'] = clipboard_control(val) + + def close_on_child_death(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['close_on_child_death'] = to_bool(val) + + def color0(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color0'] = to_color(val) + + def color1(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color1'] = to_color(val) + + def color2(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color2'] = to_color(val) + + def color3(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color3'] = to_color(val) + + def color4(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color4'] = to_color(val) + + def color5(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color5'] = to_color(val) + + def color6(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color6'] = to_color(val) + + def color7(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color7'] = to_color(val) + + def color8(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color8'] = to_color(val) + + def color9(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color9'] = to_color(val) + + def color10(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color10'] = to_color(val) + + def color11(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color11'] = to_color(val) + + def color12(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color12'] = to_color(val) + + def color13(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color13'] = to_color(val) + + def color14(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color14'] = to_color(val) + + def color15(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color15'] = to_color(val) + + def color16(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color16'] = to_color(val) + + def color17(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color17'] = to_color(val) + + def color18(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color18'] = to_color(val) + + def color19(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color19'] = to_color(val) + + def color20(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color20'] = to_color(val) + + def color21(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color21'] = to_color(val) + + def color22(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color22'] = to_color(val) + + def color23(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color23'] = to_color(val) + + def color24(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color24'] = to_color(val) + + def color25(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color25'] = to_color(val) + + def color26(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color26'] = to_color(val) + + def color27(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color27'] = to_color(val) + + def color28(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color28'] = to_color(val) + + def color29(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color29'] = to_color(val) + + def color30(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color30'] = to_color(val) + + def color31(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color31'] = to_color(val) + + def color32(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color32'] = to_color(val) + + def color33(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color33'] = to_color(val) + + def color34(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color34'] = to_color(val) + + def color35(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color35'] = to_color(val) + + def color36(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color36'] = to_color(val) + + def color37(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color37'] = to_color(val) + + def color38(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color38'] = to_color(val) + + def color39(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color39'] = to_color(val) + + def color40(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color40'] = to_color(val) + + def color41(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color41'] = to_color(val) + + def color42(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color42'] = to_color(val) + + def color43(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color43'] = to_color(val) + + def color44(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color44'] = to_color(val) + + def color45(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color45'] = to_color(val) + + def color46(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color46'] = to_color(val) + + def color47(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color47'] = to_color(val) + + def color48(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color48'] = to_color(val) + + def color49(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color49'] = to_color(val) + + def color50(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color50'] = to_color(val) + + def color51(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color51'] = to_color(val) + + def color52(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color52'] = to_color(val) + + def color53(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color53'] = to_color(val) + + def color54(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color54'] = to_color(val) + + def color55(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color55'] = to_color(val) + + def color56(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color56'] = to_color(val) + + def color57(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color57'] = to_color(val) + + def color58(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color58'] = to_color(val) + + def color59(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color59'] = to_color(val) + + def color60(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color60'] = to_color(val) + + def color61(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color61'] = to_color(val) + + def color62(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color62'] = to_color(val) + + def color63(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color63'] = to_color(val) + + def color64(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color64'] = to_color(val) + + def color65(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color65'] = to_color(val) + + def color66(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color66'] = to_color(val) + + def color67(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color67'] = to_color(val) + + def color68(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color68'] = to_color(val) + + def color69(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color69'] = to_color(val) + + def color70(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color70'] = to_color(val) + + def color71(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color71'] = to_color(val) + + def color72(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color72'] = to_color(val) + + def color73(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color73'] = to_color(val) + + def color74(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color74'] = to_color(val) + + def color75(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color75'] = to_color(val) + + def color76(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color76'] = to_color(val) + + def color77(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color77'] = to_color(val) + + def color78(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color78'] = to_color(val) + + def color79(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color79'] = to_color(val) + + def color80(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color80'] = to_color(val) + + def color81(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color81'] = to_color(val) + + def color82(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color82'] = to_color(val) + + def color83(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color83'] = to_color(val) + + def color84(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color84'] = to_color(val) + + def color85(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color85'] = to_color(val) + + def color86(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color86'] = to_color(val) + + def color87(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color87'] = to_color(val) + + def color88(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color88'] = to_color(val) + + def color89(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color89'] = to_color(val) + + def color90(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color90'] = to_color(val) + + def color91(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color91'] = to_color(val) + + def color92(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color92'] = to_color(val) + + def color93(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color93'] = to_color(val) + + def color94(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color94'] = to_color(val) + + def color95(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color95'] = to_color(val) + + def color96(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color96'] = to_color(val) + + def color97(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color97'] = to_color(val) + + def color98(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color98'] = to_color(val) + + def color99(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color99'] = to_color(val) + + def color100(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color100'] = to_color(val) + + def color101(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color101'] = to_color(val) + + def color102(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color102'] = to_color(val) + + def color103(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color103'] = to_color(val) + + def color104(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color104'] = to_color(val) + + def color105(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color105'] = to_color(val) + + def color106(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color106'] = to_color(val) + + def color107(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color107'] = to_color(val) + + def color108(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color108'] = to_color(val) + + def color109(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color109'] = to_color(val) + + def color110(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color110'] = to_color(val) + + def color111(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color111'] = to_color(val) + + def color112(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color112'] = to_color(val) + + def color113(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color113'] = to_color(val) + + def color114(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color114'] = to_color(val) + + def color115(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color115'] = to_color(val) + + def color116(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color116'] = to_color(val) + + def color117(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color117'] = to_color(val) + + def color118(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color118'] = to_color(val) + + def color119(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color119'] = to_color(val) + + def color120(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color120'] = to_color(val) + + def color121(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color121'] = to_color(val) + + def color122(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color122'] = to_color(val) + + def color123(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color123'] = to_color(val) + + def color124(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color124'] = to_color(val) + + def color125(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color125'] = to_color(val) + + def color126(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color126'] = to_color(val) + + def color127(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color127'] = to_color(val) + + def color128(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color128'] = to_color(val) + + def color129(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color129'] = to_color(val) + + def color130(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color130'] = to_color(val) + + def color131(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color131'] = to_color(val) + + def color132(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color132'] = to_color(val) + + def color133(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color133'] = to_color(val) + + def color134(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color134'] = to_color(val) + + def color135(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color135'] = to_color(val) + + def color136(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color136'] = to_color(val) + + def color137(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color137'] = to_color(val) + + def color138(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color138'] = to_color(val) + + def color139(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color139'] = to_color(val) + + def color140(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color140'] = to_color(val) + + def color141(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color141'] = to_color(val) + + def color142(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color142'] = to_color(val) + + def color143(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color143'] = to_color(val) + + def color144(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color144'] = to_color(val) + + def color145(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color145'] = to_color(val) + + def color146(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color146'] = to_color(val) + + def color147(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color147'] = to_color(val) + + def color148(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color148'] = to_color(val) + + def color149(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color149'] = to_color(val) + + def color150(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color150'] = to_color(val) + + def color151(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color151'] = to_color(val) + + def color152(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color152'] = to_color(val) + + def color153(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color153'] = to_color(val) + + def color154(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color154'] = to_color(val) + + def color155(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color155'] = to_color(val) + + def color156(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color156'] = to_color(val) + + def color157(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color157'] = to_color(val) + + def color158(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color158'] = to_color(val) + + def color159(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color159'] = to_color(val) + + def color160(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color160'] = to_color(val) + + def color161(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color161'] = to_color(val) + + def color162(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color162'] = to_color(val) + + def color163(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color163'] = to_color(val) + + def color164(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color164'] = to_color(val) + + def color165(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color165'] = to_color(val) + + def color166(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color166'] = to_color(val) + + def color167(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color167'] = to_color(val) + + def color168(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color168'] = to_color(val) + + def color169(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color169'] = to_color(val) + + def color170(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color170'] = to_color(val) + + def color171(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color171'] = to_color(val) + + def color172(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color172'] = to_color(val) + + def color173(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color173'] = to_color(val) + + def color174(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color174'] = to_color(val) + + def color175(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color175'] = to_color(val) + + def color176(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color176'] = to_color(val) + + def color177(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color177'] = to_color(val) + + def color178(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color178'] = to_color(val) + + def color179(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color179'] = to_color(val) + + def color180(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color180'] = to_color(val) + + def color181(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color181'] = to_color(val) + + def color182(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color182'] = to_color(val) + + def color183(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color183'] = to_color(val) + + def color184(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color184'] = to_color(val) + + def color185(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color185'] = to_color(val) + + def color186(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color186'] = to_color(val) + + def color187(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color187'] = to_color(val) + + def color188(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color188'] = to_color(val) + + def color189(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color189'] = to_color(val) + + def color190(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color190'] = to_color(val) + + def color191(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color191'] = to_color(val) + + def color192(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color192'] = to_color(val) + + def color193(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color193'] = to_color(val) + + def color194(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color194'] = to_color(val) + + def color195(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color195'] = to_color(val) + + def color196(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color196'] = to_color(val) + + def color197(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color197'] = to_color(val) + + def color198(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color198'] = to_color(val) + + def color199(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color199'] = to_color(val) + + def color200(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color200'] = to_color(val) + + def color201(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color201'] = to_color(val) + + def color202(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color202'] = to_color(val) + + def color203(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color203'] = to_color(val) + + def color204(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color204'] = to_color(val) + + def color205(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color205'] = to_color(val) + + def color206(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color206'] = to_color(val) + + def color207(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color207'] = to_color(val) + + def color208(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color208'] = to_color(val) + + def color209(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color209'] = to_color(val) + + def color210(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color210'] = to_color(val) + + def color211(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color211'] = to_color(val) + + def color212(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color212'] = to_color(val) + + def color213(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color213'] = to_color(val) + + def color214(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color214'] = to_color(val) + + def color215(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color215'] = to_color(val) + + def color216(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color216'] = to_color(val) + + def color217(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color217'] = to_color(val) + + def color218(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color218'] = to_color(val) + + def color219(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color219'] = to_color(val) + + def color220(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color220'] = to_color(val) + + def color221(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color221'] = to_color(val) + + def color222(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color222'] = to_color(val) + + def color223(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color223'] = to_color(val) + + def color224(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color224'] = to_color(val) + + def color225(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color225'] = to_color(val) + + def color226(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color226'] = to_color(val) + + def color227(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color227'] = to_color(val) + + def color228(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color228'] = to_color(val) + + def color229(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color229'] = to_color(val) + + def color230(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color230'] = to_color(val) + + def color231(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color231'] = to_color(val) + + def color232(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color232'] = to_color(val) + + def color233(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color233'] = to_color(val) + + def color234(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color234'] = to_color(val) + + def color235(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color235'] = to_color(val) + + def color236(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color236'] = to_color(val) + + def color237(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color237'] = to_color(val) + + def color238(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color238'] = to_color(val) + + def color239(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color239'] = to_color(val) + + def color240(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color240'] = to_color(val) + + def color241(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color241'] = to_color(val) + + def color242(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color242'] = to_color(val) + + def color243(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color243'] = to_color(val) + + def color244(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color244'] = to_color(val) + + def color245(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color245'] = to_color(val) + + def color246(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color246'] = to_color(val) + + def color247(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color247'] = to_color(val) + + def color248(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color248'] = to_color(val) + + def color249(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color249'] = to_color(val) + + def color250(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color250'] = to_color(val) + + def color251(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color251'] = to_color(val) + + def color252(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color252'] = to_color(val) + + def color253(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color253'] = to_color(val) + + def color254(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color254'] = to_color(val) + + def color255(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['color255'] = to_color(val) + + def command_on_bell(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['command_on_bell'] = to_cmdline(val) + + def confirm_os_window_close(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['confirm_os_window_close'] = positive_int(val) + + def copy_on_select(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['copy_on_select'] = copy_on_select(val) + + def cursor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor'] = to_color(val) + + def cursor_beam_thickness(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor_beam_thickness'] = positive_float(val) + + def cursor_blink_interval(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor_blink_interval'] = float(val) + + def cursor_shape(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor_shape'] = to_cursor_shape(val) + + def cursor_stop_blinking_after(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor_stop_blinking_after'] = positive_float(val) + + def cursor_text_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor_text_color'] = cursor_text_color(val) + + def cursor_underline_thickness(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['cursor_underline_thickness'] = positive_float(val) + + def default_pointer_shape(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_default_pointer_shape: + raise ValueError(f"The value {val} is not a valid choice for default_pointer_shape") + ans["default_pointer_shape"] = val + + choices_for_default_pointer_shape = frozenset(('arrow', 'beam', 'hand')) + + def detect_urls(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['detect_urls'] = to_bool(val) + + def dim_opacity(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['dim_opacity'] = unit_float(val) + + def disable_ligatures(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['disable_ligatures'] = disable_ligatures(val) + + def draw_minimal_borders(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['draw_minimal_borders'] = to_bool(val) + + def dynamic_background_opacity(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['dynamic_background_opacity'] = to_bool(val) + + def editor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['editor'] = str(val) + + def enable_audio_bell(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['enable_audio_bell'] = to_bool(val) + + def enabled_layouts(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['enabled_layouts'] = to_layout_names(val) + + def env(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k, v in env(val, ans["env"]): + ans["env"][k] = v + + def focus_follows_mouse(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['focus_follows_mouse'] = to_bool(val) + + def font_family(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['font_family'] = str(val) + + def font_features(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k, v in font_features(val): + ans["font_features"][k] = v + + def font_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['font_size'] = to_font_size(val) + + def force_ltr(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['force_ltr'] = to_bool(val) + + def foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['foreground'] = to_color(val) + + def hide_window_decorations(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['hide_window_decorations'] = hide_window_decorations(val) + + def inactive_border_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['inactive_border_color'] = to_color(val) + + def inactive_tab_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['inactive_tab_background'] = to_color(val) + + def inactive_tab_font_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['inactive_tab_font_style'] = tab_font_style(val) + + def inactive_tab_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['inactive_tab_foreground'] = to_color(val) + + def inactive_text_alpha(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['inactive_text_alpha'] = unit_float(val) + + def initial_window_height(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['initial_window_height'] = window_size(val) + + def initial_window_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['initial_window_width'] = window_size(val) + + def input_delay(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['input_delay'] = positive_int(val) + + def italic_font(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['italic_font'] = str(val) + + def kitten_alias(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k, v in kitten_alias(val): + ans["kitten_alias"][k] = v + + def kitty_mod(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['kitty_mod'] = to_modifiers(val) + + def linux_display_server(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_linux_display_server: + raise ValueError(f"The value {val} is not a valid choice for linux_display_server") + ans["linux_display_server"] = val + + choices_for_linux_display_server = frozenset(('auto', 'wayland', 'x11')) + + def listen_on(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['listen_on'] = str(val) + + def macos_custom_beam_cursor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_custom_beam_cursor'] = to_bool(val) + + def macos_hide_from_tasks(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_hide_from_tasks'] = to_bool(val) + + def macos_option_as_alt(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_option_as_alt'] = macos_option_as_alt(val) + + def macos_quit_when_last_window_closed(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_quit_when_last_window_closed'] = to_bool(val) + + def macos_show_window_title_in(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_macos_show_window_title_in: + raise ValueError(f"The value {val} is not a valid choice for macos_show_window_title_in") + ans["macos_show_window_title_in"] = val + + choices_for_macos_show_window_title_in = frozenset(('all', 'menubar', 'none', 'window')) + + def macos_thicken_font(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_thicken_font'] = positive_float(val) + + def macos_titlebar_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_titlebar_color'] = macos_titlebar_color(val) + + def macos_traditional_fullscreen(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_traditional_fullscreen'] = to_bool(val) + + def macos_window_resizable(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['macos_window_resizable'] = to_bool(val) + + def mark1_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mark1_background'] = to_color(val) + + def mark1_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mark1_foreground'] = to_color(val) + + def mark2_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mark2_background'] = to_color(val) + + def mark2_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mark2_foreground'] = to_color(val) + + def mark3_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mark3_background'] = to_color(val) + + def mark3_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mark3_foreground'] = to_color(val) + + def mouse_hide_wait(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['mouse_hide_wait'] = float(val) + + def open_url_with(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['open_url_with'] = to_cmdline(val) + + def placement_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_placement_strategy: + raise ValueError(f"The value {val} is not a valid choice for placement_strategy") + ans["placement_strategy"] = val + + choices_for_placement_strategy = frozenset(('center', 'top-left')) + + def pointer_shape_when_dragging(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_pointer_shape_when_dragging: + raise ValueError(f"The value {val} is not a valid choice for pointer_shape_when_dragging") + ans["pointer_shape_when_dragging"] = val + + choices_for_pointer_shape_when_dragging = frozenset(('arrow', 'beam', 'hand')) + + def pointer_shape_when_grabbed(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_pointer_shape_when_grabbed: + raise ValueError(f"The value {val} is not a valid choice for pointer_shape_when_grabbed") + ans["pointer_shape_when_grabbed"] = val + + choices_for_pointer_shape_when_grabbed = frozenset(('arrow', 'beam', 'hand')) + + def remember_window_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['remember_window_size'] = to_bool(val) + + def repaint_delay(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['repaint_delay'] = positive_int(val) + + def resize_debounce_time(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['resize_debounce_time'] = positive_float(val) + + def resize_draw_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['resize_draw_strategy'] = resize_draw_strategy(val) + + def resize_in_steps(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['resize_in_steps'] = to_bool(val) + + def scrollback_fill_enlarged_window(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['scrollback_fill_enlarged_window'] = to_bool(val) + + def scrollback_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['scrollback_lines'] = scrollback_lines(val) + + def scrollback_pager(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['scrollback_pager'] = to_cmdline(val) + + def scrollback_pager_history_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['scrollback_pager_history_size'] = scrollback_pager_history_size(val) + + def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['select_by_word_characters'] = str(val) + + def selection_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['selection_background'] = to_color(val) + + def selection_foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['selection_foreground'] = to_color_or_none(val) + + def shell(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['shell'] = str(val) + + def single_window_margin_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['single_window_margin_width'] = optional_edge_width(val) + + def startup_session(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['startup_session'] = config_or_absolute_path(val) + + def strip_trailing_spaces(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_strip_trailing_spaces: + raise ValueError(f"The value {val} is not a valid choice for strip_trailing_spaces") + ans["strip_trailing_spaces"] = val + + choices_for_strip_trailing_spaces = frozenset(('always', 'never', 'smart')) + + def symbol_map(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k, v in symbol_map(val): + ans["symbol_map"][k] = v + + def sync_to_monitor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['sync_to_monitor'] = to_bool(val) + + def tab_activity_symbol(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_activity_symbol'] = tab_activity_symbol(val) + + def tab_bar_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_bar_background'] = to_color_or_none(val) + + def tab_bar_edge(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_bar_edge'] = tab_bar_edge(val) + + def tab_bar_margin_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_bar_margin_width'] = positive_float(val) + + def tab_bar_min_tabs(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_bar_min_tabs'] = tab_bar_min_tabs(val) + + def tab_bar_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_tab_bar_style: + raise ValueError(f"The value {val} is not a valid choice for tab_bar_style") + ans["tab_bar_style"] = val + + choices_for_tab_bar_style = frozenset(('fade', 'hidden', 'powerline', 'separator')) + + def tab_fade(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_fade'] = tab_fade(val) + + def tab_powerline_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_tab_powerline_style: + raise ValueError(f"The value {val} is not a valid choice for tab_powerline_style") + ans["tab_powerline_style"] = val + + choices_for_tab_powerline_style = frozenset(('angled', 'round', 'slanted')) + + def tab_separator(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_separator'] = tab_separator(val) + + def tab_switch_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + val = val.lower() + if val not in self.choices_for_tab_switch_strategy: + raise ValueError(f"The value {val} is not a valid choice for tab_switch_strategy") + ans["tab_switch_strategy"] = val + + choices_for_tab_switch_strategy = frozenset(('last', 'left', 'previous', 'right')) + + def tab_title_template(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['tab_title_template'] = tab_title_template(val) + + def term(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['term'] = str(val) + + def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['touch_scroll_multiplier'] = float(val) + + def update_check_interval(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['update_check_interval'] = float(val) + + def url_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['url_color'] = to_color(val) + + def url_prefixes(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['url_prefixes'] = url_prefixes(val) + + def url_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['url_style'] = url_style(val) + + def visual_bell_duration(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['visual_bell_duration'] = positive_float(val) + + def wayland_titlebar_color(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['wayland_titlebar_color'] = macos_titlebar_color(val) + + def wheel_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['wheel_scroll_multiplier'] = float(val) + + def window_alert_on_bell(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_alert_on_bell'] = to_bool(val) + + def window_border_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_border_width'] = window_border_width(val) + + def window_margin_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_margin_width'] = edge_width(val) + + def window_padding_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_padding_width'] = edge_width(val) + + def window_resize_step_cells(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_resize_step_cells'] = positive_int(val) + + def window_resize_step_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['window_resize_step_lines'] = positive_int(val) + + def x11_hide_window_decorations(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + deprecated_hide_window_decorations_aliases('x11_hide_window_decorations', val, ans) + + def macos_hide_titlebar(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + deprecated_hide_window_decorations_aliases('macos_hide_titlebar', val, ans) + + def macos_show_window_title_in_menubar(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + deprecated_macos_show_window_title_in_menubar_alias('macos_show_window_title_in_menubar', val, ans) + + def send_text(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + deprecated_send_text('send_text', val, ans) + + def map(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k in parse_map(val): + ans['map'].append(k) + + def mouse_map(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + for k in parse_mouse_map(val): + ans['mouse_map'].append(k) + + +def create_result_dict() -> typing.Dict[str, typing.Any]: + return { + 'env': {}, + 'font_features': {}, + 'kitten_alias': {}, + 'symbol_map': {}, + 'map': [], + 'mouse_map': [], + } + + +actions = frozenset(('map', 'mouse_map')) + + +def merge_result_dicts(defaults: typing.Dict[str, typing.Any], vals: typing.Dict[str, typing.Any]) -> typing.Dict[str, typing.Any]: + ans = {} + for k, v in defaults.items(): + if isinstance(v, dict): + ans[k] = merge_dicts(v, vals.get(k, {})) + elif k in actions: + ans[k] = v + vals.get(k, []) + else: + ans[k] = vals.get(k, v) + return ans + + +parser = Parser() + + +def parse_conf_item(key: str, val: str, ans: typing.Dict[str, typing.Any]) -> bool: + func = getattr(parser, key, None) + if func is not None: + func(val, ans) + return True + return False \ No newline at end of file diff --git a/kitty/options/types.py b/kitty/options/types.py new file mode 100644 index 000000000..6c867b99f --- /dev/null +++ b/kitty/options/types.py @@ -0,0 +1,1040 @@ +# generated by gen-config.py DO NOT edit +# vim:fileencoding=utf-8 + +import typing +from kitty.options.utils import KeyDefinition, KeyMap, MouseMap, MouseMapping, SequenceMap +import kitty.options.utils +from kitty.conf.utils import KeyAction +import kitty.conf.utils +from kitty.types import FloatEdges, SingleKey +import kitty.types +from kitty.constants import is_macos +import kitty.constants +from kitty.rgb import Color +import kitty.rgb + +if typing.TYPE_CHECKING: + choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled'] + choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand'] + choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] + choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window'] + choices_for_placement_strategy = typing.Literal['center', 'top-left'] + choices_for_pointer_shape_when_dragging = typing.Literal['arrow', 'beam', 'hand'] + choices_for_pointer_shape_when_grabbed = typing.Literal['arrow', 'beam', 'hand'] + choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart'] + choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator'] + choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted'] + choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right'] +else: + choices_for_background_image_layout = str + choices_for_default_pointer_shape = str + choices_for_linux_display_server = str + choices_for_macos_show_window_title_in = str + choices_for_placement_strategy = str + choices_for_pointer_shape_when_dragging = str + choices_for_pointer_shape_when_grabbed = str + choices_for_strip_trailing_spaces = str + choices_for_tab_bar_style = str + choices_for_tab_powerline_style = str + choices_for_tab_switch_strategy = str + +option_names = ( # {{{ + 'active_border_color', + 'active_tab_background', + 'active_tab_font_style', + 'active_tab_foreground', + 'active_tab_title_template', + 'adjust_column_width', + 'adjust_line_height', + 'allow_hyperlinks', + 'allow_remote_control', + 'background', + 'background_image', + 'background_image_layout', + 'background_image_linear', + 'background_opacity', + 'background_tint', + 'bell_border_color', + 'bell_on_tab', + 'bold_font', + 'bold_italic_font', + 'box_drawing_scale', + 'clear_all_shortcuts', + 'click_interval', + 'clipboard_control', + 'close_on_child_death', + 'color0', + 'color1', + 'color2', + 'color3', + 'color4', + 'color5', + 'color6', + 'color7', + 'color8', + 'color9', + 'color10', + 'color11', + 'color12', + 'color13', + 'color14', + 'color15', + 'color16', + 'color17', + 'color18', + 'color19', + 'color20', + 'color21', + 'color22', + 'color23', + 'color24', + 'color25', + 'color26', + 'color27', + 'color28', + 'color29', + 'color30', + 'color31', + 'color32', + 'color33', + 'color34', + 'color35', + 'color36', + 'color37', + 'color38', + 'color39', + 'color40', + 'color41', + 'color42', + 'color43', + 'color44', + 'color45', + 'color46', + 'color47', + 'color48', + 'color49', + 'color50', + 'color51', + 'color52', + 'color53', + 'color54', + 'color55', + 'color56', + 'color57', + 'color58', + 'color59', + 'color60', + 'color61', + 'color62', + 'color63', + 'color64', + 'color65', + 'color66', + 'color67', + 'color68', + 'color69', + 'color70', + 'color71', + 'color72', + 'color73', + 'color74', + 'color75', + 'color76', + 'color77', + 'color78', + 'color79', + 'color80', + 'color81', + 'color82', + 'color83', + 'color84', + 'color85', + 'color86', + 'color87', + 'color88', + 'color89', + 'color90', + 'color91', + 'color92', + 'color93', + 'color94', + 'color95', + 'color96', + 'color97', + 'color98', + 'color99', + 'color100', + 'color101', + 'color102', + 'color103', + 'color104', + 'color105', + 'color106', + 'color107', + 'color108', + 'color109', + 'color110', + 'color111', + 'color112', + 'color113', + 'color114', + 'color115', + 'color116', + 'color117', + 'color118', + 'color119', + 'color120', + 'color121', + 'color122', + 'color123', + 'color124', + 'color125', + 'color126', + 'color127', + 'color128', + 'color129', + 'color130', + 'color131', + 'color132', + 'color133', + 'color134', + 'color135', + 'color136', + 'color137', + 'color138', + 'color139', + 'color140', + 'color141', + 'color142', + 'color143', + 'color144', + 'color145', + 'color146', + 'color147', + 'color148', + 'color149', + 'color150', + 'color151', + 'color152', + 'color153', + 'color154', + 'color155', + 'color156', + 'color157', + 'color158', + 'color159', + 'color160', + 'color161', + 'color162', + 'color163', + 'color164', + 'color165', + 'color166', + 'color167', + 'color168', + 'color169', + 'color170', + 'color171', + 'color172', + 'color173', + 'color174', + 'color175', + 'color176', + 'color177', + 'color178', + 'color179', + 'color180', + 'color181', + 'color182', + 'color183', + 'color184', + 'color185', + 'color186', + 'color187', + 'color188', + 'color189', + 'color190', + 'color191', + 'color192', + 'color193', + 'color194', + 'color195', + 'color196', + 'color197', + 'color198', + 'color199', + 'color200', + 'color201', + 'color202', + 'color203', + 'color204', + 'color205', + 'color206', + 'color207', + 'color208', + 'color209', + 'color210', + 'color211', + 'color212', + 'color213', + 'color214', + 'color215', + 'color216', + 'color217', + 'color218', + 'color219', + 'color220', + 'color221', + 'color222', + 'color223', + 'color224', + 'color225', + 'color226', + 'color227', + 'color228', + 'color229', + 'color230', + 'color231', + 'color232', + 'color233', + 'color234', + 'color235', + 'color236', + 'color237', + 'color238', + 'color239', + 'color240', + 'color241', + 'color242', + 'color243', + 'color244', + 'color245', + 'color246', + 'color247', + 'color248', + 'color249', + 'color250', + 'color251', + 'color252', + 'color253', + 'color254', + 'color255', + 'command_on_bell', + 'confirm_os_window_close', + 'copy_on_select', + 'cursor', + 'cursor_beam_thickness', + 'cursor_blink_interval', + 'cursor_shape', + 'cursor_stop_blinking_after', + 'cursor_text_color', + 'cursor_underline_thickness', + 'default_pointer_shape', + 'detect_urls', + 'dim_opacity', + 'disable_ligatures', + 'draw_minimal_borders', + 'dynamic_background_opacity', + 'editor', + 'enable_audio_bell', + 'enabled_layouts', + 'env', + 'focus_follows_mouse', + 'font_family', + 'font_features', + 'font_size', + 'force_ltr', + 'foreground', + 'hide_window_decorations', + 'inactive_border_color', + 'inactive_tab_background', + 'inactive_tab_font_style', + 'inactive_tab_foreground', + 'inactive_text_alpha', + 'initial_window_height', + 'initial_window_width', + 'input_delay', + 'italic_font', + 'kitten_alias', + 'kitty_mod', + 'linux_display_server', + 'listen_on', + 'macos_custom_beam_cursor', + 'macos_hide_from_tasks', + 'macos_option_as_alt', + 'macos_quit_when_last_window_closed', + 'macos_show_window_title_in', + 'macos_thicken_font', + 'macos_titlebar_color', + 'macos_traditional_fullscreen', + 'macos_window_resizable', + 'map', + 'mark1_background', + 'mark1_foreground', + 'mark2_background', + 'mark2_foreground', + 'mark3_background', + 'mark3_foreground', + 'mouse_hide_wait', + 'mouse_map', + 'open_url_with', + 'placement_strategy', + 'pointer_shape_when_dragging', + 'pointer_shape_when_grabbed', + 'remember_window_size', + 'repaint_delay', + 'resize_debounce_time', + 'resize_draw_strategy', + 'resize_in_steps', + 'scrollback_fill_enlarged_window', + 'scrollback_lines', + 'scrollback_pager', + 'scrollback_pager_history_size', + 'select_by_word_characters', + 'selection_background', + 'selection_foreground', + 'shell', + 'single_window_margin_width', + 'startup_session', + 'strip_trailing_spaces', + 'symbol_map', + 'sync_to_monitor', + 'tab_activity_symbol', + 'tab_bar_background', + 'tab_bar_edge', + 'tab_bar_margin_width', + 'tab_bar_min_tabs', + 'tab_bar_style', + 'tab_fade', + 'tab_powerline_style', + 'tab_separator', + 'tab_switch_strategy', + 'tab_title_template', + 'term', + 'touch_scroll_multiplier', + 'update_check_interval', + 'url_color', + 'url_prefixes', + 'url_style', + 'visual_bell_duration', + 'wayland_titlebar_color', + 'wheel_scroll_multiplier', + 'window_alert_on_bell', + 'window_border_width', + 'window_margin_width', + 'window_padding_width', + 'window_resize_step_cells', + 'window_resize_step_lines') # }}} + + +class Options: + active_border_color: typing.Optional[kitty.rgb.Color] = Color(red=0, green=255, blue=0) + active_tab_background: Color = Color(red=238, green=238, blue=238) + active_tab_font_style: typing.Tuple[bool, bool] = (True, True) + active_tab_foreground: Color = Color(red=0, green=0, blue=0) + active_tab_title_template: typing.Optional[str] = None + adjust_column_width: typing.Union[int, float] = 0 + adjust_line_height: typing.Union[int, float] = 0 + allow_hyperlinks: int = 1 + allow_remote_control: str = 'n' + background: Color = Color(red=0, green=0, blue=0) + background_image: typing.Optional[str] = None + background_image_layout: choices_for_background_image_layout = 'tiled' + background_image_linear: bool = False + background_opacity: float = 1.0 + background_tint: float = 0 + bell_border_color: Color = Color(red=255, green=90, blue=0) + bell_on_tab: bool = True + bold_font: str = 'auto' + bold_italic_font: str = 'auto' + box_drawing_scale: typing.Tuple[float, float, float, float] = (0.001, 1.0, 1.5, 2.0) + clear_all_shortcuts: bool = False + click_interval: float = -1.0 + clipboard_control: typing.FrozenSet[str] = frozenset({'write-primary', 'write-clipboard'}) + close_on_child_death: bool = False + color0: Color = Color(red=0, green=0, blue=0) + color1: Color = Color(red=204, green=4, blue=3) + color2: Color = Color(red=25, green=203, blue=0) + color3: Color = Color(red=206, green=203, blue=0) + color4: Color = Color(red=13, green=115, blue=204) + color5: Color = Color(red=203, green=30, blue=209) + color6: Color = Color(red=13, green=205, blue=205) + color7: Color = Color(red=221, green=221, blue=221) + color8: Color = Color(red=118, green=118, blue=118) + color9: Color = Color(red=242, green=32, blue=31) + color10: Color = Color(red=35, green=253, blue=0) + color11: Color = Color(red=255, green=253, blue=0) + color12: Color = Color(red=26, green=143, blue=255) + color13: Color = Color(red=253, green=40, blue=255) + color14: Color = Color(red=20, green=255, blue=255) + color15: Color = Color(red=255, green=255, blue=255) + color16: Color = Color(red=0, green=0, blue=0) + color17: Color = Color(red=0, green=0, blue=95) + color18: Color = Color(red=0, green=0, blue=135) + color19: Color = Color(red=0, green=0, blue=175) + color20: Color = Color(red=0, green=0, blue=215) + color21: Color = Color(red=0, green=0, blue=255) + color22: Color = Color(red=0, green=95, blue=0) + color23: Color = Color(red=0, green=95, blue=95) + color24: Color = Color(red=0, green=95, blue=135) + color25: Color = Color(red=0, green=95, blue=175) + color26: Color = Color(red=0, green=95, blue=215) + color27: Color = Color(red=0, green=95, blue=255) + color28: Color = Color(red=0, green=135, blue=0) + color29: Color = Color(red=0, green=135, blue=95) + color30: Color = Color(red=0, green=135, blue=135) + color31: Color = Color(red=0, green=135, blue=175) + color32: Color = Color(red=0, green=135, blue=215) + color33: Color = Color(red=0, green=135, blue=255) + color34: Color = Color(red=0, green=175, blue=0) + color35: Color = Color(red=0, green=175, blue=95) + color36: Color = Color(red=0, green=175, blue=135) + color37: Color = Color(red=0, green=175, blue=175) + color38: Color = Color(red=0, green=175, blue=215) + color39: Color = Color(red=0, green=175, blue=255) + color40: Color = Color(red=0, green=215, blue=0) + color41: Color = Color(red=0, green=215, blue=95) + color42: Color = Color(red=0, green=215, blue=135) + color43: Color = Color(red=0, green=215, blue=175) + color44: Color = Color(red=0, green=215, blue=215) + color45: Color = Color(red=0, green=215, blue=255) + color46: Color = Color(red=0, green=255, blue=0) + color47: Color = Color(red=0, green=255, blue=95) + color48: Color = Color(red=0, green=255, blue=135) + color49: Color = Color(red=0, green=255, blue=175) + color50: Color = Color(red=0, green=255, blue=215) + color51: Color = Color(red=0, green=255, blue=255) + color52: Color = Color(red=95, green=0, blue=0) + color53: Color = Color(red=95, green=0, blue=95) + color54: Color = Color(red=95, green=0, blue=135) + color55: Color = Color(red=95, green=0, blue=175) + color56: Color = Color(red=95, green=0, blue=215) + color57: Color = Color(red=95, green=0, blue=255) + color58: Color = Color(red=95, green=95, blue=0) + color59: Color = Color(red=95, green=95, blue=95) + color60: Color = Color(red=95, green=95, blue=135) + color61: Color = Color(red=95, green=95, blue=175) + color62: Color = Color(red=95, green=95, blue=215) + color63: Color = Color(red=95, green=95, blue=255) + color64: Color = Color(red=95, green=135, blue=0) + color65: Color = Color(red=95, green=135, blue=95) + color66: Color = Color(red=95, green=135, blue=135) + color67: Color = Color(red=95, green=135, blue=175) + color68: Color = Color(red=95, green=135, blue=215) + color69: Color = Color(red=95, green=135, blue=255) + color70: Color = Color(red=95, green=175, blue=0) + color71: Color = Color(red=95, green=175, blue=95) + color72: Color = Color(red=95, green=175, blue=135) + color73: Color = Color(red=95, green=175, blue=175) + color74: Color = Color(red=95, green=175, blue=215) + color75: Color = Color(red=95, green=175, blue=255) + color76: Color = Color(red=95, green=215, blue=0) + color77: Color = Color(red=95, green=215, blue=95) + color78: Color = Color(red=95, green=215, blue=135) + color79: Color = Color(red=95, green=215, blue=175) + color80: Color = Color(red=95, green=215, blue=215) + color81: Color = Color(red=95, green=215, blue=255) + color82: Color = Color(red=95, green=255, blue=0) + color83: Color = Color(red=95, green=255, blue=95) + color84: Color = Color(red=95, green=255, blue=135) + color85: Color = Color(red=95, green=255, blue=175) + color86: Color = Color(red=95, green=255, blue=215) + color87: Color = Color(red=95, green=255, blue=255) + color88: Color = Color(red=135, green=0, blue=0) + color89: Color = Color(red=135, green=0, blue=95) + color90: Color = Color(red=135, green=0, blue=135) + color91: Color = Color(red=135, green=0, blue=175) + color92: Color = Color(red=135, green=0, blue=215) + color93: Color = Color(red=135, green=0, blue=255) + color94: Color = Color(red=135, green=95, blue=0) + color95: Color = Color(red=135, green=95, blue=95) + color96: Color = Color(red=135, green=95, blue=135) + color97: Color = Color(red=135, green=95, blue=175) + color98: Color = Color(red=135, green=95, blue=215) + color99: Color = Color(red=135, green=95, blue=255) + color100: Color = Color(red=135, green=135, blue=0) + color101: Color = Color(red=135, green=135, blue=95) + color102: Color = Color(red=135, green=135, blue=135) + color103: Color = Color(red=135, green=135, blue=175) + color104: Color = Color(red=135, green=135, blue=215) + color105: Color = Color(red=135, green=135, blue=255) + color106: Color = Color(red=135, green=175, blue=0) + color107: Color = Color(red=135, green=175, blue=95) + color108: Color = Color(red=135, green=175, blue=135) + color109: Color = Color(red=135, green=175, blue=175) + color110: Color = Color(red=135, green=175, blue=215) + color111: Color = Color(red=135, green=175, blue=255) + color112: Color = Color(red=135, green=215, blue=0) + color113: Color = Color(red=135, green=215, blue=95) + color114: Color = Color(red=135, green=215, blue=135) + color115: Color = Color(red=135, green=215, blue=175) + color116: Color = Color(red=135, green=215, blue=215) + color117: Color = Color(red=135, green=215, blue=255) + color118: Color = Color(red=135, green=255, blue=0) + color119: Color = Color(red=135, green=255, blue=95) + color120: Color = Color(red=135, green=255, blue=135) + color121: Color = Color(red=135, green=255, blue=175) + color122: Color = Color(red=135, green=255, blue=215) + color123: Color = Color(red=135, green=255, blue=255) + color124: Color = Color(red=175, green=0, blue=0) + color125: Color = Color(red=175, green=0, blue=95) + color126: Color = Color(red=175, green=0, blue=135) + color127: Color = Color(red=175, green=0, blue=175) + color128: Color = Color(red=175, green=0, blue=215) + color129: Color = Color(red=175, green=0, blue=255) + color130: Color = Color(red=175, green=95, blue=0) + color131: Color = Color(red=175, green=95, blue=95) + color132: Color = Color(red=175, green=95, blue=135) + color133: Color = Color(red=175, green=95, blue=175) + color134: Color = Color(red=175, green=95, blue=215) + color135: Color = Color(red=175, green=95, blue=255) + color136: Color = Color(red=175, green=135, blue=0) + color137: Color = Color(red=175, green=135, blue=95) + color138: Color = Color(red=175, green=135, blue=135) + color139: Color = Color(red=175, green=135, blue=175) + color140: Color = Color(red=175, green=135, blue=215) + color141: Color = Color(red=175, green=135, blue=255) + color142: Color = Color(red=175, green=175, blue=0) + color143: Color = Color(red=175, green=175, blue=95) + color144: Color = Color(red=175, green=175, blue=135) + color145: Color = Color(red=175, green=175, blue=175) + color146: Color = Color(red=175, green=175, blue=215) + color147: Color = Color(red=175, green=175, blue=255) + color148: Color = Color(red=175, green=215, blue=0) + color149: Color = Color(red=175, green=215, blue=95) + color150: Color = Color(red=175, green=215, blue=135) + color151: Color = Color(red=175, green=215, blue=175) + color152: Color = Color(red=175, green=215, blue=215) + color153: Color = Color(red=175, green=215, blue=255) + color154: Color = Color(red=175, green=255, blue=0) + color155: Color = Color(red=175, green=255, blue=95) + color156: Color = Color(red=175, green=255, blue=135) + color157: Color = Color(red=175, green=255, blue=175) + color158: Color = Color(red=175, green=255, blue=215) + color159: Color = Color(red=175, green=255, blue=255) + color160: Color = Color(red=215, green=0, blue=0) + color161: Color = Color(red=215, green=0, blue=95) + color162: Color = Color(red=215, green=0, blue=135) + color163: Color = Color(red=215, green=0, blue=175) + color164: Color = Color(red=215, green=0, blue=215) + color165: Color = Color(red=215, green=0, blue=255) + color166: Color = Color(red=215, green=95, blue=0) + color167: Color = Color(red=215, green=95, blue=95) + color168: Color = Color(red=215, green=95, blue=135) + color169: Color = Color(red=215, green=95, blue=175) + color170: Color = Color(red=215, green=95, blue=215) + color171: Color = Color(red=215, green=95, blue=255) + color172: Color = Color(red=215, green=135, blue=0) + color173: Color = Color(red=215, green=135, blue=95) + color174: Color = Color(red=215, green=135, blue=135) + color175: Color = Color(red=215, green=135, blue=175) + color176: Color = Color(red=215, green=135, blue=215) + color177: Color = Color(red=215, green=135, blue=255) + color178: Color = Color(red=215, green=175, blue=0) + color179: Color = Color(red=215, green=175, blue=95) + color180: Color = Color(red=215, green=175, blue=135) + color181: Color = Color(red=215, green=175, blue=175) + color182: Color = Color(red=215, green=175, blue=215) + color183: Color = Color(red=215, green=175, blue=255) + color184: Color = Color(red=215, green=215, blue=0) + color185: Color = Color(red=215, green=215, blue=95) + color186: Color = Color(red=215, green=215, blue=135) + color187: Color = Color(red=215, green=215, blue=175) + color188: Color = Color(red=215, green=215, blue=215) + color189: Color = Color(red=215, green=215, blue=255) + color190: Color = Color(red=215, green=255, blue=0) + color191: Color = Color(red=215, green=255, blue=95) + color192: Color = Color(red=215, green=255, blue=135) + color193: Color = Color(red=215, green=255, blue=175) + color194: Color = Color(red=215, green=255, blue=215) + color195: Color = Color(red=215, green=255, blue=255) + color196: Color = Color(red=255, green=0, blue=0) + color197: Color = Color(red=255, green=0, blue=95) + color198: Color = Color(red=255, green=0, blue=135) + color199: Color = Color(red=255, green=0, blue=175) + color200: Color = Color(red=255, green=0, blue=215) + color201: Color = Color(red=255, green=0, blue=255) + color202: Color = Color(red=255, green=95, blue=0) + color203: Color = Color(red=255, green=95, blue=95) + color204: Color = Color(red=255, green=95, blue=135) + color205: Color = Color(red=255, green=95, blue=175) + color206: Color = Color(red=255, green=95, blue=215) + color207: Color = Color(red=255, green=95, blue=255) + color208: Color = Color(red=255, green=135, blue=0) + color209: Color = Color(red=255, green=135, blue=95) + color210: Color = Color(red=255, green=135, blue=135) + color211: Color = Color(red=255, green=135, blue=175) + color212: Color = Color(red=255, green=135, blue=215) + color213: Color = Color(red=255, green=135, blue=255) + color214: Color = Color(red=255, green=175, blue=0) + color215: Color = Color(red=255, green=175, blue=95) + color216: Color = Color(red=255, green=175, blue=135) + color217: Color = Color(red=255, green=175, blue=175) + color218: Color = Color(red=255, green=175, blue=215) + color219: Color = Color(red=255, green=175, blue=255) + color220: Color = Color(red=255, green=215, blue=0) + color221: Color = Color(red=255, green=215, blue=95) + color222: Color = Color(red=255, green=215, blue=135) + color223: Color = Color(red=255, green=215, blue=175) + color224: Color = Color(red=255, green=215, blue=215) + color225: Color = Color(red=255, green=215, blue=255) + color226: Color = Color(red=255, green=255, blue=0) + color227: Color = Color(red=255, green=255, blue=95) + color228: Color = Color(red=255, green=255, blue=135) + color229: Color = Color(red=255, green=255, blue=175) + color230: Color = Color(red=255, green=255, blue=215) + color231: Color = Color(red=255, green=255, blue=255) + color232: Color = Color(red=8, green=8, blue=8) + color233: Color = Color(red=18, green=18, blue=18) + color234: Color = Color(red=28, green=28, blue=28) + color235: Color = Color(red=38, green=38, blue=38) + color236: Color = Color(red=48, green=48, blue=48) + color237: Color = Color(red=58, green=58, blue=58) + color238: Color = Color(red=68, green=68, blue=68) + color239: Color = Color(red=78, green=78, blue=78) + color240: Color = Color(red=88, green=88, blue=88) + color241: Color = Color(red=98, green=98, blue=98) + color242: Color = Color(red=108, green=108, blue=108) + color243: Color = Color(red=118, green=118, blue=118) + color244: Color = Color(red=128, green=128, blue=128) + color245: Color = Color(red=138, green=138, blue=138) + color246: Color = Color(red=148, green=148, blue=148) + color247: Color = Color(red=158, green=158, blue=158) + color248: Color = Color(red=168, green=168, blue=168) + color249: Color = Color(red=178, green=178, blue=178) + color250: Color = Color(red=188, green=188, blue=188) + color251: Color = Color(red=198, green=198, blue=198) + color252: Color = Color(red=208, green=208, blue=208) + color253: Color = Color(red=218, green=218, blue=218) + color254: Color = Color(red=228, green=228, blue=228) + color255: Color = Color(red=238, green=238, blue=238) + command_on_bell: typing.List[str] = ['none'] + confirm_os_window_close: int = 0 + copy_on_select: str = '' + cursor: Color = Color(red=204, green=204, blue=204) + cursor_beam_thickness: float = 1.5 + cursor_blink_interval: float = -1.0 + cursor_shape: int = 1 + cursor_stop_blinking_after: float = 15.0 + cursor_text_color: typing.Optional[kitty.rgb.Color] = Color(red=17, green=17, blue=17) + cursor_underline_thickness: float = 2.0 + default_pointer_shape: choices_for_default_pointer_shape = 'beam' + detect_urls: bool = True + dim_opacity: float = 0.75 + disable_ligatures: int = 0 + draw_minimal_borders: bool = True + dynamic_background_opacity: bool = False + editor: str = '.' + enable_audio_bell: bool = True + enabled_layouts: typing.List[str] = ['fat', 'grid', 'horizontal', 'splits', 'stack', 'tall', 'vertical'] + focus_follows_mouse: bool = False + font_family: str = 'monospace' + font_size: float = 11.0 + force_ltr: bool = False + foreground: Color = Color(red=221, green=221, blue=221) + hide_window_decorations: int = 0 + inactive_border_color: Color = Color(red=204, green=204, blue=204) + inactive_tab_background: Color = Color(red=153, green=153, blue=153) + inactive_tab_font_style: typing.Tuple[bool, bool] = (False, False) + inactive_tab_foreground: Color = Color(red=68, green=68, blue=68) + inactive_text_alpha: float = 1.0 + initial_window_height: typing.Tuple[int, str] = (400, 'px') + initial_window_width: typing.Tuple[int, str] = (640, 'px') + input_delay: int = 3 + italic_font: str = 'auto' + kitty_mod: int = 5 + linux_display_server: choices_for_linux_display_server = 'auto' + listen_on: str = 'none' + macos_custom_beam_cursor: bool = False + macos_hide_from_tasks: bool = False + macos_option_as_alt: int = 0 + macos_quit_when_last_window_closed: bool = False + macos_show_window_title_in: choices_for_macos_show_window_title_in = 'all' + macos_thicken_font: float = 0 + macos_titlebar_color: int = 0 + macos_traditional_fullscreen: bool = False + macos_window_resizable: bool = True + mark1_background: Color = Color(red=152, green=211, blue=203) + mark1_foreground: Color = Color(red=0, green=0, blue=0) + mark2_background: Color = Color(red=242, green=220, blue=211) + mark2_foreground: Color = Color(red=0, green=0, blue=0) + mark3_background: Color = Color(red=242, green=116, blue=188) + mark3_foreground: Color = Color(red=0, green=0, blue=0) + mouse_hide_wait: float = 0.0 if is_macos else 3.0 + open_url_with: typing.List[str] = ['default'] + placement_strategy: choices_for_placement_strategy = 'center' + pointer_shape_when_dragging: choices_for_pointer_shape_when_dragging = 'beam' + pointer_shape_when_grabbed: choices_for_pointer_shape_when_grabbed = 'arrow' + remember_window_size: bool = True + repaint_delay: int = 10 + resize_debounce_time: float = 0.1 + resize_draw_strategy: int = 0 + resize_in_steps: bool = False + scrollback_fill_enlarged_window: bool = False + scrollback_lines: int = 2000 + scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER'] + scrollback_pager_history_size: int = 0 + select_by_word_characters: str = '@-./_~?&=%+#' + selection_background: Color = Color(red=255, green=250, blue=205) + selection_foreground: typing.Optional[kitty.rgb.Color] = Color(red=0, green=0, blue=0) + shell: str = '.' + single_window_margin_width: FloatEdges = FloatEdges(left=-1.0, top=-1.0, right=-1.0, bottom=-1.0) + startup_session: typing.Optional[str] = None + strip_trailing_spaces: choices_for_strip_trailing_spaces = 'never' + sync_to_monitor: bool = True + tab_activity_symbol: typing.Optional[str] = None + tab_bar_background: typing.Optional[kitty.rgb.Color] = None + tab_bar_edge: int = 3 + tab_bar_margin_width: float = 0 + tab_bar_min_tabs: int = 2 + tab_bar_style: choices_for_tab_bar_style = 'fade' + tab_fade: typing.Tuple[float, ...] = (0.25, 0.5, 0.75, 1.0) + tab_powerline_style: choices_for_tab_powerline_style = 'angled' + tab_separator: str = ' ┇' + tab_switch_strategy: choices_for_tab_switch_strategy = 'previous' + tab_title_template: str = '{title}' + term: str = 'xterm-kitty' + touch_scroll_multiplier: float = 1.0 + update_check_interval: float = 24.0 + url_color: Color = Color(red=0, green=135, blue=189) + url_prefixes: typing.Tuple[str, ...] = ('http', 'https', 'file', 'ftp', 'gemini', 'irc', 'gopher', 'mailto', 'news', 'git') + url_style: int = 3 + visual_bell_duration: float = 0 + wayland_titlebar_color: int = 0 + wheel_scroll_multiplier: float = 5.0 + window_alert_on_bell: bool = True + window_border_width: typing.Tuple[float, str] = (0.5, 'pt') + window_margin_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0) + window_padding_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0) + window_resize_step_cells: int = 2 + window_resize_step_lines: int = 2 + env: typing.Dict[str, str] = {} + font_features: typing.Dict[str, typing.Tuple[kitty.fonts.FontFeature, ...]] = {} + kitten_alias: typing.Dict[str, typing.List[str]] = {} + symbol_map: typing.Dict[typing.Tuple[int, int], str] = {} + map: typing.List[kitty.options.utils.KeyDefinition] = [] + keymap: KeyMap = {} + sequence_map: SequenceMap = {} + mouse_map: typing.List[kitty.options.utils.MouseMapping] = [] + mousemap: MouseMap = {} + + def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None: + if options_dict is not None: + for key in option_names: + setattr(self, key, options_dict[key]) + + @property + def _fields(self) -> typing.Tuple[str, ...]: + return option_names + + def __iter__(self) -> typing.Iterator[str]: + return iter(self._fields) + + def __len__(self) -> int: + return len(self._fields) + + def _copy_of_val(self, name: str) -> typing.Any: + ans = getattr(self, name) + if isinstance(ans, dict): + ans = ans.copy() + elif isinstance(ans, list): + ans = ans[:] + return ans + + def _asdict(self) -> typing.Dict[str, typing.Any]: + return {k: self._copy_of_val(k) for k in self} + + def _replace(self, **kw: typing.Any) -> "Options": + ans = Options() + for name in self: + setattr(ans, name, self._copy_of_val(name)) + for name, val in kw.items(): + setattr(ans, name, val) + return ans + + def __getitem__(self, key: typing.Union[int, str]) -> typing.Any: + k = option_names[key] if isinstance(key, int) else key + try: + return getattr(self, k) + except AttributeError: + pass + raise KeyError(f"No option named: {k}") + + +defaults = Options() +defaults.env = {} +defaults.font_features = {} +defaults.kitten_alias = {} +defaults.symbol_map = {} +defaults.map = [ + KeyDefinition(False, KeyAction('copy_to_clipboard'), 1024, False, 99, ()), + KeyDefinition(False, KeyAction('copy_to_clipboard'), 8, False, 99, ()), + KeyDefinition(False, KeyAction('paste_from_clipboard'), 1024, False, 118, ()), + KeyDefinition(False, KeyAction('paste_from_clipboard'), 8, False, 118, ()), + KeyDefinition(False, KeyAction('paste_from_selection'), 1024, False, 115, ()), + KeyDefinition(False, KeyAction('paste_from_selection'), 1, False, 57348, ()), + KeyDefinition(False, KeyAction('pass_selection_to_program'), 1024, False, 111, ()), + KeyDefinition(False, KeyAction('scroll_line_up'), 1024, False, 57352, ()), + KeyDefinition(False, KeyAction('scroll_line_up'), 10, False, 57354, ()), + KeyDefinition(False, KeyAction('scroll_line_up'), 8, False, 57352, ()), + KeyDefinition(False, KeyAction('scroll_line_up'), 1024, False, 107, ()), + KeyDefinition(False, KeyAction('scroll_line_down'), 1024, False, 57353, ()), + KeyDefinition(False, KeyAction('scroll_line_down'), 1024, False, 106, ()), + KeyDefinition(False, KeyAction('scroll_line_down'), 10, False, 57355, ()), + KeyDefinition(False, KeyAction('scroll_line_down'), 8, False, 57353, ()), + KeyDefinition(False, KeyAction('scroll_page_up'), 1024, False, 57354, ()), + KeyDefinition(False, KeyAction('scroll_page_up'), 8, False, 57354, ()), + KeyDefinition(False, KeyAction('scroll_page_down'), 1024, False, 57355, ()), + KeyDefinition(False, KeyAction('scroll_page_down'), 8, False, 57355, ()), + KeyDefinition(False, KeyAction('scroll_home'), 1024, False, 57356, ()), + KeyDefinition(False, KeyAction('scroll_home'), 8, False, 57356, ()), + KeyDefinition(False, KeyAction('scroll_end'), 1024, False, 57357, ()), + KeyDefinition(False, KeyAction('scroll_end'), 8, False, 57357, ()), + KeyDefinition(False, KeyAction('show_scrollback'), 1024, False, 104, ()), + KeyDefinition(False, KeyAction('new_window'), 1024, False, 57345, ()), + KeyDefinition(False, KeyAction('new_window'), 8, False, 57345, ()), + KeyDefinition(False, KeyAction('new_os_window'), 1024, False, 110, ()), + KeyDefinition(False, KeyAction('new_os_window'), 8, False, 110, ()), + KeyDefinition(False, KeyAction('close_window'), 1024, False, 119, ()), + KeyDefinition(False, KeyAction('close_window'), 9, False, 100, ()), + KeyDefinition(False, KeyAction('next_window'), 1024, False, 93, ()), + KeyDefinition(False, KeyAction('previous_window'), 1024, False, 91, ()), + KeyDefinition(False, KeyAction('move_window_forward'), 1024, False, 102, ()), + KeyDefinition(False, KeyAction('move_window_backward'), 1024, False, 98, ()), + KeyDefinition(False, KeyAction('move_window_to_top'), 1024, False, 96, ()), + KeyDefinition(False, KeyAction('start_resizing_window'), 1024, False, 114, ()), + KeyDefinition(False, KeyAction('start_resizing_window'), 8, False, 114, ()), + KeyDefinition(False, KeyAction('first_window'), 1024, False, 49, ()), + KeyDefinition(False, KeyAction('first_window'), 8, False, 49, ()), + KeyDefinition(False, KeyAction('second_window'), 1024, False, 50, ()), + KeyDefinition(False, KeyAction('second_window'), 8, False, 50, ()), + KeyDefinition(False, KeyAction('third_window'), 1024, False, 51, ()), + KeyDefinition(False, KeyAction('third_window'), 8, False, 51, ()), + KeyDefinition(False, KeyAction('fourth_window'), 1024, False, 52, ()), + KeyDefinition(False, KeyAction('fourth_window'), 8, False, 52, ()), + KeyDefinition(False, KeyAction('fifth_window'), 1024, False, 53, ()), + KeyDefinition(False, KeyAction('fifth_window'), 8, False, 53, ()), + KeyDefinition(False, KeyAction('sixth_window'), 1024, False, 54, ()), + KeyDefinition(False, KeyAction('sixth_window'), 8, False, 54, ()), + KeyDefinition(False, KeyAction('seventh_window'), 1024, False, 55, ()), + KeyDefinition(False, KeyAction('seventh_window'), 8, False, 55, ()), + KeyDefinition(False, KeyAction('eighth_window'), 1024, False, 56, ()), + KeyDefinition(False, KeyAction('eighth_window'), 8, False, 56, ()), + KeyDefinition(False, KeyAction('ninth_window'), 1024, False, 57, ()), + KeyDefinition(False, KeyAction('ninth_window'), 8, False, 57, ()), + KeyDefinition(False, KeyAction('tenth_window'), 1024, False, 48, ()), + KeyDefinition(False, KeyAction('next_tab'), 1024, False, 57351, ()), + KeyDefinition(False, KeyAction('next_tab'), 9, False, 93, ()), + KeyDefinition(False, KeyAction('next_tab'), 4, False, 57346, ()), + KeyDefinition(False, KeyAction('previous_tab'), 1024, False, 57350, ()), + KeyDefinition(False, KeyAction('previous_tab'), 9, False, 91, ()), + KeyDefinition(False, KeyAction('previous_tab'), 5, False, 57346, ()), + KeyDefinition(False, KeyAction('new_tab'), 1024, False, 116, ()), + KeyDefinition(False, KeyAction('new_tab'), 8, False, 116, ()), + KeyDefinition(False, KeyAction('close_tab'), 1024, False, 113, ()), + KeyDefinition(False, KeyAction('close_tab'), 8, False, 119, ()), + KeyDefinition(False, KeyAction('close_os_window'), 9, False, 119, ()), + KeyDefinition(False, KeyAction('move_tab_forward'), 1024, False, 46, ()), + KeyDefinition(False, KeyAction('move_tab_backward'), 1024, False, 44, ()), + KeyDefinition(False, KeyAction('set_tab_title'), 1026, False, 116, ()), + KeyDefinition(False, KeyAction('set_tab_title'), 9, False, 105, ()), + KeyDefinition(False, KeyAction('next_layout'), 1024, False, 108, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 1024, False, 61, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 1024, False, 43, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 1024, False, 57413, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 8, False, 43, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 8, False, 61, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 9, False, 61, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '-', 2.0)), 1024, False, 45, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '-', 2.0)), 1024, False, 57412, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '-', 2.0)), 8, False, 45, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, '-', 2.0)), 9, False, 45, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, None, 0.0)), 1024, False, 57347, ()), + KeyDefinition(False, KeyAction('change_font_size', (True, None, 0.0)), 8, False, 48, ()), + KeyDefinition(False, KeyAction('kitten', ('hints',)), 1024, False, 101, ()), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type path --program -')), 1024, False, 112, (SingleKey(mods=0, is_native=False, key=102),)), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type path')), 1024, False, 112, (SingleKey(mods=1, is_native=False, key=102),)), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type line --program -')), 1024, False, 112, (SingleKey(mods=0, is_native=False, key=108),)), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type word --program -')), 1024, False, 112, (SingleKey(mods=0, is_native=False, key=119),)), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type hash --program -')), 1024, False, 112, (SingleKey(mods=0, is_native=False, key=104),)), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type linenum')), 1024, False, 112, (SingleKey(mods=0, is_native=False, key=110),)), + KeyDefinition(True, KeyAction('kitten', ('hints', '--type hyperlink')), 1024, False, 112, (SingleKey(mods=0, is_native=False, key=121),)), + KeyDefinition(False, KeyAction('toggle_fullscreen'), 1024, False, 57374, ()), + KeyDefinition(False, KeyAction('toggle_maximized'), 1024, False, 57373, ()), + KeyDefinition(False, KeyAction('kitten', ('unicode_input',)), 1024, False, 117, ()), + KeyDefinition(False, KeyAction('kitten', ('unicode_input',)), 12, False, 32, ()), + KeyDefinition(False, KeyAction('edit_config_file'), 1024, False, 57365, ()), + KeyDefinition(False, KeyAction('edit_config_file'), 8, False, 44, ()), + KeyDefinition(False, KeyAction('kitty_shell', ('window',)), 1024, False, 57344, ()), + KeyDefinition(True, KeyAction('set_background_opacity', ('+0.1',)), 1024, False, 97, (SingleKey(mods=0, is_native=False, key=109),)), + KeyDefinition(True, KeyAction('set_background_opacity', ('-0.1',)), 1024, False, 97, (SingleKey(mods=0, is_native=False, key=108),)), + KeyDefinition(True, KeyAction('set_background_opacity', ('1',)), 1024, False, 97, (SingleKey(mods=0, is_native=False, key=49),)), + KeyDefinition(True, KeyAction('set_background_opacity', ('default',)), 1024, False, 97, (SingleKey(mods=0, is_native=False, key=100),)), + KeyDefinition(False, KeyAction('clear_terminal', ('reset', True)), 1024, False, 57349, ()), +] +if is_macos: + defaults.map.append(KeyDefinition(False, KeyAction('copy_to_clipboard'), 8, False, 99, ())) + defaults.map.append(KeyDefinition(False, KeyAction('paste_from_clipboard'), 8, False, 118, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_line_up'), 10, False, 57354, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_line_up'), 8, False, 57352, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_line_down'), 10, False, 57355, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_line_down'), 8, False, 57353, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_page_up'), 8, False, 57354, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_page_down'), 8, False, 57355, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_home'), 8, False, 57356, ())) + defaults.map.append(KeyDefinition(False, KeyAction('scroll_end'), 8, False, 57357, ())) + defaults.map.append(KeyDefinition(False, KeyAction('new_window'), 8, False, 57345, ())) + defaults.map.append(KeyDefinition(False, KeyAction('new_os_window'), 8, False, 110, ())) + defaults.map.append(KeyDefinition(False, KeyAction('close_window'), 9, False, 100, ())) + defaults.map.append(KeyDefinition(False, KeyAction('start_resizing_window'), 8, False, 114, ())) + defaults.map.append(KeyDefinition(False, KeyAction('first_window'), 8, False, 49, ())) + defaults.map.append(KeyDefinition(False, KeyAction('second_window'), 8, False, 50, ())) + defaults.map.append(KeyDefinition(False, KeyAction('third_window'), 8, False, 51, ())) + defaults.map.append(KeyDefinition(False, KeyAction('fourth_window'), 8, False, 52, ())) + defaults.map.append(KeyDefinition(False, KeyAction('fifth_window'), 8, False, 53, ())) + defaults.map.append(KeyDefinition(False, KeyAction('sixth_window'), 8, False, 54, ())) + defaults.map.append(KeyDefinition(False, KeyAction('seventh_window'), 8, False, 55, ())) + defaults.map.append(KeyDefinition(False, KeyAction('eighth_window'), 8, False, 56, ())) + defaults.map.append(KeyDefinition(False, KeyAction('ninth_window'), 8, False, 57, ())) + defaults.map.append(KeyDefinition(False, KeyAction('next_tab'), 9, False, 93, ())) + defaults.map.append(KeyDefinition(False, KeyAction('previous_tab'), 9, False, 91, ())) + defaults.map.append(KeyDefinition(False, KeyAction('new_tab'), 8, False, 116, ())) + defaults.map.append(KeyDefinition(False, KeyAction('close_tab'), 8, False, 119, ())) + defaults.map.append(KeyDefinition(False, KeyAction('close_os_window'), 9, False, 119, ())) + defaults.map.append(KeyDefinition(False, KeyAction('set_tab_title'), 9, False, 105, ())) + defaults.map.append(KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 8, False, 43, ())) + defaults.map.append(KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 8, False, 61, ())) + defaults.map.append(KeyDefinition(False, KeyAction('change_font_size', (True, '+', 2.0)), 9, False, 61, ())) + defaults.map.append(KeyDefinition(False, KeyAction('change_font_size', (True, '-', 2.0)), 8, False, 45, ())) + defaults.map.append(KeyDefinition(False, KeyAction('change_font_size', (True, '-', 2.0)), 9, False, 45, ())) + defaults.map.append(KeyDefinition(False, KeyAction('change_font_size', (True, None, 0.0)), 8, False, 48, ())) + defaults.map.append(KeyDefinition(False, KeyAction('kitten', ('unicode_input',)), 12, False, 32, ())) + defaults.map.append(KeyDefinition(False, KeyAction('edit_config_file'), 8, False, 44, ())) +defaults.mouse_map = [ + MouseMapping(0, 0, -2, False, KeyAction('mouse_click_url_or_select')), + MouseMapping(0, 1, -2, False, KeyAction('mouse_click_url_or_select')), + MouseMapping(0, 1, -2, True, KeyAction('mouse_click_url_or_select')), + MouseMapping(0, 5, -1, False, KeyAction('mouse_click_url')), + MouseMapping(0, 5, -1, True, KeyAction('mouse_click_url')), + MouseMapping(2, 0, -1, False, KeyAction('paste_selection')), + MouseMapping(0, 0, 1, False, KeyAction('mouse_selection', (0,))), + MouseMapping(0, 6, 1, False, KeyAction('mouse_selection', (2,))), + MouseMapping(0, 0, 2, False, KeyAction('mouse_selection', (3,))), + MouseMapping(0, 0, 3, False, KeyAction('mouse_selection', (4,))), + MouseMapping(0, 6, 3, False, KeyAction('mouse_selection', (5,))), + MouseMapping(1, 0, 1, False, KeyAction('mouse_selection', (1,))), + MouseMapping(2, 1, -1, False, KeyAction('paste_selection')), + MouseMapping(2, 1, -1, True, KeyAction('paste_selection')), + MouseMapping(0, 1, 1, False, KeyAction('mouse_selection', (0,))), + MouseMapping(0, 1, 1, True, KeyAction('mouse_selection', (0,))), + MouseMapping(0, 7, 1, False, KeyAction('mouse_selection', (2,))), + MouseMapping(0, 7, 1, True, KeyAction('mouse_selection', (2,))), + MouseMapping(0, 1, 2, False, KeyAction('mouse_selection', (3,))), + MouseMapping(0, 1, 2, True, KeyAction('mouse_selection', (3,))), + MouseMapping(0, 1, 3, False, KeyAction('mouse_selection', (4,))), + MouseMapping(0, 1, 3, True, KeyAction('mouse_selection', (4,))), + MouseMapping(0, 7, 3, False, KeyAction('mouse_selection', (5,))), + MouseMapping(0, 7, 3, True, KeyAction('mouse_selection', (5,))), + MouseMapping(1, 1, 1, False, KeyAction('mouse_selection', (1,))), + MouseMapping(1, 1, 1, True, KeyAction('mouse_selection', (1,))), +] \ No newline at end of file diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 2d08379b9..08212b66b 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -7,32 +7,30 @@ import os import re import sys from typing import ( - Any, Callable, Dict, FrozenSet, Iterable, List, NamedTuple, Optional, - Sequence, Tuple, Union + Any, Callable, Dict, FrozenSet, Iterable, List, Optional, Sequence, Tuple, + Union ) import kitty.fast_data_types as defines -from kitty.fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE - from kitty.conf.utils import ( - key_func, positive_float, positive_int, python_string, to_bool, to_cmdline, - to_color, uniq, unit_float + KeyAction, key_func, positive_float, positive_int, python_string, to_bool, + to_cmdline, to_color, uniq, unit_float ) from kitty.constants import config_dir, is_macos +from kitty.fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE from kitty.fonts import FontFeature from kitty.key_names import ( character_key_name_aliases, functional_key_name_aliases, get_key_name_lookup ) -from kitty.layout.interface import all_layouts from kitty.rgb import Color, color_as_int from kitty.types import FloatEdges, MouseEvent, SingleKey from kitty.utils import expandvars, log_error -KeyMap = Dict[SingleKey, 'KeyAction'] -MouseMap = Dict[MouseEvent, 'KeyAction'] +KeyMap = Dict[SingleKey, KeyAction] +MouseMap = Dict[MouseEvent, KeyAction] KeySequence = Tuple[SingleKey, ...] -SubSequenceMap = Dict[KeySequence, 'KeyAction'] +SubSequenceMap = Dict[KeySequence, KeyAction] SequenceMap = Dict[SingleKey, SubSequenceMap] MINIMUM_FONT_SIZE = 4 default_tab_separator = ' ┇' @@ -46,16 +44,6 @@ func_with_args, args_funcs = key_func() FuncArgsType = Tuple[str, Sequence[Any]] -class KeyAction(NamedTuple): - func: str - args: Tuple[Union[str, float, bool, int, None], ...] = () - - def __repr__(self) -> str: - if self.args: - return f'KeyAction({self.func!r}, {self.args!r})' - return f'KeyAction({self.func!r})' - - class InvalidMods(ValueError): pass @@ -512,6 +500,7 @@ def window_size(val: str) -> Tuple[int, str]: def to_layout_names(raw: str) -> List[str]: + from kitty.layout.interface import all_layouts parts = [x.strip().lower() for x in raw.split(',')] ans: List[str] = [] for p in parts: @@ -762,7 +751,7 @@ def parse_key_action(action: str, action_type: str = 'map') -> Optional[KeyActio class BaseDefinition: action: KeyAction - def resolve_kitten_aliases(self, aliases: Dict[str, Sequence[str]]) -> KeyAction: + def resolve_kitten_aliases(self, aliases: Dict[str, List[str]]) -> KeyAction: if not self.action.args or not aliases: return self.action kitten = self.action.args[0] @@ -789,7 +778,7 @@ class MouseMapping(BaseDefinition): def __repr__(self) -> str: return f'MouseMapping({self.button}, {self.mods}, {self.repeat_count}, {self.grabbed}, {self.action})' - def resolve_and_copy(self, kitty_mod: int, aliases: Dict[str, Sequence[str]]) -> 'MouseMapping': + def resolve_and_copy(self, kitty_mod: int, aliases: Dict[str, List[str]]) -> 'MouseMapping': return MouseMapping(self.button, defines.resolve_key_mods(kitty_mod, self.mods), self.repeat_count, self.grabbed, self.resolve_kitten_aliases(aliases)) @property @@ -808,7 +797,7 @@ class KeyDefinition(BaseDefinition): def __repr__(self) -> str: return f'KeyDefinition({self.is_sequence}, {self.action}, {self.trigger.mods}, {self.trigger.is_native}, {self.trigger.key}, {self.rest})' - def resolve_and_copy(self, kitty_mod: int, aliases: Dict[str, Sequence[str]]) -> 'KeyDefinition': + def resolve_and_copy(self, kitty_mod: int, aliases: Dict[str, List[str]]) -> 'KeyDefinition': def r(k: SingleKey) -> SingleKey: mods = defines.resolve_key_mods(kitty_mod, k.mods) return k._replace(mods=mods) diff --git a/kitty/options_stub.py b/kitty/options_stub.py deleted file mode 100644 index 0a18c118e..000000000 --- a/kitty/options_stub.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=utf-8 -# License: GPLv3 Copyright: 2020, Kovid Goyal - - -class Options: - pass - - -DiffOptions = Options - - -def generate_stub(): - from .config_data import all_options - from .conf.definition import as_type_stub, save_type_stub - text = as_type_stub( - all_options, - preamble_lines=( - 'from kitty.types import SingleKey', - 'from kitty.options.utils import KeyAction, KeyMap, SequenceMap, MouseMap', - 'from kitty.fonts import FontFeature', - ), - extra_fields=( - ('keymap', 'KeyMap'), - ('sequence_map', 'SequenceMap'), - ('mousemap', 'MouseMap'), - ) - ) - - from kittens.diff.config_data import all_options - text += as_type_stub( - all_options, - class_name='DiffOptions', - preamble_lines=( - 'from kitty.conf.utils import KittensKeyAction', - 'from kitty.types import ParsedShortcut', - ), - extra_fields=( - ('key_definitions', 'typing.Dict[ParsedShortcut, KittensKeyAction]'), - ) - ) - - save_type_stub(text, __file__) - - -if __name__ == '__main__': - import subprocess - subprocess.Popen([ - 'kitty', '+runpy', - 'from kitty.options_stub import generate_stub; generate_stub()' - ]) diff --git a/kitty/rc/set_spacing.py b/kitty/rc/set_spacing.py index 93d4bc013..2956b6f2e 100644 --- a/kitty/rc/set_spacing.py +++ b/kitty/rc/set_spacing.py @@ -12,7 +12,7 @@ from .base import ( if TYPE_CHECKING: from kitty.cli_stub import SetSpacingRCOptions as CLIOptions - from kitty.options_stub import Options + from kitty.options.types import Options def patch_window_edges(w: Window, s: Dict[str, Optional[float]]) -> None: diff --git a/kitty/session.py b/kitty/session.py index 847576ef1..d6c5013f0 100644 --- a/kitty/session.py +++ b/kitty/session.py @@ -10,7 +10,7 @@ from .cli_stub import CLIOptions from .options.utils import to_layout_names, window_size from .constants import kitty_exe from .layout.interface import all_layouts -from .options_stub import Options +from .options.types import Options from .os_window_size import WindowSize, WindowSizeData, WindowSizes from .typing import SpecialWindowInstance from .utils import log_error, resolved_shell diff --git a/kitty/terminfo.py b/kitty/terminfo.py index 398e07fe3..63fc9ab63 100644 --- a/kitty/terminfo.py +++ b/kitty/terminfo.py @@ -7,7 +7,7 @@ from binascii import hexlify, unhexlify from typing import TYPE_CHECKING, Dict, Generator, Optional, cast if TYPE_CHECKING: - from .options_stub import Options + from .options.types import Options def modify_key_bytes(keybytes: bytes, amt: int) -> bytes: diff --git a/kitty/typing.py b/kitty/typing.py index 1c8346a0a..e2b0c170e 100644 --- a/kitty/typing.py +++ b/kitty/typing.py @@ -22,3 +22,4 @@ PowerlineStyle = str MatchType = str Protocol = object MouseEvent = dict +OptionsProtocol = object diff --git a/kitty/typing.pyi b/kitty/typing.pyi index 72716f61b..2e325dbde 100644 --- a/kitty/typing.pyi +++ b/kitty/typing.pyi @@ -12,11 +12,10 @@ from kittens.tui.loop import ( Debug as Debug, Loop as LoopType, MouseEvent as MouseEvent, TermManager as TermManagerType ) -from kitty.conf.utils import KittensKeyAction as KittensKeyActionType from .boss import Boss as BossType from .child import Child as ChildType -from .conf.utils import BadLine as BadLineType +from .conf.utils import BadLine as BadLineType, KeyAction as KeyActionType from .config import KittyCommonOpts from .fast_data_types import ( CoreTextFont as CoreTextFont, FontConfigPattern as FontConfigPattern, @@ -25,7 +24,7 @@ from .fast_data_types import ( from .key_encoding import KeyEvent as KeyEventType from .layout.base import Layout as LayoutType from .options.utils import ( - KeyAction as KeyActionType, KeyMap as KeyMap, SequenceMap as SequenceMap + KeyMap as KeyMap, SequenceMap as SequenceMap ) from .rc.base import RemoteCommand as RemoteCommandType from .session import Session as SessionType, Tab as SessionTab @@ -56,7 +55,7 @@ __all__ = ( 'EdgeLiteral', 'MatchType', 'GRT_a', 'GRT_f', 'GRT_t', 'GRT_o', 'GRT_m', 'GRT_d', 'GraphicsCommandType', 'HandlerType', 'AbstractEventLoop', 'AddressFamily', 'Socket', 'CompletedProcess', 'PopenType', 'Protocol', 'TypedDict', 'MarkType', 'ImageManagerType', 'Debug', 'LoopType', 'MouseEvent', - 'TermManagerType', 'KittensKeyActionType', 'BossType', 'ChildType', 'BadLineType', + 'TermManagerType', 'BossType', 'ChildType', 'BadLineType', 'KeyActionType', 'KeyMap', 'KittyCommonOpts', 'SequenceMap', 'CoreTextFont', 'WindowSystemMouseEvent', 'FontConfigPattern', 'ScreenType', 'StartupCtx', 'KeyEventType', 'LayoutType', 'PowerlineStyle', 'RemoteCommandType', 'SessionType', 'SessionTab', 'SpecialWindowInstance', 'TabType', 'ScreenSize', 'WindowType' diff --git a/kitty/utils.py b/kitty/utils.py index b831869c9..2c013b44a 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -14,19 +14,23 @@ from contextlib import suppress from functools import lru_cache from time import monotonic from typing import ( - Any, Callable, Dict, Generator, Iterable, List, Mapping, Match, NamedTuple, - Optional, Tuple, Union, cast + TYPE_CHECKING, Any, Callable, Dict, Generator, Iterable, List, Mapping, + Match, NamedTuple, Optional, Tuple, Union, cast ) from .constants import ( appname, is_macos, is_wayland, read_kitty_resource, shell_path, supports_primary_selection ) -from .options_stub import Options from .rgb import Color, to_color from .types import run_once from .typing import AddressFamily, PopenType, Socket, StartupCtx +if TYPE_CHECKING: + from .options.types import Options +else: + Options = object + def expandvars(val: str, env: Mapping[str, str] = {}, fallback_to_os_env: bool = True) -> str: diff --git a/kitty/window.py b/kitty/window.py index 83ed16908..c4b95726d 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -35,7 +35,7 @@ from .fast_data_types import ( ) from .keys import keyboard_mode_name from .notify import NotificationCommand, handle_notification_cmd -from .options_stub import Options +from .options.types import Options from .rgb import to_color from .terminfo import get_capabilities from .types import MouseEvent, ScreenGeometry, WindowGeometry @@ -1016,8 +1016,8 @@ class Window: self.current_marker_spec = key def set_marker(self, spec: Union[str, Sequence[str]]) -> None: - from .options.utils import parse_marker_spec, toggle_marker from .marks import marker_from_spec + from .options.utils import parse_marker_spec, toggle_marker if isinstance(spec, str): func, (ftype, spec_, flags) = toggle_marker('toggle_marker', spec) else: diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index 18f8ae975..7b681b59c 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -6,11 +6,12 @@ import os from unittest import TestCase from kitty.config import ( - Options, defaults, finalize_keys, finalize_mouse_mappings, merge_configs + Options, defaults, finalize_keys, finalize_mouse_mappings ) from kitty.fast_data_types import ( Cursor, HistoryBuf, LineBuf, Screen, set_options ) +from kitty.options.parse import merge_result_dicts from kitty.types import MouseEvent @@ -106,7 +107,7 @@ class BaseTest(TestCase): final_options = {'scrollback_pager_history_size': 1024, 'click_interval': 0.5} if options: final_options.update(options) - options = Options(merge_configs(defaults._asdict(), final_options)) + options = Options(merge_result_dicts(defaults._asdict(), final_options)) finalize_keys(options) finalize_mouse_mappings(options) set_options(options) diff --git a/kitty_tests/main.py b/kitty_tests/main.py index 6998ffa6b..d6f37ed48 100644 --- a/kitty_tests/main.py +++ b/kitty_tests/main.py @@ -68,8 +68,6 @@ def filter_tests_by_module(suite: unittest.TestSuite, *names: str) -> unittest.T def type_check() -> NoReturn: from kitty.cli_stub import generate_stub # type:ignore generate_stub() - from kitty.options_stub import generate_stub # type: ignore - generate_stub() from kittens.tui.operations_stub import generate_stub # type: ignore generate_stub() os.execlp(sys.executable, 'python', '-m', 'mypy', '--pretty') diff --git a/setup.py b/setup.py index f751107f9..72c8e7bb8 100755 --- a/setup.py +++ b/setup.py @@ -1110,9 +1110,9 @@ def package(args: Options, bundle_type: str) -> None: if for_freeze: shutil.copytree('kitty_tests', os.path.join(libdir, 'kitty_tests')) if args.update_check_interval != 24.0: - with open(os.path.join(libdir, 'kitty/config_data.py'), 'r+', encoding='utf-8') as f: + with open(os.path.join(libdir, 'kitty/options/types.py'), 'r+', encoding='utf-8') as f: raw = f.read() - nraw = raw.replace("update_check_interval', 24", "update_check_interval', {}".format(args.update_check_interval), 1) + nraw = raw.replace('update_check_interval: float = 24.0', f'update_check_interval: float = {args.update_check_interval!r}', 1) if nraw == raw: raise SystemExit('Failed to change the value of update_check_interval') f.seek(0), f.truncate(), f.write(nraw)