Skip to content

feat(tui): add hotbar action registry foundation#2866

Merged
Hmbown merged 2 commits into
Hmbown:codex/v0.9.0-stewardshipfrom
reidliu41:feat/hotbar-action-registry
Jun 6, 2026
Merged

feat(tui): add hotbar action registry foundation#2866
Hmbown merged 2 commits into
Hmbown:codex/v0.9.0-stewardshipfrom
reidliu41:feat/hotbar-action-registry

Conversation

@reidliu41
Copy link
Copy Markdown
Contributor

@reidliu41 reidliu41 commented Jun 6, 2026

Summary:

  • Adds the hotbar action trait, dispatch result, and registry.
  • Registers the built-in app actions required for the first hotbar foundation slice.
  • Initializes the built-in registry on TUI app startup.

Scope:

Not in this slice:

  • Hotbar config schema and persistence.
  • Sidebar rendering.
  • Number-key dispatch.
  • Slash/MCP/skill/plugin adapters.
  • /hotbar setup wizard.
  • Docs and screenshots.

Issue:

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features
  • cargo test --workspace --all-features

Checklist

  • Updated docs or comments as needed
  • Added or updated tests where relevant
  • Verified TUI behavior manually if UI changes

Greptile Summary

This PR introduces the hotbar action registry foundation for the TUI: a HotbarAction trait, a HotbarDispatch result type, and a HotbarActionRegistry backed by a BTreeMap<String, Arc<dyn HotbarAction>>. Ten built-in app actions are registered at App::new via with_builtins(), and each is covered by unit tests for lookup, active-state reporting, and dispatch behavior.

  • Registry layer: HotbarActionRegistry stores trait objects keyed by stable string IDs; register_builtins is correctly scoped to pub(crate) and the public register method is kept open for future slash/MCP/skill/plugin adapters.
  • Built-in actions: Ten actions (voice.toggle, session.compact, mode.*, reasoning.cycle, sidebar.toggle, filetree.toggle, palette.open, trust.toggle) are implemented with guard logic (e.g., compaction re-entrancy check, auto_model bail for reasoning cycle).
  • App integration: hotbar_actions is added as a #[allow(dead_code)] field to App and initialised in App::new, with the field marked public for the future rendering and key-dispatch layers.

Confidence Score: 5/5

Safe to merge — this is a pure foundation layer with no active dispatch wiring yet; all built-in actions are unit-tested and the only integration change is an initialisation call in App::new.

