Input Nexus
Overview
Integrate and extend input-nexus as the single source of truth for command palette state (InputState), while keeping rendering and command execution in the host application.
Workflow Decision Tree
- Need a palette/completion UI in a specific framework: implement a renderer adapter (event mapping + draw contract). See
references/integration.md. - Need to add/merge commands/contexts/placeholders: extend the registry and feed dynamic choices. See
Command Registry. - Need to cut a new release: follow the maintainer checklist. See
references/release.md.
Integration (Renderer Adapter)
- Add dependency:
input-nexus = "0.2.1"- For local dev: use
[patch.crates-io] input-nexus = { path = "../input-nexus" }
- Construct an
InputController:InputController::new()thenregister_context+register_command, orInputController::with_registry(command_set![ ... ])
- Map framework input events into
InputKey, then callhandle_key:- Handle
InputResult::Completed(cmd)by executing the command in your app. - Use
InputResult::Updated(state)to re-render from the new state.
- Handle
- Render purely from
controller.state()(InputState):buffer+cursoris the single line the user is editing.phasedecides which extra UI to show (candidate list / placeholder editor).
See references/integration.md for adapter patterns and concrete mappings.
Command Registry
- Prefer template-driven definitions:
command_set![ "id" => "ctx" => "br add <addr> [comment]" => "desc", ... ]register_from_template(id, ctx, template, desc)for runtime injection (scripts/plugins).
- Use
update_placeholder_choices(command_id, placeholder, choices)to inject dynamic lists (modules, processes, recent symbols, etc.). - Group in the UI:
- Primary:
CommandSpec.context_id(source grouping like built-in/script/internal). - Optional:
CommandSpec.groupfor sub-grouping within a context (e.g. scripts/aslr). - Use
InputController::contexts()/InputController::context(id)to render context labels/descriptions.
- Primary:
Renderer Contract (What To Draw)
Renderers should treat InputState as a read-only snapshot:
- Always draw:
bufferand a caret atcursor.
- If
phase == SelectingCommand:- Draw
completion_candidatesand highlightcandidate_index. - Use
selected_commandfor preview/details.
- Draw
- If
phase == EditingPlaceholder:- Highlight the
active_placeholdersegment in the buffer. - Use
placeholder_bindingsfor field labels/values (empty values render as<name>). - If
choice_candidatesis non-empty, show a list and highlightchoice_index.
- Highlight the
Key Semantics (Non-obvious)
Use these rules to avoid “why didn’t that key work?” issues:
Tab:Idle: populate candidates from currentbuffer.trim()and enterSelectingCommandif there is at least one match.SelectingCommand: cycle candidate selection.EditingPlaceholder: apply choice selection (if any), otherwise move to next placeholder.
Enter:SelectingCommand: confirm the selected command; enterEditingPlaceholderif it has placeholders.EditingPlaceholder: complete only when all required placeholders are filled; otherwise move to next placeholder.
Space:SelectingCommand: confirm the selected command (same asEnter).EditingPlaceholder: jump to next placeholder when not on the last placeholder; insert space when on the last placeholder (free-form rest-of-line values like comment/title/expression).
BackspaceinEditingPlaceholder:- Deletes inside the active placeholder.
- When the placeholder becomes empty, it stays in placeholder editing (so the UI can keep showing
<name>). - When the cursor is at the start of the first placeholder, another
Backspaceaborts placeholder editing and returns toIdle(keeping the command template in the buffer).
Up/Down:SelectingCommand: cycle candidates.EditingPlaceholder: cyclechoice_candidatesif present; otherwise move between placeholders.Idle: history navigation.
CtrlW:- Implement it only for the “whole line” editing mode (not placeholder mode), unless you add placeholder-specific word delete. (
InputState::stepeditsbufferdirectly.)
- Implement it only for the “whole line” editing mode (not placeholder mode), unless you add placeholder-specific word delete. (
Release (Maintainer)
Follow references/release.md to bump version, validate packaging, publish to crates.io, and tag.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.