diff --git a/docs/conf.py b/docs/conf.py index 743b9d067..c89529e98 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,7 +32,7 @@ kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if kitty_src not in sys.path: sys.path.insert(0, kitty_src) -from kitty.conf.definition import Option, Shortcut # noqa +from kitty.conf.definition import Option, Shortcut, OptionOrAction, MouseAction # noqa from kitty.constants import str_version # noqa @@ -447,8 +447,8 @@ def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str: return sig -def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence['Shortcut']]]) -> str: - from kitty.conf.definition import merged_opts, Option, Group +def render_conf(conf_name: str, all_options: Iterable[OptionOrAction]) -> str: + from kitty.conf.definition import merged_opts, Group ans = ['.. default-domain:: conf', ''] a = ans.append current_group: Optional[Group] = None @@ -499,7 +499,7 @@ def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence[' a(expand_opt_references(conf_name, opt.long_text)) a('') - def handle_shortcuts(shortcuts: Sequence[Shortcut]) -> None: + def handle_shortcuts(shortcuts: Sequence[Union[Shortcut, MouseAction]]) -> None: sc = shortcuts[0] handle_group(sc.group, True) sc_text = f'{conf_name}.{sc.short_text}' @@ -511,7 +511,7 @@ def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence[' a('') for x in shortcuts: if x.add_to_default: - a(' map {} {}'.format(x.key.replace('kitty_mod', kitty_mod), x.action_def)) + a(' ' + x.line.replace('kitty_mod', kitty_mod)) a('') if sc.long_text: a(expand_opt_references(conf_name, sc.long_text)) @@ -572,7 +572,7 @@ def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None: sc_role.warn_dangling = True sc_role.process_link = process_shortcut_link - def generate_default_config(all_options: Dict[str, Union[Option, Sequence[Shortcut]]], name: str) -> None: + def generate_default_config(all_options: Dict[str, OptionOrAction], name: str) -> None: from kitty.conf.definition import as_conf_file with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f: print('.. highlight:: conf\n', file=f) diff --git a/kittens/diff/config_data.py b/kittens/diff/config_data.py index 856daae69..b2347d6c5 100644 --- a/kittens/diff/config_data.py +++ b/kittens/diff/config_data.py @@ -6,16 +6,16 @@ # Utils {{{ from functools import partial from gettext import gettext as _ -from typing import Any, Dict, Sequence, Union +from typing import Any, Dict -from kitty.conf.definition import Option, Shortcut, option_func +from kitty.conf.definition import Option, OptionOrAction, option_func from kitty.conf.utils import python_string, to_color, to_color_or_none from kitty.utils import positive_int # }}} -all_options: Dict[str, Union[Option, Sequence[Shortcut]]] = {} -o, k, g, all_groups = option_func(all_options, { +all_options: Dict[str, OptionOrAction] = {} +o, k, m, g, all_groups = option_func(all_options, { 'colors': [_('Colors')], 'diff': [_('Diffing'), ], 'shortcuts': [_('Keyboard shortcuts')], diff --git a/kitty/conf/definition.py b/kitty/conf/definition.py index d1e3bcf5b..d13afe366 100644 --- a/kitty/conf/definition.py +++ b/kitty/conf/definition.py @@ -78,6 +78,26 @@ class Shortcut: 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], @@ -120,7 +140,7 @@ def shortcut( short_text: str = '', long_text: str = '', add_to_default: bool = True, - add_to_docs: 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 @@ -128,17 +148,40 @@ def shortcut( return ans -def option_func(all_options: Dict[str, Any], all_groups: Dict[str, Sequence[str]]) -> Tuple[Callable, Callable, Callable[[str], None], Dict[str, Group]]: +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), 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_ -def merged_opts(all_options: Sequence[Union[Option, Sequence[Shortcut]]], opt: Option, i: int) -> Generator[Option, None, None]: +OptionOrAction = Union[Option, Sequence[Shortcut], Sequence[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] @@ -208,7 +251,7 @@ def render_block(text: str) -> str: return '\n'.join(wrapped_block(lines)) -def as_conf_file(all_options: Iterable[Union[Option, Sequence[Shortcut]]]) -> List[str]: +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 @@ -242,11 +285,11 @@ def as_conf_file(all_options: Iterable[Union[Option, Sequence[Shortcut]]]) -> Li current_group = new_group render_group(current_group, is_shortcut) - def handle_shortcut(shortcuts: Sequence[Shortcut]) -> None: + 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('map {} {}'.format(sc.key, sc.action_def)) + a(sc.line) if sc.long_text: a(''), a(render_block(sc.long_text.strip())), a('') @@ -279,7 +322,7 @@ def as_conf_file(all_options: Iterable[Union[Option, Sequence[Shortcut]]]) -> Li start: Optional[int] = None count: Optional[int] = None for i, line in enumerate(ans): - if line.startswith('map '): + if line.startswith('map ') or line.startswith('mouse_map '): if start is None: start = i count = 1 @@ -303,7 +346,7 @@ def as_conf_file(all_options: Iterable[Union[Option, Sequence[Shortcut]]]) -> Li def config_lines( - all_options: Dict[str, Union[Option, Sequence[Shortcut]]], + all_options: Dict[str, OptionOrAction], ) -> Generator[str, None, None]: for opt in all_options.values(): if isinstance(opt, Option): @@ -316,7 +359,7 @@ def config_lines( def as_type_stub( - all_options: Dict[str, Union[Option, Sequence[Shortcut]]], + all_options: Dict[str, OptionOrAction], special_types: Optional[Dict[str, str]] = None, preamble_lines: Union[Tuple[str, ...], List[str], Iterable[str]] = (), extra_fields: Union[Tuple[Tuple[str, str], ...], List[Tuple[str, str]], Iterable[Tuple[str, str]]] = (), diff --git a/kitty/config.py b/kitty/config.py index 7d919868f..c26e91d8e 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -462,14 +462,13 @@ def parse_mouse_action(val: str, mouse_mappings: List[MouseMapping]) -> None: xbutton, event, modes, action = parts kparts = xbutton.split('+') if len(kparts) > 1: - mparts, obutton = parts[:-1], parts[-1].lower() + mparts, obutton = kparts[:-1], kparts[-1].lower() mods = parse_mods(mparts, obutton) if mods is None: return else: obutton = parts[0].lower() mods = 0 - obutton = xbutton.lower() try: b = {'left': 'b1', 'middle': 'b3', 'right': 'b2'}.get(obutton, obutton)[1:] button = getattr(defines, f'GLFW_MOUSE_BUTTON_{b}') diff --git a/kitty/config_data.py b/kitty/config_data.py index 68e600d2a..ddab3b590 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -6,12 +6,12 @@ import os from gettext import gettext as _ from typing import ( - Any, Callable, Dict, FrozenSet, Iterable, List, Optional, Sequence, Set, + Any, Callable, 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.definition import Option, OptionOrAction, option_func from .conf.utils import ( choices, to_bool, to_cmdline as tc, to_color, to_color_or_none, unit_float ) @@ -112,10 +112,10 @@ def uniq(vals: Iterable[T]) -> List[T]: # Groups {{{ -all_options: Dict[str, Union[Option, Sequence[Shortcut]]] = {} +all_options: Dict[str, OptionOrAction] = {} -o, k, g, all_groups = option_func(all_options, { +o, k, m, g, all_groups = option_func(all_options, { 'fonts': [ _('Fonts'), _('kitty has very powerful font management. You can configure individual\n' @@ -139,6 +139,9 @@ as color16 to color255.''') ], 'advanced': [_('Advanced')], 'os': [_('OS specific tweaks')], + 'mousemap': [ + _('Mouse actions'), + ], 'shortcuts': [ _('Keyboard shortcuts'), _('''\ @@ -1351,6 +1354,11 @@ automatically. Set it to :code:`x11` or :code:`wayland` to force the choice.''')) # }}} +g('mousemap') # {{{ + +m('click_url', 'ctrl+shift+left', 'release', 'grabbed,ungrabbed', 'mouse_click_url', _('Click the link under the mouse cursor')) +# }}} + g('shortcuts') # {{{ o('kitty_mod', 'ctrl+shift', option_type=to_modifiers, long_text=_('''