The change adds a new registry struct and 10 built-in action impls that are stored but not yet called from any live code path (the field is #[allow(dead_code)]). Guard logic for compaction re-entrancy and auto-model reasoning is in place and tested. The only nit is one test unnecessarily declared async.

No files require special attention; actions.rs contains the bulk of the logic and is well covered by unit tests.

Important Files Changed

Filename Overview
crates/tui/src/tui/hotbar/actions.rs New file: defines HotbarAction trait, HotbarDispatch result, HotbarActionRegistry, and 10 built-in app actions with full unit tests; one test is unnecessarily marked async/#[tokio::test] when all operations are synchronous
crates/tui/src/tui/hotbar/mod.rs New module root: re-exports HotbarActionRegistry from the actions submodule with a brief doc comment scoping future hotbar slices
crates/tui/src/tui/app.rs Adds hotbar_actions: HotbarActionRegistry field to App struct (dead_code allowed for now) and initialises it via with_builtins() in App::new
crates/tui/src/tui/mod.rs Adds pub mod hotbar declaration to expose the new hotbar module

Sequence Diagram

sequenceDiagram
    participant App
    participant HotbarActionRegistry
    participant HotbarAction
    participant EventLoop

    Note over App: App::new()
    App->>HotbarActionRegistry: with_builtins()
    HotbarActionRegistry->>HotbarActionRegistry: register_builtins() [10 actions]
    HotbarActionRegistry-->>App: registry stored as hotbar_actions

    Note over EventLoop: Future: key dispatch (not in this slice)
    EventLoop->>HotbarActionRegistry: get(slot_id)
    HotbarActionRegistry-->>EventLoop: "Arc<dyn HotbarAction>"
    EventLoop->>HotbarAction: "is_active(&app)"
    HotbarAction-->>EventLoop: bool
    EventLoop->>HotbarAction: "dispatch(&mut app)"
    alt Handled
        HotbarAction-->>EventLoop: Ok(HotbarDispatch::Handled)
    else AppAction
        HotbarAction-->>EventLoop: Ok(HotbarDispatch::AppAction(action))
        EventLoop->>EventLoop: route AppAction to handler
    else Error
        HotbarAction-->>EventLoop: Err(anyhow)
    end
Loading

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Reviews (2): Last reviewed commit: "fix(tui): harden hotbar action dispatch" | Re-trigger Greptile

  Introduce the hotbar action trait and registry, and register the built-in app
  actions needed by the first hotbar slice.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

Thanks @reidliu41 for taking the time to contribute.

This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in .github/APPROVED_CONTRIBUTORS will be closed automatically.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant PR access by commenting /lgtm on a pull request.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a hotbar action registry foundation for the TUI, defining the HotbarAction trait, a registry for built-in actions (such as mode toggles, sidebar toggles, and command palette triggers), and integrating it into the main App state. The review feedback highlights several areas for improvement: ensuring that app.needs_redraw = true is set when updating status messages, pushing views, or toggling trust mode to guarantee immediate UI updates; avoiding hardcoded user-facing strings to comply with internationalization standards; and handling runtime conditions gracefully instead of using bail!, which could disrupt the TUI event loop.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +198 to +199
app.status_message =
Some("Voice input is not available in this terminal session yet.".to_string());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoded user-facing strings violate the internationalization (i18n) standards of the project. Consider using app.tr(MessageId::...) to retrieve localized strings instead of hardcoding English text.

Comment on lines +198 to +200
app.status_message =
Some("Voice input is not available in this terminal session yet.".to_string());
Ok(HotbarDispatch::Handled)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When handling a hotbar action that updates the application state (such as setting app.status_message), you should set app.needs_redraw = true to ensure the UI immediately reflects the changes.

                app.status_message =
                    Some("Voice input is not available in this terminal session yet.".to_string());
                app.needs_redraw = true;
                Ok(HotbarDispatch::Handled)

Comment on lines +214 to +216
if app.auto_model {
bail!("Reasoning effort is controlled by auto model routing.");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Returning a hard Result::Err (via bail!) for a common runtime condition (such as trying to cycle reasoning effort when auto model routing is active) can propagate up to the main event loop and potentially disrupt the TUI. Instead, handle this gracefully by setting a status message and returning Ok(HotbarDispatch::Handled).

Suggested change
if app.auto_model {
bail!("Reasoning effort is controlled by auto model routing.");
}
if app.auto_model {
app.status_message = Some("Reasoning effort is controlled by auto model routing.".to_string());
app.needs_redraw = true;
return Ok(HotbarDispatch::Handled);
}

Comment on lines +251 to +259
app.view_stack
.push(CommandPaletteView::new(build_command_palette_entries(
app.ui_locale,
&app.skills_dir,
&app.workspace,
&app.mcp_config_path,
app.mcp_snapshot.as_ref(),
)));
Ok(HotbarDispatch::Handled)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Pushing a new view onto the view_stack changes the active modal/view. Set app.needs_redraw = true so the command palette is rendered immediately.

                app.view_stack
                    .push(CommandPaletteView::new(build_command_palette_entries(
                        app.ui_locale,
                        &app.skills_dir,
                        &app.workspace,
                        &app.mcp_config_path,
                        app.mcp_snapshot.as_ref(),
                    )));
                app.needs_redraw = true;
                Ok(HotbarDispatch::Handled)

Comment on lines +262 to +268
app.trust_mode = !app.trust_mode;
app.status_message = Some(if app.trust_mode {
"Workspace trust mode enabled.".to_string()
} else {
"Workspace trust mode disabled.".to_string()
});
Ok(HotbarDispatch::Handled)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Toggling the workspace trust mode and updating the status message requires a redraw to update the UI elements (such as the footer/status bar). Set app.needs_redraw = true before returning.

                app.trust_mode = !app.trust_mode;
                app.status_message = Some(if app.trust_mode {
                    "Workspace trust mode enabled.".to_string()
                } else {
                    "Workspace trust mode disabled.".to_string()
                });
                app.needs_redraw = true;
                Ok(HotbarDispatch::Handled)

Comment thread crates/tui/src/tui/hotbar/actions.rs
Comment thread crates/tui/src/tui/hotbar/actions.rs Outdated
Comment thread crates/tui/src/tui/hotbar/actions.rs Outdated
@Hmbown Hmbown changed the base branch from main to codex/v0.9.0-stewardship June 6, 2026 17:36
@Hmbown Hmbown merged commit a7c1c03 into Hmbown:codex/v0.9.0-stewardship Jun 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants