From 01efa57c2a9547ae37add7ebb11cafd8de50ddbf Mon Sep 17 00:00:00 2001 From: blasty Date: Thu, 9 Jul 2026 12:58:10 +0200 Subject: search UX: visible prompt + incremental (as-you-type) highlighting - Fix overlap: #search, #status and Footer all docked bottom, and Input defaults to a 3-row bordered widget squeezed into 1 row. Now the search bar is a clean 1-row (border:none) that REPLACES the status line while active (status hidden), so the query is always visible. - Incremental search: highlight all matches + preview-jump from the origin on every keystroke (Input.Changed), not just on submit. Disasm indexes once then each keystroke is instant. Enter keeps; empty Enter repeats last; Esc cancels and restores the origin cursor + status line. - pilot suite 23/23 (adds: bar-visible/no-overlap, incremental-before-Enter, Esc-cancel). --- tests/test_tui.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/test_tui.py b/tests/test_tui.py index 3b97739..2156fad 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -13,7 +13,7 @@ import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from idatui.app import DecompView, DisasmView, FunctionsPanel, IdaTui # noqa: E402 -from textual.widgets import DataTable, Static # noqa: E402 +from textual.widgets import DataTable, Input, Static # noqa: E402 PASS = FAIL = 0 @@ -181,6 +181,24 @@ async def run(db): check("'?' repeats to previous match", dis.cursor in dis._matches, f"cursor={dis.cursor}") + # Incremental search + visible bar + Esc cancel. + si = app.query_one("#search", Input) + status = app.query_one("#status", Static) + await pilot.press("slash") + await pilot.pause(0.2) + check("search bar visible, status hidden (no overlap)", + si.display and not status.display, f"si={si.display} status={status.display}") + for ch in term: + await pilot.press(ch) + await pilot.pause(0.1) + check("matches highlight incrementally (before Enter)", + len(dis._matches) > 0 and si.value == term, f"val={si.value!r}") + await pilot.press("escape") + await pilot.pause(0.2) + check("Esc cancels: status restored, matches cleared", + status.display and not si.display and not dis._matches, + f"status={status.display} si={si.display} m={len(dis._matches)}") + def main(argv): db = None -- cgit v1.3.1-sl0p