diff options
| author | blasty <blasty@local> | 2026-07-09 14:34:17 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-09 14:34:17 +0200 |
| commit | e10d5f3e83610ad1b3552ec1db1ef65f82cfa313 (patch) | |
| tree | 7af98ede0086b7e8e286baceec731ec168758540 | |
| parent | track pseudocode-view cursor position across jumps (diff) | |
| download | ida-tui-e10d5f3e83610ad1b3552ec1db1ef65f82cfa313.tar.gz ida-tui-e10d5f3e83610ad1b3552ec1db1ef65f82cfa313.tar.xz ida-tui-e10d5f3e83610ad1b3552ec1db1ef65f82cfa313.zip | |
sortable function list: click column headers (addr/name/size)
- on_data_table_header_selected sorts the cached function list by the clicked
column (address / name / size); clicking the same header reverses. Header
label shows a ▲/▼ arrow. Sorting composes with the active filter.
- pilot suite 41/41.
| -rw-r--r-- | idatui/app.py | 28 | ||||
| -rw-r--r-- | tests/test_tui.py | 21 |
2 files changed, 49 insertions, 0 deletions
diff --git a/idatui/app.py b/idatui/app.py index 8d4ab18..f46a334 100644 --- a/idatui/app.py +++ b/idatui/app.py @@ -936,6 +936,8 @@ class IdaTui(App): self._filter_term = "" self._pending_filter = "" self._filter_timer = None + self._sort_col = 0 # 0=addr, 1=name, 2=size + self._sort_reverse = False self._active = "disasm" # or "decomp" self._cur: NavEntry | None = None self._search_ctx: tuple[object | None, int] = (None, 1) @@ -1072,6 +1074,12 @@ class IdaTui(App): i = hay.find(needle) if i >= 0: matched.append((f, (i, i + len(term)))) + keyfn = { + 0: lambda fr: fr[0].addr, + 1: lambda fr: fr[0].name.lower(), + 2: lambda fr: fr[0].size, + }[self._sort_col] + matched.sort(key=keyfn, reverse=self._sort_reverse) table = self.query_one("#func-table", DataTable) table.clear() for f, rng in matched: @@ -1093,6 +1101,26 @@ class IdaTui(App): def clear_filter(self) -> None: self._apply_filter("") + def on_data_table_header_selected(self, event: DataTable.HeaderSelected) -> None: + """Click a column header to sort by it; click again to reverse.""" + col = event.column_index + if col == self._sort_col: + self._sort_reverse = not self._sort_reverse + else: + self._sort_col = col + self._sort_reverse = False + self._update_sort_headers() + self._apply_filter(self._filter_term) + + def _update_sort_headers(self) -> None: + table = self.query_one("#func-table", DataTable) + bases = ["Address", "Function", "Size"] + arrow = " ▼" if self._sort_reverse else " ▲" + for i, col in enumerate(table.columns.values()): + col.label = Text(bases[i] + (arrow if i == self._sort_col else "")) + table._require_update_dimensions = True + table.refresh() + # -- actions ----------------------------------------------------------- # def action_toggle_functions(self) -> None: """Show/hide the functions pane; give the disasm view all the width.""" diff --git a/tests/test_tui.py b/tests/test_tui.py index bd110c1..f7cbc81 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -384,6 +384,27 @@ async def run(db): dec.cursor == drow and dec.word_under_cursor() == dsym, f"cursor={dec.cursor} (want {drow}) word={dec.word_under_cursor()!r}") + # Column sort: click headers to sort by name / address. + if app._filter_term: + app._apply_filter("") + await pilot.pause(0.1) + await pilot.click(table, offset=(15, 0)) # Function header + await pilot.pause(0.3) + snames = [str(table.get_row_at(i)[1]) for i in range(min(20, table.row_count))] + check("click Function header sorts by name", + app._sort_col == 1 and snames == sorted(snames, key=str.lower), + f"sort_col={app._sort_col}") + first_asc = str(table.get_row_at(0)[1]) + await pilot.click(table, offset=(15, 0)) # reverse + await pilot.pause(0.3) + check("click again reverses the sort", + app._sort_reverse and str(table.get_row_at(0)[1]) != first_asc) + await pilot.click(table, offset=(3, 0)) # Address header + await pilot.pause(0.3) + saddrs = [int(str(table.get_row_at(i)[0]), 16) for i in range(min(20, table.row_count))] + check("click Address header sorts by address", + app._sort_col == 0 and saddrs == sorted(saddrs), f"sort_col={app._sort_col}") + def main(argv): db = None |
