From 4938f252452ccb153eab6a92f9f05f7e20ade178 Mon Sep 17 00:00:00 2001 From: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:24:55 -0700 Subject: [PATCH] Implement input flushing to prevent type-ahead issues in prompts --- src/clabe/ui/questionary_ui_helper.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/clabe/ui/questionary_ui_helper.py b/src/clabe/ui/questionary_ui_helper.py index e8ce2a79..8126a8ad 100644 --- a/src/clabe/ui/questionary_ui_helper.py +++ b/src/clabe/ui/questionary_ui_helper.py @@ -1,5 +1,6 @@ import asyncio import logging +import sys from typing import List, Optional import questionary @@ -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. @@ -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") @@ -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))