From b441f2d89bd9273dad9253914a09765e52679666 Mon Sep 17 00:00:00 2001 From: blasty Date: Thu, 9 Jul 2026 14:07:22 +0200 Subject: column cursor: real left/right movement + follow the ref UNDER the cursor - ColumnCursor mixin for both views: h/l/left/right, w/b word-hops, 0/$ line ends; block cursor cell + word-under-cursor highlight rendered on the cursor line (region-refresh so it stays cheap). vertical moves clamp the column. - follow/xrefs now use the token under the cursor, so a line with multiple refs follows the one you're pointing at (proven: 'return sub_A(sub_B,..)' -> cursor on sub_B follows sub_B). decomp matches a decompiler ref by exact name; disasm resolves the symbol, falling back to the line's from-xref (address column / hex operands are excluded so the default position still follows the target). - horizontal scroll follows the cursor in the pseudocode view. - dropped the f/b paging aliases (b is now word-back). - pilot suite 34/34. --- tests/test_tui.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'tests') diff --git a/tests/test_tui.py b/tests/test_tui.py index 999d341..22d50b1 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -9,6 +9,7 @@ status update. Uses ~/ida-venv python (has textual). """ import asyncio import os +import re import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -265,6 +266,33 @@ async def run(db): check("Esc closes the xrefs popup", not isinstance(app.screen, XrefsScreen)) + # Column cursor: h/l move it; following the symbol under the cursor. + dis.focus() + dis.cursor = call_idx + dis.cursor_x = 5 + dis.refresh() + await pilot.press("h") + check("h moves the column cursor left", dis.cursor_x == 4, f"x={dis.cursor_x}") + await pilot.press("l") + await pilot.press("l") + check("l moves the column cursor right", dis.cursor_x == 6, f"x={dis.cursor_x}") + plain = dis._line_plain(call_idx) or "" + m = re.search(r"\b(sub_[0-9A-Fa-f]+)", plain) + if m: + dis.cursor = call_idx + dis.cursor_x = m.start(1) + 1 + dis.refresh() + await pilot.pause(0.1) + check("word-under-cursor is the operand symbol", + dis.word_under_cursor() == m.group(1), + f"{dis.word_under_cursor()!r} vs {m.group(1)!r}") + depth = len(app._nav) + want = app.program.resolve(m.group(1)) + await pilot.press("enter") + await wait_until(pilot, lambda: len(app._nav) > depth, timeout=25) + check("follows the symbol under the cursor", + app._cur.ea == want, f"cur={app._cur.ea:#x} want={want:#x}") + def main(argv): db = None -- cgit v1.3.1-sl0p