mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Move aliasing/normalisation logic into Key
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Awaitable, Callable, Type, TypeVar
|
from typing import TYPE_CHECKING, Awaitable, Callable, Type, TypeVar, Iterable
|
||||||
|
|
||||||
import rich.repr
|
import rich.repr
|
||||||
from rich.style import Style
|
from rich.style import Style
|
||||||
|
|
||||||
from ._types import MessageTarget
|
from ._types import MessageTarget
|
||||||
from .geometry import Offset, Size
|
from .geometry import Offset, Size
|
||||||
|
from .keys import _get_key_aliases
|
||||||
from .message import Message
|
from .message import Message
|
||||||
|
|
||||||
MouseEventT = TypeVar("MouseEventT", bound="MouseEvent")
|
MouseEventT = TypeVar("MouseEventT", bound="MouseEvent")
|
||||||
@@ -209,7 +210,13 @@ class Key(InputEvent):
|
|||||||
@property
|
@property
|
||||||
def key_name(self) -> str | None:
|
def key_name(self) -> str | None:
|
||||||
"""Name of a key suitable for use as a Python identifier."""
|
"""Name of a key suitable for use as a Python identifier."""
|
||||||
return self.key.replace("+", "_")
|
return _normalize_key(self.key)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_aliases(self) -> Iterable[str]:
|
||||||
|
"""Get the aliases for the key, including the key itself"""
|
||||||
|
for alias in _get_key_aliases(self.key):
|
||||||
|
yield _normalize_key(alias)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_printable(self) -> bool:
|
def is_printable(self) -> bool:
|
||||||
@@ -222,6 +229,11 @@ class Key(InputEvent):
|
|||||||
return False if self.char is None else self.char.isprintable()
|
return False if self.char is None else self.char.isprintable()
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_key(key: str) -> str:
|
||||||
|
"""Convert the key string to a name suitable for use as a Python identifier."""
|
||||||
|
return key.replace("+", "_")
|
||||||
|
|
||||||
|
|
||||||
@rich.repr.auto
|
@rich.repr.auto
|
||||||
class MouseEvent(InputEvent, bubble=True):
|
class MouseEvent(InputEvent, bubble=True):
|
||||||
"""Sent in response to a mouse event.
|
"""Sent in response to a mouse event.
|
||||||
|
|||||||
@@ -548,11 +548,6 @@ class MessagePump(metaclass=MessagePumpMeta):
|
|||||||
private_handler_name = f"_key_{key}"
|
private_handler_name = f"_key_{key}"
|
||||||
private_handler = getattr(pump, private_handler_name, None)
|
private_handler = getattr(pump, private_handler_name, None)
|
||||||
|
|
||||||
if public_handler and private_handler:
|
|
||||||
_raise_duplicate_key_handlers_error(
|
|
||||||
key, public_handler_name, private_handler_name
|
|
||||||
)
|
|
||||||
|
|
||||||
return public_handler or private_handler
|
return public_handler or private_handler
|
||||||
|
|
||||||
invoked_method = None
|
invoked_method = None
|
||||||
@@ -560,9 +555,8 @@ class MessagePump(metaclass=MessagePumpMeta):
|
|||||||
if not key_name:
|
if not key_name:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
key_aliases = _get_key_aliases(event.key)
|
for key_alias in event.key_aliases:
|
||||||
for key_alias in key_aliases:
|
key_method = get_key_handler(self, key_alias)
|
||||||
key_method = get_key_handler(self, key_alias.replace("+", "_"))
|
|
||||||
if key_method is not None:
|
if key_method is not None:
|
||||||
if invoked_method:
|
if invoked_method:
|
||||||
_raise_duplicate_key_handlers_error(
|
_raise_duplicate_key_handlers_error(
|
||||||
|
|||||||
@@ -47,14 +47,6 @@ class DuplicateHandlersWidget(Widget):
|
|||||||
self.called_by = self.key_ctrl_i
|
self.called_by = self.key_ctrl_i
|
||||||
|
|
||||||
|
|
||||||
async def test_dispatch_key_raises_when_public_and_private_handlers():
|
|
||||||
"""When both a public and private handler exists for one key, we fail fast via exception."""
|
|
||||||
widget = DuplicateHandlersWidget()
|
|
||||||
with pytest.raises(DuplicateKeyHandlers):
|
|
||||||
await widget.dispatch_key(Key(widget, key="x", char="x"))
|
|
||||||
assert widget.called_by is None
|
|
||||||
|
|
||||||
|
|
||||||
async def test_dispatch_key_raises_when_conflicting_handler_aliases():
|
async def test_dispatch_key_raises_when_conflicting_handler_aliases():
|
||||||
"""If you've got a handler for e.g. ctrl+i and a handler for tab, that's probably a mistake.
|
"""If you've got a handler for e.g. ctrl+i and a handler for tab, that's probably a mistake.
|
||||||
In the terminal, they're the same thing, so we fail fast via exception here."""
|
In the terminal, they're the same thing, so we fail fast via exception here."""
|
||||||
|
|||||||
Reference in New Issue
Block a user