From 0c785598b37dba00b4692a78f9fc725bd760db21 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Apr 2026 14:25:58 -0700 Subject: [PATCH] Keep slash command popup columns stable while scrolling (#19511) ## Why Fixes #19499. The slash-command popup recalculated the command-name column from only the rows visible in the current viewport. That made the description column shift horizontally while scrolling through `/` commands whenever longer command names entered or left the visible window. ## What Changed `codex-rs/tui/src/bottom_pane/command_popup.rs` now uses the shared selection-popup `AutoAllRows` column-width mode for both height measurement and rendering. This keeps the command description column based on the full filtered slash-command list instead of the current viewport. ## Verification - `cargo test -p codex-tui bottom_pane::command_popup` --- codex-rs/tui/src/bottom_pane/command_popup.rs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/codex-rs/tui/src/bottom_pane/command_popup.rs b/codex-rs/tui/src/bottom_pane/command_popup.rs index 3b880a5f1..1ec258fb3 100644 --- a/codex-rs/tui/src/bottom_pane/command_popup.rs +++ b/codex-rs/tui/src/bottom_pane/command_popup.rs @@ -4,8 +4,11 @@ use ratatui::widgets::WidgetRef; use super::popup_consts::MAX_POPUP_ROWS; use super::scroll_state::ScrollState; +use super::selection_popup_common::ColumnWidthConfig; +use super::selection_popup_common::ColumnWidthMode; use super::selection_popup_common::GenericDisplayRow; -use super::selection_popup_common::render_rows; +use super::selection_popup_common::measure_rows_height_with_col_width_mode; +use super::selection_popup_common::render_rows_with_col_width_mode; use super::slash_commands; use crate::render::Insets; use crate::render::RectExt; @@ -15,6 +18,10 @@ use crate::slash_command::SlashCommand; // `quit` is an alias of `exit`, so we skip `quit` here. // `approvals` is an alias of `permissions`. const ALIAS_COMMANDS: &[SlashCommand] = &[SlashCommand::Quit, SlashCommand::Approvals]; +const COMMAND_COLUMN_WIDTH: ColumnWidthConfig = ColumnWidthConfig::new( + ColumnWidthMode::AutoAllRows, + /*name_column_width*/ None, +); /// A selectable item in the popup. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -109,10 +116,15 @@ impl CommandPopup { /// Determine the preferred height of the popup for a given width. /// Accounts for wrapped descriptions so that long tooltips don't overflow. pub(crate) fn calculate_required_height(&self, width: u16) -> u16 { - use super::selection_popup_common::measure_rows_height; let rows = self.rows_from_matches(self.filtered()); - measure_rows_height(&rows, &self.state, MAX_POPUP_ROWS, width) + measure_rows_height_with_col_width_mode( + &rows, + &self.state, + MAX_POPUP_ROWS, + width, + COMMAND_COLUMN_WIDTH, + ) } /// Compute exact/prefix matches over built-in commands and user prompts, @@ -223,7 +235,7 @@ impl CommandPopup { impl WidgetRef for CommandPopup { fn render_ref(&self, area: Rect, buf: &mut Buffer) { let rows = self.rows_from_matches(self.filtered()); - render_rows( + render_rows_with_col_width_mode( area.inset(Insets::tlbr( /*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0, )), @@ -232,6 +244,7 @@ impl WidgetRef for CommandPopup { &self.state, MAX_POPUP_ROWS, "no matches", + COMMAND_COLUMN_WIDTH, ); } }