diff options
| author | blasty <blasty@local> | 2026-07-09 12:52:02 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-09 12:52:02 +0200 |
| commit | 4f18db24e61bd0b85376020c6c749d86ec58a749 (patch) | |
| tree | 924c616fca1c16ac7da875ace51cba5c45aade86 /tests | |
| parent | fix decompiler highlighting + cursor jank (diff) | |
| download | ida-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.py | 34 |
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 |
