Repository navigation
fix(snapshot): escape line breaks in UI tree names and values - #615
Open
tanishqbaweja wants to merge 1 commit into
Open
tanishqbaweja wants to merge 1 commit into
tanishqbaweja wants to merge 1 commit into
Conversation
semantic_tree_to_string() printed each element's name and value as the walk stored them, and the walk strips only their ends. A name or value that spans lines, such as the text of a multi-line field, split its element across several lines of the UI tree. The lines after the first had no tree prefix, so they read like separate entries, and in the Snapshot response they also kept dedent() from removing the template's indentation, which shifted the whole UI Tree section four spaces right. Escape CR and LF in each rendered tree line as \r and \n, as the text selection already is, through one helper that both now use. Only the rendering changes: the walk still stores names and values as they are, so WaitFor and Scrape see the same text, and lines without line breaks render exactly as before.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Snapshot's UI tree (
semantic_tree_to_string()intree/views.py) prints each element's name and value as the walk stored them, and the walk strips only their ends (CachedName.strip(),value.strip()). When a name or value spans lines, its element spans several lines of the tree. The lines after the first have no tree prefix, coordinates or action, so they read like other entries and the agent cannot tell where the element ends. A multi-line field is the common case: for an edit or document element the walk reads its value, which is the text in the field.Those lines also shift the tree in the response.
build_snapshot_response()passes theUI Tree:section throughdedent(), and a line that starts at column 0 leaves it nothing to remove, so the header and every tree line move four spaces right.The text selection already avoids this: #551 escaped its CR and LF "so it stays on its element's tree line".
Reproduction
At 106b50c on Windows 11 (build 22631) with Python 3.14.9, with mocks only. A script built a window out of MagicMock UIA elements that hold the cached properties the walk reads: an edit "Comments" whose value is
"Works well.\r\nOne crash on resume."and a button "Submit". It ran them through the realTree.get_state()andtree_traversal(), withControlFromHandle, the cache requests and the children lookup patched, then through the realcapture_desktop_state()andbuild_snapshot_response()with a stand-in desktop. The end of the response onmain:With a one-line value the section starts at column 0, as below.
semantic_tree_to_string()returns 5 lines for these 4 nodes with CRLF, with LF alone and with CR alone (counted withsplitlines());dedent()only counts LF, so a lone CR does not shift the section.Fix
tree/views.py:_render_semantic_node()escapes CR and LF in each tree line as\rand\n. The escape is #551's, moved into_escape_line_breaks(), which_selection_preview()now calls. The reproduction then gives:interactive_elements_to_string(),scrollable_elements_to_string()) are unchanged; Snapshot does not print them.\nin a name looks like an escaped break.Tests
New
TestLineBreaksintests/test_tree_views.py, which builds the dataclasses only:test_multiline_value_stays_on_its_element_line: an edit whose value isone\r\ntwo\rthree\nfour(CRLF, CR and LF). The tree keeps 3 lines and the edit's line ends with[value:"one\r\ntwo\rthree\nfour"].test_multiline_names_stay_on_their_element_lines: a window, a group, a button, a scrollable pane and a text with that name. The tree keeps one line per node, each with the escaped name.I ran each file on its own, in the project's environment:
On
main, both new tests fail on the line count:assert 6 == 3andassert 21 == 6. Both pass on this branch, as do the file's 29 other tests, #551'stest_multiline_selection_stays_on_one_tree_lineamong them. These pass onmainand on this branch with the same counts:tests/test_tree_service.py(50 passed),tests/test_surrogate_repair.py(18) andtests/test_snapshot_display_filter.py(37). I did not run the whole suite.ruff checkis clean on both changed files. Neither file is formatted onmain; this change adds nothing to theirruff format --diff.Not tested
A real app: everything ran against mocks. To check it on a real machine, type two lines into a multi-line text box (Notepad's, say) and call Snapshot. On
main, the box's value should continue at the start of the next line of the UI tree, with theUI Tree:section indented four spaces; with this change the value should stay on the element's line, with\r\nor\rwhere the text breaks.