From 54bdb4bac0924b37a7e3785745483c09c23cca5d Mon Sep 17 00:00:00 2001 From: darrenburns Date: Tue, 4 Oct 2022 18:37:06 +0100 Subject: [PATCH] Fix comma separated string in "Bindings" (#797) --- sandbox/darren/just_a_box.py | 2 +- src/textual/binding.py | 22 +++++++++++++++++----- tests/test_binding.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 tests/test_binding.py diff --git a/sandbox/darren/just_a_box.py b/sandbox/darren/just_a_box.py index 080157a52..c499c5b94 100644 --- a/sandbox/darren/just_a_box.py +++ b/sandbox/darren/just_a_box.py @@ -8,7 +8,7 @@ from textual.widgets import Static, Footer class JustABox(App): BINDINGS = [ Binding(key="t", action="text_fade_out", description="text-opacity fade out"), - Binding(key="o", action="widget_fade_out", description="opacity fade out"), + Binding(key="o,f,w", action="widget_fade_out", description="opacity fade out"), ] def compose(self) -> ComposeResult: diff --git a/src/textual/binding.py b/src/textual/binding.py index 3bec593e1..d413c50e6 100644 --- a/src/textual/binding.py +++ b/src/textual/binding.py @@ -1,17 +1,16 @@ from __future__ import annotations import sys -import rich.repr - from dataclasses import dataclass from typing import Iterable, MutableMapping +import rich.repr + if sys.version_info >= (3, 10): from typing import TypeAlias else: # pragma: no cover from typing_extensions import TypeAlias - BindingType: TypeAlias = "Binding | tuple[str, str, str]" @@ -23,7 +22,7 @@ class NoBinding(Exception): """A binding was not found.""" -@dataclass +@dataclass(frozen=True) class Binding: key: str """Key to bind.""" @@ -47,7 +46,20 @@ class Bindings: def make_bindings(bindings: Iterable[BindingType]) -> Iterable[Binding]: for binding in bindings: if isinstance(binding, Binding): - yield binding + binding_keys = binding.key.split(",") + if len(binding_keys) > 1: + for key in binding_keys: + new_binding = Binding( + key=key, + action=binding.action, + description=binding.description, + show=binding.show, + key_display=binding.key_display, + allow_forward=binding.allow_forward, + ) + yield new_binding + else: + yield binding else: if len(binding) != 3: raise BindingError( diff --git a/tests/test_binding.py b/tests/test_binding.py new file mode 100644 index 000000000..d2d61ac18 --- /dev/null +++ b/tests/test_binding.py @@ -0,0 +1,31 @@ +import pytest + +from textual.binding import Bindings, Binding + +BINDING1 = Binding("a,b", action="action1", description="description1") +BINDING2 = Binding("c", action="action2", description="description2") + + +@pytest.fixture +def bindings(): + yield Bindings([BINDING1, BINDING2]) + + +def test_bindings_get_key(bindings): + assert bindings.get_key("b") == Binding("b", action="action1", description="description1") + assert bindings.get_key("c") == BINDING2 + + +def test_bindings_merge_simple(bindings): + left = Bindings([BINDING1]) + right = Bindings([BINDING2]) + assert Bindings.merge([left, right]).keys == bindings.keys + + +def test_bindings_merge_overlap(): + left = Bindings([BINDING1]) + another_binding = Binding("a", action="another_action", description="another_description") + assert Bindings.merge([left, Bindings([another_binding])]).keys == { + "a": another_binding, + "b": Binding("b", action="action1", description="description1"), + }