Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/textual/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import unicodedata
import inspect
import re
from abc import ABC, abstractmethod
from abc import ABC, ABCMeta, abstractmethod
from typing import TYPE_CHECKING, Callable, ClassVar, Generic, Iterator, TypeVar
from enum import Enum
from dataclasses import dataclass
Expand All @@ -18,6 +18,14 @@
NodeT = TypeVar("NodeT", bound="DOMNode", contravariant=True)


class KeyDeclarationType(ABCMeta):
"""A key-declaring class, including declarations supplied by a metaclass."""

def permits_key_overlap(cls, other: KeyDeclarationType) -> bool:
"""An explicitly declared alternative may share this declaration's key."""
return False


class KeyInvocation(ABC):
"""The concrete command a binding invokes, independent of its active mode."""

Expand Down Expand Up @@ -51,7 +59,7 @@ def visible_for_focus(self, mode: type[EditingMode], focused: frozenset[str]) ->
def permits_invocation_overlap(self, other: KeyInvocation) -> bool:
return False

def overlaps_declaration(self, other: type[KeyDeclaration]) -> bool:
def overlaps_declaration(self, other: KeyDeclarationType) -> bool:
return False


Expand All @@ -62,7 +70,7 @@ def __get__(self, instance: object, owner: type[KeyDeclaration]) -> str:
return owner.default_title()


class KeyDeclaration(KeyInvocation, Generic[NodeT]):
class KeyDeclaration(KeyInvocation, Generic[NodeT], metaclass=KeyDeclarationType):
"""Shared metadata for application actions and native editor commands.

Each provider retains its existing family registry. This view discovers the
Expand Down Expand Up @@ -109,7 +117,7 @@ def key_system(self) -> bool:
def permits_invocation_overlap(self, other: KeyInvocation) -> bool:
return other.overlaps_declaration(type(self))

def overlaps_declaration(self, other: type[KeyDeclaration]) -> bool:
def overlaps_declaration(self, other: KeyDeclarationType) -> bool:
return type(self).permits_key_overlap(other)

@abstractmethod
Expand All @@ -125,11 +133,6 @@ def bindings_for(cls, mode: type[EditingMode]) -> tuple[Binding, ...]:
def summary(cls) -> str:
return inspect.cleandoc(cls.__doc__ or "")

@classmethod
def permits_key_overlap(cls, other: type[KeyDeclaration]) -> bool:
"""An explicitly declared alternative may share a key with another declaration."""
return False

@classmethod
def declarations(cls) -> Iterator[type[KeyDeclaration]]:
"""Project each key family from the declaration owner's registry."""
Expand Down