aboutsummaryrefslogtreecommitdiffstats
path: root/idatui
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-24 16:17:58 +0200
committerblasty <blasty@local>2026-07-24 16:17:58 +0200
commit31f00a82ab992add03dd3891c96a5e6292be2ed2 (patch)
treee5656992556ff3dca02dc38b85883451ff8e59eb /idatui
parentux: omit the splash logo when the terminal is too small for it (diff)
downloadida-tui-31f00a82ab992add03dd3891c96a5e6292be2ed2.tar.gz
ida-tui-31f00a82ab992add03dd3891c96a5e6292be2ed2.tar.xz
ida-tui-31f00a82ab992add03dd3891c96a5e6292be2ed2.zip
palette: replace the stock Ctrl+P command palette with real ida-tui actions
The Ctrl+P palette was Textual's stock system commands (change theme / take screenshot / quit) -- useless for RE. Add an IdaCommands command Provider and set IdaTui.COMMANDS = {IdaCommands} so the palette lists real actions instead: goto, find symbol, follow, xrefs, toggle disasm/pseudocode, continuous listing, hex, rename, retype, comment, define code/func, make data/string, undefine, toggle opcodes, structs editor, filter, names pane, save, quit -- each with its keybind as help text, fuzzy-searchable. App-level actions run directly; cursor-scoped ones (rename/xrefs/comment/...) are dispatched to the active code view via IdaTui._palette_action (focus + run the view's action_*), so a palette pick does exactly what the key does. Verified live over RPC: 'hex' switches view, 'goto' opens the prompt, 'struct' opens the StructEditor modal, and the stock 'theme' command is gone. Pilot command_palette scenario: Ctrl+P opens it and a command executes (7/7).
Diffstat (limited to 'idatui')
-rw-r--r--idatui/app.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/idatui/app.py b/idatui/app.py
index ac55864..2a3e617 100644
--- a/idatui/app.py
+++ b/idatui/app.py
@@ -28,6 +28,7 @@ from rich.text import Text
from textual import work
from textual.app import App, ComposeResult
from textual.binding import Binding
+from textual.command import DiscoveryHit, Hit, Provider
from textual.containers import Horizontal, Vertical
from textual.geometry import Region, Size
from textual.message import Message
@@ -2342,7 +2343,71 @@ class StructEditor(ModalScreen):
# --------------------------------------------------------------------------- #
# The app
# --------------------------------------------------------------------------- #
+class IdaCommands(Provider):
+ """Fills the Ctrl+P command palette with real ida-tui actions instead of the
+ stock Textual system commands (change theme / take screenshot / …).
+
+ App-level actions run directly; cursor-scoped ones (rename/xrefs/comment/…)
+ are dispatched to the active code view via ``IdaTui._palette_action``."""
+
+ def _commands(self):
+ app = self.app
+ va = app._palette_action # dispatch to the focused code view
+ return (
+ ("Goto address / symbol…", "jump to an address or name (g)",
+ app.action_goto),
+ ("Find symbol…", "fuzzy function finder (Ctrl+N)", app.action_symbols),
+ ("Follow symbol under cursor", "jump to the referenced symbol (Enter)",
+ lambda: va("follow")),
+ ("Show xrefs to symbol", "cross-references to the cursor symbol (x)",
+ lambda: va("xrefs")),
+ ("Back", "navigation history (Esc)", app.action_back),
+ ("Toggle disassembly / pseudocode", "decompile / listing (F5, Tab)",
+ app.action_toggle_view),
+ ("Continuous listing here", "flat segment listing (L)",
+ app.action_continuous_here),
+ ("Hex view", "raw bytes at the cursor (\\)", app.action_hex),
+ ("Rename symbol…", "rename the symbol under the cursor (n)",
+ lambda: va("rename")),
+ ("Set type / prototype…", "retype the symbol under the cursor (y)",
+ lambda: va("retype")),
+ ("Add comment…", "comment at the cursor (;)", lambda: va("comment")),
+ ("Define code", "make code at the cursor (c)", lambda: va("define_code")),
+ ("Create function", "define a function at the cursor (p)",
+ lambda: va("define_func")),
+ ("Make data", "define a data item at the cursor (d)",
+ lambda: va("make_data")),
+ ("Make string", "define a string at the cursor (a)",
+ lambda: va("make_string")),
+ ("Undefine", "undefine the item at the cursor (u)",
+ lambda: va("undefine")),
+ ("Toggle opcode bytes", "cycle the opcode-bytes column (o)",
+ lambda: va("toggle_opcodes")),
+ ("Structs / types editor", "view + edit local types (Ctrl+T)",
+ app.action_structs),
+ ("Filter functions…", "glob-filter the function list (/)",
+ app.action_filter),
+ ("Toggle names pane", "function-list sidebar (Ctrl+B)",
+ app.action_toggle_functions),
+ ("Save database (.i64)", "persist changes (Ctrl+S)", app.action_save),
+ ("Quit", "exit ida-tui (q)", app.action_quit),
+ )
+
+ async def discover(self):
+ for title, help_text, cb in self._commands():
+ yield DiscoveryHit(title, cb, help=help_text)
+
+ async def search(self, query: str):
+ matcher = self.matcher(query)
+ for title, help_text, cb in self._commands():
+ score = matcher.match(title)
+ if score > 0:
+ yield Hit(score, matcher.highlight(title), cb, help=help_text)
+
+
class IdaTui(App):
+ COMMANDS = {IdaCommands} # replace the stock system-commands palette
+
CSS = """
Screen { layout: vertical; }
#panes { height: 1fr; }
@@ -4061,6 +4126,20 @@ class IdaTui(App):
return self.query_one(DecompView)
return None
+ def _palette_action(self, name: str) -> None:
+ """Run a cursor-scoped code-view action (rename/xrefs/follow/…) picked from
+ the command palette against the active code view."""
+ view = self._active_code_view()
+ if view is None:
+ self._status("open a function first")
+ return
+ view.focus()
+ fn = getattr(view, f"action_{name}", None)
+ if fn is None:
+ self._status(f"'{name}' isn't available in this view")
+ return
+ fn()
+
def action_continuous_here(self) -> None:
"""'L': open the continuous segment listing at the cursor — one long
flat view where functions, data and undefined bytes are interleaved,