diff --git a/src/textual/drivers/linux_inline_driver.py b/src/textual/drivers/linux_inline_driver.py index 39bfdf77eb..783fdaf26d 100644 --- a/src/textual/drivers/linux_inline_driver.py +++ b/src/textual/drivers/linux_inline_driver.py @@ -14,6 +14,8 @@ import rich.repr from textual import events +from textual._loop import loop_last +from textual._parser import ParseError from textual._xterm_parser import XTermParser from textual.driver import Driver from textual.geometry import Size @@ -132,23 +134,47 @@ def run_input_thread(self) -> None: decode = utf8_decoder read = os.read + def process_selector_events( + selector_events: list[tuple[selectors.SelectorKey, int]], + final: bool = False, + ) -> None: + """Process events from selector. + + Args: + selector_events: List of selector events. + final: True if this is the last call. + + """ + for last, (_selector_key, mask) in loop_last(selector_events): + if mask & EVENT_READ: + unicode_data = decode(read(fileno, 1024 * 4), final=final and last) + if not unicode_data: + # This can occur if the stdin is piped + break + for event in feed(unicode_data): + if isinstance(event, events.CursorPosition): + self.cursor_origin = (event.x, event.y) + else: + self.process_event(event) + for event in tick(): + if isinstance(event, events.CursorPosition): + self.cursor_origin = (event.x, event.y) + else: + self.process_event(event) + self.process_event(event) + try: while not self.exit_event.is_set(): - selector_events = selector.select(0.1) - for event in tick(): - self.process_event(event) - for _selector_key, mask in selector_events: - if mask & EVENT_READ: - unicode_data = decode( - read(fileno, 1024), final=self.exit_event.is_set() - ) - for event in feed(unicode_data): - if isinstance(event, events.CursorPosition): - self.cursor_origin = (event.x, event.y) - else: - self.process_event(event) + process_selector_events(selector.select(0.1)) + process_selector_events(selector.select(0.1), final=True) + finally: selector.close() + try: + for event in feed(""): + pass + except ParseError: + pass def start_application_mode(self) -> None: loop = asyncio.get_running_loop()