<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ida-tui.git/tests, branch main</title>
<subtitle>tui for headless ida</subtitle>
<id>https://git.sl0p.foo/ida-tui.git/atom/tests?h=main</id>
<link rel='self' href='https://git.sl0p.foo/ida-tui.git/atom/tests?h=main'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/'/>
<updated>2026-07-10T14:43:32Z</updated>
<entry>
<title>app: multi-line comments via literal \\n (long notes were clipping)</title>
<updated>2026-07-10T14:43:32Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T14:43:32Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=7ae37ba3b432bbb2482df9c99864350e685b0241'/>
<id>urn:sha1:7ae37ba3b432bbb2482df9c99864350e685b0241</id>
<content type='text'>
The comment prompt is single-line, so a long note rendered as one giant
'//' line that ran off the right edge and got clipped. Interpret a literal
'\\n' (backslash-n) in the comment text as a real newline in _do_comment
(the single choke point for the ';' prompt and the RPC 'comment' verb) —
Hex-Rays renders each as its own '//' line. Verified live and locked in
the comment_func scenario (multi-line render); suite 104 green.
</content>
</entry>
<entry>
<title>drive: ergonomic RE helper over the RPC socket (terse text, auto socket)</title>
<updated>2026-07-10T14:17:50Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T14:17:50Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=33bd85e41221a82a8ee7b71d39eda59d89b78ee7'/>
<id>urn:sha1:33bd85e41221a82a8ee7b71d39eda59d89b78ee7</id>
<content type='text'>
Driving via rpcclient meant re-exporting the socket every fresh shell,
long invocations, and piping ~every call through python -c to pull one
field or grep pseudocode. idatui.drive fixes that: it auto-resolves the
socket (the single live pane from the registry), prints compact text
instead of JSON, and bundles the common gestures:

  where | go | pc &lt;fn&gt; [substr] | dis &lt;fn&gt; [n] | callees/callers &lt;fn&gt; |
  names &lt;substr&gt; | rename &lt;old&gt; &lt;new&gt; | mv old=new... | note &lt;fn&gt; &lt;text&gt; |
  screen | raw &lt;method&gt; k=v

So 'goto+rename+parse' becomes 'drive rename old new', and 'pseudocode |
python -c grep' becomes 'drive pc fn needle'. rpcclient stays the raw
transport. rpc_smoke drives it end-to-end (29 green).
</content>
</entry>
<entry>
<title>app: comment on a no-address line -&gt; function comment (was refused)</title>
<updated>2026-07-10T14:12:22Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T14:12:22Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=3b4e397f48e4519c6b5a24fede2e41707e355a92'/>
<id>urn:sha1:3b4e397f48e4519c6b5a24fede2e41707e355a92</id>
<content type='text'>
Pressing ';' on the decompiler's signature or local-declaration lines did
nothing ('no address on this line to comment') because those lines carry
no /*0xEA*/ marker. Fall back to the current function's entry ea so
commenting the header annotates the function itself; the prompt says
'function comment @ ...'. Body-line comments are unchanged.

New scenario comment_func locks it (suite 104 green).
</content>
</entry>
<entry>
<title>app: drop the Header (keep the Footer); rpc: function-scope xrefs_from</title>
<updated>2026-07-10T14:01:54Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T14:01:54Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=ead2125f041649024ede36d0b4eb8e4c4c466e32'/>
<id>urn:sha1:ead2125f041649024ede36d0b4eb8e4c4c466e32</id>
<content type='text'>
The clock/title Header added noise (and made screen() non-deterministic);
remove it from the app itself — the Footer stays. Layout shifts up a row;
scenario suite still 101 green.

xrefs_from on a function was near-useless: the server's xrefs_from is
address-scoped, so passing the entry ea only returned the fall-through
from the first instruction. For a function target it now returns
whole-body references from the decompiler (callees + string/data refs:
{to,name,string,is_func,type}); an explicit 0xADDR stays address-scoped.
Verified live: xrefs_from main now lists setlocale/getopt_long/sub_* etc.
rpc_smoke: 25 green.
</content>
</entry>
<entry>
<title>pane: auto-start the ida-pro-mcp supervisor if it's down</title>
<updated>2026-07-10T13:50:30Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T13:50:30Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=23a63681a61c2b522576d77dfd140f2174273a95'/>
<id>urn:sha1:23a63681a61c2b522576d77dfd140f2174273a95</id>
<content type='text'>
Before creating the TUI pane, spawn probes 127.0.0.1:8745 and, if nothing
is listening, launches ./spawn.sh in its own detached tmux pane and waits
for the port (server_started/server_pane are reported in the JSON). Only
for a local server, never a duplicate (spawn.sh binds the port), and it's
not killed on 'stop' (shared across TUIs). --no-ensure-server opts out;
IDATUI_SERVER_CMD overrides the launch command (used by the test).

