Skip to content

Commit 399085d

Browse files
authored
Add help screen to studio (#461)
feat: add help screen
1 parent 98b22e6 commit 399085d

8 files changed

Lines changed: 135 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
- Search: Search by name/names to allow regex match.
1010
- Studio: Enhance search to be by name, regex, or attribute query.
1111
- Studio: Refactor actions to implement base class.
12+
- Studio: Add help screen.
1213
- Test: Test for studio.
1314
### Fixed:
1415
- Query: Query method for inequality to cover cases where attribute is not present.

bigtree/tree/studio/app.py

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@
5858

5959
import bigtree.tree.studio.actions as actions
6060
import bigtree.tree.studio.utils as studio_utils
61-
from bigtree.tree.studio.details import Details
62-
from bigtree.tree.studio.prompt import Prompt
61+
from bigtree.tree.studio.screens import Details, Help, Prompt
6362
from bigtree.tree.tree import Tree as BTTree
6463
from bigtree.utils import exceptions
6564

@@ -116,25 +115,7 @@ class Studio(App): # type: ignore[misc]
116115
padding: 1;
117116
}
118117
"""
119-
120-
BINDINGS = [
121-
# space: Expand
122-
# single click: view attribute
123-
# double click: Expand
124-
("a", "add_node", "Add Child"),
125-
("A", "add_sibling", "Add Sibling"),
126-
("d", "delete_node", "Delete"),
127-
("r", "rename_node", "Rename"),
128-
("t", "edit_attr", "Edit Attribute"),
129-
("/", "search", "Search"),
130-
("n", "next_match", "Next"),
131-
("N", "prev_match", "Prev"),
132-
("e", "toggle_expand", "Expand"),
133-
("E", "expand_all", "Expand All"),
134-
("z", "collapse_all", "Collapse All"),
135-
("S", "save_as", "Save As"),
136-
("q", "quit", "Quit"),
137-
]
118+
BINDINGS = studio_utils.BINDINGS
138119

139120
def __init__(self, tree: BTTree, depth: int = 2):
140121
super().__init__()
@@ -302,6 +283,9 @@ def _save_as(self, value: Optional[str]) -> None:
302283
f"Saved to {value}", title="Save Successful", severity="information"
303284
)
304285

286+
def action_help(self) -> None:
287+
self.push_screen(Help())
288+
305289

306290
def run_app_cli() -> None:
307291
parser = argparse.ArgumentParser()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from .details import Details # noqa
2+
from .help import Help # noqa
3+
from .prompt import Prompt # noqa
4+
5+
__all__ = [
6+
"Details",
7+
"Help",
8+
"Prompt",
9+
]
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import bigtree.tree.studio.utils as studio_utils
2+
3+
try:
4+
from textual.app import ComposeResult
5+
from textual.containers import Vertical
6+
from textual.screen import ModalScreen
7+
from textual.widgets import Input, Label, Static
8+
9+
except ImportError: # pragma: no cover
10+
from unittest.mock import MagicMock
11+
12+
ComposeResult = MagicMock()
13+
Vertical = MagicMock()
14+
Static = Input = Label = MagicMock()
15+
ModalScreen = MagicMock()
16+
17+
18+
class Help(ModalScreen[str]): # type: ignore[misc]
19+
20+
CSS = """
21+
Help {
22+
align: center middle;
23+
background: $background 50%
24+
}
25+
26+
Vertical {
27+
width: 72;
28+
height: auto;
29+
padding: 1 2;
30+
background: $surface;
31+
border: round $primary;
32+
}
33+
34+
.title {
35+
text-style: bold;
36+
content-align: center middle;
37+
margin-bottom: 1;
38+
}
39+
40+
.section {
41+
text-style: bold;
42+
color: $accent;
43+
margin-top: 1;
44+
}
45+
46+
.footer {
47+
margin-top: 1;
48+
color: $text-muted;
49+
content-align: center middle;
50+
}
51+
"""
52+
53+
def compose(self) -> ComposeResult:
54+
yield Vertical(
55+
Label("Keyboard Shortcuts", classes="title"),
56+
*self._build_help(),
57+
Static("[dim]Press Esc to close[/]", classes="footer"),
58+
)
59+
60+
@staticmethod
61+
def _build_help() -> list[Static]:
62+
widgets = []
63+
64+
for section, bindings in studio_utils.HELP.items():
65+
widgets.append(Static(f"[b]{section}[/]", classes="section"))
66+
67+
lines = []
68+
for key, *description in bindings:
69+
lines.append(f"[cyan]{key:<22}[/] {description[-1]}")
70+
widgets.append(Static("\n".join(lines)))
71+
return widgets
72+
73+
def on_key(self, event: Input.Submitted) -> None:
74+
if event.key in ("escape", "question_mark"):
75+
event.stop()
76+
self.dismiss(None)

bigtree/tree/studio/utils.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,49 @@
2626
]
2727

2828

29+
# Shortcut, key binding function, footer description, help description
30+
HELP: dict[str, list[tuple[str, ...]]] = {
31+
"Navigation": [
32+
("↑ / ↓", "Move selection"),
33+
("Enter / Click", "View node attributes"),
34+
("Space / Double Click", "Expand or collapse node"),
35+
],
36+
"Editing": [
37+
("a", "add_node", "Add Child", "Add child node"),
38+
("A", "add_sibling", "Add Sibling", "Add sibling node"),
39+
("r", "rename_node", "Rename", "Rename selected node"),
40+
("d", "delete_node", "Delete", "Delete selected node"),
41+
("t", "edit_attr", "Edit Attributes", "Edit attributes"),
42+
],
43+
"Search": [
44+
("/", "search", "Search", "Search"),
45+
("n", "next_match", "Next", "Next search result"),
46+
("N", "prev_match", "Prev", "Previous search result"),
47+
],
48+
"View": [
49+
("e", "toggle_expand", "Expand", "Toggle expand"),
50+
("E", "expand_all", "Expand All", "Expand all"),
51+
("z", "collapse_all", "Collapse All", "Collapse all"),
52+
],
53+
"File": [
54+
("S", "save_as", "Save As", "Save As"),
55+
("q", "quit", "Quit", "Quit Studio"),
56+
],
57+
}
58+
59+
BINDINGS = [
60+
# enter / single click: View attribute
61+
# space / double click: Expand or collapse
62+
*(
63+
(item[0], item[1], item[2])
64+
for section, items in HELP.items()
65+
if section in ["Editing", "Search", "View", "File"]
66+
for item in items
67+
),
68+
("?", "help", "Help"),
69+
]
70+
71+
2972
SEARCH_EXAMPLES = """[b]Examples[/]
3073
[cyan]alice[/] Exact name
3174
[cyan]name:^ali.*[/] Regex name

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,8 @@ omit = [
149149
"*/tests/*",
150150
"*/workflows/*",
151151
"bigtree/tree/construct/render.py",
152+
"bigtree/tree/studio/screens/*",
152153
"bigtree/tree/studio/app.py",
153-
"bigtree/tree/studio/details.py",
154-
"bigtree/tree/studio/prompt.py",
155154
]
156155

157156
[tool.coverage.report]

0 commit comments

Comments
 (0)