aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-24 21:48:20 +0200
committerblasty <blasty@local>2026-07-24 21:48:20 +0200
commit41b42e4e7ebb9303e7a861ee8c6d948d8cd813fa (patch)
treede39ed2d30e47441839bf7d1911a37e1de025f6e /tests
parentdecomp: fix stuck 'decompiling' spinner when re-opening a loaded function (diff)
downloadida-tui-41b42e4e7ebb9303e7a861ee8c6d948d8cd813fa.tar.gz
ida-tui-41b42e4e7ebb9303e7a861ee8c6d948d8cd813fa.tar.xz
ida-tui-41b42e4e7ebb9303e7a861ee8c6d948d8cd813fa.zip
split-view phase 1: side-by-side listing <-> pseudocode layout
The Ghidra-style dual view, layout + toggle (no cursor sync yet — that's phase 2). 's' (and a "Split view" palette command) toggles a _split mode where the listing (left) and pseudocode (right) show together, divided by a keyline, one focused. Entering split loads the listing + decompiles the current function into both panes; Tab/F5 switches the focused pane; any single-view target (hex, etc.) or 's' again collapses back to the focused pane. * app: _split flag; _show_active gains a split branch (both panes, load decomp, focus active, #panes.split class); action_toggle_split + _enter_split worker; action_toggle_view switches panes when split; 's' binding + palette entry; #panes.split ListingView divider CSS. * docs/SPLIT_VIEW.md: the full design + phased roadmap (the hard part — line<->EA set mapping via a sweep of cfunc.get_line_item — is scoped for phase 3). * tests: split_view scenario (enter/load/tab-focus/exit, 5 checks). Also fix disasm_nav's stale goto-bottom (press ctrl+end; plain 'end' is end-of-line now). Verified live over RPC (both panes render, Tab flips focus, 's' exits) and pilot split_view 5/5.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_scenarios.py31
1 files changed, 29 insertions, 2 deletions
diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py
index 39f8d86..aa0ecbf 100644
--- a/tests/test_scenarios.py
+++ b/tests/test_scenarios.py
@@ -338,6 +338,32 @@ async def s_command_palette(c: Ctx):
await c.wait(lambda: app._active != "hex", 5)
+@scenario("split_view")
+async def s_split_view(c: Ctx):
+ app, lst, dec = c.app, c.lst, c.dec
+ await c.open_biggest("listing")
+ await c.press("s")
+ shown = await c.wait(lambda: app._split and lst.display and dec.display, 20)
+ c.check("'s' enters split view (both panes shown)", shown,
+ f"split={app._split} lst={lst.display} dec={dec.display}")
+ 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}")
+ 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}")
+ await c.press("tab")
+ await c.pause(0.1)
+ c.check("Tab again focuses the listing pane", app._active == "listing",
+ f"active={app._active}")
+ await c.press("s")
+ gone = await c.wait(lambda: not app._split and lst.display
+ 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}")
+
+
@scenario("decomp_fallback")
async def s_fallback(c: Ctx):
app = c.app
@@ -485,8 +511,9 @@ async def s_disasm_nav(c: Ctx):
await c.wait(lambda: app._clipboard == cur_line, 10)
c.check("Ctrl+Y copies the current code line to the clipboard",
bool(cur_line) and app._clipboard == cur_line, f"clip={app._clipboard!r}")
- # goto-bottom must not hang on a huge function.
- await c.press("end")
+ # goto-bottom must not hang on a huge function (ctrl+end; plain 'end' now
+ # moves the cursor to end-of-line).
+ await c.press("ctrl+end")
await c.pause(0.05)
c.check("goto-bottom lands near end", view.cursor >= view.total - 1,
f"cursor={view.cursor}/{view.total}")