tests/pane_smoke.py exercises the machinery with a dummy port-binder in a
pane (start / detect / idempotent / remote-guard), 5 green.
</content>
</entry>
<entry>
<title>rpc: cursor_on + word= edits, single-driver gate, colored screen</title>
<updated>2026-07-10T13:45:51Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T13:45:51Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=b90ae8d52623e9a59d6f5ee68ff2f96537bf965d'/>
<id>urn:sha1:b90ae8d52623e9a59d6f5ee68ff2f96537bf965d</id>
<content type='text'>
cursor_on {word,line?,occurrence?} places the cursor on a token, verified
with the app's own tokenizer (so 'main' won't match inside 'domain');
rename/retype/follow gain an optional word= that runs it first — the
ergonomic way to edit a named symbol without a manual view+cursor dance.

Single-driver gate: the socket now serves one client at a time; a second
concurrent connection is refused with 'busy' (no multi-driver support yet,
by request). Sequential connections are unaffected.

screen gains format=text|html|svg (html/svg are colored — for an
out-of-band web viewer). rpc_smoke: 24 green.
</content>
</entry>
<entry>
<title>rpc: readiness, quit, methods discovery, not-ready guard</title>
<updated>2026-07-10T13:35:21Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T13:35:21Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=0531f0e1787061aff06b01981d0e72d3718e3637'/>
<id>urn:sha1:0531f0e1787061aff06b01981d0e72d3718e3637</id>
<content type='text'>
Spawn-and-drive needs to know when the freshly-launched TUI is usable:
ping/state now carry {ready,functions,complete} (cheap; no health call)
and ping adds the module name. Add a graceful 'quit' verb (acks, then
exits on a short delay so the reply still flushes) and a self-documenting
'methods' table. Program-dependent verbs are refused with a clear
'not ready' instead of exploding in a worker while still loading.

rpc_smoke covers readiness, methods and quit (21 green).
</content>
</entry>
<entry>
<title>rpc: more verbs — structured reads, modal select, in-view search, save</title>
<updated>2026-07-10T13:29:21Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T13:29:21Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=9583334d0d413d8f4962b5d8fa1eccdbc196dd33'/>
<id>urn:sha1:9583334d0d413d8f4962b5d8fa1eccdbc196dd33</id>
<content type='text'>
Introspection (offloaded to a thread so a big fetch can't freeze the
render): pseudocode (full body), disassembly (bounded), xrefs_to/from
(structured), resolve (name-&gt;ea). These let an agent reason about a
function and the call graph without scraping screen().

Semantic: select (choose the highlighted/nth item in the open xrefs or
symbol-palette list and activate it — the natural follow-up to xrefs/
symbols), search (/ or ? incremental in the active code view), save
(Ctrl+S). rpc_smoke exercises all of them end-to-end (18 green).
</content>
</entry>
<entry>
<title>rpc: semantic verbs (typed-with-delay ops + fast movement)</title>
<updated>2026-07-10T13:14:49Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T13:14:49Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=85c717ac6aa7e6a2559c1ffb8e4e4f344419a667'/>
<id>urn:sha1:85c717ac6aa7e6a2559c1ffb8e4e4f344419a667</id>
<content type='text'>
Layer high-level verbs over the raw injection: goto/open, rename, comment,
retype, follow, back, toggle_view, hex, xrefs, symbols, structs, close,
plus fast move/cursor. Editing/goto verbs type through the real prompts
with a per-char delay (default 35ms) so viewers see it typed; movement
uses bare keypresses with a pump-only settle to stay snappy. Each verb
settles on an op-specific predicate where one exists (goto lands on the
target, follow grows the nav stack, toggle flips _active, modals open),
so the returned state is never stale.

rpc_smoke now drives the semantic path end-to-end (rename round-trip via
the prompt-fill seam), 11 green.
</content>
</entry>
<entry>
<title>rpc: unix-socket puppeteering server (raw keys + introspection + screen)</title>
<updated>2026-07-10T13:10:25Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-07-10T13:10:25Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=690a34512eaed933917f2d2c1cf12327923b39ac'/>
<id>urn:sha1:690a34512eaed933917f2d2c1cf12327923b39ac</id>
<content type='text'>
Run the TUI with --rpc &lt;sock&gt; and it renders normally while an asyncio
listener on the same loop lets another process drive it. Handlers touch
the UI directly (same loop, no thread hop), so every injected key has the
identical on-screen effect a keyboard would — the point for livestreaming.

Newline-delimited JSON. v1 methods: keys/text (raw injection, via the same
_press_keys the pilot uses; text can interleave wait:&lt;ms&gt; for a typed-out
look), state/view/screen/functions (introspection; screen() is a full
plain-text render of exactly what the viewer sees). No auth by design —
the socket is 0600, local only.

tests/rpc_smoke.py drives it end-to-end over a real socket (7 green).
</content>
</entry>
</feed>
