aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 12:52:02 +0200
committerblasty <blasty@local>2026-07-09 12:52:02 +0200
commit4f18db24e61bd0b85376020c6c749d86ec58a749 (patch)
tree924c616fca1c16ac7da875ace51cba5c45aade86 /tests
parentfix decompiler highlighting + cursor jank (diff)
downloadida-tui-4f18db24e61bd0b85376020c6c749d86ec58a749.tar.gz
ida-tui-4f18db24e61bd0b85376020c6c749d86ec58a749.tar.xz
ida-tui-4f18db24e61bd0b85376020c6c749d86ec58a749.zip
vim-style search in disasm + pseudocode views
- SearchMixin shared by both views: '/' search forward, '?' backward, empty query repeats last; n/N next/prev. Smartcase. All matches highlighted (substring overlay), cursor lands on current match; status shows k/N. - disasm indexes line text lazily in a worker (handles huge funcs); pseudocode has text in hand. Substring highlight via crop/join Strip overlay. - app: bottom search prompt, SearchRequested routing; '/' is context-sensitive (filters when the function table is focused, searches in code views). - gotcha fixed: Textual only merges BINDINGS from DOMNode subclasses, so mixin bindings are ignored -> each view lists SEARCH_BINDINGS explicitly. - pilot suite 20/20 (adds search finds/hl/repeat-fwd/repeat-back).
Diffstat (limited to 'tests')
-rw-r--r--tests/test_tui.py34
1 files changed, 33 insertions, 1 deletions
diff --git a/tests/test_tui.py b/tests/test_tui.py
index 0054765..3b97739 100644
--- a/tests/test_tui.py
+++ b/tests/test_tui.py
@@ -100,7 +100,11 @@ async def run(db):
check("goto-bottom lands near end",
view.cursor >= view.total - 1, f"cursor={view.cursor}/{view.total}")
- # Filter round-trip.
+ # Filter round-trip. '/' is context-sensitive: it filters when the
+ # function table is focused (and searches when a code view is focused),
+ # so focus the table first.
+ table.focus()
+ await pilot.pause(0.1)
await pilot.press("slash")
await pilot.pause(0.1)
for ch in "sub_1*":
@@ -149,6 +153,34 @@ async def run(db):
app._active == "disasm" and dis.display and not dec.display,
f"active={app._active}")
+ # Vim-style search in the disassembly view.
+ line0 = dis.model.cached_line(0)
+ raw = (line0.text.split() or ["push"])[0] if line0 else "push"
+ term = "".join(c for c in raw if c.isalnum())[:4] or "push"
+ await pilot.press("slash")
+ await pilot.pause(0.2)
+ for ch in term:
+ await pilot.press(ch)
+ await pilot.press("enter")
+ await wait_until(pilot, lambda: bool(dis._matches), timeout=25)
+ check("search finds matches", len(dis._matches) > 0, f"term={term!r}")
+ check("cursor sits on a match", dis.cursor in dis._matches, f"cursor={dis.cursor}")
+ check("match substring highlighted",
+ bool(dis._ranges.get(dis.cursor)), str(dis._ranges.get(dis.cursor)))
+ prev = dis.cursor
+ await pilot.press("slash")
+ await pilot.pause(0.1)
+ await pilot.press("enter")
+ await pilot.pause(0.1)
+ check("'/' repeats to next match",
+ dis.cursor != prev and dis.cursor in dis._matches, f"cursor={dis.cursor}")
+ await pilot.press("question_mark")
+ await pilot.pause(0.1)
+ await pilot.press("enter")
+ await pilot.pause(0.1)
+ check("'?' repeats to previous match", dis.cursor in dis._matches,
+ f"cursor={dis.cursor}")
+
def main(argv):
db = None