Move type parsers for config into own module
This commit is contained in:
parent
a4daa49f70
commit
fe94f4cbb4
@ -9,8 +9,9 @@ from gettext import gettext as _
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from kitty.conf.definition import OptionOrAction, option_func
|
from kitty.conf.definition import OptionOrAction, option_func
|
||||||
from kitty.conf.utils import python_string, to_color, to_color_or_none
|
from kitty.conf.utils import (
|
||||||
from kitty.utils import positive_int
|
positive_int, python_string, to_color, to_color_or_none
|
||||||
|
)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|||||||
@ -15,13 +15,12 @@ from typing import (
|
|||||||
Sequence, Tuple, Union
|
Sequence, Tuple, Union
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from kitty.conf.utils import positive_float, positive_int
|
||||||
from kitty.fast_data_types import create_canvas
|
from kitty.fast_data_types import create_canvas
|
||||||
from kitty.typing import (
|
from kitty.typing import (
|
||||||
CompletedProcess, GRT_a, GRT_d, GRT_f, GRT_m, GRT_o, GRT_t, HandlerType
|
CompletedProcess, GRT_a, GRT_d, GRT_f, GRT_m, GRT_o, GRT_t, HandlerType
|
||||||
)
|
)
|
||||||
from kitty.utils import (
|
from kitty.utils import ScreenSize, find_exe, fit_image
|
||||||
ScreenSize, find_exe, fit_image, positive_float, positive_int
|
|
||||||
)
|
|
||||||
|
|
||||||
from .operations import cursor
|
from .operations import cursor
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ from .config import (
|
|||||||
KeyAction, SubSequenceMap, common_opts_as_dict,
|
KeyAction, SubSequenceMap, common_opts_as_dict,
|
||||||
prepare_config_file_for_editing
|
prepare_config_file_for_editing
|
||||||
)
|
)
|
||||||
from .config_data import MINIMUM_FONT_SIZE
|
from .options_types import MINIMUM_FONT_SIZE
|
||||||
from .constants import (
|
from .constants import (
|
||||||
appname, config_dir, is_macos, kitty_exe, supports_primary_selection
|
appname, config_dir, is_macos, kitty_exe, supports_primary_selection
|
||||||
)
|
)
|
||||||
|
|||||||
@ -174,7 +174,7 @@ def option_func(all_options: Dict[str, Any], all_groups: Dict[str, Sequence[str]
|
|||||||
return partial(option, all_options, group), partial(shortcut, all_options, group), partial(mouse_action, all_options, group), change_group, all_groups_
|
return partial(option, all_options, group), partial(shortcut, all_options, group), partial(mouse_action, all_options, group), change_group, all_groups_
|
||||||
|
|
||||||
|
|
||||||
OptionOrAction = Union[Option, Sequence[Shortcut], Sequence[MouseAction]]
|
OptionOrAction = Union[Option, List[Union[Shortcut, MouseAction]]]
|
||||||
|
|
||||||
|
|
||||||
def merged_opts(all_options: Sequence[OptionOrAction], opt: Option, i: int) -> Generator[Option, None, None]:
|
def merged_opts(all_options: Sequence[OptionOrAction], opt: Option, i: int) -> Generator[Option, None, None]:
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import re
|
|||||||
import shlex
|
import shlex
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, FrozenSet, Generator, Iterable, Iterator, List,
|
Any, Callable, Dict, FrozenSet, Generator, Iterable, Iterator, List,
|
||||||
NamedTuple, Optional, Sequence, Tuple, Type, TypeVar, Union
|
NamedTuple, Optional, Sequence, Tuple, Type, TypeVar, Union, Set
|
||||||
)
|
)
|
||||||
|
|
||||||
from ..rgb import Color, to_color as as_color
|
from ..rgb import Color, to_color as as_color
|
||||||
@ -24,6 +24,14 @@ class BadLine(NamedTuple):
|
|||||||
exception: Exception
|
exception: Exception
|
||||||
|
|
||||||
|
|
||||||
|
def positive_int(x: ConvertibleToNumbers) -> int:
|
||||||
|
return max(0, int(x))
|
||||||
|
|
||||||
|
|
||||||
|
def positive_float(x: ConvertibleToNumbers) -> float:
|
||||||
|
return max(0, float(x))
|
||||||
|
|
||||||
|
|
||||||
def to_color(x: str) -> Color:
|
def to_color(x: str) -> Color:
|
||||||
ans = as_color(x, validate=True)
|
ans = as_color(x, validate=True)
|
||||||
if ans is None: # this is only for type-checking
|
if ans is None: # this is only for type-checking
|
||||||
@ -342,3 +350,9 @@ def parse_kittens_key(
|
|||||||
return None
|
return None
|
||||||
ans = parse_kittens_func_args(action, funcs_with_args)
|
ans = parse_kittens_func_args(action, funcs_with_args)
|
||||||
return ans, parse_shortcut(sc)
|
return ans, parse_shortcut(sc)
|
||||||
|
|
||||||
|
|
||||||
|
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)]
|
||||||
|
|||||||
@ -9,8 +9,8 @@ import sys
|
|||||||
from contextlib import contextmanager, suppress
|
from contextlib import contextmanager, suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional,
|
Any, Callable, Dict, FrozenSet, Generator, Iterable, List, NamedTuple,
|
||||||
Sequence, Set, Tuple, Type, Union, FrozenSet
|
Optional, Sequence, Set, Tuple, Type, Union
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import fast_data_types as defines
|
from . import fast_data_types as defines
|
||||||
@ -19,10 +19,11 @@ from .conf.utils import (
|
|||||||
BadLine, init_config, key_func, load_config as _load_config, merge_dicts,
|
BadLine, init_config, key_func, load_config as _load_config, merge_dicts,
|
||||||
parse_config_base, python_string, to_bool, to_cmdline
|
parse_config_base, python_string, to_bool, to_cmdline
|
||||||
)
|
)
|
||||||
from .config_data import InvalidMods, all_options, parse_mods, parse_shortcut
|
from .config_data import all_options
|
||||||
from .constants import cache_dir, defconf, is_macos
|
from .constants import cache_dir, defconf, is_macos
|
||||||
from .fonts import FontFeature
|
from .fonts import FontFeature
|
||||||
from .options_stub import Options as OptionsStub
|
from .options_stub import Options as OptionsStub
|
||||||
|
from .options_types import InvalidMods, parse_mods, parse_shortcut
|
||||||
from .types import MouseEvent, SingleKey
|
from .types import MouseEvent, SingleKey
|
||||||
from .typing import TypedDict
|
from .typing import TypedDict
|
||||||
from .utils import expandvars, log_error
|
from .utils import expandvars, log_error
|
||||||
|
|||||||
@ -3,106 +3,31 @@
|
|||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
# Utils {{{
|
# Utils {{{
|
||||||
import os
|
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from typing import (
|
from typing import Dict
|
||||||
Callable, Dict, FrozenSet, Iterable, List, Optional, Set,
|
|
||||||
Tuple, TypeVar, Union
|
|
||||||
)
|
|
||||||
|
|
||||||
from . import fast_data_types as defines
|
from . import fast_data_types as defines
|
||||||
from .conf.definition import OptionOrAction, option_func
|
from .conf.definition import OptionOrAction, option_func
|
||||||
from .conf.utils import (
|
from .conf.utils import (
|
||||||
choices, to_bool, to_cmdline, to_color, to_color_or_none, unit_float
|
choices, positive_float, positive_int, to_cmdline, to_color,
|
||||||
|
to_color_or_none, unit_float
|
||||||
)
|
)
|
||||||
from .constants import config_dir, is_macos
|
from .constants import is_macos
|
||||||
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
|
from .options_types import (
|
||||||
from .key_names import (
|
active_tab_title_template, adjust_line_height, allow_hyperlinks,
|
||||||
character_key_name_aliases, functional_key_name_aliases,
|
allow_remote_control, box_drawing_scale, clipboard_control,
|
||||||
get_key_name_lookup
|
config_or_absolute_path, copy_on_select, cursor_text_color,
|
||||||
|
default_tab_separator, disable_ligatures, edge_width,
|
||||||
|
hide_window_decorations, macos_option_as_alt, macos_titlebar_color,
|
||||||
|
optional_edge_width, resize_draw_strategy, scrollback_lines,
|
||||||
|
scrollback_pager_history_size, 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,
|
||||||
|
url_prefixes, url_style, window_border_width, window_size, to_modifiers
|
||||||
)
|
)
|
||||||
from .layout.interface import all_layouts
|
from .rgb import color_as_sharp, color_from_int
|
||||||
from .rgb import Color, color_as_int, color_as_sharp, color_from_int
|
|
||||||
from .types import FloatEdges, SingleKey
|
|
||||||
from .utils import log_error, positive_float, positive_int
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidMods(ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
MINIMUM_FONT_SIZE = 4
|
|
||||||
mod_map = {'CTRL': 'CONTROL', 'CMD': 'SUPER', '⌘': 'SUPER',
|
|
||||||
'⌥': 'ALT', 'OPTION': 'ALT', 'KITTY_MOD': 'KITTY'}
|
|
||||||
character_key_name_aliases_with_ascii_lowercase = character_key_name_aliases.copy()
|
|
||||||
for x in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
|
|
||||||
character_key_name_aliases_with_ascii_lowercase[x] = x.lower()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_mods(parts: Iterable[str], sc: str) -> Optional[int]:
|
|
||||||
|
|
||||||
def map_mod(m: str) -> str:
|
|
||||||
return mod_map.get(m, m)
|
|
||||||
|
|
||||||
mods = 0
|
|
||||||
for m in parts:
|
|
||||||
try:
|
|
||||||
mods |= getattr(defines, 'GLFW_MOD_' + map_mod(m.upper()))
|
|
||||||
except AttributeError:
|
|
||||||
if m.upper() != 'NONE':
|
|
||||||
log_error('Shortcut: {} has unknown modifier, ignoring'.format(sc))
|
|
||||||
return None
|
|
||||||
|
|
||||||
return mods
|
|
||||||
|
|
||||||
|
|
||||||
def to_modifiers(val: str) -> int:
|
|
||||||
return parse_mods(val.split('+'), val) or 0
|
|
||||||
|
|
||||||
|
|
||||||
def parse_shortcut(sc: str) -> SingleKey:
|
|
||||||
if sc.endswith('+') and len(sc) > 1:
|
|
||||||
sc = sc[:-1] + 'plus'
|
|
||||||
parts = sc.split('+')
|
|
||||||
mods = 0
|
|
||||||
if len(parts) > 1:
|
|
||||||
mods = parse_mods(parts[:-1], sc) or 0
|
|
||||||
if not mods:
|
|
||||||
raise InvalidMods('Invalid shortcut')
|
|
||||||
q = parts[-1]
|
|
||||||
q = character_key_name_aliases_with_ascii_lowercase.get(q.upper(), q)
|
|
||||||
is_native = False
|
|
||||||
if q.startswith('0x'):
|
|
||||||
try:
|
|
||||||
key = int(q, 16)
|
|
||||||
except Exception:
|
|
||||||
key = 0
|
|
||||||
else:
|
|
||||||
is_native = True
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
key = ord(q)
|
|
||||||
except Exception:
|
|
||||||
uq = q.upper()
|
|
||||||
uq = functional_key_name_aliases.get(uq, uq)
|
|
||||||
x: Optional[int] = getattr(defines, f'GLFW_FKEY_{uq}', None)
|
|
||||||
if x is None:
|
|
||||||
lf = get_key_name_lookup()
|
|
||||||
key = lf(q, False) or 0
|
|
||||||
is_native = key > 0
|
|
||||||
else:
|
|
||||||
key = x
|
|
||||||
|
|
||||||
return SingleKey(mods, is_native, key or 0)
|
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T')
|
|
||||||
|
|
||||||
|
|
||||||
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)]
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Groups {{{
|
# Groups {{{
|
||||||
@ -306,11 +231,6 @@ o('bold_font', 'auto')
|
|||||||
o('italic_font', 'auto')
|
o('italic_font', 'auto')
|
||||||
o('bold_italic_font', 'auto')
|
o('bold_italic_font', 'auto')
|
||||||
|
|
||||||
|
|
||||||
def to_font_size(x: str) -> float:
|
|
||||||
return max(MINIMUM_FONT_SIZE, float(x))
|
|
||||||
|
|
||||||
|
|
||||||
o('font_size', 11.0, long_text=_('Font size (in pts)'), option_type=to_font_size)
|
o('font_size', 11.0, long_text=_('Font size (in pts)'), option_type=to_font_size)
|
||||||
|
|
||||||
o('force_ltr', False, long_text=_("""
|
o('force_ltr', False, long_text=_("""
|
||||||
@ -331,16 +251,6 @@ support, because it will force kitty to always treat the text as LTR, which
|
|||||||
FriBidi expects for terminals."""))
|
FriBidi expects for terminals."""))
|
||||||
|
|
||||||
|
|
||||||
def adjust_line_height(x: str) -> Union[int, float]:
|
|
||||||
if x.endswith('%'):
|
|
||||||
ans = float(x[:-1].strip()) / 100.0
|
|
||||||
if ans < 0:
|
|
||||||
log_error('Percentage adjustments of cell sizes must be positive numbers')
|
|
||||||
return 0
|
|
||||||
return ans
|
|
||||||
return int(x)
|
|
||||||
|
|
||||||
|
|
||||||
o('adjust_line_height', 0, option_type=adjust_line_height, long_text=_('''
|
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,
|
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
|
which are interpreted as pixels or percentages (number followed by %), which
|
||||||
@ -367,11 +277,6 @@ Syntax is::
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def disable_ligatures(x: str) -> int:
|
|
||||||
cmap = {'never': 0, 'cursor': 1, 'always': 2}
|
|
||||||
return cmap.get(x.lower(), 0)
|
|
||||||
|
|
||||||
|
|
||||||
o('disable_ligatures', 'never', option_type=disable_ligatures, long_text=_('''
|
o('disable_ligatures', 'never', option_type=disable_ligatures, long_text=_('''
|
||||||
Choose how you want to handle multi-character ligatures. The default is to
|
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
|
always render them. You can tell kitty to not render them when the cursor is
|
||||||
@ -439,13 +344,6 @@ You can do this with e.g.::
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
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[0], ans[1], ans[2], ans[3]
|
|
||||||
|
|
||||||
|
|
||||||
o(
|
o(
|
||||||
'box_drawing_scale',
|
'box_drawing_scale',
|
||||||
'0.001, 1, 1.5, 2',
|
'0.001, 1, 1.5, 2',
|
||||||
@ -461,30 +359,6 @@ and very thick lines.
|
|||||||
|
|
||||||
g('cursor') # {{{
|
g('cursor') # {{{
|
||||||
|
|
||||||
cshapes = {
|
|
||||||
'block': CURSOR_BLOCK,
|
|
||||||
'beam': CURSOR_BEAM,
|
|
||||||
'underline': CURSOR_UNDERLINE
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def to_cursor_shape(x: str) -> int:
|
|
||||||
try:
|
|
||||||
return cshapes[x.lower()]
|
|
||||||
except KeyError:
|
|
||||||
raise ValueError(
|
|
||||||
'Invalid cursor shape: {} allowed values are {}'.format(
|
|
||||||
x, ', '.join(cshapes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def cursor_text_color(x: str) -> Optional[Color]:
|
|
||||||
if x.lower() == 'background':
|
|
||||||
return None
|
|
||||||
return to_color(x)
|
|
||||||
|
|
||||||
|
|
||||||
o('cursor', '#cccccc', _('Default cursor color'), option_type=to_color)
|
o('cursor', '#cccccc', _('Default cursor color'), option_type=to_color)
|
||||||
o('cursor_text_color', '#111111', option_type=cursor_text_color, long_text=_('''
|
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
|
Choose the color of text under the cursor. If you want it rendered with the
|
||||||
@ -510,18 +384,6 @@ inactivity. Set to zero to never stop blinking.
|
|||||||
g('scrollback') # {{{
|
g('scrollback') # {{{
|
||||||
|
|
||||||
|
|
||||||
def scrollback_lines(x: str) -> int:
|
|
||||||
ans = int(x)
|
|
||||||
if ans < 0:
|
|
||||||
ans = 2 ** 32 - 1
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
def scrollback_pager_history_size(x: str) -> int:
|
|
||||||
ans = int(max(0, float(x)) * 1024 * 1024)
|
|
||||||
return min(ans, 4096 * 1024 * 1024 - 1)
|
|
||||||
|
|
||||||
|
|
||||||
o('scrollback_lines', 2000, option_type=scrollback_lines, long_text=_('''
|
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
|
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
|
on demand. Negative numbers are (effectively) infinite scrollback. Note that using
|
||||||
@ -574,16 +436,6 @@ o('url_color', '#0087bd', option_type=to_color, long_text=_('''
|
|||||||
The color and style for highlighting URLs on mouse-over.
|
The color and style for highlighting URLs on mouse-over.
|
||||||
:code:`url_style` can be one of: none, single, double, curly'''))
|
:code:`url_style` can be one of: none, single, double, curly'''))
|
||||||
|
|
||||||
|
|
||||||
def url_style(x: str) -> int:
|
|
||||||
return url_style_map.get(x, url_style_map['curly'])
|
|
||||||
|
|
||||||
|
|
||||||
url_style_map = dict(
|
|
||||||
((v, i) for i, v in enumerate('none single double curly'.split()))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
o('url_style', 'curly', option_type=url_style)
|
o('url_style', 'curly', option_type=url_style)
|
||||||
|
|
||||||
o('open_url_with', 'default', option_type=to_cmdline, long_text=_('''
|
o('open_url_with', 'default', option_type=to_cmdline, long_text=_('''
|
||||||
@ -592,10 +444,6 @@ The special value :code:`default` means to use the
|
|||||||
operating system's default URL handler.'''))
|
operating system's default URL handler.'''))
|
||||||
|
|
||||||
|
|
||||||
def url_prefixes(x: str) -> Tuple[str, ...]:
|
|
||||||
return tuple(a.lower() for a in x.replace(',', ' ').split())
|
|
||||||
|
|
||||||
|
|
||||||
o('url_prefixes', 'http https file ftp gemini irc gopher mailto news git', option_type=url_prefixes, long_text=_('''
|
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.'''))
|
The set of URL prefixes to look for when detecting a URL under the mouse cursor.'''))
|
||||||
|
|
||||||
@ -605,16 +453,6 @@ with an underline and the mouse cursor becomes a hand over them.
|
|||||||
Even if this option is disabled, URLs are still clickable.'''))
|
Even if this option is disabled, URLs are still clickable.'''))
|
||||||
|
|
||||||
|
|
||||||
def copy_on_select(raw: str) -> str:
|
|
||||||
q = raw.lower()
|
|
||||||
# boolean values special cased for backwards compat
|
|
||||||
if q in ('y', 'yes', 'true', 'clipboard'):
|
|
||||||
return 'clipboard'
|
|
||||||
if q in ('n', 'no', 'false', ''):
|
|
||||||
return ''
|
|
||||||
return raw
|
|
||||||
|
|
||||||
|
|
||||||
o('copy_on_select', 'no', option_type=copy_on_select, long_text=_('''
|
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
|
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
|
:code:`clipboard`, simply selecting text with the mouse will cause the text to
|
||||||
@ -747,30 +585,10 @@ number of cells instead of pixels.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
o('initial_window_width', '640', option_type=window_size)
|
o('initial_window_width', '640', option_type=window_size)
|
||||||
o('initial_window_height', '400', option_type=window_size)
|
o('initial_window_height', '400', option_type=window_size)
|
||||||
|
|
||||||
|
|
||||||
def to_layout_names(raw: str) -> List[str]:
|
|
||||||
parts = [x.strip().lower() for x in raw.split(',')]
|
|
||||||
ans: List[str] = []
|
|
||||||
for p in parts:
|
|
||||||
if p in ('*', 'all'):
|
|
||||||
ans.extend(sorted(all_layouts))
|
|
||||||
continue
|
|
||||||
name = p.partition(':')[0]
|
|
||||||
if name not in all_layouts:
|
|
||||||
raise ValueError('The window layout {} is unknown'.format(p))
|
|
||||||
ans.append(p)
|
|
||||||
return uniq(ans)
|
|
||||||
|
|
||||||
|
|
||||||
o('enabled_layouts', '*', option_type=to_layout_names, long_text=_('''
|
o('enabled_layouts', '*', option_type=to_layout_names, long_text=_('''
|
||||||
The enabled window layouts. A comma separated list of layout names. The special
|
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
|
value :code:`all` means all layouts. The first listed layout will be used as the
|
||||||
@ -786,20 +604,6 @@ for vertical resizing.
|
|||||||
o('window_resize_step_lines', 2, option_type=positive_int)
|
o('window_resize_step_lines', 2, option_type=positive_int)
|
||||||
|
|
||||||
|
|
||||||
def window_border_width(x: Union[str, int, float]) -> Tuple[float, str]:
|
|
||||||
unit = 'pt'
|
|
||||||
if isinstance(x, str):
|
|
||||||
trailer = x[-2:]
|
|
||||||
if trailer in ('px', 'pt'):
|
|
||||||
unit = trailer
|
|
||||||
val = float(x[:-2])
|
|
||||||
else:
|
|
||||||
val = float(x)
|
|
||||||
else:
|
|
||||||
val = float(x)
|
|
||||||
return max(0, val), unit
|
|
||||||
|
|
||||||
|
|
||||||
o('window_border_width', '0.5pt', option_type=window_border_width, long_text=_('''
|
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
|
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
|
in pts will be rounded to the nearest number of pixels based on screen
|
||||||
@ -815,27 +619,6 @@ a non-zero window margin overrides this and causes all borders to be drawn.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def edge_width(x: str, converter: Callable[[str], float] = positive_float) -> FloatEdges:
|
|
||||||
parts = str(x).split()
|
|
||||||
num = len(parts)
|
|
||||||
if num == 1:
|
|
||||||
val = converter(parts[0])
|
|
||||||
return FloatEdges(val, val, val, val)
|
|
||||||
if num == 2:
|
|
||||||
v = converter(parts[0])
|
|
||||||
h = converter(parts[1])
|
|
||||||
return FloatEdges(h, v, h, v)
|
|
||||||
if num == 3:
|
|
||||||
top, h, bottom = map(converter, parts)
|
|
||||||
return FloatEdges(h, top, h, bottom)
|
|
||||||
top, right, bottom, left = map(converter, parts)
|
|
||||||
return FloatEdges(left, top, right, bottom)
|
|
||||||
|
|
||||||
|
|
||||||
def optional_edge_width(x: str) -> FloatEdges:
|
|
||||||
return edge_width(x, float)
|
|
||||||
|
|
||||||
|
|
||||||
edge_desc = _(
|
edge_desc = _(
|
||||||
'A single value sets all four sides. Two values set the vertical and horizontal sides.'
|
'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.')
|
' Three values set top, horizontal and bottom. Four values set top, right, bottom and left.')
|
||||||
@ -875,14 +658,6 @@ zero and one, with zero being fully faded).
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def hide_window_decorations(x: str) -> int:
|
|
||||||
if x == 'titlebar-only':
|
|
||||||
return 0b10
|
|
||||||
if to_bool(x):
|
|
||||||
return 0b01
|
|
||||||
return 0b00
|
|
||||||
|
|
||||||
|
|
||||||
o('hide_window_decorations', 'no', option_type=hide_window_decorations, long_text=_('''
|
o('hide_window_decorations', 'no', option_type=hide_window_decorations, long_text=_('''
|
||||||
Hide the window decorations (title-bar and window borders) with :code:`yes`.
|
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.
|
On macOS, :code:`titlebar-only` can be used to only hide the titlebar.
|
||||||
@ -897,11 +672,6 @@ operating system sends events corresponding to the start and end
|
|||||||
of a resize, this number is ignored.'''))
|
of a resize, this number is ignored.'''))
|
||||||
|
|
||||||
|
|
||||||
def resize_draw_strategy(x: str) -> int:
|
|
||||||
cmap = {'static': 0, 'scale': 1, 'blank': 2, 'size': 3}
|
|
||||||
return cmap.get(x.lower(), 0)
|
|
||||||
|
|
||||||
|
|
||||||
o('resize_draw_strategy', 'static', option_type=resize_draw_strategy, long_text=_('''
|
o('resize_draw_strategy', 'static', option_type=resize_draw_strategy, long_text=_('''
|
||||||
Choose how kitty draws a window while a resize is in progress.
|
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:`static` means draw the current window contents, mostly unchanged.
|
||||||
@ -926,31 +696,6 @@ OS windows, via the quit action).
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
g('tabbar') # {{{
|
g('tabbar') # {{{
|
||||||
default_tab_separator = ' ┇'
|
|
||||||
|
|
||||||
|
|
||||||
def tab_separator(x: str) -> str:
|
|
||||||
for q in '\'"':
|
|
||||||
if x.startswith(q) and x.endswith(q):
|
|
||||||
x = x[1:-1]
|
|
||||||
if not x:
|
|
||||||
return ''
|
|
||||||
break
|
|
||||||
if not x.strip():
|
|
||||||
x = ('\xa0' * len(x)) if x else default_tab_separator
|
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
def tab_bar_edge(x: str) -> int:
|
|
||||||
return {'top': 1, 'bottom': 3}.get(x.lower(), 3)
|
|
||||||
|
|
||||||
|
|
||||||
def tab_font_style(x: str) -> Tuple[bool, bool]:
|
|
||||||
return {
|
|
||||||
'bold-italic': (True, True),
|
|
||||||
'bold': (True, False),
|
|
||||||
'italic': (False, True)
|
|
||||||
}.get(x.lower().replace('_', '-'), (False, False))
|
|
||||||
|
|
||||||
|
|
||||||
o('tab_bar_edge', 'bottom', option_type=tab_bar_edge, long_text=_('''
|
o('tab_bar_edge', 'bottom', option_type=tab_bar_edge, long_text=_('''
|
||||||
@ -968,10 +713,6 @@ presents you with a list of tabs and allows for easy switching to a tab.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
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=_('''
|
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
|
The minimum number of tabs that must exist before the tab bar is shown
|
||||||
'''))
|
'''))
|
||||||
@ -985,10 +726,6 @@ A value of :code:`last` will switch to the right-most tab.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def tab_fade(x: str) -> Tuple[float, ...]:
|
|
||||||
return tuple(map(unit_float, x.split()))
|
|
||||||
|
|
||||||
|
|
||||||
o('tab_fade', '0.25 0.5 0.75 1', option_type=tab_fade, long_text=_('''
|
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
|
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
|
:opt:`tab_bar_style`. Each number is an alpha (between zero and one) that controls
|
||||||
@ -1006,31 +743,10 @@ as the :opt:`tab_bar_style`, can be one of: :code:`angled`, :code:`slanted`, or
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def tab_activity_symbol(x: str) -> Optional[str]:
|
|
||||||
if x == 'none':
|
|
||||||
return None
|
|
||||||
return x or None
|
|
||||||
|
|
||||||
|
|
||||||
o('tab_activity_symbol', 'none', option_type=tab_activity_symbol, long_text=_('''
|
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
|
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.'''))
|
not have focus has some activity.'''))
|
||||||
|
|
||||||
|
|
||||||
def tab_title_template(x: str) -> str:
|
|
||||||
if x:
|
|
||||||
for q in '\'"':
|
|
||||||
if x.startswith(q) and x.endswith(q):
|
|
||||||
x = x[1:-1]
|
|
||||||
break
|
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
def active_tab_title_template(x: str) -> Optional[str]:
|
|
||||||
x = tab_title_template(x)
|
|
||||||
return None if x == 'none' else x
|
|
||||||
|
|
||||||
|
|
||||||
o('tab_title_template', '"{title}"', option_type=tab_title_template, long_text=_('''
|
o('tab_title_template', '"{title}"', option_type=tab_title_template, long_text=_('''
|
||||||
A template to render the tab title. The default just renders
|
A template to render the tab title. The default just renders
|
||||||
the title. If you wish to include the tab-index as well,
|
the title. If you wish to include the tab-index as well,
|
||||||
@ -1086,16 +802,6 @@ default as it has a performance cost)
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def config_or_absolute_path(x: str) -> Optional[str]:
|
|
||||||
if x.lower() == 'none':
|
|
||||||
return None
|
|
||||||
x = os.path.expanduser(x)
|
|
||||||
x = os.path.expandvars(x)
|
|
||||||
if not os.path.isabs(x):
|
|
||||||
x = os.path.join(config_dir, x)
|
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
o('background_image', 'none', option_type=config_or_absolute_path, long_text=_('''
|
o('background_image', 'none', option_type=config_or_absolute_path, long_text=_('''
|
||||||
Path to a background image. Must be in PNG format.'''))
|
Path to a background image. Must be in PNG format.'''))
|
||||||
|
|
||||||
@ -1189,12 +895,6 @@ terminal can fail silently because their stdout/stderr/stdin no longer work.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def allow_remote_control(x: str) -> str:
|
|
||||||
if x != 'socket-only':
|
|
||||||
x = 'y' if to_bool(x) else 'n'
|
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
o('allow_remote_control', 'no', option_type=allow_remote_control, long_text=_('''
|
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
|
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
|
control all aspects of kitty, including sending text to kitty windows, opening
|
||||||
@ -1249,10 +949,6 @@ Environment variables in the path are expanded.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
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=_('''
|
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
|
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:
|
control exactly which actions are allowed. The set of possible actions is:
|
||||||
@ -1265,12 +961,6 @@ program, even one running on a remote server via SSH can read your clipboard.
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def allow_hyperlinks(x: str) -> int:
|
|
||||||
if x == 'ask':
|
|
||||||
return 0b11
|
|
||||||
return 1 if to_bool(x) else 0
|
|
||||||
|
|
||||||
|
|
||||||
o('allow_hyperlinks', 'yes', option_type=allow_hyperlinks, long_text=_('''
|
o('allow_hyperlinks', 'yes', option_type=allow_hyperlinks, long_text=_('''
|
||||||
Process hyperlink (OSC 8) escape sequences. If disabled OSC 8 escape
|
Process hyperlink (OSC 8) escape sequences. If disabled OSC 8 escape
|
||||||
sequences are ignored. Otherwise they become clickable links, that you
|
sequences are ignored. Otherwise they become clickable links, that you
|
||||||
@ -1293,15 +983,6 @@ key-presses, to colors, to various advanced features may not work.
|
|||||||
g('os') # {{{
|
g('os') # {{{
|
||||||
|
|
||||||
|
|
||||||
def macos_titlebar_color(x: str) -> int:
|
|
||||||
x = x.strip('"')
|
|
||||||
if x == 'system':
|
|
||||||
return 0
|
|
||||||
if x == 'background':
|
|
||||||
return 1
|
|
||||||
return (color_as_int(to_color(x)) << 8) | 2
|
|
||||||
|
|
||||||
|
|
||||||
o('wayland_titlebar_color', 'system', option_type=macos_titlebar_color, long_text=_('''
|
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.
|
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:`system` means to use the default system color,
|
||||||
@ -1322,19 +1003,6 @@ probably better off just hiding the titlebar with :opt:`hide_window_decorations`
|
|||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def macos_option_as_alt(x: str) -> int:
|
|
||||||
x = x.lower()
|
|
||||||
if x == 'both':
|
|
||||||
return 0b11
|
|
||||||
if x == 'left':
|
|
||||||
return 0b10
|
|
||||||
if x == 'right':
|
|
||||||
return 0b01
|
|
||||||
if to_bool(x):
|
|
||||||
return 0b11
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
o('macos_option_as_alt', 'no', option_type=macos_option_as_alt, long_text=_('''
|
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
|
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
|
the macOS native :kbd:`Option+Key` = unicode character behavior. This will
|
||||||
|
|||||||
@ -4,11 +4,10 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Dict, Optional
|
||||||
|
|
||||||
from .constants import is_macos
|
from .constants import is_macos
|
||||||
|
|
||||||
|
|
||||||
functional_key_name_aliases = {
|
functional_key_name_aliases = {
|
||||||
'ESC': 'ESCAPE',
|
'ESC': 'ESCAPE',
|
||||||
'PGUP': 'PAGE_UP',
|
'PGUP': 'PAGE_UP',
|
||||||
@ -26,7 +25,7 @@ functional_key_name_aliases = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
character_key_name_aliases = {
|
character_key_name_aliases: Dict[str, str] = {
|
||||||
'SPC': ' ',
|
'SPC': ' ',
|
||||||
'SPACE': ' ',
|
'SPACE': ' ',
|
||||||
'STAR': '*',
|
'STAR': '*',
|
||||||
|
|||||||
347
kitty/options_types.py
Normal file
347
kitty/options_types.py
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import (
|
||||||
|
Callable, Dict, FrozenSet, Iterable, List, Optional, Tuple, Union
|
||||||
|
)
|
||||||
|
|
||||||
|
import kitty.fast_data_types as defines
|
||||||
|
from kitty.fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
|
||||||
|
|
||||||
|
from .conf.utils import (
|
||||||
|
positive_float, positive_int, to_bool, to_color, uniq, unit_float
|
||||||
|
)
|
||||||
|
from .constants import config_dir
|
||||||
|
from .key_names import (
|
||||||
|
character_key_name_aliases, functional_key_name_aliases,
|
||||||
|
get_key_name_lookup
|
||||||
|
)
|
||||||
|
from .layout.interface import all_layouts
|
||||||
|
from .rgb import Color, color_as_int
|
||||||
|
from .types import FloatEdges, SingleKey
|
||||||
|
from .utils import log_error
|
||||||
|
|
||||||
|
MINIMUM_FONT_SIZE = 4
|
||||||
|
default_tab_separator = ' ┇'
|
||||||
|
mod_map = {'CTRL': 'CONTROL', 'CMD': 'SUPER', '⌘': 'SUPER',
|
||||||
|
'⌥': 'ALT', 'OPTION': 'ALT', 'KITTY_MOD': 'KITTY'}
|
||||||
|
character_key_name_aliases_with_ascii_lowercase: Dict[str, str] = character_key_name_aliases.copy()
|
||||||
|
for x in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
|
||||||
|
character_key_name_aliases_with_ascii_lowercase[x] = x.lower()
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidMods(ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def parse_mods(parts: Iterable[str], sc: str) -> Optional[int]:
|
||||||
|
|
||||||
|
def map_mod(m: str) -> str:
|
||||||
|
return mod_map.get(m, m)
|
||||||
|
|
||||||
|
mods = 0
|
||||||
|
for m in parts:
|
||||||
|
try:
|
||||||
|
mods |= getattr(defines, 'GLFW_MOD_' + map_mod(m.upper()))
|
||||||
|
except AttributeError:
|
||||||
|
if m.upper() != 'NONE':
|
||||||
|
log_error('Shortcut: {} has unknown modifier, ignoring'.format(sc))
|
||||||
|
return None
|
||||||
|
|
||||||
|
return mods
|
||||||
|
|
||||||
|
|
||||||
|
def to_modifiers(val: str) -> int:
|
||||||
|
return parse_mods(val.split('+'), val) or 0
|
||||||
|
|
||||||
|
|
||||||
|
def parse_shortcut(sc: str) -> SingleKey:
|
||||||
|
if sc.endswith('+') and len(sc) > 1:
|
||||||
|
sc = sc[:-1] + 'plus'
|
||||||
|
parts = sc.split('+')
|
||||||
|
mods = 0
|
||||||
|
if len(parts) > 1:
|
||||||
|
mods = parse_mods(parts[:-1], sc) or 0
|
||||||
|
if not mods:
|
||||||
|
raise InvalidMods('Invalid shortcut')
|
||||||
|
q = parts[-1]
|
||||||
|
q = character_key_name_aliases_with_ascii_lowercase.get(q.upper(), q)
|
||||||
|
is_native = False
|
||||||
|
if q.startswith('0x'):
|
||||||
|
try:
|
||||||
|
key = int(q, 16)
|
||||||
|
except Exception:
|
||||||
|
key = 0
|
||||||
|
else:
|
||||||
|
is_native = True
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
key = ord(q)
|
||||||
|
except Exception:
|
||||||
|
uq = q.upper()
|
||||||
|
uq = functional_key_name_aliases.get(uq, uq)
|
||||||
|
x: Optional[int] = getattr(defines, f'GLFW_FKEY_{uq}', None)
|
||||||
|
if x is None:
|
||||||
|
lf = get_key_name_lookup()
|
||||||
|
key = lf(q, False) or 0
|
||||||
|
is_native = key > 0
|
||||||
|
else:
|
||||||
|
key = x
|
||||||
|
|
||||||
|
return SingleKey(mods, is_native, key or 0)
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_line_height(x: str) -> Union[int, float]:
|
||||||
|
if x.endswith('%'):
|
||||||
|
ans = float(x[:-1].strip()) / 100.0
|
||||||
|
if ans < 0:
|
||||||
|
log_error('Percentage adjustments of cell sizes must be positive numbers')
|
||||||
|
return 0
|
||||||
|
return ans
|
||||||
|
return int(x)
|
||||||
|
|
||||||
|
|
||||||
|
def to_font_size(x: str) -> float:
|
||||||
|
return max(MINIMUM_FONT_SIZE, float(x))
|
||||||
|
|
||||||
|
|
||||||
|
def disable_ligatures(x: str) -> int:
|
||||||
|
cmap = {'never': 0, 'cursor': 1, 'always': 2}
|
||||||
|
return cmap.get(x.lower(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
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[0], ans[1], ans[2], ans[3]
|
||||||
|
|
||||||
|
|
||||||
|
def cursor_text_color(x: str) -> Optional[Color]:
|
||||||
|
if x.lower() == 'background':
|
||||||
|
return None
|
||||||
|
return to_color(x)
|
||||||
|
|
||||||
|
|
||||||
|
cshapes = {
|
||||||
|
'block': CURSOR_BLOCK,
|
||||||
|
'beam': CURSOR_BEAM,
|
||||||
|
'underline': CURSOR_UNDERLINE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def to_cursor_shape(x: str) -> int:
|
||||||
|
try:
|
||||||
|
return cshapes[x.lower()]
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError(
|
||||||
|
'Invalid cursor shape: {} allowed values are {}'.format(
|
||||||
|
x, ', '.join(cshapes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def scrollback_lines(x: str) -> int:
|
||||||
|
ans = int(x)
|
||||||
|
if ans < 0:
|
||||||
|
ans = 2 ** 32 - 1
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
def scrollback_pager_history_size(x: str) -> int:
|
||||||
|
ans = int(max(0, float(x)) * 1024 * 1024)
|
||||||
|
return min(ans, 4096 * 1024 * 1024 - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def url_style(x: str) -> int:
|
||||||
|
return url_style_map.get(x, url_style_map['curly'])
|
||||||
|
|
||||||
|
|
||||||
|
url_style_map = dict(
|
||||||
|
((v, i) for i, v in enumerate('none single double curly'.split()))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def url_prefixes(x: str) -> Tuple[str, ...]:
|
||||||
|
return tuple(a.lower() for a in x.replace(',', ' ').split())
|
||||||
|
|
||||||
|
|
||||||
|
def copy_on_select(raw: str) -> str:
|
||||||
|
q = raw.lower()
|
||||||
|
# boolean values special cased for backwards compat
|
||||||
|
if q in ('y', 'yes', 'true', 'clipboard'):
|
||||||
|
return 'clipboard'
|
||||||
|
if q in ('n', 'no', 'false', ''):
|
||||||
|
return ''
|
||||||
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def to_layout_names(raw: str) -> List[str]:
|
||||||
|
parts = [x.strip().lower() for x in raw.split(',')]
|
||||||
|
ans: List[str] = []
|
||||||
|
for p in parts:
|
||||||
|
if p in ('*', 'all'):
|
||||||
|
ans.extend(sorted(all_layouts))
|
||||||
|
continue
|
||||||
|
name = p.partition(':')[0]
|
||||||
|
if name not in all_layouts:
|
||||||
|
raise ValueError('The window layout {} is unknown'.format(p))
|
||||||
|
ans.append(p)
|
||||||
|
return uniq(ans)
|
||||||
|
|
||||||
|
|
||||||
|
def window_border_width(x: Union[str, int, float]) -> Tuple[float, str]:
|
||||||
|
unit = 'pt'
|
||||||
|
if isinstance(x, str):
|
||||||
|
trailer = x[-2:]
|
||||||
|
if trailer in ('px', 'pt'):
|
||||||
|
unit = trailer
|
||||||
|
val = float(x[:-2])
|
||||||
|
else:
|
||||||
|
val = float(x)
|
||||||
|
else:
|
||||||
|
val = float(x)
|
||||||
|
return max(0, val), unit
|
||||||
|
|
||||||
|
|
||||||
|
def edge_width(x: str, converter: Callable[[str], float] = positive_float) -> FloatEdges:
|
||||||
|
parts = str(x).split()
|
||||||
|
num = len(parts)
|
||||||
|
if num == 1:
|
||||||
|
val = converter(parts[0])
|
||||||
|
return FloatEdges(val, val, val, val)
|
||||||
|
if num == 2:
|
||||||
|
v = converter(parts[0])
|
||||||
|
h = converter(parts[1])
|
||||||
|
return FloatEdges(h, v, h, v)
|
||||||
|
if num == 3:
|
||||||
|
top, h, bottom = map(converter, parts)
|
||||||
|
return FloatEdges(h, top, h, bottom)
|
||||||
|
top, right, bottom, left = map(converter, parts)
|
||||||
|
return FloatEdges(left, top, right, bottom)
|
||||||
|
|
||||||
|
|
||||||
|
def optional_edge_width(x: str) -> FloatEdges:
|
||||||
|
return edge_width(x, float)
|
||||||
|
|
||||||
|
|
||||||
|
def hide_window_decorations(x: str) -> int:
|
||||||
|
if x == 'titlebar-only':
|
||||||
|
return 0b10
|
||||||
|
if to_bool(x):
|
||||||
|
return 0b01
|
||||||
|
return 0b00
|
||||||
|
|
||||||
|
|
||||||
|
def resize_draw_strategy(x: str) -> int:
|
||||||
|
cmap = {'static': 0, 'scale': 1, 'blank': 2, 'size': 3}
|
||||||
|
return cmap.get(x.lower(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
def tab_separator(x: str) -> str:
|
||||||
|
for q in '\'"':
|
||||||
|
if x.startswith(q) and x.endswith(q):
|
||||||
|
x = x[1:-1]
|
||||||
|
if not x:
|
||||||
|
return ''
|
||||||
|
break
|
||||||
|
if not x.strip():
|
||||||
|
x = ('\xa0' * len(x)) if x else default_tab_separator
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def tab_bar_edge(x: str) -> int:
|
||||||
|
return {'top': 1, 'bottom': 3}.get(x.lower(), 3)
|
||||||
|
|
||||||
|
|
||||||
|
def tab_font_style(x: str) -> Tuple[bool, bool]:
|
||||||
|
return {
|
||||||
|
'bold-italic': (True, True),
|
||||||
|
'bold': (True, False),
|
||||||
|
'italic': (False, True)
|
||||||
|
}.get(x.lower().replace('_', '-'), (False, False))
|
||||||
|
|
||||||
|
|
||||||
|
def tab_bar_min_tabs(x: str) -> int:
|
||||||
|
return max(1, positive_int(x))
|
||||||
|
|
||||||
|
|
||||||
|
def tab_fade(x: str) -> Tuple[float, ...]:
|
||||||
|
return tuple(map(unit_float, x.split()))
|
||||||
|
|
||||||
|
|
||||||
|
def tab_activity_symbol(x: str) -> Optional[str]:
|
||||||
|
if x == 'none':
|
||||||
|
return None
|
||||||
|
return x or None
|
||||||
|
|
||||||
|
|
||||||
|
def tab_title_template(x: str) -> str:
|
||||||
|
if x:
|
||||||
|
for q in '\'"':
|
||||||
|
if x.startswith(q) and x.endswith(q):
|
||||||
|
x = x[1:-1]
|
||||||
|
break
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def active_tab_title_template(x: str) -> Optional[str]:
|
||||||
|
x = tab_title_template(x)
|
||||||
|
return None if x == 'none' else x
|
||||||
|
|
||||||
|
|
||||||
|
def config_or_absolute_path(x: str) -> Optional[str]:
|
||||||
|
if x.lower() == 'none':
|
||||||
|
return None
|
||||||
|
x = os.path.expanduser(x)
|
||||||
|
x = os.path.expandvars(x)
|
||||||
|
if not os.path.isabs(x):
|
||||||
|
x = os.path.join(config_dir, x)
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def allow_remote_control(x: str) -> str:
|
||||||
|
if x != 'socket-only':
|
||||||
|
x = 'y' if to_bool(x) else 'n'
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def clipboard_control(x: str) -> FrozenSet[str]:
|
||||||
|
return frozenset(x.lower().split())
|
||||||
|
|
||||||
|
|
||||||
|
def allow_hyperlinks(x: str) -> int:
|
||||||
|
if x == 'ask':
|
||||||
|
return 0b11
|
||||||
|
return 1 if to_bool(x) else 0
|
||||||
|
|
||||||
|
|
||||||
|
def macos_titlebar_color(x: str) -> int:
|
||||||
|
x = x.strip('"')
|
||||||
|
if x == 'system':
|
||||||
|
return 0
|
||||||
|
if x == 'background':
|
||||||
|
return 1
|
||||||
|
return (color_as_int(to_color(x)) << 8) | 2
|
||||||
|
|
||||||
|
|
||||||
|
def macos_option_as_alt(x: str) -> int:
|
||||||
|
x = x.lower()
|
||||||
|
if x == 'both':
|
||||||
|
return 0b11
|
||||||
|
if x == 'left':
|
||||||
|
return 0b10
|
||||||
|
if x == 'right':
|
||||||
|
return 0b01
|
||||||
|
if to_bool(x):
|
||||||
|
return 0b11
|
||||||
|
return 0
|
||||||
@ -7,7 +7,7 @@ import sys
|
|||||||
from typing import Generator, List, Optional, Sequence, Union
|
from typing import Generator, List, Optional, Sequence, Union
|
||||||
|
|
||||||
from .cli_stub import CLIOptions
|
from .cli_stub import CLIOptions
|
||||||
from .config_data import to_layout_names
|
from .options_types import to_layout_names, window_size
|
||||||
from .constants import kitty_exe
|
from .constants import kitty_exe
|
||||||
from .layout.interface import all_layouts
|
from .layout.interface import all_layouts
|
||||||
from .options_stub import Options
|
from .options_stub import Options
|
||||||
@ -127,7 +127,6 @@ def parse_session(raw: str, opts: Options, default_title: Optional[str] = None)
|
|||||||
elif cmd == 'title':
|
elif cmd == 'title':
|
||||||
ans.set_next_title(rest)
|
ans.set_next_title(rest)
|
||||||
elif cmd == 'os_window_size':
|
elif cmd == 'os_window_size':
|
||||||
from kitty.config_data import window_size
|
|
||||||
w, h = map(window_size, rest.split(maxsplit=1))
|
w, h = map(window_size, rest.split(maxsplit=1))
|
||||||
ans.os_window_size = WindowSizes(WindowSize(*w), WindowSize(*h))
|
ans.os_window_size = WindowSizes(WindowSize(*w), WindowSize(*h))
|
||||||
elif cmd == 'os_window_class':
|
elif cmd == 'os_window_class':
|
||||||
|
|||||||
@ -680,11 +680,3 @@ class SSHConnectionData(NamedTuple):
|
|||||||
binary: str
|
binary: str
|
||||||
hostname: str
|
hostname: str
|
||||||
port: Optional[int] = None
|
port: Optional[int] = None
|
||||||
|
|
||||||
|
|
||||||
def positive_int(x: ConvertibleToNumbers) -> int:
|
|
||||||
return max(0, int(x))
|
|
||||||
|
|
||||||
|
|
||||||
def positive_float(x: ConvertibleToNumbers) -> float:
|
|
||||||
return max(0, float(x))
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user