From f8991ce3c8ed33c5fb618d7370f60030027600ff Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 26 Jan 2023 21:14:21 +0530 Subject: [PATCH] ask kitten: Get readline to work even when stdout is redirected --- kittens/ask/main.py | 26 +++++++++++++++++--------- kittens/tui/operations.py | 17 +++++++++-------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/kittens/ask/main.py b/kittens/ask/main.py index 05d129548..df12b1e8a 100644 --- a/kittens/ask/main.py +++ b/kittens/ask/main.py @@ -495,16 +495,20 @@ def main(args: List[str]) -> Response: loop.loop(phandler) return {'items': items, 'response': phandler.response} - import readline as rl - readline = rl - init_readline() - response = None + orig_stdout = os.dup(sys.stdout.fileno()) + try: + with open(os.ctermid(), 'r') as tty: + os.dup2(tty.fileno(), sys.stdin.fileno()) + with open(os.ctermid(), 'w') as tty: + os.dup2(tty.fileno(), sys.stdout.fileno()) + import readline as rl + readline = rl + init_readline() + response = None - with alternate_screen(), HistoryCompleter(cli_opts.name): - if cli_opts.message: - print(styled(cli_opts.message, bold=True)) - - with suppress(KeyboardInterrupt, EOFError): + with alternate_screen(), HistoryCompleter(cli_opts.name), suppress(KeyboardInterrupt, EOFError): + if cli_opts.message: + print(styled(cli_opts.message, bold=True)) if cli_opts.default: def prefill_text() -> None: readline.insert_text(cli_opts.default or '') @@ -514,6 +518,10 @@ def main(args: List[str]) -> Response: readline.set_pre_input_hook() else: response = input(prompt) + sys.stdout.flush() + os.dup2(orig_stdout, sys.stdout.fileno()) + finally: + os.close(orig_stdout) return {'items': items, 'response': response} diff --git a/kittens/tui/operations.py b/kittens/tui/operations.py index 00b740991..e3b5ed42d 100644 --- a/kittens/tui/operations.py +++ b/kittens/tui/operations.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 # License: GPL v3 Copyright: 2018, Kovid Goyal +import os import sys from contextlib import contextmanager from enum import Enum, auto from functools import wraps -from typing import IO, Any, Callable, Dict, Generator, Optional, TypeVar, Union +from typing import Any, Callable, Dict, Generator, Optional, TypeVar, Union from kitty.fast_data_types import Color from kitty.rgb import color_as_sharp, to_color @@ -348,13 +349,13 @@ def cursor(write: Callable[[str], None]) -> Generator[None, None, None]: @contextmanager -def alternate_screen(f: Optional[IO[str]] = None) -> Generator[None, None, None]: - f = f or sys.stdout - print(set_mode(Mode.ALTERNATE_SCREEN), end='', file=f) - try: - yield - finally: - print(reset_mode(Mode.ALTERNATE_SCREEN), end='', file=f) +def alternate_screen() -> Generator[None, None, None]: + with open(os.ctermid(), 'w') as f: + print(set_mode(Mode.ALTERNATE_SCREEN), end='', file=f, flush=True) + try: + yield + finally: + print(reset_mode(Mode.ALTERNATE_SCREEN), end='', file=f, flush=True) @contextmanager