1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Keyboard helpers for pyratatui KeyEvent values."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Protocol, runtime_checkable
_vim_enabled: bool = False
@runtime_checkable
class KeyLike(Protocol):
@property
def code(self) -> str: ...
@property
def ctrl(self) -> bool: ...
@property
def alt(self) -> bool: ...
@property
def shift(self) -> bool: ...
@dataclass(frozen=True, slots=True)
class Key:
"""Test-friendly stand-in for ``pyratatui.KeyEvent``."""
code: str
ctrl: bool = False
alt: bool = False
shift: bool = False
def key(code: str, *, ctrl: bool = False, alt: bool = False, shift: bool = False) -> Key:
return Key(code=code, ctrl=ctrl, alt=alt, shift=shift)
def set_vim_enabled(enabled: bool) -> None:
global _vim_enabled
_vim_enabled = enabled
def vim_enabled() -> bool:
return _vim_enabled
def is_quit(ev: KeyLike) -> bool:
return ev.code.casefold() == "q" or (ev.code == "c" and ev.ctrl)
def is_up(ev: KeyLike) -> bool:
if ev.code == "Up":
return True
return _vim_enabled and ev.code in {"k", "K"}
def is_down(ev: KeyLike) -> bool:
if ev.code == "Down":
return True
return _vim_enabled and ev.code in {"j", "J"}
def is_left(ev: KeyLike) -> bool:
if ev.code == "Left":
return True
return _vim_enabled and ev.code in {"h", "H"}
def is_right(ev: KeyLike) -> bool:
if ev.code == "Right":
return True
return _vim_enabled and ev.code in {"l", "L"}
def is_enter(ev: KeyLike) -> bool:
return ev.code == "Enter"
def is_esc(ev: KeyLike) -> bool:
return ev.code == "Esc"
def is_tab(ev: KeyLike) -> bool:
return ev.code == "Tab" and not ev.shift
def is_backtab(ev: KeyLike) -> bool:
return ev.code in {"BackTab", "Backtab"} or (ev.code == "Tab" and ev.shift)
def is_backspace(ev: KeyLike) -> bool:
return ev.code == "Backspace"
def is_space(ev: KeyLike) -> bool:
return ev.code == " "
def is_slash(ev: KeyLike) -> bool:
return ev.code == "/" and not ev.ctrl and not ev.alt
def printable_char(ev: KeyLike) -> str | None:
if ev.ctrl or ev.alt:
return None
if len(ev.code) == 1 and ev.code.isprintable():
return ev.code
return None
def move_hint() -> str:
return "j/k move" if _vim_enabled else "arrows move"
def tab_hint() -> str:
return "H/L switch tab" if _vim_enabled else "←/→ switch tab"
def board_hint() -> str:
return "H/L switch board" if _vim_enabled else "←/→ switch board"