<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ida-tui.git/tests/test_tui.py, branch main</title>
<subtitle>tui for headless ida</subtitle>
<id>https://git.sl0p.foo/ida-tui.git/atom/tests/test_tui.py?h=main</id>
<link rel='self' href='https://git.sl0p.foo/ida-tui.git/atom/tests/test_tui.py?h=main'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/'/>
<updated>2026-07-10T12:53:59Z</updated>
<entry>
<title>tests: retire the monolithic test_tui.py (superseded by test_scenarios)</title>
<updated>2026-07-10T12:53:59Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T12:53:59Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=ab9dad156891a1f44eca17a9ea6d979b56564c3e'/>
<id>urn:sha1:ab9dad156891a1f44eca17a9ea6d979b56564c3e</id>
<content type='text'>
The scenario suite now covers every behavior the monolith did (all check
names accounted for, modulo renames), so drop the old single-session
runner.
</content>
</entry>
<entry>
<title>hex view: raw image bytes (VA-addressed), synced to the code cursor</title>
<updated>2026-07-10T12:03:16Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T12:03:16Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=636a6cb34e83523c3c513fb62ca39e0f6c10098f'/>
<id>urn:sha1:636a6cb34e83523c3c513fb62ca39e0f6c10098f</id>
<content type='text'>
New HexView: a line-virtualized 16-bytes/row dump of the whole loaded image,
addressed by virtual address. Format-agnostic — the range/segments come from IDA
(image_range over sections()), not any file header; gaps read back as zeros.

Backslash toggles it, synced to the address under the disasm/pseudocode cursor
(see the naked bytes of some code/data). In hex: hjkl/paging navigate a byte
cursor (status shows the section), Enter jumps the code view to the byte,
Tab/Esc/backslash return to the preferred code view. A third _active state; block
-cached + prefetched like the disasm model.

domain: HexModel + Program.hex_model/read_bytes/image_range (get_bytes regions).
Fixed a self-deadlock (hex_model held _lock while sections() re-locked).
Pilot: sync, actual bytes, byte-step, return. full suite 98/98.
</content>
</entry>
<entry>
<title>retype: set variable/function types with 'y' (IDA-style), via structured tools</title>
<updated>2026-07-10T11:30:48Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T11:30:48Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=6d83015906f850b872261655f014ef14612a8ba5'/>
<id>urn:sha1:6d83015906f850b872261655f014ef14612a8ba5</id>
<content type='text'>
Instead of parsing pseudocode text, add structured server tools (server/
patch_server.py, alongside del_type):
 - func_types(addr): prototype + local variables (name/type/is_arg)
 - set_lvar_type(addr,var,type): retype a decompiler local, working on auto/
   register vars too (stock set_type only updates already-user-modified lvars)

'y' in a code view retypes what's under the cursor: a local variable (prompt
prefilled with its current type) or a function (prompt prefilled with its full
prototype). Applies via set_lvar_type / set_type, then recompiles + refreshes.
Copy-line moved off 'y' to Ctrl+Y.

domain: Program.func_types / set_function_type / set_lvar_type (LVar/FuncTypes).
Pilot: function-prototype retype (prefill + apply). full suite 94/94.
</content>
</entry>
<entry>
<title>struct editor: auto-format the definition on save</title>
<updated>2026-07-10T11:02:05Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T11:02:05Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=ae3399da08a54e3ecdc8b4c3e622efbf54b55dae'/>
<id>urn:sha1:ae3399da08a54e3ecdc8b4c3e622efbf54b55dae</id>
<content type='text'>
After a successful declare, re-fetch the canonical struct_source and put it back
in the editor, so the normalized layout/types show immediately instead of only
after re-selecting the struct from the list (e.g. a pasted one-liner becomes
multi-line, 'unsigned long' -&gt; 'unsigned __int64'). _loaded_src is updated to the
formatted text so it isn't considered dirty. Pilot check. full suite 92/92.
</content>
</entry>
<entry>
<title>struct editor: loud save errors + guard unsaved edits</title>
<updated>2026-07-10T10:38:51Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T10:38:51Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=50cbb7e982e03be863ad7f1979638520ffc95f55'/>
<id>urn:sha1:50cbb7e982e03be863ad7f1979638520ffc95f55</id>
<content type='text'>
A struct with a field IDA's C parser rejects (notably '__unused', a predefined
macro) failed to re-declare, but the failure was silent: the edit looked applied,
then reloading showed the old definition (lost work). Now:

- a failed declare shows a loud, styled 'save failed' status and, when it can,
  names the offending reserved field ('__unused') instead of IDA's empty
  'Failed to parse'; the type is left unchanged and the editor keeps your text.
