Skip to content

feat(tui): render hotbar in sidebar#2945

Merged
Hmbown merged 1 commit into
Hmbown:mainfrom
reidliu41:feat/hotbar-sidebar-render
Jun 10, 2026
Merged

feat(tui): render hotbar in sidebar#2945
Hmbown merged 1 commit into
Hmbown:mainfrom
reidliu41:feat/hotbar-sidebar-render

Conversation

@reidliu41

Copy link
Copy Markdown
Contributor

Summary

Ref: #2065
Part of #2061

This adds the sidebar rendering layer for the Hotbar work:

  • load resolved hotbar bindings from config/defaults into app state
  • render the Hotbar panel at the bottom of the right sidebar
  • show slots in compact two-row layout
  • highlight active slots and keep unknown configured actions visible
  • keep narrow sidebar rows within available width so later slots do not wrap or get clipped

This PR only adds the visible Hotbar panel. Key dispatch for 1-8 / Alt+1..8 remains a separate follow-up.

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
  • Harvested/co-authored credit uses a GitHub numeric noreply address

  Render configured/default hotbar slots at the bottom of the sidebar.

  Load resolved hotbar bindings into app state, display them as compact sidebar rows, highlight active slots, and preserve unknown
  actions visibly. Keep narrow sidebar rows within the available width so slots do not wrap or disappear.

  Add focused sidebar hotbar render and layout tests.

@greptile-apps greptile-apps Bot left a comment

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.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

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

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.

Code Review

This pull request introduces a configurable hotbar panel at the bottom of the TUI sidebar. It resolves hotbar bindings from the configuration, splits the sidebar layout vertically to allocate space for the hotbar when the terminal height is sufficient, and renders the hotbar slots with active/inactive states and custom labels. The review feedback suggests two improvements in crates/tui/src/tui/sidebar.rs: first, using unicode_width::UnicodeWidthStr::width instead of standard Rust formatting padding to prevent layout overflow when hotbar labels contain double-width characters or emojis; second, avoiding unnecessary cloning of binding.label by using .as_ref() and .cloned() during the filtering step.

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 +2191 to +2192
let text = truncate_line_to_width(&format!("{}:{label}", cell.slot), cell_width);
let padded = format!("{text:<cell_width$}");

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.

high

Using Rust's standard formatting width specifier (e.g., {text:<cell_width$}) pads based on the number of Unicode code points (char count) rather than the actual visual display width. If the hotbar action labels contain double-width characters (such as East Asian characters or emojis), this will cause the padded cells to exceed cell_width in visual width, leading to layout overflow or clipping in the sidebar.\n\nWe can resolve this by calculating the visual width using unicode_width::UnicodeWidthStr::width and manually extending the string with the correct number of spaces.

            let mut padded = truncate_line_to_width(&format!("{}:{label}", cell.slot), cell_width);\n            let text_width = unicode_width::UnicodeWidthStr::width(padded.as_str());\n            padded.extend(std::iter::repeat(' ').take(cell_width.saturating_sub(text_width)));

Comment on lines +2144 to +2147
let label = binding
.label
.clone()
.filter(|label| !label.trim().is_empty())

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

Avoid cloning the optional binding.label string unnecessarily. We can use .as_ref() to filter the label and only clone it (.cloned()) if it is present and non-empty.

            let label = binding\n                .label\n                .as_ref()\n                .filter(|label| !label.trim().is_empty())\n                .cloned()

@Hmbown Hmbown changed the base branch from codex/v0.9.0-stewardship to main June 10, 2026 04:16
@Hmbown Hmbown merged commit 3c97ba0 into Hmbown:main Jun 10, 2026
2 checks passed
@Hmbown

Hmbown commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Merged to main — thanks @reidliu41. Retargeted from the stewardship branch since your fork point was already contained in main. Key dispatch (1-8 / Alt+1..8) green-lit as the follow-up slice; part of the #2061 Hotbar program.

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