Skip to content

Slash command popup columns shift while scrolling #19499

@Xeonacid

Description

@Xeonacid

What version of Codex CLI is running?

0.125.0, or latest main HEAD

What subscription do you have?

ChatGPT Plus

Which model were you using?

Unrelated

What platform is your computer?

Linux 6.19.11-arch1-1 x86_64 unknown

What terminal emulator and version are you using (if applicable)?

Windows Terminal

What issue are you seeing?

The TUI slash command popup recalculates the command-name column width from only the currently visible rows. As a result, the description column shifts left or right while scrolling through the / command list, depending on the longest command name visible in the current viewport.

What steps can reproduce the bug?

  1. Open the TUI.
  2. Type / to show the slash command popup.
  3. Scroll through the list.

One viewport may render with a narrower name column:

  /copy        copy last response as markdown
  /diff        show git diff (including untracked files)
  /mention     mention a file
  /status      show current session configuration and token usage
  /title       configure which items appear in the terminal title
  /statusline  configure which items appear in the status line
  /theme       choose a syntax highlighting theme
  /mcp         list configured MCP tools; use /mcp verbose for details

After scrolling, the same popup may render with a wider name column:

  /permissions   choose what Codex is allowed to do
  /experimental  toggle experimental features
  /memories      configure memory use and generation
  /skills        use skills to improve how Codex performs specific tasks
  /review        review my current changes and find issues
  /rename        rename the current thread
  /new           start a new chat during a conversation
  /resume        resume a saved chat

What is the expected behavior?

The description column should remain stable while scrolling. For a given filtered slash command list, the popup should reserve the width needed by the longest matching command name, not just the longest command visible in the current viewport.

Additional information

I understand external pull requests are by invitation only, so I am opening this as an issue first with analysis and a small proposed patch. If this approach aligns with the intended fix, I would appreciate an invitation to submit a PR.

CommandPopup currently uses the default selection popup row measurement and
rendering helpers:

  • measure_rows_height
  • render_rows

Those use the default ColumnWidthMode::AutoVisible, which derives the left column width from visible rows only. This is useful for compact generic lists, but it causes visible layout movement in the slash command popup.

The shared selection popup code already supports ColumnWidthMode::AutoAllRows, which derives the column width from all rows and is intended for stable columns while scrolling.

The following patch switches slash command popup measurement and rendering to AutoAllRows.

diff --git a/codex-rs/tui/src/bottom_pane/command_popup.rs b/codex-rs/tui/src/bottom_pane/command_popup.rs
index 28c749cb57..50aeed738d 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)]
@@ -107,10 +114,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,
@@ -221,7 +233,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,
             )),
@@ -230,6 +242,7 @@ impl WidgetRef for CommandPopup {
             &self.state,
             MAX_POPUP_ROWS,
             "no matches",
+            COMMAND_COLUMN_WIDTH,
         );
     }
 }

I have tested locally and it is fixed by this patch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions