Confirm quitting with a vertical leave dialog
Choosing "quit" or pressing Esc at the top menu asked to leave through a horizontal Yes/No toggle that sat at odds with the rest of the TUI, which is select lists everywhere else. Replace it with a small select dialog in that same style: "Quit and disconnect" is the highlighted default so Enter leaves, while Esc — or choosing "Stay" — returns to the menu. select() grows optional filterable/footer_hint passthroughs so this short, fixed choice skips type-to-filter and shows a tailored "Enter quit · Esc stay" hint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
6b84281d0b
commit
ebac6c3a4f
2 files changed
+40
-5
No files matched your search
+22
-1
@@ -186,8 +186,29 @@ async def _menu_loop(ctx: AppContext, session: TuiSession) -> None:
|
||||
selection = await session.select(
|
||||
"What would you like to do?", items, default=last_selection
|
||||
)
|
||||
# Both picking "quit" and pressing Esc at the top level ask to leave; confirm on a
|
||||
# small dialog first so a stray key doesn't drop the user out of the session. Enter
|
||||
# takes the highlighted default (Quit) and leaves; Esc — or choosing "Stay" — returns
|
||||
# to the menu (select maps a cancel to None).
|
||||
if selection in (None, "__quit__"):
|
||||
return
|
||||
leave = await session.select(
|
||||
"Leave MeshTerm?",
|
||||
[
|
||||
Choice(title="Quit and disconnect", value="quit"),
|
||||
Choice(title="Stay", value="stay"),
|
||||
],
|
||||
default="quit",
|
||||
wrap=False,
|
||||
filterable=False,
|
||||
footer_hint="↑↓ move · Enter quit · Esc stay",
|
||||
)
|
||||
if leave == "quit":
|
||||
return
|
||||
# Keep the cursor on "quit" when that is what they chose, so a follow-up
|
||||
# attempt lands where they expect; a stray Esc leaves it where it was.
|
||||
if selection == "__quit__":
|
||||
last_selection = "__quit__"
|
||||
continue
|
||||
last_selection = selection
|
||||
await _run_selection(ctx, selection)
|
||||
|
||||
|
||||
@@ -146,12 +146,26 @@ class TuiSession:
|
||||
self.pop(screen)
|
||||
|
||||
async def select(
|
||||
self, title: str, items: list, *, default: Any = None, wrap: bool = True
|
||||
self,
|
||||
title: str,
|
||||
items: list,
|
||||
*,
|
||||
default: Any = None,
|
||||
wrap: bool = True,
|
||||
filterable: bool = True,
|
||||
footer_hint: Optional[str] = None,
|
||||
) -> Any:
|
||||
"""Show a select screen; return the chosen value or ``None`` if cancelled."""
|
||||
result = await self.run_screen(
|
||||
SelectScreen(title, items, default=default, wrap=wrap)
|
||||
"""Show a select screen; return the chosen value or ``None`` if cancelled.
|
||||
|
||||
``filterable`` and ``footer_hint`` are forwarded to the screen for short, fixed
|
||||
lists (a yes-or-no style choice) that want no type-to-filter and a tailored hint.
|
||||
"""
|
||||
screen = (
|
||||
SelectScreen(title, items, default=default, wrap=wrap, filterable=filterable, footer_hint=footer_hint)
|
||||
if footer_hint is not None
|
||||
else SelectScreen(title, items, default=default, wrap=wrap, filterable=filterable)
|
||||
)
|
||||
result = await self.run_screen(screen)
|
||||
return None if result is CANCEL else result
|
||||
|
||||
async def select_startup(
|
||||
|
||||
Reference in new issue
Block a user