diff --git a/evidence/native-scene-transition-owner-20261005/SCOPE.md b/evidence/native-scene-transition-owner-20261005/SCOPE.md new file mode 100644 index 0000000000..9f7dac5574 --- /dev/null +++ b/evidence/native-scene-transition-owner-20261005/SCOPE.md @@ -0,0 +1,40 @@ +# Use the original scene and size owners for frame transitions + +Base: merged native70 c5e7eba344bd2982f30338e8acd18210e19de2ac. +Same completed native checkout; Text70/68/69 source proofs and wheels retained. + +Source finding: reflow_visible substitutes an empty predecessor when the last +committed scene is a full map. Its damage comparison then treats the root and +unchanged chrome as new. Full reflow after scrolling also uses the old full map +for damage instead of the latest viewport scene. These are source-supported +wrong predecessor choices, not attribution of the original RichVisual sample +or a measured CPU/FPS improvement. + +Compositor owns the existing published scene map. Make that acquisition carry +reflow, visible reflow, lazy full geometry publication and layer projection; +delete their independent predecessor choices. Keep logical show/hide membership +and conservative viewport exposure separate: a complete geometry query does +not prove that every widget has consumed native size publication. Capture +geometry and current-placement validity retain their existing contracts. + +Widget._size_updated already owns size, virtual extent and container changes +and explicitly returns whether a Resize event should be sent. Screen must use +that result instead of the parallel region-size-only ReflowResult.resized set. +Delete the set, field, comparison and every consumer. ScrollView keeps its +independently authored virtual extent and container projection but reuses the +existing Widget size commit; its original scrollbar resource retirement stays +with its existing scrollbar update behavior. No change to the size-hook ABI or +Toad Body/Window callbacks. + +AST and complete declaration/caller/lifetime reading precede edits. Preserve +native show/hide order, viewport geometry targets, stable paint ties, authored +scroll extents, scrollbar feedback, capture and lazy-layout semantics. No new +map/cache/type/state flag, caller-built readiness predicate or alternate paint +path. Native Compositor/Screen/ScrollView only; no Toad writes. + +Batch source and affected native App checks after the coherent implementation. +Existing Heisenberg workflow owns the next meaningful changed installed frame +and motion qualification; no repeat of native70/68/69 controls, provider, +recording, environment, installed package or native SDK build. Source-only +until those boundaries are qualified. CI is deferred; results are recorded +without adding a delivery wait. diff --git a/evidence/native-scene-transition-owner-20261005/before.json b/evidence/native-scene-transition-owner-20261005/before.json new file mode 100644 index 0000000000..54cb7b90c3 --- /dev/null +++ b/evidence/native-scene-transition-owner-20261005/before.json @@ -0,0 +1,2137 @@ +{ + "roots": [ + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "head": "c78c5b4ba63bb81e14be17389c01a2e7710bf659", + "root": "src/textual", + "parsed": 249, + "omitted": [] + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "head": "c78c5b4ba63bb81e14be17389c01a2e7710bf659", + "root": "tests", + "parsed": 460, + "omitted": [] + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "head": "6d46e34233851971840df8278e8613c2b46e0c1e", + "root": "src/toad", + "parsed": 288, + "omitted": [] + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "head": "6d46e34233851971840df8278e8613c2b46e0c1e", + "root": "tests", + "parsed": 397, + "omitted": [] + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "head": "6d46e34233851971840df8278e8613c2b46e0c1e", + "root": "tools", + "parsed": 41, + "omitted": [] + }, + { + "repository": "/home/ts/wt/comms-cleanup-live-integration-20260929", + "head": "88d4b8e90185de84b523a49f14c179c0a1e91f35", + "root": "src/agent_comms", + "parsed": 324, + "omitted": [] + } + ], + "sites": [ + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 56, + "node": "ClassDef", + "name": "ReflowResult", + "source": "class ReflowResult(NamedTuple):" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 668, + "node": "FunctionDef", + "name": "reflow", + "source": " def reflow(" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 725, + "node": "FunctionDef", + "name": "reflow_visible", + "source": " def reflow_visible(" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 762, + "node": "FunctionDef", + "name": "_damage_geometry", + "source": " def _damage_geometry(" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1374, + "node": "FunctionDef", + "name": "_get_geometry", + "source": " def _get_geometry(self, widget: Widget) -> MapGeometry | None:" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1393, + "node": "FunctionDef", + "name": "_get_published_geometry", + "source": " def _get_published_geometry(self, widget: Widget) -> MapGeometry | None:" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1408, + "node": "FunctionDef", + "name": "_using_geometry", + "source": " def _using_geometry(self, root: Widget, geometry: CompositorMap) -> Iterator[None]:" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1613, + "node": "FunctionDef", + "name": "published_geometry", + "source": " def published_geometry(" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 61, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 671, + "node": "Name", + "name": "ReflowResult", + "source": "ReflowResult" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 539, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 540, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 545, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 592, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 593, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 687, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 712, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 741, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 752, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 772, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 791, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 811, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 613, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 613, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 623, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 685, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 685, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 709, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 711, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 718, + "node": "Attribute", + "name": "_damage_geometry", + "source": "self._damage_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 719, + "node": "Name", + "name": "ReflowResult", + "source": "ReflowResult" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 746, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 758, + "node": "Attribute", + "name": "_damage_geometry", + "source": "self._damage_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 799, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 806, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 807, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 808, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1185, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1185, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1367, + "node": "Attribute", + "name": "_get_geometry", + "source": "self._get_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1391, + "node": "Attribute", + "name": "_get_published_geometry", + "source": "self._get_published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1397, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1401, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1747, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 591, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 804, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 804, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 805, + "node": "Attribute", + "name": "_damage_geometry", + "source": "self._damage_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1185, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1625, + "node": "Attribute", + "name": "_get_published_geometry", + "source": "self._get_published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1646, + "node": "Attribute", + "name": "_using_geometry", + "source": "self._using_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1744, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "self._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 685, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 804, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1202, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1202, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1398, + "node": "Attribute", + "name": "_full_map", + "source": "self._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 1402, + "node": "Attribute", + "name": "_visible_map", + "source": "self._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/_compositor.py", + "line": 780, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1371, + "node": "Attribute", + "name": "reflow_visible", + "source": "self._compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1411, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1398, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1398, + "node": "Attribute", + "name": "reflow", + "source": "self._compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1402, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1402, + "node": "Attribute", + "name": "reflow", + "source": "self._compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1423, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/screen.py", + "line": 1386, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/scroll_view.py", + "line": 86, + "node": "FunctionDef", + "name": "_size_updated", + "source": " def _size_updated(" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/scroll_view.py", + "line": 111, + "node": "Attribute", + "name": "_scroll_update", + "source": "self._scroll_update" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/scroll_view.py", + "line": 107, + "node": "Attribute", + "name": "_scrollbar_changes", + "source": "self._scrollbar_changes" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 4348, + "node": "FunctionDef", + "name": "_size_updated", + "source": " def _size_updated(" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 4393, + "node": "FunctionDef", + "name": "_scroll_update", + "source": " def _scroll_update(self, virtual_size: Size) -> None:" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 552, + "node": "Attribute", + "name": "_scrollbar_changes", + "source": "self._scrollbar_changes" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 2313, + "node": "Attribute", + "name": "_scrollbar_changes", + "source": "self._scrollbar_changes" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 2329, + "node": "Attribute", + "name": "_scrollbar_changes", + "source": "self._scrollbar_changes" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 2331, + "node": "Attribute", + "name": "_scrollbar_changes", + "source": "self._scrollbar_changes" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widget.py", + "line": 4388, + "node": "Attribute", + "name": "_scroll_update", + "source": "self._scroll_update" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "src/textual", + "path": "src/textual/widgets/_option_list.py", + "line": 838, + "node": "Attribute", + "name": "_scroll_update", + "source": "self._scroll_update" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/frame_damage_installed_pilot.py", + "line": 15, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 160, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 193, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 204, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 157, + "node": "Attribute", + "name": "reflow_visible", + "source": "compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 161, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 190, + "node": "Attribute", + "name": "reflow_visible", + "source": "compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 199, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 208, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 163, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor.py", + "line": 195, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 270, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 16, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 51, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 222, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 223, + "node": "Attribute", + "name": "resized", + "source": "result.resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 228, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 230, + "node": "Attribute", + "name": "resized", + "source": "result.resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 235, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 237, + "node": "Attribute", + "name": "resized", + "source": "result.resized" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 269, + "node": "Attribute", + "name": "reflow_visible", + "source": "compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 272, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 287, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 303, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 176, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 187, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 278, + "node": "Attribute", + "name": "_using_geometry", + "source": "compositor._using_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 286, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_compositor_frame_damage.py", + "line": 294, + "node": "Attribute", + "name": "_using_geometry", + "source": "compositor._using_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_removed_scene_ownership.py", + "line": 113, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_removed_scene_ownership.py", + "line": 125, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_removed_scene_ownership.py", + "line": 126, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_reparent.py", + "line": 85, + "node": "Attribute", + "name": "_full_map", + "source": "previous._compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 108, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 136, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 186, + "node": "Attribute", + "name": "_visible_map", + "source": "screen._compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 187, + "node": "Attribute", + "name": "_visible_map", + "source": "screen._compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 201, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 201, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 204, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 205, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 208, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 225, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 226, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 226, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 247, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 248, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 258, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 258, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 274, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 275, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 287, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 288, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 74, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 127, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 161, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 162, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 167, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 200, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 222, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 257, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 72, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 114, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 131, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 158, + "node": "Constant", + "name": "reflow_visible", + "source": "\"reflow_visible\"" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 163, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 188, + "node": "Attribute", + "name": "published_geometry", + "source": "screen._compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 73, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 158, + "node": "Attribute", + "name": "reflow_visible", + "source": "compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_geometry_targets.py", + "line": 203, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_layout.py", + "line": 56, + "node": "Attribute", + "name": "reflow", + "source": "screen._compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_layout.py", + "line": 61, + "node": "Attribute", + "name": "reflow", + "source": "screen._compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_viewport_layout.py", + "line": 40, + "node": "Attribute", + "name": "reflow", + "source": "screen._compositor.reflow" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 157, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 37, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 41, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 88, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 99, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 115, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 129, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 142, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 160, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 171, + "node": "Attribute", + "name": "_size_updated", + "source": "group._size_updated" + }, + { + "repository": "/home/ts/wt/textual-native-subtree-strips-20261002", + "root": "tests", + "path": "tests/test_widget_measurement_commit.py", + "line": 49, + "node": "Attribute", + "name": "_size_updated", + "source": "widget._size_updated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/conversation.py", + "line": 2128, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/history_anchor.py", + "line": 215, + "node": "FunctionDef", + "name": "_size_updated", + "source": " def _size_updated(self, size, virtual_size, container_size, layout=True) -> bool:" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/history_anchor.py", + "line": 355, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/history_anchor.py", + "line": 356, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/history_anchor.py", + "line": 219, + "node": "Attribute", + "name": "_size_updated", + "source": "super()._size_updated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/history_anchor.py", + "line": 355, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 208, + "node": "FunctionDef", + "name": "resized", + "source": " def resized(self, size):" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 362, + "node": "FunctionDef", + "name": "resized", + "source": " def resized(self, size):" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 450, + "node": "FunctionDef", + "name": "resized", + "source": " def resized(self, size):" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 554, + "node": "FunctionDef", + "name": "_size_updated", + "source": " def _size_updated(self, size, virtual_size, container_size, layout=True):" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 555, + "node": "Attribute", + "name": "_size_updated", + "source": "super()._size_updated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 363, + "node": "Attribute", + "name": "resized", + "source": "self.previous.resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 556, + "node": "Attribute", + "name": "resized", + "source": "self._body_measurement.resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "src/toad", + "path": "src/toad/widgets/viewport_body.py", + "line": 644, + "node": "Attribute", + "name": "published_geometry", + "source": "compositor.published_geometry" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/cold_thread_latency_pilot.py", + "line": 163, + "node": "Attribute", + "name": "reflow", + "source": "screen._compositor.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/cold_thread_latency_pilot.py", + "line": 165, + "node": "Attribute", + "name": "_size_updated", + "source": "Footer._size_updated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/cold_thread_latency_pilot.py", + "line": 255, + "node": "Name", + "name": "reflow", + "source": "reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/cold_thread_latency_pilot.py", + "line": 253, + "node": "Constant", + "name": "reflow", + "source": "\"reflow\"" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/cold_thread_latency_pilot.py", + "line": 264, + "node": "Constant", + "name": "_size_updated", + "source": "\"_size_updated\"" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/cold_thread_latency_pilot.py", + "line": 279, + "node": "Name", + "name": "reflow", + "source": "reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/goal_geometry_pilot.py", + "line": 31, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/goal_resize_pilot.py", + "line": 57, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/goal_resize_pilot.py", + "line": 58, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/goal_resize_pilot.py", + "line": 61, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/goal_resize_pilot.py", + "line": 67, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/goal_resize_pilot.py", + "line": 76, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/history_anchor_geometry_pilot.py", + "line": 65, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/history_anchor_geometry_pilot.py", + "line": 64, + "node": "Attribute", + "name": "reflow_visible", + "source": "compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/history_anchor_geometry_pilot.py", + "line": 66, + "node": "Attribute", + "name": "reflow", + "source": "compositor.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/history_page_batch_mount_pilot.py", + "line": 155, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/history_page_batch_mount_pilot.py", + "line": 159, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/history_page_batch_mount_pilot.py", + "line": 161, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/native_goal_read_first_paint_pilot.py", + "line": 81, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/native_goal_read_first_paint_pilot.py", + "line": 135, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/native_goal_read_first_paint_pilot.py", + "line": 103, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/native_goal_read_first_paint_pilot.py", + "line": 138, + "node": "Name", + "name": "resized", + "source": "resized" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/native_loaded_return_cache_pilot.py", + "line": 133, + "node": "Constant", + "name": "reflow", + "source": "\"reflow\"" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/native_loaded_return_cache_pilot.py", + "line": 250, + "node": "Attribute", + "name": "_full_map", + "source": "app.screen._compositor._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 173, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 377, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 209, + "node": "Attribute", + "name": "_full_map", + "source": "scene._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 209, + "node": "Attribute", + "name": "_visible_map", + "source": "scene._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 213, + "node": "Attribute", + "name": "_full_map", + "source": "scene._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 214, + "node": "Attribute", + "name": "_visible_map", + "source": "scene._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 257, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 312, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 324, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 368, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 70, + "node": "Attribute", + "name": "_visible_map", + "source": "current_scene._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 210, + "node": "Attribute", + "name": "published_geometry", + "source": "scene.published_geometry" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 287, + "node": "Attribute", + "name": "reflow", + "source": "scene.reflow" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 303, + "node": "Attribute", + "name": "reflow_visible", + "source": "scene.reflow_visible" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 305, + "node": "Attribute", + "name": "_visible_map", + "source": "scene._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/scroll_select_latency_pilot.py", + "line": 260, + "node": "Attribute", + "name": "_visible_map", + "source": "app.screen._compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/sidebar_preparation_boundary_pilot.py", + "line": 25, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/sidebar_preparation_boundary_pilot.py", + "line": 26, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/throbber_scroll_cost_pilot.py", + "line": 43, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/throbber_scroll_cost_pilot.py", + "line": 42, + "node": "Attribute", + "name": "reflow_visible", + "source": "compositor.reflow_visible" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tests", + "path": "tests/worker_native_size_pilot.py", + "line": 125, + "node": "Attribute", + "name": "reflow_visible", + "source": "scene.reflow_visible" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/capture_state.py", + "line": 191, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/capture_state.py", + "line": 229, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/capture_state.py", + "line": 229, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/replay_state.py", + "line": 164, + "node": "Attribute", + "name": "_full_map", + "source": "node._compositor._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/replay_state.py", + "line": 165, + "node": "Attribute", + "name": "_visible_map", + "source": "node._compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/scroll_travel_observation.py", + "line": 108, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/scroll_travel_observation.py", + "line": 109, + "node": "Attribute", + "name": "_full_map", + "source": "compositor._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/scroll_travel_observation.py", + "line": 124, + "node": "Attribute", + "name": "_full_map_invalidated", + "source": "compositor._full_map_invalidated" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/scroll_travel_observation.py", + "line": 108, + "node": "Attribute", + "name": "_visible_map", + "source": "compositor._visible_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/sidebar_validation_driver.py", + "line": 243, + "node": "Attribute", + "name": "_full_map", + "source": "self._compositor._full_map" + }, + { + "repository": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "root": "tools", + "path": "tools/performance/sidebar_validation_driver.py", + "line": 242, + "node": "Attribute", + "name": "_visible_map", + "source": "self._compositor._visible_map" + } + ], + "limits": "AST records declarations, accesses, writes and calls by name. Unrelated BodyMeasurement.resized remains a distinct fact; names alone do not prove dynamic resolution. Runtime-created/rebound classes and undeclared external consumers remain unproved. No source checks or application execution." +} diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index 5e1057d58d..2c15127332 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -54,11 +54,10 @@ class ReflowResult(NamedTuple): - """The result of a reflow operation. Describes the chances to widgets.""" + """Logical show and hide membership after reflow.""" hidden: set[Widget] # Widgets that are hidden shown: set[Widget] # Widgets that are shown - resized: set[Widget] # Widgets that have been resized # Maps a widget on to its geometry (information that describes its position in the composition) @@ -665,6 +664,11 @@ def __rich_repr__(self) -> rich.repr.Result: yield "size", self.size yield "widgets", self.widgets + @property + def _published_map(self) -> CompositorMap: + """Last committed scene, including a legitimately empty viewport.""" + return self._visible_map if self._visible_map is not None else self._full_map + def reflow( self, parent: Widget, size: Size, *, visible_only: bool = False, retain_geometry: Iterable[Widget] = (), @@ -680,9 +684,10 @@ def reflow( using viewport layout, without traversing unrelated descendants. Returns: - Hidden, shown, and resized widgets. + Hidden and shown widgets. """ - previous_map = self._visible_map if visible_only and self._visible_map is not None else self._full_map + previous_scene = self._published_map + previous_map = previous_scene if visible_only else self._full_map self._invalidate_render_projection() self._visible_map = None self.root = parent @@ -715,12 +720,8 @@ def reflow( self._invalidate_render_projection() self.widgets = widgets - resized_widgets = self._damage_geometry(old_map, map, parent) - return ReflowResult( - hidden=hidden_widgets, - shown=shown_widgets, - resized=resized_widgets, - ) + self._damage_geometry(previous_scene, map, parent) + return ReflowResult(hidden=hidden_widgets, shown=shown_widgets) def reflow_visible( self, parent: Widget, size: Size, *, retain_geometry: Iterable[Widget], @@ -738,6 +739,7 @@ def reflow_visible( Set of widgets that were exposed by the scroll. """ self._invalidate_render_projection() + previous_scene = self._published_map self._full_map_invalidated = True self.root = parent self.size = size @@ -755,29 +757,26 @@ def reflow_visible( exposed_widgets = map.keys() - old_map.keys() - self._damage_geometry(old_map, map, parent) + self._damage_geometry(previous_scene, map, parent) return exposed_widgets def _damage_geometry( self, before: Mapping[Widget, MapGeometry], after: Mapping[Widget, MapGeometry], owner: Widget, - ) -> set[Widget]: - """Derive damage and resized membership from the original scene change. + ) -> None: + """Retain both paint rectangles from the original scene change. Compare each new placement with its previous one. Retain both clipped rectangles without hashing complete geometry records into temporary - sets; the same comparison supplies normal reflow's resize notification. + sets. Widget size publication owns resize notification separately. """ - resized: set[Widget] = set() track_damage = self.size.region not in self._dirty_regions for widget, geometry in after.items(): previous = before.get(widget) if previous == geometry: continue if previous is not None: - if previous.region.size != geometry.region.size: - resized.add(widget) if track_damage and (region := previous.visible_region): self._dirty_regions.add(region) if track_damage and (region := geometry.visible_region): @@ -788,7 +787,6 @@ def _damage_geometry( self._dirty_regions.add(region) if self._dirty_regions: owner.check_idle() - return resized @property def full_map(self) -> CompositorMap: @@ -801,7 +799,7 @@ def full_map(self) -> CompositorMap: # A geometry query also publishes this scene. Retain the damage # from its original visible coordinates before replacing the map; # a later reflow can no longer recover that previous geometry. - previous = self._visible_map if self._visible_map is not None else self._full_map + previous = self._published_map self._damage_geometry(previous, map, self.root) self._full_map = map self._full_map_invalidated = False @@ -1182,9 +1180,8 @@ def add_widget(widget, virtual_region, region, order, layer_order, clip, visible @property def layers(self) -> list[tuple[Widget, MapGeometry]]: """Get widgets and geometry in layer order.""" - map = self._visible_map if self._visible_map is not None else self._full_map if self._layers is None: - self._layers = self._ordered_geometry(map) + self._layers = self._ordered_geometry(self._published_map) return self._layers def __contains__(self, widget: Widget) -> bool: diff --git a/src/textual/screen.py b/src/textual/screen.py index 8ba271734d..44a8d57604 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -1388,18 +1388,18 @@ def _refresh_layout(self, size: Size | None = None, scroll: bool = False) -> Non ): widget.post_message( ResizeEvent( - region.size, virtual_size, container_size + widget.outer_size, widget.virtual_size, widget.container_size ) ) else: viewport_layout = self._use_viewport_layout() if viewport_layout: - hidden, shown, resized = self._compositor.reflow( + hidden, shown = self._compositor.reflow( self, size, visible_only=True, retain_geometry=geometry_targets, ) else: - hidden, shown, resized = self._compositor.reflow(self, size) + hidden, shown = self._compositor.reflow(self, size) self._layout_widgets.clear() Hide = events.Hide Show = events.Show @@ -1407,9 +1407,6 @@ def _refresh_layout(self, size: Size | None = None, scroll: bool = False) -> Non for widget in hidden: widget.post_message(Hide()) - # We want to send a resize event to widgets that were just added or change since last layout - send_resize = shown | resized - layers = self._compositor.layers for widget, ( region, @@ -1421,9 +1418,9 @@ def _refresh_layout(self, size: Size | None = None, scroll: bool = False) -> Non _, ) in layers: size_changed = widget._size_updated(region.size, virtual_size, container_size) - if widget in send_resize or (viewport_layout and size_changed): + if widget in shown or size_changed: widget.post_message( - ResizeEvent(region.size, virtual_size, container_size) + ResizeEvent(widget.outer_size, widget.virtual_size, widget.container_size) ) for widget in shown: diff --git a/src/textual/scroll_view.py b/src/textual/scroll_view.py index 7323f08d54..ee70b3c5ac 100644 --- a/src/textual/scroll_view.py +++ b/src/textual/scroll_view.py @@ -97,20 +97,15 @@ def _size_updated( Returns: True if a resize event should be sent, otherwise False. """ - if size_changed := self._size != size: - self._set_dirty() - if ( - size_changed - or virtual_size != self.virtual_size - or container_size != self.container_size - ): - self._scrollbar_changes.clear() - self._size = size - virtual_size = self.virtual_size - self._container_size = size - self.styles.gutter.totals - self._scroll_update(virtual_size) - - return size_changed or self._container_size != container_size + # The line surface authors its virtual extent. Commit native bounds + # without feeding layout measurements or reactive validation into it. + return super()._size_updated( + size, self.virtual_size, size - self.styles.gutter.totals, layout=False + ) + + def _scroll_update(self, virtual_size: Size) -> None: + self._scrollbar_changes.clear() + super()._scroll_update(self.virtual_size) def render(self) -> RenderableType: """Render the scrollable region (if `render_lines` is not implemented). diff --git a/tests/test_compositor_frame_damage.py b/tests/test_compositor_frame_damage.py index e85532fc4a..729140c4a0 100644 --- a/tests/test_compositor_frame_damage.py +++ b/tests/test_compositor_frame_damage.py @@ -200,7 +200,7 @@ def compose(self): assert [strip.text.rstrip() for strip in strips] == ["ABC界DEF", "SECOND_ROW", "THIRD_ROW"] -async def test_scene_change_retains_both_rectangles_and_native_resize_membership(): +async def test_scene_change_retains_both_rectangles_and_widget_size_publication(): """Movement, resizing, hide and show consume original native scene records.""" from textual.geometry import Region @@ -220,21 +220,27 @@ def compose(self): box.styles.width = 12 box.styles.offset = (4, 3) result = compositor.reflow(app.screen, Size(40, 12)) - assert box in result.resized + placement = compositor.find_widget(box) + assert box._size_updated( + placement.region.size, placement.virtual_size, placement.container_size + ) assert {Region(2, 1, 8, 2), Region(4, 3, 12, 2)} <= compositor._dirty_regions compositor._dirty_regions.clear() box.display = False result = compositor.reflow(app.screen, Size(40, 12)) assert box in result.hidden - assert box not in result.resized + assert box.outer_size == Size(12, 2) assert Region(4, 3, 12, 2) in compositor._dirty_regions compositor._dirty_regions.clear() box.display = True result = compositor.reflow(app.screen, Size(40, 12)) assert box in result.shown - assert box not in result.resized + placement = compositor.find_widget(box) + assert not box._size_updated( + placement.region.size, placement.virtual_size, placement.container_size + ) assert Region(4, 3, 12, 2) in compositor._dirty_regions diff --git a/tests/test_native_scene_size_publication.py b/tests/test_native_scene_size_publication.py new file mode 100644 index 0000000000..196322ef4c --- /dev/null +++ b/tests/test_native_scene_size_publication.py @@ -0,0 +1,146 @@ +"""Exercise scene transitions and size receipts through original native Apps.""" + +from textual import events +from textual.app import App +from textual.containers import VerticalScroll +from textual.geometry import Size +from textual.scroll_view import ScrollView +from textual.widgets import Static + + +class SizeReceipts: + def on_resize(self, event: events.Resize) -> None: + self.receipts.append((event.size, event.virtual_size, event.container_size)) + + +async def test_screen_delivers_virtual_only_resize_after_child_mount(): + """A fixed outer region must still publish its changed child extent.""" + + class History(SizeReceipts, VerticalScroll): + def __init__(self): + super().__init__(Static("FIRST", classes="row")) + self.receipts = [] + + history = History() + + class SizeApp(App): + CSS = "History { width: 30; height: 8; } .row { height: 2; }" + + def compose(self): + yield history + + async with SizeApp().run_test(size=(40, 12)) as pilot: + await pilot.pause() + previous_size = history.outer_size + previous_virtual = history.virtual_size + history.receipts.clear() + await history.mount(*(Static(f"ROW {i}", classes="row") for i in range(8))) + await pilot.pause() + assert history.outer_size == previous_size + assert history.virtual_size.height > previous_virtual.height + assert history.receipts[-1] == ( + history.outer_size, + history.virtual_size, + history.container_size, + ) + + +async def test_screen_delivers_container_only_resize_for_authored_line_surface(): + """Gutter changes publish native bounds without replacing authored extent.""" + + class Lines(SizeReceipts, ScrollView): + def __init__(self): + super().__init__() + self.receipts = [] + + lines = Lines() + authored = Size(80, 100) + lines.virtual_size = authored + + class SizeApp(App): + CSS = "Lines { width: 30; height: 8; }" + + def compose(self): + yield lines + + async with SizeApp().run_test(size=(40, 12)) as pilot: + await pilot.pause() + previous_size = lines.outer_size + previous_container = lines.container_size + assert lines.virtual_size == authored + lines.receipts.clear() + lines.styles.padding = 1 + await pilot.pause() + assert lines.outer_size == previous_size + assert lines.container_size == previous_container - Size(2, 2) + assert lines.virtual_size == authored + assert lines.receipts[-1] == (previous_size, authored, lines.container_size) + assert lines.vertical_scrollbar.window_virtual_size == authored.height + assert ( + lines.vertical_scrollbar.window_size + == lines.container_size.height - lines.scrollbar_size_horizontal + ) + + +async def test_first_scroll_after_full_scene_does_not_damage_unchanged_chrome(): + """A missing viewport projection is not an empty committed paint scene.""" + + class SceneApp(App): + CSS = "#chrome { dock: top; height: 1; } .row { height: 2; }" + + def compose(self): + yield Static("UNCHANGED CHROME", id="chrome") + with VerticalScroll(id="history"): + for index in range(30): + yield Static(f"ROW {index}", classes="row") + + app = SceneApp() + async with app.run_test(size=(40, 12)) as pilot: + await pilot.pause() + screen = app.screen + compositor = screen._compositor + history = screen.query_one("#history", VerticalScroll) + chrome = screen.query_one("#chrome") + assert compositor._visible_map is None + original_chrome = compositor.full_map[chrome] + compositor._dirty_regions.clear() + history.set_reactive(VerticalScroll.scroll_y, 4) + exposed = compositor.reflow_visible(screen, app.size, retain_geometry=()) + assert chrome in exposed # Exposure still conservatively initializes sizes. + assert compositor._visible_map[chrome] == original_chrome + assert compositor._dirty_regions + assert app.size.region not in compositor._dirty_regions + assert all( + not region.overlaps(original_chrome.visible_region) + for region in compositor._dirty_regions + ) + + # A later full scene must compare against the just-published viewport, + # rather than the stale pre-scroll full geometry. + visible_row = screen.query(".row")[3] + previous = compositor._visible_map[visible_row].visible_region + compositor._dirty_regions.clear() + history.set_reactive(VerticalScroll.scroll_y, 0) + compositor.reflow(screen, app.size) + assert previous in compositor._dirty_regions + assert compositor.full_map[chrome] == original_chrome + + +async def test_empty_committed_viewport_is_not_replaced_by_full_geometry(): + """A real empty visible scene remains the predecessor for full publication.""" + + class SceneApp(App): + def compose(self): + yield Static("ORIGINAL") + + app = SceneApp() + async with app.run_test(size=(40, 12)) as pilot: + await pilot.pause() + compositor = app.screen._compositor + # A detached native root has no mounted scene members. No assigned map. + compositor.reflow_visible(Static("DETACHED"), app.size, retain_geometry=()) + assert compositor._visible_map == {} + assert compositor._published_map is compositor._visible_map + compositor._dirty_regions.clear() + compositor.reflow(app.screen, app.size) + assert app.size.region in compositor._dirty_regions