diff --git a/evidence/native-paint-clip-custody-20261005/SCOPE.md b/evidence/native-paint-clip-custody-20261005/SCOPE.md new file mode 100644 index 0000000000..ff0c6a8edf --- /dev/null +++ b/evidence/native-paint-clip-custody-20261005/SCOPE.md @@ -0,0 +1,97 @@ +# Native paint rectangle custody + +Base: actual Textual main06771827eeff2a98c40a41fd2bc6cb6313db7a87. +Merged65 source, e253 wheel and all controls remain untouched. + +The existing compositor paint mapping derives ordered widget paint from original +MapGeometry. It currently stores an unbounded clip and each cuts/render/chops +consumer re-intersects the same original region. Make `_paint_regions` own the +positive rectangle within original scene/capture bounds, then consumers borrow +that fact. Damage crop and foreground exposure are distinct later selections. +Raw MapGeometry, source order, geometry lookup, membership and retirement remain +their original owners. Existing layers are already cached per published scene; +complete widget membership remains necessary and is not removed. + +Claims: `_paint_regions`, `_cuts_for_regions`, `_get_renders`, `_render_chops` and +related compositor paint-query consumers. No new type, field, map, flag, cache, +timer or alternate scene. Heis owns Toad body/frame consumers. Native source App qualified below; no installed package, provider, recording +or gain qualification. + +Complete roots and consumer evidence precede changes. Source semantics first, +coherent caller migration, then proportionate validation under an actual later +grant. Pattern IMPL-12: repeated geometry acquisition by related consumers. + +## Published coherent source + +Production7934c06e0cbb03aa4e10fb53bc1a09f088f49e73: one production file, +16 added /23 deleted lines relative to actual main06771827. Native source +App controls qualified below; installed Toad/frame/performance not qualified. + +The first pair member stays the ORIGINAL widget region, including its origin and +logical dimensions. The second is the positive original region/clip intersection +within this screen or detached capture's bounds. Only this existing paint mapping +owns that admitted rectangle. MapGeometry itself and all considered/invisible +membership remain unchanged, including offscreen explicit geometry and full-map +or complete body capture. + +Cuts trust this already bounded rectangle rather than intersecting region, clip +and bounds again. Widget rendering keeps the distinct vertical damaged-row crop +and foreground-exposure selection. It emits the actual selected rectangle plus +strips; the only native unpack consumer now borrows that rectangle directly. The +unused original-region return and the repeated chop intersection are deleted. +Original widget origin is still used to request relative render_lines, preserving +metadata/selection/link coordinate semantics. Partial horizontal damage retains +original cut alignment; no dirty-x clipping or renderer policy is added. + +Existing layer sorting is already cached per published scene, so it stays. The +unbounded geometric clip is still available from original MapGeometry to geometry +consumers. Positive-pixel paint membership is distinct from complete native widget +membership; empty intersections cannot paint and remain available to logical +geometry/lifetime consumers through their original owners. + +Complete native249/tests460 and Toad288/tests397/tools41 roots parsed without +omissions before. After native249/tests460 parsed without omissions. All actual +native cut/render/chop producers and callers were migrated; wrappers in existing +controls only delegate to the original renderer and do not unpack its old triple. +No obsolete triple annotation/unpack/reintersection remains in the owned roots. +The original graph and after acquisitions are in owner-consumers.json; dynamic +aliases/external private-method overrides remain explicit limitations. + +Heis confirmed no known Toad reader requires the paint pair's unbounded clip. +Pager edge readers borrow the unchanged original region, not paint extent. His +pixel/window consumers keep their genuine Window clipping fact; once normally +paired with this library, their extra region intersection can be reviewed as an +identity operation. No such caller migration is made against old native65 or the +current installed prefix, and no compatibility/version branch is introduced. + +At the original2e8e source checkpoint, no source App/control run, wheel, +package access, keeper, provider, capture or frame/CPU measurement was performed. Final affected controls remain to exercise +partial horizontal/vertical damage, offscreen-origin body capture, overlays, +selection/link metadata and native interaction/retirement under the next actual +grant. Frozen65/e253/controls and Heis453 tuple remain immutable. + + +## Scoped source qualification + +Source/control7e0ad94ca9f19506f9a1ed2b8bb2f2e3bd939569; production remains +7934c06e0cbb03aa4e10fb53bc1a09f088f49e73. ONE affected native source App batch: +22PASS/2.54s pytest,3.745s controller, exit0. System /usr/bin/python with existing +dependencies and PYTHONPATH=src; no new environment/build/installed prefix access. +Exact command, log and SHA are source-batch01.json/source-batch01.log. + +The existing point-hit scene checks original extent/origin vs bounded positive +paint, negative origins, fully clipped logical membership, hide/move/remove and +original raw clip. Existing capture controls check nonzero and negative original +bounds, cuts and full row content, original maps/offsets, hidden descendant refusal +and renderer-error resource release. Existing damage/exposure controls check +sparse vertical rows, dirty-x cut alignment, overlap exclusion and terminal parity. +The horizontal exposure case additionally checks authored link/click metadata; +existing wide-cell and native selection controls preserve selected pixels and +metadata. Pending actual Unmount controls ensure paint projection retirement +cannot retain old geometry/cover or revive pointer/selection resources. + +These controls confirm native source behavior for this family. They do not prove +installed Toad pairing, Linux terminal frame timing, cold/warm motion, CPU gain, +144Hz or full performance. Frozen65/e253 and original negatives remain unchanged. +Future changed installed integration belongs to Heis; no current holder purpose +or native66 wheel is implied. No further accepted-source repeat requested. diff --git a/evidence/native-paint-clip-custody-20261005/owner-consumers.json b/evidence/native-paint-clip-custody-20261005/owner-consumers.json new file mode 100644 index 0000000000..6b939c0e67 --- /dev/null +++ b/evidence/native-paint-clip-custody-20261005/owner-consumers.json @@ -0,0 +1,1914 @@ +{ + "before": { + "roots": { + "/home/ts/wt/textual-native-subtree-strips-20261002/src/textual": { + "source": "06771827eeff2a98c40a41fd2bc6cb6313db7a87", + "parsed": 249, + "omissions": [] + }, + "/home/ts/wt/textual-native-subtree-strips-20261002/tests": { + "source": "06771827eeff2a98c40a41fd2bc6cb6313db7a87", + "parsed": 460, + "omissions": [] + }, + "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001/src/toad": { + "source": "0eb1494d446934c6c01636fc78ddb890a7310fbe", + "parsed": 288, + "omissions": [] + }, + "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001/tests": { + "source": "0eb1494d446934c6c01636fc78ddb890a7310fbe", + "parsed": 397, + "omissions": [] + }, + "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001/tools": { + "source": "0eb1494d446934c6c01636fc78ddb890a7310fbe", + "parsed": 41, + "omissions": [] + } + }, + "sites": [ + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 802, + "symbol": "visible_widgets", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 814, + "symbol": "_ordered_geometry", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 820, + "symbol": "_paint_regions", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1223, + "symbol": "get_widgets_at", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1425, + "symbol": "_cuts_for_regions", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1443, + "symbol": "_get_renders", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1622, + "symbol": "render_subtree_strips", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1644, + "symbol": "_render_chops", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1737, + "symbol": "update_widgets", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1219, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1253, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1289, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1421, + "symbol": "_cuts_for_regions", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1421, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1552, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1584, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1600, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1637, + "symbol": "_paint_regions", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1638, + "symbol": "_cuts_for_regions", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1709, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1752, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 810, + "symbol": "_paint_regions", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1175, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1553, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1585, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1601, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1637, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1640, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1235, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1753, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/_compositor.py", + "line": 1746, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/layout.py", + "line": 106, + "symbol": "visible_widgets", + "kind": "Name" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/layout.py", + "line": 107, + "symbol": "visible_widgets", + "kind": "Name" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/layout.py", + "line": 111, + "symbol": "visible_widgets", + "kind": "Name" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 688, + "symbol": "get_widgets_at", + "kind": "FunctionDef" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 388, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 698, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 1364, + "symbol": "update_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 2227, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 2245, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 676, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/screen.py", + "line": 1279, + "symbol": "update_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/selection.py", + "line": 358, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/widget.py", + "line": 729, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/widget.py", + "line": 4059, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "src/textual/widget.py", + "line": 4083, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/css/test_programmatic_style_changes.py", + "line": 51, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/css/test_programmatic_style_changes.py", + "line": 175, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/css/test_programmatic_style_changes.py", + "line": 178, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/css/test_programmatic_style_changes.py", + "line": 234, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 114, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 358, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 278, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 322, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 33, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 40, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor.py", + "line": 47, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor_frame_damage.py", + "line": 124, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_compositor_horizontal_damage.py", + "line": 45, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_display_constraints.py", + "line": 39, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_display_constraints.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_remove_transaction.py", + "line": 37, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_remove_transaction.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 108, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 128, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 134, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 32, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 111, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 40, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_removed_scene_ownership.py", + "line": 131, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_selection.py", + "line": 222, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 68, + "symbol": "_paint_regions", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 74, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 75, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 123, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 240, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 271, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 68, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_geometry_targets.py", + "line": 281, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_layout.py", + "line": 38, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/textual-native-subtree-strips-20261002", + "path": "tests/test_viewport_layout.py", + "line": 42, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/goal_interaction.py", + "line": 214, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/mounted_message_history.py", + "line": 176, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/mounted_message_history.py", + "line": 301, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/transcript_filter.py", + "line": 191, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/transcript_filter.py", + "line": 130, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/committed_presentation.py", + "line": 294, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/conversation.py", + "line": 317, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/conversation.py", + "line": 173, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/goal_bar.py", + "line": 54, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/history_anchor.py", + "line": 246, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/recovery_view.py", + "line": 112, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/side_bar.py", + "line": 40, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/thread_comms.py", + "line": 367, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/throbber.py", + "line": 132, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/tool_call.py", + "line": 285, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/transcript_history.py", + "line": 562, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/transcript_history.py", + "line": 790, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/viewport_body.py", + "line": 808, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/viewport_body.py", + "line": 948, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/viewport_body.py", + "line": 653, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "src/toad/widgets/viewport_body.py", + "line": 1086, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/agent_configuration_native_installed_pilot.py", + "line": 33, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/agent_selection_configured_installed_pilot.py", + "line": 150, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/attachment_request_pilot.py", + "line": 124, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/canonical_wire_conversation_installed_pilot.py", + "line": 265, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/canonical_wire_conversation_installed_pilot.py", + "line": 173, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/channel_roster_retention_pilot.py", + "line": 34, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/command_family_pilot.py", + "line": 72, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/comms_pilot.py", + "line": 882, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/core_events_native_installed_pilot.py", + "line": 64, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/cursor_extent_pilot.py", + "line": 60, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/cursor_extent_pilot.py", + "line": 100, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/cursor_extent_pilot.py", + "line": 76, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/cursor_request_pilot.py", + "line": 138, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/guards/test_plan_presentation.py", + "line": 61, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/history_availability_installed_pilot.py", + "line": 71, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/history_availability_installed_pilot.py", + "line": 74, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/history_edge_scheduling_pilot.py", + "line": 78, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/history_frame_publication_pilot.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/history_mounted_budget_pilot.py", + "line": 59, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/history_page_batch_mount_pilot.py", + "line": 121, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/independent_native_writer_pilot.py", + "line": 109, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/independent_native_writer_pilot.py", + "line": 131, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/independent_native_writer_pilot.py", + "line": 134, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/l0a_native_installed_pilot.py", + "line": 76, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/l0a_native_installed_pilot.py", + "line": 47, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/late_native_after_join_pilot.py", + "line": 54, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/late_native_application_pilot.py", + "line": 54, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/markdown_return_reuse_pilot.py", + "line": 47, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/message_dividers_pilot.py", + "line": 129, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/native_loaded_return_cache_pilot.py", + "line": 242, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/native_loaded_return_cache_pilot.py", + "line": 381, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/native_loaded_return_cache_pilot.py", + "line": 279, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/original_stream_headers_installed_pilot.py", + "line": 37, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/plan_status_installed_pilot.py", + "line": 30, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/plan_status_installed_pilot.py", + "line": 122, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/plan_status_installed_pilot.py", + "line": 123, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/prompt_completion_installed_pilot.py", + "line": 38, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/prompt_popup_new_case_pilot.py", + "line": 48, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/queue_admission_pilot.py", + "line": 127, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/readonly_saved_reader_pilot.py", + "line": 136, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/recovery_view_boundaries_pilot.py", + "line": 139, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/response_source_custody_pilot.py", + "line": 46, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 399, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 212, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/retained_fragment_geometry_pilot.py", + "line": 288, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/retained_tool_text_pilot.py", + "line": 115, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/retained_tool_text_pilot.py", + "line": 48, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/retained_tool_text_pilot.py", + "line": 141, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/saved_state_user_journey_pilot.py", + "line": 71, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/scroll_select_latency_pilot.py", + "line": 244, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/scroll_select_latency_pilot.py", + "line": 232, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/scroll_select_latency_pilot.py", + "line": 233, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/scroll_select_latency_pilot.py", + "line": 239, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/session_details_pilot.py", + "line": 62, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/session_details_pilot.py", + "line": 101, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/shared_channels_pilot.py", + "line": 51, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/sidebar_direction_pilot.py", + "line": 42, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/sidebar_edge_anchor_installed_pilot.py", + "line": 71, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/sidebar_retirement_pilot.py", + "line": 58, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/tab_history_controls_pilot.py", + "line": 104, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/tab_history_controls_pilot.py", + "line": 74, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/tab_history_controls_pilot.py", + "line": 143, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/tail_anchor_policy_pilot.py", + "line": 31, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/thread_navigation_installed_journey.py", + "line": 130, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/thread_navigation_installed_journey.py", + "line": 100, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/throbber_busy_pilot.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/throbber_scroll_cost_pilot.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/throbber_scroll_cost_pilot.py", + "line": 45, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/throbber_scroll_cost_pilot.py", + "line": 46, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_body_order_pilot.py", + "line": 372, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_body_order_pilot.py", + "line": 386, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_demand_custody_pilot.py", + "line": 48, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_idle_cadence_pilot.py", + "line": 58, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_idle_cadence_pilot.py", + "line": 97, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_idle_cadence_pilot.py", + "line": 48, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_rapid_scroll_pilot.py", + "line": 94, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_rapid_scroll_pilot.py", + "line": 107, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_rapid_scroll_pilot.py", + "line": 20, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_rapid_scroll_pilot.py", + "line": 79, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_recent_tabs_pilot.py", + "line": 141, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_recent_tabs_pilot.py", + "line": 100, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_recent_tabs_pilot.py", + "line": 238, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_runway_pilot.py", + "line": 53, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_selection_diff_pilot.py", + "line": 43, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/viewport_selection_diff_pilot.py", + "line": 57, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/worker_native_size_pilot.py", + "line": 100, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tests/worker_native_size_pilot.py", + "line": 147, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tools/performance/benchmark_spinner.py", + "line": 69, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tools/performance/capture_state.py", + "line": 202, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tools/performance/capture_state.py", + "line": 101, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tools/performance/replay_state.py", + "line": 306, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "repo": "/home/ts/wt/toad-viewport-raster-cpu-continuation-20261001", + "path": "tools/performance/sidebar_validation_driver.py", + "line": 576, + "symbol": "visible_widgets", + "kind": "Attribute" + } + ], + "limits": "Syntactic declarations/attributes over complete roots. Aliases, third-party subclasses and dynamically supplied private mappings are unresolved." + }, + "after": { + "roots": { + "src/textual": { + "source": "7934c06e0cbb03aa4e10fb53bc1a09f088f49e73", + "parsed": 249, + "omissions": [] + }, + "tests": { + "source": "7934c06e0cbb03aa4e10fb53bc1a09f088f49e73", + "parsed": 460, + "omissions": [] + } + }, + "sites": [ + { + "path": "src/textual/_compositor.py", + "line": 802, + "symbol": "visible_widgets", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 814, + "symbol": "_ordered_geometry", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 820, + "symbol": "_paint_regions", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1223, + "symbol": "get_widgets_at", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1425, + "symbol": "_cuts_for_regions", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1440, + "symbol": "_get_renders", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1617, + "symbol": "render_subtree_strips", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1639, + "symbol": "_render_chops", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1730, + "symbol": "update_widgets", + "kind": "FunctionDef" + }, + { + "path": "src/textual/_compositor.py", + "line": 1219, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1253, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1289, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1421, + "symbol": "_cuts_for_regions", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1421, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1547, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1579, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1595, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1632, + "symbol": "_paint_regions", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1633, + "symbol": "_cuts_for_regions", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1704, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1745, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 810, + "symbol": "_paint_regions", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1175, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1548, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1580, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1596, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1632, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1635, + "symbol": "_render_chops", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1235, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1746, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/_compositor.py", + "line": 1739, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/layout.py", + "line": 106, + "symbol": "visible_widgets", + "kind": "Name" + }, + { + "path": "src/textual/layout.py", + "line": 107, + "symbol": "visible_widgets", + "kind": "Name" + }, + { + "path": "src/textual/layout.py", + "line": 111, + "symbol": "visible_widgets", + "kind": "Name" + }, + { + "path": "src/textual/screen.py", + "line": 688, + "symbol": "get_widgets_at", + "kind": "FunctionDef" + }, + { + "path": "src/textual/screen.py", + "line": 388, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/screen.py", + "line": 698, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "src/textual/screen.py", + "line": 1364, + "symbol": "update_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/screen.py", + "line": 2227, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/screen.py", + "line": 2245, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/screen.py", + "line": 676, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "src/textual/screen.py", + "line": 1279, + "symbol": "update_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/selection.py", + "line": 358, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/widget.py", + "line": 729, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "src/textual/widget.py", + "line": 4059, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "src/textual/widget.py", + "line": 4083, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/css/test_programmatic_style_changes.py", + "line": 51, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/css/test_programmatic_style_changes.py", + "line": 175, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/css/test_programmatic_style_changes.py", + "line": 178, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/css/test_programmatic_style_changes.py", + "line": 234, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 114, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 358, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 278, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 322, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 33, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 40, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor.py", + "line": 47, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor_frame_damage.py", + "line": 124, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "path": "tests/test_compositor_horizontal_damage.py", + "line": 45, + "symbol": "_get_renders", + "kind": "Attribute" + }, + { + "path": "tests/test_display_constraints.py", + "line": 39, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_display_constraints.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_remove_transaction.py", + "line": 37, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_remove_transaction.py", + "line": 44, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 108, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 128, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 134, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 32, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 111, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 40, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_removed_scene_ownership.py", + "line": 131, + "symbol": "get_widgets_at", + "kind": "Attribute" + }, + { + "path": "tests/test_selection.py", + "line": 222, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 68, + "symbol": "_paint_regions", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 74, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 75, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 123, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 240, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 271, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 68, + "symbol": "_ordered_geometry", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_geometry_targets.py", + "line": 281, + "symbol": "render_subtree_strips", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_layout.py", + "line": 38, + "symbol": "visible_widgets", + "kind": "Attribute" + }, + { + "path": "tests/test_viewport_layout.py", + "line": 42, + "symbol": "visible_widgets", + "kind": "Attribute" + } + ], + "limits": "Syntactic declarations/attributes over complete roots. Aliases, third-party subclasses and dynamically supplied private mappings are unresolved." + }, + "original_owned_acquisitions": { + "_paint_regions": [ + { + "line": 825, + "source": "entry.visible_region.intersection(bounds)" + } + ], + "_cuts_for_regions": [], + "_get_renders": [ + { + "line": 1471, + "source": "intersection(clip, _Region(clip.x, crop.y, clip.width, crop.height))" + } + ], + "_render_chops": [] + }, + "contract": "Original widget region plus positive scene-bounded paint rectangle. Raw geometry/membership unchanged; damage/exposure distinct. _get_renders emits selectedrectangle+strips, sole native unpack consumer migrated.", + "dynamic_limits": "Syntactic declarations/attributes over complete roots. Aliases, third-party subclasses and dynamically supplied private mappings are unresolved.", + "external_window_consumer": "Heis confirmed Toad region readers ignore clip for source extents. Pixel/window selection must preserve originalregion; further Window clip selection legitimate. Native66 paired future may remove its now-identity region intersection; no migration on native65/current prefix." +} diff --git a/evidence/native-paint-clip-custody-20261005/source-batch01.json b/evidence/native-paint-clip-custody-20261005/source-batch01.json new file mode 100644 index 0000000000..c6bdb135cc --- /dev/null +++ b/evidence/native-paint-clip-custody-20261005/source-batch01.json @@ -0,0 +1,28 @@ +{ + "source": "7e0ad94ca9f19506f9a1ed2b8bb2f2e3bd939569", + "argv": [ + "/usr/bin/python", + "-m", + "pytest", + "-q", + "tests/test_compositor.py::test_point_hits_follow_layer_clip_visibility_and_scene_changes", + "tests/test_compositor.py::test_covered_widgets_skip_rendering_without_changing_output", + "tests/test_compositor.py::test_partial_redraw_requests_only_damaged_vertical_rows", + "tests/test_compositor.py::test_partly_covered_widgets_render_only_exposed_rows", + "tests/test_compositor_horizontal_damage.py", + "tests/test_compositor_frame_damage.py", + "tests/test_viewport_geometry_targets.py::test_body_capture_descendants_use_original_arrangement_and_screen_coordinates", + "tests/test_removed_scene_ownership.py::test_pending_removal_retires_each_original_scene_and_cover", + "tests/test_removed_scene_ownership.py::test_pending_removal_revokes_pointer_intent_but_keeps_surviving_selection", + "tests/test_selection.py::test_double_width" + ], + "interpreter": "/usr/bin/python", + "seconds": 3.7450953139923513, + "exit_code": 0, + "log": "evidence/native-paint-clip-custody-20261005/source-batch01.log", + "scope": "Actual native source App: original origin/paint clipping/capture bounds/damage/exposure/links/metadata/selection and pending scene retirement. No installed prefix, Toad, provider, SDK, recording or CPU/frame measurement.", + "log_sha256": "be411550c051a1d9ae9061a21e6d90a92680a381d5dbcc8cd78647462f4f4f46", + "result": "22 passed in 2.54s; controller3.7450953139923513s; exit0", + "production_source": "7934c06e0cbb03aa4e10fb53bc1a09f088f49e73", + "production_delta_from_qualified_controls": "" +} diff --git a/evidence/native-paint-clip-custody-20261005/source-batch01.log b/evidence/native-paint-clip-custody-20261005/source-batch01.log new file mode 100644 index 0000000000..0e41219a28 --- /dev/null +++ b/evidence/native-paint-clip-custody-20261005/source-batch01.log @@ -0,0 +1,2 @@ +...................... [100%] +22 passed in 2.54s diff --git a/src/textual/_compositor.py b/src/textual/_compositor.py index f7073d7b1a..f01879ef40 100644 --- a/src/textual/_compositor.py +++ b/src/textual/_compositor.py @@ -536,7 +536,7 @@ def __init__(self, *, max_subtree_geometry_entries: int = DEFAULT_SUBTREE_GEOMET # Note this may be a superset of self.full_map.keys() as some widgets may be invisible for various reasons self.widgets: set[Widget] = set() - # Mapping of visible widgets on to their region, and clip region + # Original widget origins and their bounded positive paint rectangles. self._visible_widgets: dict[Widget, tuple[Region, Region]] | None = None # The top level widget @@ -800,7 +800,7 @@ def full_map(self) -> CompositorMap: @property def visible_widgets(self) -> dict[Widget, tuple[Region, Region]]: - """Get a mapping of widgets on to region and clip. + """Get widget origins and rectangles admitted to this original scene. Returns: Visible widget mapping. @@ -819,10 +819,10 @@ def _ordered_geometry(geometry: Mapping[Widget, MapGeometry] @staticmethod def _paint_regions(layers: Iterable[tuple[Widget, MapGeometry]], bounds: Region ) -> dict[Widget, tuple[Region, Region]]: - """Clip the original ordered cohort without acquiring its order again.""" - return {widget: (entry.region, entry.clip) + """Own each positive paint rectangle within the original scene bounds.""" + return {widget: (entry.region, paint_region) for widget, entry in layers - if bounds.overlaps(entry.region) and entry.clip.overlaps(entry.region)} + if (paint_region := entry.visible_region.intersection(bounds))} def _arrange_root( self, root: Widget, size: Size, visible_only: bool = True, @@ -1424,18 +1424,15 @@ def cuts(self) -> list[list[int]]: @staticmethod def _cuts_for_regions(bounds: Region, widgets: Mapping[Widget, tuple[Region, Region]] ) -> list[list[int]]: - """Derive chop boundaries from the original ordered paint regions.""" + """Derive cuts from the positive rectangles owned by paint admission.""" cuts = [[bounds.x, bounds.right] for _ in range(bounds.height)] - intersection = Region.intersection extend = list.extend - for region, clip in widgets.values(): - x, y, region_width, region_height = intersection(intersection(region, clip), bounds) - if region_width and region_height: - region_cuts = (x, x + region_width) - for cut in cuts[y - bounds.y : y - bounds.y + region_height]: - extend(cut, region_cuts) + for _, (x, y, region_width, region_height) in widgets.values(): + region_cuts = (x, x + region_width) + for cut in cuts[y - bounds.y : y - bounds.y + region_height]: + extend(cut, region_cuts) # Sort the cuts for each line return [sorted(set(line_cuts)) for line_cuts in cuts] @@ -1444,7 +1441,7 @@ def _get_renders( self, crop: Region | None = None, render_regions: Callable[[Region], Iterable[Region]] | None = None, *, widgets: Mapping[Widget, tuple[Region, Region]], - ) -> Iterable[tuple[Region, Region, list[Strip]]]: + ) -> Iterable[tuple[Region, list[Strip]]]: """Get rendered widgets (lists of segments) in the composition. Args: @@ -1452,7 +1449,7 @@ def _get_renders( render_regions: Select still-exposed damaged rows within each widget. Returns: - An iterable of , , and + An iterable of original selected paint rectangles and their strips. """ # If a renderable throws an error while rendering, the user likely doesn't care about the traceback # up to this point. @@ -1472,16 +1469,14 @@ def _get_renders( # clip boundaries intact: compositor chops are aligned to those # cuts and may extend past the narrower dirty x span. clip = intersection(clip, _Region(clip.x, crop.y, clip.width, crop.height)) - visible_region = intersection(region, clip) - if visible_region: + if clip: regions = ( - (visible_region,) if render_regions is None - else render_regions(visible_region) + (clip,) if render_regions is None + else render_regions(clip) ) for render_region in regions: new_x, new_y, new_width, new_height = render_region yield ( - region, render_region, widget.render_lines( _Region( @@ -1707,10 +1702,8 @@ def render_regions(region: Region) -> Iterable[Region]: # Go through all the renders in reverse order and fill buckets with no render renders = self._get_renders(crop, render_regions, widgets=widgets) - intersection = Region.intersection - for region, clip, strips in renders: - render_region = intersection(region, clip) + for render_region, strips in renders: render_x = render_region.x first_cut, last_cut = render_region.column_span diff --git a/tests/test_compositor.py b/tests/test_compositor.py index ea6338b60e..7b91dfa450 100644 --- a/tests/test_compositor.py +++ b/tests/test_compositor.py @@ -9,6 +9,7 @@ async def test_point_hits_follow_layer_clip_visibility_and_scene_changes(): from textual.errors import NoWidget + from textual.geometry import Region class PointApp(App): CSS = """ @@ -29,6 +30,12 @@ def compose(self): front = app.query_one("#front") compositor = app.screen._compositor + # Paint admission clips pixels without changing the original source + # origin/extent returned to hit and pager geometry consumers. + assert compositor.visible_widgets[front] == ( + Region(2, 2, 12, 3), Region(2, 2, 8, 3), + ) + assert compositor.find_widget(front).clip == Region(2, 2, 8, 4) assert compositor.get_widget_at(3, 2) == (front, front.region) assert [widget for widget, _ in compositor.get_widgets_at(3, 2)] == [ front, back, pane, app.screen, @@ -43,13 +50,38 @@ def compose(self): front.visible = False await pilot.pause() + assert front not in compositor.visible_widgets assert compositor.get_widget_at(3, 2)[0] is back assert all(widget is not front for widget, _ in compositor.get_widgets_at(3, 2)) front.visible = True pane.styles.offset = (4, 3) await pilot.pause() + assert compositor.visible_widgets[front] == ( + Region(4, 3, 12, 3), Region(4, 3, 8, 3), + ) assert compositor.get_widget_at(3, 2)[0] is app.screen assert compositor.get_widget_at(5, 3)[0] is front + + pane.styles.offset = (-2, -1) + await pilot.pause() + assert compositor.visible_widgets[front] == ( + Region(-2, -1, 12, 3), Region(0, 0, 6, 2), + ) + assert compositor.get_widget_at(0, 0) == (front, Region(-2, -1, 12, 3)) + assert compositor.cuts[0] == [0, 6, 20] + assert compositor.cuts[2] == [0, 6, 20] + assert compositor.cuts[3] == [0, 20] + + # A completely clipped descendant still belongs to native geometry, + # but contributes neither paint pixels nor pointer hits. + front.styles.offset = (8, 0) + await pilot.pause() + assert front in compositor.widgets and front in compositor.full_map + assert front not in compositor.visible_widgets + assert compositor.get_widget_at(0, 0)[0] is back + pane.styles.offset = (4, 3) + front.styles.offset = (0, 0) + await pilot.pause() await front.remove() await pilot.pause() assert compositor.get_widget_at(5, 3)[0] is back diff --git a/tests/test_compositor_frame_damage.py b/tests/test_compositor_frame_damage.py index 1e1fbd7192..37411ef4fc 100644 --- a/tests/test_compositor_frame_damage.py +++ b/tests/test_compositor_frame_damage.py @@ -125,6 +125,26 @@ def compose(self): assert size == Size(12, 3) assert [strip.text.rstrip() for strip in strips] == ["ABC界DEF", "SECOND_ROW", "THIRD_ROW"] + # Capturing a partly offscreen body still owns its full original rows. + # Native screen painting clips it; capture has distinct nonzero bounds. + from textual.geometry import Region + body.styles.offset = (-2, -1) + await pilot.pause() + [(original, placement)] = list(compositor.published_geometry([body])) + assert placement.region == Region(-2, -1, 12, 3) + assert compositor.visible_widgets[body] == ( + placement.region, Region(0, 0, 10, 2), + ) + geometry, _ = compositor._arrange_root( + original, compositor.size, visible_only=False, root_geometry=placement, + ) + paint = compositor._paint_regions(compositor._ordered_geometry(geometry), placement.region) + assert paint[body] == (placement.region, placement.region) + assert compositor._cuts_for_regions(placement.region, paint) == [[-2, 10]] * 3 + size, strips = compositor.render_subtree_strips(original, placement) + assert size == Size(12, 3) + 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(): """Movement, resizing, hide and show consume original native scene records.""" diff --git a/tests/test_compositor_horizontal_damage.py b/tests/test_compositor_horizontal_damage.py index 5c7d276890..5dbf40efaa 100644 --- a/tests/test_compositor_horizontal_damage.py +++ b/tests/test_compositor_horizontal_damage.py @@ -1,6 +1,8 @@ from unittest.mock import patch import pytest +from rich.style import Style +from rich.text import Text from textual.app import App from textual.geometry import Region @@ -11,7 +13,10 @@ async def test_horizontal_occlusion_skips_covered_cells_with_native_render_parity(offset, width): class Counted(Static): def __init__(self): - super().__init__("[bold]界 café 界[/bold] " * 50) + super().__init__(Text("界 café 界 " * 50, style=Style( + bold=True, link="https://example.com/original-row", + meta={"@click": "original_row"}, + ))) self.crops = [] def render_lines(self, crop): @@ -46,3 +51,10 @@ def compose(self): with patch.object(compositor, "_get_renders", lambda crop=None, render_regions=None, *, widgets: original(crop, widgets=widgets)): reference = compositor.render_strips() assert optimized == reference + # Strip parity includes authored links and click metadata, rather than + # only terminal text after cutting around the foreground overlay. + authored = [segment.style for strip in optimized for segment in strip + if segment.style and segment.style.link] + assert authored + assert all(style.link == "https://example.com/original-row" + and style.meta["@click"] == "original_row" for style in authored)