Skip to content

Fix TextArea scrollbar initial wrap flicker (#5103)#6499

Draft
glaziermag wants to merge 1 commit intoTextualize:mainfrom
glaziermag:fix/issue-5103-layout-flicker
Draft

Fix TextArea scrollbar initial wrap flicker (#5103)#6499
glaziermag wants to merge 1 commit intoTextualize:mainfrom
glaziermag:fix/issue-5103-layout-flicker

Conversation

@glaziermag
Copy link
Copy Markdown

Fix TextArea scrollbar initial wrap flicker (#5103)

This commit forces an internal geometry double-pass exclusively during _rewrap_and_refresh_virtual_size if the wrap calculation triggers an appearance/disappearance of the scrollbar dynamically. This mathematically sets the width before flushing the virtual DOM to the visual layer, preventing the flicker loop reported in #5103.

The Epistemic Before vs After Logs

Input Command:

$ python3 scratch/test_layout.py

Before Logs:
Notice how the layout unpredictably triggers events during resize pushing to an async queue and bouncing between 15 and 13.

=== HEADLESS RENDER OUTCOME ===
REWRAP: width=0, v_scroll=False, size=Size(width=0, height=0), scroll_region=Size(width=0, height=0)
REWRAP: width=15, v_scroll=False, size=Size(width=16, height=3), scroll_region=Size(width=16, height=3)
  File "/Users/gabe/textual/src/textual/widgets/_text_area.py", line 1085, in _on_resize
    self._rewrap_and_refresh_virtual_size()

REWRAP: width=13, v_scroll=True, size=Size(width=16, height=3), scroll_region=Size(width=14, height=3)
  File "/Users/gabe/textual/src/textual/reactive.py", line 355, in _set
  File "/Users/gabe/textual/src/textual/widgets/_text_area.py", line 861, in _watch_show_vertical_scrollbar
    self._rewrap_and_refresh_virtual_size()

After Logs:
The geometry natively stabilizes in memory perfectly inside the bounding box before being rendered.

=== HEADLESS RENDER OUTCOME ===
Container Size: Size(width=16, height=3)
Scrollable Content Region Size: Size(width=14, height=3)
Computed wrap_width: 13
Scrollables: vertical=True, horizontal=False
Wrapped lines total: 12
  Line 0: length=13 'XXXXXXXXXXXXX'

302 Pytest assertions passed locally in 33.49s ensuring no downstream caching regressions.

This commit forces an internal geometry double-pass exclusively during
_rewrap_and_refresh_virtual_size if the wrap calculation triggers an
appearance/disappearance of the scrollbar, mathematical locking the
width instead of allowing an async render flush flicker.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant