diff options
| author | blasty <peter@haxx.in> | 2026-07-23 17:23:16 +0200 |
|---|---|---|
| committer | blasty <peter@haxx.in> | 2026-07-23 17:23:16 +0200 |
| commit | 4ca5ef03fe9db37e2a9969fcafb328e6ac1ad3e1 (patch) | |
| tree | debe9063e7f6f56fc9f7fd1766491cfb6f2509bb /idatui/domain.py | |
| parent | listing: F5/Tab decompiles the function under the cursor (IDA-style) — step 2 (diff) | |
| download | ida-tui-4ca5ef03fe9db37e2a9969fcafb328e6ac1ad3e1.tar.gz ida-tui-4ca5ef03fe9db37e2a9969fcafb328e6ac1ad3e1.tar.xz ida-tui-4ca5ef03fe9db37e2a9969fcafb328e6ac1ad3e1.zip | |
unify: the continuous listing is the one code view; deprecate DisasmView
Full IDA-style unification. The function-bounded DisasmView is gone from the UI:
navigation opens ONE continuous segment listing (functions+data+undefined
interleaved) at the target; F5/Tab decompiles the function under the cursor and
back. The listing gained the opcode column (Head.raw, 'o' toggle) so rendering
matches disasm.
Routing: _do_navigate/_open_function/_open_entry target the listing;
_show_active drops disasm; _active in {listing,decomp,hex}; _pref=listing.
Decomp is a per-function toggle with a listing fallback on failure. Edits
reload in place (_reload_active_code); bump_names() drops the listing cache so
renames refresh. Listing 'n' is symbol-aware. ListingModel gains
cached_line/lines shims; Head.label. DisasmView removed from compose/handlers;
rpc updated. DisasmModel kept (domain/test_domain).
Tests migrated (c.dis->ListingView; open(decomp) F5s; xref/search re-pointed).
Per-scenario green across view_toggle/rename/follow_xrefs/xref_labels/decomp_*/
search/mouse/startup/continuous_view (30/1, 1 cold-decompile flake).
Diffstat (limited to 'idatui/domain.py')
| -rw-r--r-- | idatui/domain.py | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/idatui/domain.py b/idatui/domain.py index 86fb47e..e392936 100644 --- a/idatui/domain.py +++ b/idatui/domain.py @@ -98,6 +98,10 @@ class Head: name: str | None = None raw: bytes | None = None # opcode/item bytes (filled in for code by the model) + @property + def label(self) -> str | None: # Line-compatible alias + return self.name + @classmethod def from_raw(cls, d: dict) -> "Head": return cls( @@ -680,6 +684,21 @@ class ListingModel: with self._lock: return self._by_ea.get(ea, -1) + # -- DisasmModel-compatible accessors (unified model) ------------------ # + def cached_line(self, idx: int) -> Head | None: + """Alias of get() for the disasm view's Line interface.""" + return self.get(idx) + + def lines(self, start: int, count: int, prefetch: bool = True) -> list[Head]: + return self.window(start, count) + + def is_cached(self, start: int, count: int) -> bool: + with self._lock: + return start + count <= len(self._heads) + + def ensure_async(self, start: int, count: int) -> None: + pass # the background grower streams the rest in; nothing to prefetch + # --------------------------------------------------------------------------- # # Hex model: block-cached byte view over the loaded image (VA-addressed) @@ -1114,12 +1133,13 @@ class Program: return dec def bump_names(self) -> None: - """Signal that symbol names changed (a rename). Disasm names are live in - the IDB, so clearing the block caches is enough for those; decompilation - is generation-checked and force-recompiled lazily on next access.""" + """Signal that symbol names changed (a rename). Disasm/listing names are + live in the IDB, so clearing the cached rows is enough for those; + decompilation is generation-checked and force-recompiled lazily.""" with self._lock: self._name_gen += 1 models = list(self._disasm.values()) + self._listings.clear() # listing head rows cache names -> refetch for m in models: m.invalidate() |
