Create an auto-generated stub file for the kitty Options object

This commit is contained in:
Kovid Goyal 2020-03-04 19:14:50 +05:30
parent ec8c96b8e6
commit 0f4e7921ee
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
11 changed files with 654 additions and 118 deletions

View File

@ -4,11 +4,12 @@
import re
from functools import partial
from typing import Any, Dict, List, Set, Tuple, Union, get_type_hints, Optional
from .utils import to_bool
def to_string(x):
def to_string(x: str) -> str:
return x
@ -33,6 +34,32 @@ class Option:
self.add_to_docs = add_to_docs
self.line = self.name + ' ' + self.defval_as_string
def type_definition(self, is_multiple: bool, 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__))
if is_multiple:
ans = 'typing.Dict[str, str]'
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
if type(self.option_type) is type:
return type_name(self.option_type)
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:
@ -275,3 +302,18 @@ def config_lines(all_options):
for sc in opt:
if sc.add_to_default:
yield sc.line
def as_type_stub(all_options: Dict[str, Union[Option, List[Shortcut]]], special_types: Optional[Dict[str, str]] = None) -> str:
ans = ['import typing\n', '', 'class Options:']
imports: Set[Tuple[str, str]] = set()
overrides = special_types or {}
for name, val in all_options.items():
if isinstance(val, Option):
is_multiple = ' ' in name
field_name = name.partition(' ')[0]
ans.append(' {}: {}'.format(field_name, overrides.get(field_name, val.type_definition(is_multiple, imports))))
for mod, name in imports:
ans.insert(0, 'from {} import {}'.format(mod, name))
ans.insert(0, 'import {}'.format(mod))
return '\n'.join(ans)

View File

