Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ 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

### Changed

- Optimized startup https://github.com/Textualize/textual/pull/5869
- New blank visual which makes background faster to render (note this will break snapshots tests this version) https://github.com/Textualize/textual/pull/5869

## [3.4.0] - 2025-06-14

### Fixed
Expand Down
535 changes: 224 additions & 311 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ tree-sitter-yaml = { version = ">=0.6.0", optional = true, python = ">=3.9" }
tree-sitter-html = { version = ">=0.23.0", optional = true, python = ">=3.9" }
tree-sitter-css = { version = ">=0.23.0", optional = true, python = ">=3.9" }
tree-sitter-javascript = { version = ">=0.23.0", optional = true, python = ">=3.9" }
tree-sitter-rust = { version = ">=0.23.0", optional = true, python = ">=3.9" }
tree-sitter-rust = { version = ">=0.23.0,<=0.23.2", optional = true, python = ">=3.9" }
tree-sitter-go = { version = ">=0.23.0", optional = true, python = ">=3.9" }
tree-sitter-regex = { version = ">=0.24.0", optional = true, python = ">=3.9" }
tree-sitter-xml = { version = ">=0.7.0", optional = true, python = ">=3.9" }
Expand Down
4 changes: 2 additions & 2 deletions src/textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,8 +791,8 @@ def __init__(
perform work after the app has resumed.
"""

self.set_class(self.current_theme.dark, "-dark-mode")
self.set_class(not self.current_theme.dark, "-light-mode")
self.set_class(self.current_theme.dark, "-dark-mode", update=False)
self.set_class(not self.current_theme.dark, "-light-mode", update=False)

self.animation_level: AnimationLevel = constants.TEXTUAL_ANIMATIONS
"""Determines what type of animations the app will display.
Expand Down
6 changes: 4 additions & 2 deletions src/textual/dom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1684,9 +1684,9 @@ def set_class(self, add: bool, *class_names: str, update: bool = True) -> Self:
Self.
"""
if add:
self.add_class(*class_names, update=update and self.is_attached)
self.add_class(*class_names, update=update)
else:
self.remove_class(*class_names, update=update and self.is_attached)
self.remove_class(*class_names, update=update)
return self

def set_classes(self, classes: str | Iterable[str]) -> Self:
Expand All @@ -1707,6 +1707,8 @@ def _update_styles(self) -> None:

Should be called whenever CSS classes / pseudo classes change.
"""
if not self.is_attached:
return
try:
self.app.update_styles(self)
except NoActiveAppError:
Expand Down
48 changes: 30 additions & 18 deletions src/textual/renderables/blank.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
from __future__ import annotations

from rich.console import Console, ConsoleOptions, RenderResult
from rich.segment import Segment
from rich.style import Style
from rich.style import Style as RichStyle

from textual.color import Color
from textual.content import Style
from textual.css.styles import RulesMap
from textual.selection import Selection
from textual.strip import Strip
from textual.visual import Visual


class Blank:
class Blank(Visual):
"""Draw solid background color."""

def __init__(self, color: Color | str = "transparent") -> None:
background = Color.parse(color)
self._style = Style.from_color(bgcolor=background.rich_color)

def __rich_console__(
self, console: Console, options: ConsoleOptions
) -> RenderResult:
width = options.max_width
height = options.height or options.max_height

segment = Segment(" " * width, self._style)
line = Segment.line()
for _ in range(height):
yield segment
yield line
self._rich_style = RichStyle.from_color(bgcolor=Color.parse(color).rich_color)

def visualize(self) -> Blank:
return self

def get_optimal_width(self, rules: RulesMap, container_width: int) -> int:
return container_width

def get_height(self, rules: RulesMap, width: int) -> int:
return 1

def render_strips(
self,
rules: RulesMap,
width: int,
height: int | None,
style: Style,
selection: Selection | None = None,
selection_style: Style | None = None,
post_style: Style | None = None,
) -> list[Strip]:
line_count = 1 if height is None else height
return [Strip.blank(width, self._rich_style)] * line_count
13 changes: 8 additions & 5 deletions src/textual/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1318,14 +1318,16 @@ def _get_inline_height(self, size: Size) -> int:

def _screen_resized(self, size: Size) -> None:
"""Called by App when the screen is resized."""
if self.stack_updates:
if self.stack_updates and self.is_attached:
self._refresh_layout(size)

def _on_screen_resume(self) -> None:
"""Screen has resumed."""
if self.app.SUSPENDED_SCREEN_CLASS:
self.remove_class(self.app.SUSPENDED_SCREEN_CLASS)

self.stack_updates += 1

self.app._refresh_notifications()
size = self.app.size

Expand All @@ -1340,10 +1342,11 @@ def _on_screen_resume(self) -> None:
self.set_focus(widget)
break

self._compositor_refresh()
self.app.stylesheet.update(self)
self._refresh_layout(size)
self.refresh()
if self.is_attached:
self._compositor_refresh()
self.app.stylesheet.update(self)
self._refresh_layout(size)
self.refresh()

def _on_screen_suspend(self) -> None:
"""Screen has suspended."""
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading