From 91fd7126465058952ee6f894127522341fe7ce09 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 23 Sep 2024 19:12:26 +0100 Subject: [PATCH 1/3] fix error exiting inline mode --- src/textual/drivers/linux_driver.py | 1 + src/textual/drivers/linux_inline_driver.py | 8 ++++++-- src/textual/screen.py | 2 +- src/textual/widgets/_directory_tree.py | 1 + src/textual/widgets/_tree.py | 2 ++ 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/textual/drivers/linux_driver.py b/src/textual/drivers/linux_driver.py index 0456e9b764..40c35f6bc7 100644 --- a/src/textual/drivers/linux_driver.py +++ b/src/textual/drivers/linux_driver.py @@ -408,6 +408,7 @@ def process_selector_events( try: while not self.exit_event.is_set(): process_selector_events(selector.select(0.1)) + selector.unregister(self.fileno) process_selector_events(selector.select(0.1), final=True) finally: diff --git a/src/textual/drivers/linux_inline_driver.py b/src/textual/drivers/linux_inline_driver.py index c12eb3219f..8c4ebdc64b 100644 --- a/src/textual/drivers/linux_inline_driver.py +++ b/src/textual/drivers/linux_inline_driver.py @@ -161,11 +161,11 @@ def process_selector_events( self.cursor_origin = (event.x, event.y) else: self.process_event(event) - self.process_event(event) try: while not self.exit_event.is_set(): process_selector_events(selector.select(0.1)) + selector.unregister(self.fileno) process_selector_events(selector.select(0.1), final=True) finally: @@ -296,7 +296,10 @@ def disable_input(self) -> None: if self._key_thread is not None: self._key_thread.join() self.exit_event.clear() - termios.tcflush(self.fileno, termios.TCIFLUSH) + try: + termios.tcflush(self.fileno, termios.TCIFLUSH) + except termios.error: + pass except Exception as error: # TODO: log this @@ -312,6 +315,7 @@ def stop_application_mode(self) -> None: self.disable_input() self.write("\x1b[ RenderableType: background = self.styles.background try: base_screen = visible_screen_stack.get().pop() - except IndexError: + except LookupError: base_screen = None if base_screen is not None and background.a < 1: diff --git a/src/textual/widgets/_directory_tree.py b/src/textual/widgets/_directory_tree.py index f122f8186f..28bd0501e6 100644 --- a/src/textual/widgets/_directory_tree.py +++ b/src/textual/widgets/_directory_tree.py @@ -35,6 +35,7 @@ class DirectoryTree(Tree[DirEntry]): ICON_NODE_EXPANDED = "📂 " ICON_NODE = "📁 " ICON_FILE = "📄 " + """Unicode 'icon' to represent a file.""" COMPONENT_CLASSES: ClassVar[set[str]] = { "directory-tree--extension", diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index 5182fd39f9..210d193d28 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -517,7 +517,9 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True): """A widget for displaying and navigating data in a tree.""" ICON_NODE = "▶ " + """Unicode 'icon' to use for an expandable node.""" ICON_NODE_EXPANDED = "▼ " + """Unicode 'icon' to use for an expanded node.""" BINDINGS: ClassVar[list[BindingType]] = [ Binding("shift+left", "cursor_parent", "Cursor to parent", show=False), From 7536d6a754c5403991dd77176edf9b24b55cf5c6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 24 Sep 2024 11:16:05 +0100 Subject: [PATCH 2/3] tests --- src/textual/drivers/linux_inline_driver.py | 1 - tests/test_app.py | 35 +++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/textual/drivers/linux_inline_driver.py b/src/textual/drivers/linux_inline_driver.py index 8c4ebdc64b..22bb349505 100644 --- a/src/textual/drivers/linux_inline_driver.py +++ b/src/textual/drivers/linux_inline_driver.py @@ -315,7 +315,6 @@ def stop_application_mode(self) -> None: self.disable_input() self.write("\x1b[ None: + # Exit after creating app + self.exit() + + app = AppExit() + async with app.run_test(): + pass + + +def test_early_exit_inline(): + """Test exiting early in inline mode doesn't break.""" + from textual.app import App + + class AppExit(App): + def compose(self): + yield Static("Hello") + + def on_mount(self) -> None: + # Exit after creating app + self.exit() + + app = AppExit() + app.run(inline=True, inline_no_clear=True) From 8212f4c18d834f5f026b0806afb3cc61b934bdb7 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 24 Sep 2024 11:20:08 +0100 Subject: [PATCH 3/3] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13b83925f6..556c442ea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased + +### Fixed + +- Fixed crash when exiting the app prematurely https://github.com/Textualize/textual/pull/5039 + ## [0.80.0] - 2024-09-23 ### Added