Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-textual for openSUSE:Factory checked in at 2026-04-18 21:35:17 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-textual (Old) and /work/SRC/openSUSE:Factory/.python-textual.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-textual" Sat Apr 18 21:35:17 2026 rev:9 rq:1347831 version:8.2.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-textual/python-textual.changes 2026-03-30 18:34:37.315392832 +0200 +++ /work/SRC/openSUSE:Factory/.python-textual.new.11940/python-textual.changes 2026-04-18 21:35:27.611326621 +0200 @@ -1,0 +2,7 @@ +Thu Apr 16 13:07:57 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 8.2.2 + * Reduce lag when resizing window, by moving resize from + idle to a timer + +------------------------------------------------------------------- Old: ---- textual-8.2.1.tar.gz New: ---- textual-8.2.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-textual.spec ++++++ --- /var/tmp/diff_new_pack.DpFIoP/_old 2026-04-18 21:35:28.311355151 +0200 +++ /var/tmp/diff_new_pack.DpFIoP/_new 2026-04-18 21:35:28.311355151 +0200 @@ -26,7 +26,7 @@ %endif %{?sle15_python_module_pythons} Name: python-textual%{psuffix} -Version: 8.2.1 +Version: 8.2.3 Release: 0 Summary: TUI framework for Python License: MIT ++++++ textual-8.2.1.tar.gz -> textual-8.2.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/PKG-INFO new/textual-8.2.3/PKG-INFO --- old/textual-8.2.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: textual -Version: 8.2.1 +Version: 8.2.3 Summary: Modern Text User Interface framework License: MIT License-File: LICENSE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/pyproject.toml new/textual-8.2.3/pyproject.toml --- old/textual-8.2.1/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ [tool.poetry] name = "textual" -version = "8.2.1" +version = "8.2.3" homepage = "https://github.com/Textualize/textual" repository = "https://github.com/Textualize/textual" documentation = "https://textual.textualize.io/" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/src/textual/app.py new/textual-8.2.3/src/textual/app.py --- old/textual-8.2.1/src/textual/app.py 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/src/textual/app.py 1970-01-01 01:00:00.000000000 +0100 @@ -876,6 +876,9 @@ ) ) + self._resize_timer: Timer | None = None + """Timer used to invoke screen resize.""" + def get_line_filters(self) -> Sequence[LineFilter]: """Get currently enabled line filters. @@ -1630,6 +1633,8 @@ width, height = self._driver._size else: width, height = self.console.size + if self._driver is not None: + self._driver._size = (width, height) return Size(width, height) @property @@ -4308,8 +4313,16 @@ async def _on_resize(self, event: events.Resize) -> None: event.stop() - self._size = event.size self._resize_event = event + if self._size is None: + self._size = event.size + self._check_resize() + return + if self._size == event.size: + return + self._size = event.size + if self._resize_timer is None: + self._resize_timer = self.set_timer(1 / 120, self._check_resize) async def _on_app_focus(self, event: events.AppFocus) -> None: """App has focus.""" @@ -4976,9 +4989,20 @@ self.log.debug(message) def _on_idle(self) -> None: - """Send app resize events on idle, so we don't do more resizing that necessary.""" + if self._resize_event is not None and self._resize_timer is None: + self._check_resize() + + def _check_resize(self) -> None: + """Send a resize event to screen(s) (invoked from `self._resize_timer`).""" event = self._resize_event + if self._resize_timer is not None: + self._resize_timer.stop() + self._resize_timer = None if event is not None: + try: + self.screen + except ScreenError: + return self._resize_event = None self.screen.post_message(event) for screen in self._background_screens: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/src/textual/dom.py new/textual-8.2.3/src/textual/dom.py --- old/textual-8.2.1/src/textual/dom.py 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/src/textual/dom.py 1970-01-01 01:00:00.000000000 +0100 @@ -125,8 +125,9 @@ else: class_names = set(classes) check_identifiers("class name", *class_names) - obj._classes = class_names - obj.update_node_styles() + if obj._classes != class_names: + obj._classes = class_names + obj.update_node_styles() @rich.repr.auto @@ -1795,10 +1796,9 @@ Self. """ check_identifiers("class name", *class_names) - old_classes = self._classes.copy() - self._classes.update(class_names) - if old_classes == self._classes: + if self._classes.issuperset(class_names): return self + self._classes.update(class_names) if update: self.update_node_styles() return self @@ -1814,10 +1814,9 @@ Self. """ check_identifiers("class name", *class_names) - old_classes = self._classes.copy() - self._classes.difference_update(class_names) - if old_classes == self._classes: + if self._classes.isdisjoint(class_names): return self + self._classes.difference_update(class_names) if update: self.update_node_styles() return self diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/src/textual/drivers/linux_driver.py new/textual-8.2.3/src/textual/drivers/linux_driver.py --- old/textual-8.2.1/src/textual/drivers/linux_driver.py 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/src/textual/drivers/linux_driver.py 1970-01-01 01:00:00.000000000 +0100 @@ -241,6 +241,7 @@ send_size_event() signal.signal(signal.SIGWINCH, on_terminal_resize) + send_size_event() self.write("\x1b[?1049h") # Alt screen @@ -277,7 +278,7 @@ self.flush() self._key_thread = Thread(target=self._run_input_thread, name="textual-input") - send_size_event() + self._key_thread.start() self._request_terminal_sync_mode_support() self._query_in_band_window_resize() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/src/textual/screen.py new/textual-8.2.3/src/textual/screen.py --- old/textual-8.2.1/src/textual/screen.py 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/src/textual/screen.py 1970-01-01 01:00:00.000000000 +0100 @@ -1528,27 +1528,52 @@ ) or [] width, height = event.size - if horizontal_breakpoints: - self._set_breakpoints(width, horizontal_breakpoints) - if vertical_breakpoints: - self._set_breakpoints(height, vertical_breakpoints) - def _set_breakpoints( + if horizontal_breakpoints or vertical_breakpoints: + + remove_breakpoint_classes = { + breakpoint for _, breakpoint in horizontal_breakpoints + } | {breakpoint for _, breakpoint in vertical_breakpoints} + remove_breakpoint_classes = self._classes.intersection( + remove_breakpoint_classes + ) + + breakpoint_classes: set[str] = set() + + if horizontal_breakpoints: + breakpoint_classes |= self._get_breakpoint_classes( + width, horizontal_breakpoints + ) + if vertical_breakpoints: + breakpoint_classes |= self._get_breakpoint_classes( + height, vertical_breakpoints + ) + + remove_breakpoint_classes -= breakpoint_classes + classes = self._classes.copy() + if remove_breakpoint_classes: + self._classes.difference_update(remove_breakpoint_classes) + if breakpoint_classes: + self._classes.update(breakpoint_classes) + if self._classes != classes: + self.update_node_styles(animate=False) + + def _get_breakpoint_classes( self, dimension: int, breakpoints: list[tuple[int, str]] - ) -> None: - """Set horizontal or vertical breakpoints. + ) -> set[str]: + """Get breakpoint classes for given dimension. Args: - dimension: Either the width or the height. - breakpoints: A list of breakpoints. + dimension: Size in cells. + breakpoints: Associated breakpoints. + Returns: + A set containing a breakpoint, or an empty set if none apply. """ - class_names = [class_name for _breakpoint, class_name in breakpoints] - self.remove_class(*class_names) for breakpoint, class_name in sorted(breakpoints, reverse=True): if dimension >= breakpoint: - self.add_class(class_name) - return + return {class_name} + return set() def _update_tooltip(self, widget: Widget) -> None: """Update the content of the tooltip.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/textual-8.2.1/src/textual/selection.py new/textual-8.2.3/src/textual/selection.py --- old/textual-8.2.1/src/textual/selection.py 1970-01-01 01:00:00.000000000 +0100 +++ new/textual-8.2.3/src/textual/selection.py 1970-01-01 01:00:00.000000000 +0100 @@ -40,10 +40,10 @@ if not lines: return "" if self.start is None: - start_line = 0 + start_line_index = 0 start_offset = 0 else: - start_line, start_offset = self.start.transpose + start_line_index, start_offset = self.start.transpose if self.end is None: end_line = len(lines) @@ -52,18 +52,21 @@ end_line, end_offset = self.end.transpose end_line = min(len(lines), end_line) - if start_line == end_line: - return lines[start_line][start_offset:end_offset] + if start_line_index == end_line: + return lines[start_line_index][start_offset:end_offset] selection: list[str] = [] - selected_lines = lines[start_line : end_line + 1] + selected_lines = lines[start_line_index : end_line + 1] if len(selected_lines) >= 2: first_line, *mid_lines, last_line = selected_lines selection.append(first_line[start_offset:]) selection.extend(mid_lines) selection.append(last_line[:end_offset]) else: - return lines[start_line][start_offset:end_offset] + try: + selection.append(lines[start_line_index][start_offset:end_offset]) + except IndexError: + pass return "\n".join(selection) def get_span(self, y: int) -> tuple[int, int] | None:
