aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 14:30:13 +0200
committerblasty <blasty@local>2026-07-09 14:30:13 +0200
commit9aa8d8a381a2afc81ffdcfa095247ea66b019b63 (patch)
treee006fdead8005c395eb9dd0519606e6190644e6f /tests
parentpreserve cursor line+column in the jump history (diff)
downloadida-tui-9aa8d8a381a2afc81ffdcfa095247ea66b019b63.tar.gz
ida-tui-9aa8d8a381a2afc81ffdcfa095247ea66b019b63.tar.xz
ida-tui-9aa8d8a381a2afc81ffdcfa095247ea66b019b63.zip
track pseudocode-view cursor position across jumps
NavEntry now also stores dec_cursor/dec_cursor_x. DecompView posts a CursorMoved (with the line's /*0xEA*/ address) on move/click; the app keeps the top-of-history pseudocode position current and DecompView.show restores it when returning to a function. So Esc after a jump lands on the exact pseudocode line+column too, independent of the disasm position. pilot suite 38/38.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_tui.py47
1 files changed, 47 insertions, 0 deletions
diff --git a/tests/test_tui.py b/tests/test_tui.py
index 5567eb5..bd110c1 100644
--- a/tests/test_tui.py
+++ b/tests/test_tui.py
@@ -337,6 +337,53 @@ async def run(db):
dis.cursor == mline and dis.word_under_cursor() == msym,
f"cursor={dis.cursor} (want {mline}) word={dis.word_under_cursor()!r}")
+ # Pseudocode-view position is tracked independently across jumps.
+ prog = app.program
+ fi = prog.functions()
+ fi.ensure(500)
+ pick = None
+ for fn in fi.all_loaded()[:500]:
+ d = prog.decompile(fn.addr)
+ if d.failed or not d.code:
+ continue
+ dl = d.code.split("\n")
+ if len(dl) < 12:
+ continue
+ for i, txt in enumerate(dl):
+ if i < 8:
+ continue
+ dm2 = re.search(r"\b(sub_[0-9A-Fa-f]+)", txt)
+ if dm2 and dm2.group(1) != fn.name:
+ pick = (fn, i, dm2.start(1), dm2.group(1))
+ break
+ if pick:
+ break
+ if pick is None:
+ check("found a pseudocode line to test decomp nav", False)
+ else:
+ fn, drow, dcol, dsym = pick
+ await pilot.press("g")
+ await pilot.pause(0.2)
+ for ch in fn.name:
+ await pilot.press(ch)
+ await pilot.press("enter")
+ await wait_until(pilot, lambda: dis.total > 0, timeout=20)
+ await pilot.press("tab")
+ await wait_until(pilot, lambda: dec.loaded_ea == fn.addr, timeout=20)
+ dec.cursor = drow
+ dec.cursor_x = dcol
+ dec._after_cursor_move()
+ await pilot.pause(0.1)
+ depth = len(app._nav)
+ await pilot.press("enter") # follow the sym under the pseudocode cursor
+ await wait_until(pilot, lambda: len(app._nav) > depth, timeout=25)
+ await pilot.press("escape")
+ await wait_until(pilot, lambda: dec.loaded_ea == fn.addr, timeout=25)
+ await pilot.pause(0.2)
+ check("pseudocode-view position restored after jump+back",
+ dec.cursor == drow and dec.word_under_cursor() == dsym,
+ f"cursor={dec.cursor} (want {drow}) word={dec.word_under_cursor()!r}")
+
def main(argv):
db = None