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
23 changes: 23 additions & 0 deletions src/clabe/ui/questionary_ui_helper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import logging
import sys
from typing import List, Optional

import questionary
Expand All @@ -25,6 +26,23 @@
)


def _flush_input() -> None:
"""Discard any characters already queued in the stdin buffer.

Prevents type-ahead from a previous prompt being passed straight to the
next one when there is processing work between prompts.
"""
if sys.platform == "win32":
import msvcrt

while msvcrt.kbhit():
msvcrt.getwch()
else:
import termios

termios.tcflush(sys.stdin, termios.TCIFLUSH)


def _ask_sync(question: questionary.Question):
# TODO: We should just implement an async version of the UIHelper and avoid this complexity.
"""Ask question, handling both sync and async contexts.
Expand Down Expand Up @@ -67,10 +85,12 @@ def print(self, message: str) -> None:

def input(self, prompt: str) -> str:
"""Prompts the user for input with custom styling."""
_flush_input()
return _ask_sync(questionary.text(prompt, style=self.style)) or ""

def prompt_pick_from_list(self, value: List[str], prompt: str, **kwargs) -> Optional[str]:
"""Interactive list selection with visual highlighting using arrow keys or number shortcuts."""
_flush_input()
allow_0_as_none = kwargs.get("allow_0_as_none", True)
zero_label = kwargs.get("zero_label", "None")

Expand Down Expand Up @@ -102,14 +122,17 @@ def prompt_pick_from_list(self, value: List[str], prompt: str, **kwargs) -> Opti

def prompt_yes_no_question(self, prompt: str) -> bool:
"""Prompts the user with a yes/no question using custom styling."""
_flush_input()
return _ask_sync(questionary.confirm(prompt, style=self.style)) or False

def prompt_text(self, prompt: str) -> str:
"""Prompts the user for generic text input using custom styling."""
_flush_input()
return _ask_sync(questionary.text(prompt, style=self.style)) or ""

def prompt_float(self, prompt: str) -> float:
"""Prompts the user for a float input using custom styling."""
_flush_input()
while True:
try:
value_str = _ask_sync(questionary.text(prompt, style=self.style))
Expand Down
Loading