@ -6,61 +6,77 @@ import os
import re
import shlex
from collections import namedtuple
from typing import Callable, FrozenSet, List, Optional, Union, Dict, Any, Iterator, Type
from ..rgb import to_color as as_color
from ..rgb import Color, to_color as as_color
from ..utils import log_error
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
BadLine = namedtuple('BadLine', 'number line exception')
def to_color(x):
return as_color(x, validate=True)
def to_color(x: str) -> Color:
ans = as_color(x, validate=True)
if ans is None: # this is only for type-checking
ans = Color(0, 0, 0)
return ans
def to_color_or_none(x):
def to_color_or_none(x: str) -> Optional[Color]:
return None if x.lower() == 'none' else to_color(x)
def positive_int(x):
ConvertibleToNumbers = Union[str, bytes, int, float]
def positive_int(x: ConvertibleToNumbers) -> int:
return max(0, int(x))
def positive_float(x):
def positive_float(x: ConvertibleToNumbers) -> float:
return max(0, float(x))
def unit_float(x):
def unit_float(x: ConvertibleToNumbers) -> float:
return max(0, min(float(x), 1))
def to_bool(x):
def to_bool(x: str) -> bool:
return x.lower() in ('y', 'yes', 'true')
def to_cmdline(x):
return list(map(
lambda y: os.path.expandvars(os.path.expanduser(y)), shlex.split(x)))
def to_cmdline(x: str) -> List[str]:
return list(
map(
lambda y: os.path.expandvars(os.path.expanduser(y)),
shlex.split(x)
)
)
def python_string(text):
def python_string(text: str) -> str:
import ast
return ast.literal_eval("'''" + text.replace("'''", "'\\''") + "'''")
def choices(*choices):
defval = choices[0]
choices = frozenset(choices)
def choices(*choices) -> Callable[[str], str]:
defval: str = choices[0]
uc: FrozenSet[str] = frozenset(choices)
def choice(x):
def choice(x: str) -> str:
x = x.lower()
if x not in choices:
if x not in uc:
x = defval
return x
return choice
def parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_includes):
def parse_line(
line: str, type_map: Dict[str, Any], special_handling: Callable,
ans: Dict[str, Any], all_keys: Optional[FrozenSet[str]],
base_path_for_includes: str
) -> None:
line = line.strip()
if not line or line.startswith('#'):
return
@ -79,9 +95,15 @@ def parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_in
with open(val, encoding='utf-8', errors='replace') as include:
_parse(include, type_map, special_handling, ans, all_keys)
except FileNotFoundError:
log_error('Could not find included config file: {}, ignoring'.format(val))
log_error(
'Could not find included config file: {}, ignoring'.
format(val)
)
except OSError:
log_error('Could not read from included config file: {}, ignoring'.format(val))
log_error(
'Could not read from included config file: {}, ignoring'.
format(val)
)
return
if all_keys is not None and key not in all_keys:
log_error('Ignoring unknown config key: {}'.format(key))
@ -92,7 +114,14 @@ def parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_in
ans[key] = val
def _parse(lines, type_map, special_handling, ans, all_keys, accumulate_bad_lines=None):
def _parse(
lines: Iterator[str],
type_map: Dict[str, Any],
special_handling: Callable,
ans: Dict[str, Any],
all_keys: Optional[FrozenSet[str]],
accumulate_bad_lines: Optional[List[BadLine]] = None
) -> None:
name = getattr(lines, 'name', None)
if name:
base_path_for_includes = os.path.dirname(os.path.abspath(name))
@ -101,7 +130,10 @@ def _parse(lines, type_map, special_handling, ans, all_keys, accumulate_bad_line
base_path_for_includes = config_dir
for i, line in enumerate(lines):
try:
parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_includes)
parse_line(
line, type_map, special_handling, ans, all_keys,
base_path_for_includes
)
except Exception as e:
if accumulate_bad_lines is None:
raise
@ -109,16 +141,23 @@ def _parse(lines, type_map, special_handling, ans, all_keys, accumulate_bad_line
def parse_config_base(
lines, defaults, type_map, special_handling, ans, check_keys=True,
accumulate_bad_lines=None
lines: Iterator[str],
defaults: Any,
type_map: Dict[str, Any],
special_handling: Callable,
ans: Dict[str, Any],
check_keys=True,
accumulate_bad_lines: Optional[List[BadLine]] = None
):
all_keys = defaults._asdict() if check_keys else None
_parse(lines, type_map, special_handling, ans, all_keys, accumulate_bad_lines)
all_keys: Optional[FrozenSet[str]] = defaults._asdict() if check_keys else None
_parse(
lines, type_map, special_handling, ans, all_keys, accumulate_bad_lines
)
def create_options_class(keys):
keys = tuple(sorted(keys))
slots = keys + ('_fields',)
def create_options_class(all_keys: Iterator[str]) -> Type:
keys = tuple(sorted(all_keys))
slots = keys + ('_fields', )
def __init__(self, kw):
for k, v in kw.items():
@ -146,11 +185,18 @@ def create_options_class(keys):
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
ans = type(
'Options', (), {
'__slots__': slots,
'__init__': __init__,
'_asdict': _asdict,
'_replace': _replace,
'__iter__': __iter__,
'__len__': __len__,
'__getitem__': __getitem__
}
)
ans._fields = keys # type: ignore
return ans
@ -171,7 +217,9 @@ def resolve_config(SYSTEM_CONF, defconf, config_files_on_cmd_line):
yield defconf
def load_config(Options, defaults, parse_config, merge_configs, *paths, overrides=None):
def load_config(
Options, defaults, parse_config, merge_configs, *paths, overrides=None
):
ans = defaults._asdict()
for path in paths:
if not path:
@ -196,17 +244,20 @@ def init_config(default_config_lines, parse_config):
def key_func():
ans = {}
ans: Dict[str, Callable] = {}
def func_with_args(*names):
def w(f):
for name in names:
if ans.setdefault(name, f) is not f:
raise ValueError('the args_func {} is being redefined'.format(name))
raise ValueError(
'the args_func {} is being redefined'.format(name)
)
return f
return w
return func_with_args, ans
@ -216,15 +267,17 @@ def parse_kittens_shortcut(sc):
parts = list(filter(None, sc.rstrip('+').split('+') + ['+']))
else:
parts = sc.split('+')
mods = parts[:-1] or None
if mods is not None:
qmods = parts[:-1]
if qmods:
resolved_mods = 0
for mod in mods:
for mod in qmods:
m = config_mod_map.get(mod.upper())
if m is None:
raise ValueError('Unknown shortcut modifiers: {}'.format(sc))
resolved_mods |= m
mods = resolved_mods
mods: Optional[int] = resolved_mods
else:
mods = None
is_text = False
rkey = parts[-1]
tkey = text_match(rkey)
@ -260,7 +313,7 @@ def parse_kittens_func_args(action, args_funcs):
raise ValueError('Unknown key action: {}'.format(action))
if not isinstance(args, (list, tuple)):
args = (args,)
args = (args, )
return func, tuple(args)

View File

@ -5,13 +5,15 @@
# Utils {{{
import os
from gettext import gettext as _
from typing import Dict, Union
from typing import (
Dict, FrozenSet, Iterable, List, Optional, Set, Tuple, TypeVar, Union
)
from . import fast_data_types as defines
from .conf.definition import Option, Shortcut, option_func
from .conf.utils import (
choices, positive_float, positive_int, to_bool, to_cmdline, to_color,
to_color_or_none, unit_float
Color, choices, positive_float, positive_int, to_bool, to_cmdline,
to_color, to_color_or_none, unit_float
)
from .constants import config_dir, is_macos
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
@ -42,14 +44,17 @@ def parse_mods(parts, sc):
return mods
def to_modifiers(val):
def to_modifiers(val: str) -> int:
return parse_mods(val.split('+'), val) or 0
def uniq(vals, result_type=list):
seen = set()
T = TypeVar('T')
def uniq(vals: Iterable[T]) -> List[T]:
seen: Set[T] = set()
seen_add = seen.add
return result_type(x for x in vals if x not in seen and not seen_add(x))
return [x for x in vals if x not in seen and not seen_add(x)]
# }}}
# Groups {{{
@ -221,7 +226,7 @@ o('italic_font', 'auto')
o('bold_italic_font', 'auto')
def to_font_size(x):
def to_font_size(x: str) -> float:
return max(MINIMUM_FONT_SIZE, float(x))
@ -245,7 +250,7 @@ support, because it will force kitty to always treat the text as LTR, which
FriBidi expects for terminals."""))
def adjust_line_height(x):
def adjust_line_height(x: str) -> Union[int, float]:
if x.endswith('%'):
ans = float(x[:-1].strip()) / 100.0
if ans < 0:
@ -281,7 +286,7 @@ Syntax is::
'''))
def disable_ligatures(x):
def disable_ligatures(x: str) -> int:
cmap = {'never': 0, 'cursor': 1, 'always': 2}
return cmap.get(x.lower(), 0)
@ -345,11 +350,11 @@ You can do this with e.g.::
'''))
def box_drawing_scale(x):
ans = tuple(float(x.strip()) for x in x.split(','))
def box_drawing_scale(x: str) -> Tuple[float, float, float, float]:
ans = tuple(float(q.strip()) for q in x.split(','))
if len(ans) != 4:
raise ValueError('Invalid box_drawing scale, must have four entries')
return ans
return ans[0], ans[1], ans[2], ans[3]
o(
@ -374,7 +379,7 @@ cshapes = {
}
def to_cursor_shape(x):
def to_cursor_shape(x: str) -> int:
try:
return cshapes[x.lower()]
except KeyError:
@ -385,9 +390,9 @@ def to_cursor_shape(x):
)
def cursor_text_color(x):
def cursor_text_color(x: str) -> Optional[Color]:
if x.lower() == 'background':
return
return None
return to_color(x)
@ -416,14 +421,14 @@ inactivity. Set to zero to never stop blinking.
g('scrollback') # {{{
def scrollback_lines(x):
x = int(x)
if x < 0:
x = 2 ** 32 - 1
return x
def scrollback_lines(x: str) -> int:
ans = int(x)
if ans < 0:
ans = 2 ** 32 - 1
return ans
def scrollback_pager_history_size(x):
def scrollback_pager_history_size(x: str) -> int:
ans = int(max(0, float(x)) * 1024 * 1024)
return min(ans, 4096 * 1024 * 1024 - 1)
@ -497,7 +502,7 @@ The special value :code:`default` means to use the
operating system's default URL handler.'''))
def copy_on_select(raw):
def copy_on_select(raw: str) -> str:
q = raw.lower()
# boolean values special cased for backwards compat
if q in ('y', 'yes', 'true', 'clipboard'):
@ -612,7 +617,7 @@ number of cells instead of pixels.
'''))
def window_size(val):
def window_size(val: str) -> Tuple[int, str]:
val = val.lower()
unit = 'cells' if val.endswith('c') else 'px'
return positive_int(val.rstrip('c')), unit
@ -622,9 +627,9 @@ o('initial_window_width', '640', option_type=window_size)
o('initial_window_height', '400', option_type=window_size)
def to_layout_names(raw):
def to_layout_names(raw: str) -> List[str]:
parts = [x.strip().lower() for x in raw.split(',')]
ans = []
ans: List[str] = []
for p in parts:
if p in ('*', 'all'):
ans.extend(sorted(all_layouts))
@ -695,7 +700,7 @@ zero and one, with zero being fully faded).
'''))
def hide_window_decorations(x):
def hide_window_decorations(x: str) -> int:
if x == 'titlebar-only':
return 0b10
if to_bool(x):
@ -717,7 +722,7 @@ operating system sends events corresponding to the start and end
of a resize, this number is ignored.'''))
def resize_draw_strategy(x):
def resize_draw_strategy(x: str) -> int:
cmap = {'static': 0, 'scale': 1, 'blank': 2, 'size': 3}
return cmap.get(x.lower(), 0)
@ -743,7 +748,7 @@ g('tabbar') # {{{
default_tab_separator = ''
def tab_separator(x):
def tab_separator(x: str) -> str:
for q in '\'"':
if x.startswith(q) and x.endswith(q):
x = x[1:-1]
@ -753,11 +758,11 @@ def tab_separator(x):
return x
def tab_bar_edge(x):
def tab_bar_edge(x: str) -> int:
return {'top': 1, 'bottom': 3}.get(x.lower(), 3)
def tab_font_style(x):
def tab_font_style(x: str) -> Tuple[bool, bool]:
return {
'bold-italic': (True, True),
'bold': (True, False),
@ -777,7 +782,12 @@ In the fade style, each tab's edges fade into the background color, in the separ
separated by a configurable separator, and the powerline shows the tabs as a continuous line.
'''))
o('tab_bar_min_tabs', 2, option_type=lambda x: max(1, positive_int(x)), long_text=_('''
def tab_bar_min_tabs(x: str) -> int:
return max(1, positive_int(x))
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
'''))
@ -789,7 +799,7 @@ of :code:`last` will switch to the right-most tab.
'''))
def tab_fade(x):
def tab_fade(x: str) -> Tuple[float, ...]:
return tuple(map(unit_float, x.split()))
@ -805,7 +815,7 @@ o('tab_separator', '"{}"'.format(default_tab_separator), option_type=tab_separat
The separator between tabs in the tab bar when using :code:`separator` as the :opt:`tab_bar_style`.'''))
def tab_title_template(x):
def tab_title_template(x: str) -> str:
if x:
for q in '\'"':
if x.startswith(q) and x.endswith(q):
@ -814,7 +824,7 @@ def tab_title_template(x):
return x
def active_tab_title_template(x):
def active_tab_title_template(x: str) -> Optional[str]:
x = tab_title_template(x)
return None if x == 'none' else x
@ -865,9 +875,9 @@ default as it has a performance cost)
'''))
def config_or_absolute_path(x):
def config_or_absolute_path(x: str) -> Optional[str]:
if x.lower() == 'none':
return
return None
x = os.path.expanduser(x)
x = os.path.expandvars(x)
if not os.path.isabs(x):
@ -903,9 +913,10 @@ How much to dim text that has the DIM/FAINT attribute set. One means no dimming
zero means fully dimmed (i.e. invisible).'''))
def selection_foreground(x):
def selection_foreground(x: str) -> Optional[Color]:
if x.lower() != 'none':
return to_color(x)
return None
o('selection_foreground', '#000000', option_type=selection_foreground, long_text=_('''
@ -974,7 +985,7 @@ terminal can fail silently because their stdout/stderr/stdin no longer work.
'''))
def allow_remote_control(x):
def allow_remote_control(x: str) -> str:
if x != 'socket-only':
x = 'y' if to_bool(x) else 'n'
return x
@ -1020,7 +1031,12 @@ 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=lambda x: frozenset(x.lower().split()), long_text=_('''
def clipboard_control(x: str) -> FrozenSet[str]:
return frozenset(x.lower().split())
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
@ -1046,7 +1062,7 @@ key-presses, to colors, to various advanced features may not work.
g('os') # {{{
def macos_titlebar_color(x):
def macos_titlebar_color(x: str) -> int:
x = x.strip('"')
if x == 'system':
return 0
@ -1067,7 +1083,7 @@ probably better off just hiding the titlebar with :opt:`hide_window_decorations`
'''))
def macos_option_as_alt(x):
def macos_option_as_alt(x: str) -> int:
x = x.lower()
if x == 'both':
return 0b11

View File

@ -402,7 +402,7 @@ def coretext_all_fonts() -> Tuple[Dict[str, Any], ...]:
pass
def add_timer(callback: Callable[[int], None], interval: float, repeats: bool = True) -> int:
def add_timer(callback: Callable[[Optional[int]], bool], interval: float, repeats: bool = True) -> int:
pass

View File

@ -3,14 +3,18 @@
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from kitty.cli import parse_args
from kitty.fast_data_types import set_clipboard_string
from kitty.utils import set_primary_selection
from functools import lru_cache
from typing import Dict
from .child import Child
from .cli import parse_args
from .fast_data_types import set_clipboard_string
from .utils import set_primary_selection
@lru_cache(maxsize=2)
def options_spec():
if not hasattr(options_spec, 'ans'):
OPTIONS = '''
return '''
--window-title --title
The title to set for the new window. By default, title is controlled by the
child process.
@ -124,8 +128,6 @@ screen.
Create a marker that highlights text in the newly created window. The syntax is
the same as for the :code:`toggle_marker` map action (see :doc:`/marks`).
'''
options_spec.ans = OPTIONS
return options_spec.ans
def parse_launch_args(args=None):
@ -137,8 +139,8 @@ def parse_launch_args(args=None):
return opts, args
def get_env(opts, active_child):
env = {}
def get_env(opts, active_child: Child) -> Dict[str, str]:
env: Dict[str, str] = {}
if opts.copy_env and active_child:
env.update(active_child.foreground_environ)
for x in opts.env:

View File

@ -5,7 +5,7 @@
from collections import namedtuple
from functools import lru_cache, partial
from itertools import islice, repeat
from typing import Callable, Dict, Generator, List, Optional, Tuple, Union
from typing import Callable, Dict, Generator, List, Optional, Tuple, Union, cast
from .constants import WindowGeometry
from .fast_data_types import (
@ -1416,7 +1416,7 @@ class Splits(Layout):
# Instantiation {{{
all_layouts = {o.name: o for o in globals().values() if isinstance(o, type) and issubclass(o, Layout) and o is not Layout}
all_layouts = {cast(str, o.name): o for o in globals().values() if isinstance(o, type) and issubclass(o, Layout) and o is not Layout}
class CreateLayoutObjectFor:

34
kitty/options_stub.py Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import os
class Options:
pass
def generate_stub():
from .config_data import all_options
from .conf.definition import as_type_stub
text = as_type_stub(
all_options,
special_types={
'symbol_map': 'typing.Dict[typing.Tuple[int, int], str]'
}
)
with open(__file__ + 'i', 'w') as f:
print(
'# Update this file by running: python {}'.format(os.path.relpath(os.path.abspath(__file__))),
file=f
)
f.write(text)
if __name__ == '__main__':
import subprocess
subprocess.Popen([
'kitty', '+runpy',
'from kitty.options_stub import generate_stub; generate_stub()'
])

383
kitty/options_stub.pyi Normal file
View File

@ -0,0 +1,383 @@
# Update this file by running: python kitty/options_stub.py
import kitty.rgb
from kitty.rgb import Color
import typing
class Options:
font_family: str
bold_font: str
italic_font: str
bold_italic_font: str
font_size: float
force_ltr: bool
adjust_line_height: typing.Union[int, float]
adjust_column_width: typing.Union[int, float]
symbol_map: typing.Dict[typing.Tuple[int, int], str]
disable_ligatures: int
font_features: str
box_drawing_scale: typing.Tuple[float, float, float, float]
cursor: Color
cursor_text_color: typing.Union[kitty.rgb.Color, None]
cursor_shape: int
cursor_beam_thickness: float
cursor_underline_thickness: float
cursor_blink_interval: float
cursor_stop_blinking_after: float
scrollback_lines: int
scrollback_pager: typing.List[str]
scrollback_pager_history_size: int
wheel_scroll_multiplier: float
touch_scroll_multiplier: float
mouse_hide_wait: float
url_color: Color
url_style: int
open_url_modifiers: int
open_url_with: typing.List[str]
copy_on_select: str
strip_trailing_spaces: str
rectangle_select_modifiers: int
terminal_select_modifiers: int
select_by_word_characters: str
click_interval: float
focus_follows_mouse: bool
pointer_shape_when_grabbed: str
repaint_delay: int
input_delay: int
sync_to_monitor: bool
enable_audio_bell: bool
visual_bell_duration: float
window_alert_on_bell: bool
bell_on_tab: bool
command_on_bell: typing.List[str]
remember_window_size: bool
initial_window_width: typing.Tuple[int, str]
initial_window_height: typing.Tuple[int, str]
enabled_layouts: typing.List[str]
window_resize_step_cells: int
window_resize_step_lines: int
window_border_width: float
draw_minimal_borders: bool
window_margin_width: float
single_window_margin_width: float
window_padding_width: float
placement_strategy: str
active_border_color: typing.Union[kitty.rgb.Color, None]
inactive_border_color: Color
bell_border_color: Color
inactive_text_alpha: float
hide_window_decorations: int
resize_debounce_time: float
resize_draw_strategy: int
resize_in_steps: bool
tab_bar_edge: int
tab_bar_margin_width: float
tab_bar_style: str
tab_bar_min_tabs: int
tab_switch_strategy: str
tab_fade: typing.Tuple[float, ...]
tab_separator: str
tab_title_template: str
active_tab_title_template: typing.Union[str, None]
active_tab_foreground: Color
active_tab_background: Color
active_tab_font_style: typing.Tuple[bool, bool]
inactive_tab_foreground: Color
inactive_tab_background: Color
inactive_tab_font_style: typing.Tuple[bool, bool]
tab_bar_background: typing.Union[kitty.rgb.Color, None]
foreground: Color
background: Color
background_opacity: float
background_image: typing.Union[str, None]
background_image_layout: str
background_image_linear: bool
dynamic_background_opacity: bool
background_tint: float
dim_opacity: float
selection_foreground: typing.Union[kitty.rgb.Color, None]
selection_background: Color
color0: Color
color8: Color
color1: Color
color9: Color
color2: Color
color10: Color
color3: Color
color11: Color
color4: Color
color12: Color
color5: Color
color13: Color
color6: Color
color14: Color
color7: Color
color15: Color
mark1_foreground: Color
mark1_background: Color
mark2_foreground: Color
mark2_background: Color
mark3_foreground: Color
mark3_background: Color
color16: Color
color17: Color
color18: Color
color19: Color
color20: Color
color21: Color
color22: Color
color23: Color
color24: Color
color25: Color
color26: Color
color27: Color
color28: Color
color29: Color
color30: Color
color31: Color
color32: Color
color33: Color
color34: Color
color35: Color
color36: Color
color37: Color
color38: Color
color39: Color
color40: Color
color41: Color
color42: Color
color43: Color
color44: Color
color45: Color
color46: Color
color47: Color
color48: Color
color49: Color
color50: Color
color51: Color
color52: Color
color53: Color
color54: Color
color55: Color
color56: Color
color57: Color
color58: Color
color59: Color
color60: Color
color61: Color
color62: Color
color63: Color
color64: Color
color65: Color
color66: Color
color67: Color
color68: Color
color69: Color
color70: Color
color71: Color
color72: Color
color73: Color
color74: Color
color75: Color
color76: Color
color77: Color
color78: Color
color79: Color
color80: Color
color81: Color
color82: Color
color83: Color
color84: Color
color85: Color
color86: Color
color87: Color
color88: Color
color89: Color
color90: Color
color91: Color
color92: Color
color93: Color
color94: Color
color95: Color
color96: Color
color97: Color
color98: Color
color99: Color
color100: Color
color101: Color
color102: Color
color103: Color
color104: Color
color105: Color
color106: Color
color107: Color
color108: Color
color109: Color
color110: Color
color111: Color
color112: Color
color113: Color
color114: Color
color115: Color
color116: Color
color117: Color
color118: Color
color119: Color
color120: Color
color121: Color
color122: Color
color123: Color
color124: Color
color125: Color
color126: Color
color127: Color
color128: Color
color129: Color
color130: Color
color131: Color
color132: Color
color133: Color
color134: Color
color135: Color
color136: Color
color137: Color
color138: Color
color139: Color
color140: Color
color141: Color
color142: Color
color143: Color
color144: Color
color145: Color
color146: Color
color147: Color
color148: Color
color149: Color
color150: Color
color151: Color
color152: Color
color153: Color
color154: Color
color155: Color
color156: Color
color157: Color
color158: Color
color159: Color
color160: Color
color161: Color
color162: Color
color163: Color
color164: Color
color165: Color
color166: Color
color167: Color
color168: Color
color169: Color
color170: Color
color171: Color
color172: Color
color173: Color
color174: Color
color175: Color
color176: Color
color177: Color
color178: Color
color179: Color
color180: Color
color181: Color
color182: Color
color183: Color
color184: Color
color185: Color
color186: Color
color187: Color
color188: Color
color189: Color
color190: Color
color191: Color
color192: Color
color193: Color
color194: Color
color195: Color
color196: Color
color197: Color
color198: Color
color199: Color
color200: Color
color201: Color
color202: Color
color203: Color
color204: Color
color205: Color
color206: Color
color207: Color
color208: Color
color209: Color
color210: Color
color211: Color
color212: Color
color213: Color
color214: Color
color215: Color
color216: Color
color217: Color
color218: Color
color219: Color
color220: Color
color221: Color
color222: Color
color223: Color
color224: Color
color225: Color
color226: Color
color227: Color
color228: Color
color229: Color
color230: Color
color231: Color
color232: Color
color233: Color
color234: Color
color235: Color
color236: Color
color237: Color
color238: Color
color239: Color
color240: Color
color241: Color
color242: Color
color243: Color
color244: Color
color245: Color
color246: Color
color247: Color
color248: Color
color249: Color
color250: Color
color251: Color
color252: Color
color253: Color
color254: Color
color255: Color
shell: str
editor: str
close_on_child_death: bool
allow_remote_control: str
env: typing.Dict[str, str]
update_check_interval: float
startup_session: typing.Union[str, None]
clipboard_control: typing.FrozenSet[str]
term: str
macos_titlebar_color: int
macos_option_as_alt: int
macos_hide_from_tasks: bool
macos_quit_when_last_window_closed: bool
macos_window_resizable: bool
macos_thicken_font: float
macos_traditional_fullscreen: bool
macos_show_window_title_in: str
macos_custom_beam_cursor: bool
linux_display_server: str
kitty_mod: int
clear_all_shortcuts: bool
kitten_alias: str

25
kitty/rgb.py generated
View File

@ -5,15 +5,16 @@
import re
from collections import namedtuple
from contextlib import suppress
from typing import Optional
Color = namedtuple('Color', 'red green blue')
def alpha_blend_channel(top_color, bottom_color, alpha):
def alpha_blend_channel(top_color: int, bottom_color: int, alpha: float) -> int:
return int(alpha * top_color + (1 - alpha) * bottom_color)
def alpha_blend(top_color, bottom_color, alpha):
def alpha_blend(top_color: Color, bottom_color: Color, alpha: float) -> Color:
return Color(
alpha_blend_channel(top_color.red, bottom_color.red, alpha),
alpha_blend_channel(top_color.green, bottom_color.green, alpha),
@ -21,48 +22,50 @@ def alpha_blend(top_color, bottom_color, alpha):
)
def parse_single_color(c):
def parse_single_color(c: str) -> int:
if len(c) == 1:
c += c
return int(c[:2], 16)
def parse_sharp(spec):
def parse_sharp(spec: str) -> Optional[Color]:
if len(spec) in (3, 6, 9, 12):
part_len = len(spec) // 3
colors = re.findall(r'[a-fA-F0-9]{%d}' % part_len, spec)
return Color(*map(parse_single_color, colors))
return None
def parse_rgb(spec):
def parse_rgb(spec: str) -> Optional[Color]:
colors = spec.split('/')
if len(colors) == 3:
return Color(*map(parse_single_color, colors))
return None
def color_from_int(x):
def color_from_int(x: int) -> Color:
return Color((x >> 16) & 255, (x >> 8) & 255, x & 255)
def color_as_int(x):
def color_as_int(x: Color) -> int:
return x.red << 16 | x.green << 8 | x.blue
def color_as_sharp(x):
def color_as_sharp(x: Color) -> str:
return '#{:02x}{:02x}{:02x}'.format(*x)
def color_as_sgr(x):
def color_as_sgr(x: Color) -> str:
return ':2:{}:{}:{}'.format(*x)
def to_color(raw, validate=False):
def to_color(raw: str, validate: bool = False) -> Optional[Color]:
# See man XParseColor
x = raw.strip().lower()
ans = color_names.get(x)
if ans is not None:
return ans
val = None
val: Optional[Color] = None
with suppress(Exception):
if raw.startswith('#'):
val = parse_sharp(raw[1:])

View File

@ -7,6 +7,7 @@ import subprocess
import time
from collections import namedtuple
from contextlib import suppress
from typing import Optional
from urllib.request import urlopen
from .config import atomic_save
@ -95,7 +96,7 @@ def process_current_release(raw):
notify_new_version(release_version)
def run_worker():
def run_worker() -> None:
import time
import random
time.sleep(random.randint(1000, 4000) / 1000)
@ -103,7 +104,7 @@ def run_worker():
print(get_released_version())
def update_check(timer_id=None):
def update_check(timer_id: Optional[int] = None) -> bool:
try:
p = subprocess.Popen([
kitty_exe(), '+runpy',
@ -113,10 +114,13 @@ def update_check(timer_id=None):
log_error('Failed to run kitty for update check, with error: {}'.format(e))
return False
monitor_pid(p.pid)
get_boss().set_update_check_process(p)
return True
boss = get_boss()
if boss is not None:
boss.set_update_check_process(p)
return True
return False
def run_update_check(interval=CHECK_INTERVAL):
def run_update_check(interval: int = CHECK_INTERVAL) -> None:
if update_check():
add_timer(update_check, interval)

View File

@ -14,14 +14,13 @@ from collections import namedtuple
from contextlib import suppress
from functools import lru_cache
from time import monotonic
from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
from typing import Any, Dict, List, Optional, cast
from .constants import (
appname, is_macos, is_wayland, shell_path, supports_primary_selection
)
from .options_stub import Options
from .rgb import Color, to_color
if TYPE_CHECKING:
from .cli import Namespace # noqa
BASE = os.path.dirname(os.path.abspath(__file__))
@ -468,7 +467,7 @@ def func_name(f):
return str(f)
def resolved_shell(opts: Optional['Namespace'] = None) -> List[str]:
def resolved_shell(opts: Optional[Options] = None) -> List[str]:
ans = getattr(opts, 'shell', '.')
if ans == '.':
ans = [shell_path]
@ -478,7 +477,7 @@ def resolved_shell(opts: Optional['Namespace'] = None) -> List[str]:
return ans
def read_shell_environment(opts: Optional['Namespace'] = None) -> Dict[str, str]:
def read_shell_environment(opts: Optional[Options] = None) -> Dict[str, str]:
ans = getattr(read_shell_environment, 'ans', None)
if ans is None:
from .child import openpty, remove_blocking