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
5 changes: 4 additions & 1 deletion src/textual/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,10 @@ def render_keyline(self, container: Widget) -> StripRenderable:
Returns:
A renderable to draw the keylines.
"""
width, height = container.outer_size
# Keylines and their child rectangles belong to the same geometry.
# A complete subtree capture admits offscreen boxes before those
# widgets receive resize notifications; outer_size is that older value.
width, height = container.region.size
canvas = Canvas(width, height)

line_style, keyline_color = container.styles.keyline
Expand Down
40 changes: 40 additions & 0 deletions tests/test_viewport_geometry_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,46 @@
from textual.widgets import Static


async def test_complete_markdown_capture_keeps_offscreen_table_keylines():
from textual.widgets import Markdown
from textual.widgets._markdown import MarkdownTableContent

source = "\n\n".join(
f"| key | value |\n| --- | --- |\n| TABLE_{index:02} | owned source |"
for index in range(12)
)
body = Markdown(source)

class TableScreen(Screen):
def _use_viewport_layout(self):
return True

def compose(self):
with VerticalScroll():
yield body

app = App()
async with app.run_test(size=(60, 12)) as pilot:
screen = TableScreen()
await app.push_screen(screen)
await pilot.pause()
compositor = screen._compositor
tables = list(body.query(MarkdownTableContent))
assert len(tables) == 12
assert tables[-1].outer_size.height == 0
assert tables[-1] not in compositor._published_map
_, placement = next(compositor.published_geometry((body,)))
published = compositor._full_map, compositor._visible_map
_, strips = compositor.render_subtree_strips(body, placement)
rows = [strip.text for strip in strips]
for index in range(12):
row = next(row for row in rows if f"TABLE_{index:02}" in row)
assert "│" in row, f"Offscreen table {index} lost its captured keyline"
assert compositor._full_map is published[0]
assert compositor._visible_map is published[1]
assert tables[-1].outer_size.height == 0


class TargetedScreen(Screen):
CSS = "VerticalScroll { width: 1fr; } VerticalGroup, Static { height: auto; }"
targets = ()
Expand Down
Loading