aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/app.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-07 02:49:28 +0200
committeruser <user@clank>2026-08-07 02:49:28 +0200
commit625b067ed89f773bf1601d4dcb01484826db34c0 (patch)
treedb3e0a1158144c42b5e999a2028f35777c578c19 /idatui/app.py
parentSearch the whole segment as ONE joined string. Every line is concatenated onc... (diff)
downloadida-tui-625b067ed89f773bf1601d4dcb01484826db34c0.tar.gz
ida-tui-625b067ed89f773bf1601d4dcb01484826db34c0.tar.xz
ida-tui-625b067ed89f773bf1601d4dcb01484826db34c0.zip
HexView.render_line emits style RUNS instead of one Segment per byte cell (35 -> 7 segments per row), and Head is a NamedTuple rather than a frozen dataclass (tuple.__new__ 1.9us vs a dataclass __init__ 2.9us, and it is built once per listing row walked).
Result: {"status":"keep","total_ms":17784.1,"lg_boot_ms":680.8,"lg_decomp_ms":2344,"lg_graph_ms":1106.5,"lg_hex_ms":576.4,"lg_index_ms":96.5,"lg_listing_cold_ms":552.9,"lg_listing_warm_ms":431.3,"lg_nav_ms":6256.4,"lg_palette_ms":4.8,"lg_render_ms":224.1,"lg_search_ms":1916.5,"pure_graph_ms":241.3,"sm_boot_ms":442.6,"sm_decomp_ms":591.3,"sm_graph_ms":663.9,"sm_hex_ms":419.2,"sm_index_ms":0,"sm_listing_cold_ms":258.2,"sm_listing_warm_ms":281.8,"sm_nav_ms":374.4,"sm_palette_ms":0.3,"sm_render_ms":251.1,"sm_search_ms":69.8,"fails":0}
Diffstat (limited to 'idatui/app.py')
-rw-r--r--idatui/app.py34
1 files changed, 28 insertions, 6 deletions
diff --git a/idatui/app.py b/idatui/app.py
index abdaa1e..20aed88 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -2052,10 +2052,31 @@ class HexView(ScrollView, can_focus=True):
if data is None:
segs.append(Segment("… fetching", _S_DIM))
else:
+ # Emit RUNS, not one segment per byte. A row is 32 cells whose style
+ # almost never changes (one cursor cell, or a trace boundary), and a
+ # segment per cell made every hex frame 1540 segments for the
+ # compositor to cut and merge again.
n = len(data)
+ run: list[str] = []
+ run_st = None
+
+ def flush(st=None, _segs=segs) -> None:
+ nonlocal run, run_st
+ if run:
+ _segs.append(Segment("".join(run), run_st))
+ run = []
+ run_st = st
+
+ def put(text: str, st) -> None:
+ nonlocal run_st
+ if st is not run_st:
+ flush(st)
+ run.append(text)
+
+ run_st = _S_HEX
for i in range(16):
if i == 8:
- segs.append(Segment(" ", _S_HEX))
+ put(" ", _S_HEX)
if i < n:
live = tknown is not None and tknown[i]
val = tmem[i] if live else data[i]
@@ -2065,10 +2086,10 @@ class HexView(ScrollView, can_focus=True):
st = _S_HEX
else:
st = _S_HEX_LIVE if live else _S_HEX_STALE
- segs.append(Segment(f"{val:02X} ", st))
+ put(f"{val:02X} ", st)
else:
- segs.append(Segment(" ", _S_HEX))
- segs.append(Segment(" |", _S_DIM))
+ put(" ", _S_HEX)
+ put(" |", _S_DIM)
for i in range(16):
if i < n:
live = tknown is not None and tknown[i]
@@ -2082,8 +2103,9 @@ class HexView(ScrollView, can_focus=True):
st = _S_HEX_LIVE if live else _S_HEX_STALE
else:
ch, st = " ", _S_ASCII
- segs.append(Segment(ch, st))
- segs.append(Segment("|", _S_DIM))
+ put(ch, st)
+ put("|", _S_DIM)
+ flush()
return Strip(segs).adjust_cell_length(width, _S_HEX)