diff --git a/src/loveletter_cli/session.py b/src/loveletter_cli/session.py index 7042cce..3d18617 100644 --- a/src/loveletter_cli/session.py +++ b/src/loveletter_cli/session.py @@ -9,7 +9,6 @@ import more_itertools as mitt import valid8 -from aioconsole import ainput, aprint from multimethod import multimethod import loveletter.game @@ -22,6 +21,8 @@ from loveletter_cli.exceptions import Restart from loveletter_cli.server_process import ServerProcess from loveletter_cli.ui import ( + ainput, + aprint, async_ask_valid_input, draw_game, pause, diff --git a/src/loveletter_cli/ui/input.py b/src/loveletter_cli/ui/input.py index 4414b03..e576810 100644 --- a/src/loveletter_cli/ui/input.py +++ b/src/loveletter_cli/ui/input.py @@ -1,11 +1,13 @@ import enum import functools +import os +import sys import textwrap from typing import Callable, Tuple, Type, TypeVar +import aioconsole import more_itertools import valid8 -from aioconsole import ainput, aprint from .misc import printable_width @@ -14,6 +16,41 @@ _DEFAULT = object() +# Define ainput() based on OS: if the OS uses the O_NONBLOCK flag, we have to +# clear it after every call to ainput() to ensure compatibility with blocking +# IO such as print() and input(). +if hasattr(os, "set_blocking"): + + @functools.wraps(aioconsole.ainput) + async def ainput(*args, **kwargs): + result = await aioconsole.ainput(*args, **kwargs) + os.set_blocking(sys.stdin.fileno(), True) + return result + + @functools.wraps(aioconsole.ainput) + async def aprint(*args, **kwargs): + result = await aioconsole.aprint(*args, **kwargs) + os.set_blocking(sys.stdin.fileno(), True) + return result + +else: + ainput = aioconsole.ainput + aprint = aioconsole.aprint + + +def ask_valid_input(*args, **kwargs) -> _T: + error_message, parser, prompt, validation_errors = _ask_valid_input_parse_args( + *args, **kwargs + ) + + while True: + raw_input = input(prompt) + try: + return _parse_input(raw_input, parser, error_message, validation_errors) + except (valid8.ValidationError, *validation_errors): + continue + + async def async_ask_valid_input(*args, **kwargs): """Asynchronous version of :func:`ask_valid_input`.""" error_message, parser, prompt, validation_errors = _ask_valid_input_parse_args( @@ -152,8 +189,4 @@ def _decorate_prompt(prompt: str) -> str: async def pause() -> None: - # Using ainput() instead of regular input() sometimes causes trouble: - # the user has to enter twice before input is detected; - # but the asynchronous nature is needed to ensure other events are handled in time - # (e.g. when the connection is lost). - await ainput("Enter something to continue... ") + input("Enter something to continue... ")