- switching structs / starting new / closing with unsaved edits prompts to
  discard first (ConfirmScreen), so edits aren't silently reloaded away.

Pilot: rejected save is loud/named/non-destructive; switching structs guards
unsaved edits. full suite 91/91.
</content>
</entry>
<entry>
<title>clipboard: keyboard copy (OSC 52 + tmux) since mouse-select is captured</title>
<updated>2026-07-10T10:23:52Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T10:23:52Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=4fd71ed6202c4c9925963c9e9156d3cb0e549b35'/>
<id>urn:sha1:4fd71ed6202c4c9925963c9e9156d3cb0e549b35</id>
<content type='text'>
The app captures the mouse (SGR tracking), so terminal/tmux drag-select can't
grab text. Add explicit copy actions:
 - code views: 'y' copies the current line
 - struct editor: Ctrl+Y copies the selection, else the whole C definition

App._copy() emits OSC 52 (Textual copy_to_clipboard) AND, inside tmux, pipes
through 'tmux load-buffer -w -' — the combination is what actually reaches the
system clipboard over tmux/ssh. Status shows the char count.

full suite 87/87.
</content>
</entry>
<entry>
<title>struct editor: discoverable, confirmed delete (d/Del + ConfirmScreen)</title>
<updated>2026-07-10T10:04:48Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T10:04:48Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=bc03ad0a233927dfbcbe6d91c6ddd89d33e8ebc8'/>
<id>urn:sha1:bc03ad0a233927dfbcbe6d91c6ddd89d33e8ebc8</id>
<content type='text'>
Delete was wired to the Del key but undiscoverable (modal has no footer) and
unguarded. Add a 'd' alias (Del still works), and route delete through a small
ConfirmScreen (Enter/y confirm, Esc/n cancel) since it's destructive. 'd' in the
editor pane types normally; only the list triggers delete. Hint updated to
'd/Del delete'.

Pilot: 'd' opens the confirm, Esc cancels (kept), Enter deletes. full suite 85/85.
</content>
</entry>
<entry>
<title>struct editor: C-style CRUD for local types (Ctrl+T)</title>
<updated>2026-07-10T07:53:56Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T07:53:56Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=29f8a238d0e316c4a0fe4081c5412a18f5bb3c64'/>
<id>urn:sha1:29f8a238d0e316c4a0fe4081c5412a18f5bb3c64</id>
<content type='text'>
New StructEditor overlay: left is the list of local structs/unions, right is an
editable C definition. Enter loads a struct (reconstructed as C from its member
layout via type_inspect), Ctrl+S declares it (create or update via declare_type),
Ctrl+N starts a new one, Del deletes, Esc returns to the list then closes.

Domain: Struct model + Program.list_structs / struct_source / declare_type /
delete_type (anonymous $-types filtered).

Delete needs a 'del_type' tool the ida-pro-mcp server doesn't currently expose;
delete_type detects its absence and reports a clear message instead of failing.
Create/read/update work fully.

Pilot checks: open, list, view C, create, update-in-place, delete(-or-report),
close. full suite 84/84.
</content>
</entry>
<entry>
<title>decompiler: fall back to disassembly when decompilation fails</title>
<updated>2026-07-09T21:28:37Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-09T21:28:37Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=0c738bbcf00cf329847d9409f9639a84adeeced0'/>
<id>urn:sha1:0c738bbcf00cf329847d9409f9639a84adeeced0</id>
<content type='text'>
Opening a function that Hex-Rays can't decompile (import/PLT stubs, mis-analyzed
monsters) now shows the disassembly instead of a '/* decompilation failed */'
panel. A separate _pref (the preferred view, set by Tab) is kept, so only the
failing function falls back — the next decompilable function still opens as
pseudocode. _apply_decomp ignores a stale result if you've navigated away.

Pilot checks: failing func -&gt; disasm (pref kept), next func -&gt; pseudocode.
full suite 77/77.
</content>
</entry>
<entry>
<title>default to the pseudocode view instead of disassembly</title>
<updated>2026-07-09T21:12:02Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-09T21:12:02Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=c6ef8ceeba6b11ce0f6024ff089eff50e8de3579'/>
<id>urn:sha1:c6ef8ceeba6b11ce0f6024ff089eff50e8de3579</id>
<content type='text'>
Opening a function now shows the decompiler by default (Tab still toggles to
disassembly; the choice persists across opens). Startup focuses the decompiler
view, and Ctrl+B / back focus the active view rather than hard-coding disasm.

Tests: assert pseudocode-by-default on the first open, then normalize per-section
(the disasm-scrolling/search/follow blocks switch to disassembly explicitly).
full suite 75/75.
</content>
</entry>
</feed>
