aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-24 22:10:25 +0200
committerblasty <blasty@local>2026-07-24 22:10:25 +0200
commit2d6541a93992790b7013feb3b0756c381f2c8fa6 (patch)
tree9a8a0b09f9a4bb18bb7ca011ae9566ae69966999 /tests
parentsplit: guard toggle behind prompt-active; clear _split in the pilot reset (diff)
downloadida-tui-2d6541a93992790b7013feb3b0756c381f2c8fa6.tar.gz
ida-tui-2d6541a93992790b7013feb3b0756c381f2c8fa6.tar.xz
ida-tui-2d6541a93992790b7013feb3b0756c381f2c8fa6.zip
split-view phase 2: cursor sync + linked-row highlight
The Ghidra sync: in split, the focused pane drives and the companion shows a subtle band (_S_LINK) on the linked location + scrolls it into view. The companion's cursor never moves (band + scroll only), so there's no echo/ ping-pong and no guard is needed. * _sync_split(source): listing drives -> DecompView.line_for_ea (largest /*ea*/ marker <= cursor ea) bands the covering C line; decomp drives -> ListingModel.ensure_ea bands the covering instruction row. * wired into on_listing/decomp_view_cursor_moved (gated on the focused pane), the Tab focus-switch (re-link from the new driver), _apply_decomp (link once the pseudocode loads) and _apply_enter_split; bands cleared on leaving split. * ListingView/DecompView gain _link_rows/_link_line + set_link/reveal, a render_line apply_style(_S_LINK) band, and DecompView.line_for_ea. Still single-ea per line (one instruction highlighted) — the full instruction range is phase 3 (the decomp_map tool). Pilot split_view now covers both sync directions + that the band actually paints (10/10); full suite 151/2-flake.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_scenarios.py36
1 files changed, 36 insertions, 0 deletions
diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py
index cfa3e3a..9099035 100644
--- a/tests/test_scenarios.py
+++ b/tests/test_scenarios.py
@@ -350,10 +350,43 @@ async def s_split_view(c: Ctx):
loaded = await c.wait(lambda: dec.loaded_ea == app._cur.ea, 25)
c.check("split loads the pseudocode alongside the listing", loaded,
f"loaded={dec.loaded_ea} cur={app._cur.ea if app._cur else None}")
+ # listing drives: move it, the decomp band must track the covering C line
+ lst.focus()
+ for _ in range(6):
+ await c.press("j")
+ await c.pause(0.2)
+ lea = lst._cursor_ea()
+ dl = dec._link_line
+ c.check("listing cursor links the covering pseudocode line",
+ dl is not None and lea is not None and dec._line_eas[dl] is not None
+ and dec._line_eas[dl] <= lea,
+ f"link_line={dl} lea={hex(lea) if lea else None}")
await c.press("tab")
await c.pause(0.1)
c.check("Tab in split focuses the pseudocode pane", app._active == "decomp",
f"active={app._active}")
+ # decomp drives: put the cursor on an addressed pseudocode line (past the
+ # variable decls); the listing band must track the covering instruction row.
+ target = next((i for i, e in enumerate(dec._line_eas) if e is not None), None)
+ c.check("pseudocode has addressed lines", target is not None,
+ "no /*0xEA*/ markers in the pseudocode")
+ if target is not None:
+ dec.cursor = target
+ app._sync_split("decomp")
+ await c.pause(0.1)
+ want = lst.model.ensure_ea(dec._line_eas[target])
+ c.check("decomp cursor links the instruction row in the listing",
+ want in lst._link_rows,
+ f"link_rows={sorted(lst._link_rows)[:6]} want={want}")
+ # and that linked row actually paints a background band (base rows have
+ # no bg; `want` is a deep code row, never the listing's own cursor row)
+ lst.reveal(want)
+ await c.pause(0.05)
+ y = want - round(lst.scroll_offset.y)
+ banded = (0 <= y < lst.size.height and any(
+ s.style and s.style.bgcolor is not None for s in lst.render_line(y)))
+ c.check("the linked instruction row renders a highlight band", banded,
+ f"y={y} cursor_row={lst.cursor}")
await c.press("tab")
await c.pause(0.1)
c.check("Tab again focuses the listing pane", app._active == "listing",
@@ -363,6 +396,9 @@ async def s_split_view(c: Ctx):
and not dec.display, 10)
c.check("'s' exits split back to a single view", gone,
f"split={app._split} lst={lst.display} dec={dec.display}")
+ c.check("exiting split clears the link bands",
+ not lst._link_rows and dec._link_line is None,
+ f"rows={lst._link_rows} line={dec._link_line}")
@scenario("decomp_fallback")