Allow more options for what to do in a custom keyboard mode on unknown and action events

This commit is contained in:
Kovid Goyal 2023-12-03 20:07:29 +05:30
parent ca6c607148
commit d191896528
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 51 additions and 17 deletions

View file

@ -1369,6 +1369,13 @@ class Boss:
return False
if self.global_shortcuts_map and get_shortcut(self.global_shortcuts_map, ev):
return True
if not is_root_mode:
if mode.on_unknown in ('beep', 'ignore'):
if mode.on_unknown == 'beep' and get_options().enable_audio_bell:
ring_bell()
return True
if mode.on_unknown == 'passthrough':
return False
if not self.pop_keyboard_mode():
if get_options().enable_audio_bell:
ring_bell()
@ -1380,7 +1387,7 @@ class Boss:
if final_actions[0].is_sequence:
if not mode.is_sequence:
sm = KeyboardMode('__sequence__')
sm.end_on_action = True
sm.on_action = 'end'
sm.is_sequence = True
for fa in final_actions:
sm.keymap[fa.rest[0]].append(fa.shift_sequence_and_copy())
@ -1399,7 +1406,7 @@ class Boss:
return True
final_action = final_actions[0]
consumed = self.combine(final_action.definition)
if consumed and not is_root_mode and mode.end_on_action:
if consumed and not is_root_mode and mode.on_action == 'end':
if mode_pos < len(self.keyboard_mode_stack) and self.keyboard_mode_stack[mode_pos] is mode:
del self.keyboard_mode_stack[mode_pos]
if not self.keyboard_mode_stack:
@ -1463,7 +1470,7 @@ class Boss:
self.current_visual_select.window_used_for_selection_id = 0 if w is None else w.id
return
km = KeyboardMode('__visual_select__')
km.end_on_action = True
km.on_action = 'end'
fmap = get_name_to_functional_number_map()
alphanumerics = get_options().visual_window_select_characters
for idx, window in tab.windows.iter_windows_with_number(only_visible=True):

View file

@ -105,8 +105,8 @@ def finalize_keys(opts: Options, accumulate_bad_lines: Optional[List[BadLine]] =
for defn in defns:
if defn.options.new_mode:
modes[defn.options.new_mode] = nm = KeyboardMode(defn.options.new_mode)
nm.passthrough_unknown = defn.options.passthrough_unknown
nm.end_on_action = defn.options.end_on_action
nm.on_unknown = defn.options.on_unknown
nm.on_action = defn.options.on_action
defn.definition = f'push_keyboard_mode {defn.options.new_mode}'
try:
m = modes[defn.options.mode]

View file

@ -8,7 +8,25 @@ import sys
from collections import defaultdict
from dataclasses import dataclass, fields
from functools import lru_cache
from typing import Any, Callable, Container, Dict, FrozenSet, Iterable, Iterator, List, NamedTuple, Optional, Sequence, Tuple, Union
from typing import (
Any,
Callable,
Container,
Dict,
FrozenSet,
Generic,
Iterable,
Iterator,
List,
Literal,
NamedTuple,
Optional,
Sequence,
Tuple,
TypeVar,
Union,
get_args,
)
import kitty.fast_data_types as defines
from kitty.conf.utils import (
@ -1134,20 +1152,29 @@ class MouseMapping(BaseDefinition):
return MouseEvent(self.button, self.mods, self.repeat_count, self.grabbed)
class BoolField:
def __init__(self, default: bool = False):
self._default = default
T = TypeVar('T')
class LiteralField(Generic[T]):
def __init__(self, vals: Tuple[T, ...]):
self._vals = vals
def __set_name__(self, owner: object, name: str) -> None:
self._name = "_" + name
def __get__(self, obj: object, type: Optional[type] = None) -> bool:
def __get__(self, obj: object, type: Optional[type] = None) -> T:
if obj is None:
return self._default
return getattr(obj, self._name, self._default)
return self._vals[0]
return getattr(obj, self._name, self._vals[0])
def __set__(self, obj: object, value: str) -> None:
setattr(obj, self._name, to_bool(value))
if value not in self._vals:
raise KeyError(f'Invalid value for {self._name[1:]}: {value!r}')
setattr(obj, self._name, value)
OnUnknown = Literal['beep', 'end', 'ignore', 'passthrough']
OnAction = Literal['keep', 'end']
@dataclass(init=False, frozen=True)
@ -1155,8 +1182,8 @@ class KeyMapOptions:
when_focus_on: str = ''
new_mode: str = ''
mode: str = ''
passthrough_unknown: BoolField = BoolField(False)
end_on_action: BoolField = BoolField(False)
on_unknown = LiteralField[OnUnknown](get_args(OnUnknown))
on_action = LiteralField[OnAction](get_args(OnAction))
default_key_map_options = KeyMapOptions()
@ -1205,8 +1232,8 @@ class KeyDefinition(BaseDefinition):
class KeyboardMode:
passthrough_unknown: bool = False
end_on_action: bool = False
on_unknown: OnUnknown = get_args(OnUnknown)[0]
on_action : OnAction = get_args(OnAction)[0]
is_sequence: bool = False
def __init__(self, name: str = '') -> None: