From 6e20c5af8ca7355b393ed0ef2e1fbf482bfc881e Mon Sep 17 00:00:00 2001 From: Charles Cunningham Date: Thu, 12 Mar 2026 13:54:48 -0700 Subject: [PATCH] tui: refine slash help search controls Co-authored-by: Codex --- codex-rs/tui/src/bottom_pane/help_view.rs | 16 ++++++++++---- ..._chatwidget__tests__slash_help_output.snap | 2 +- codex-rs/tui/src/chatwidget/tests.rs | 22 +++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/codex-rs/tui/src/bottom_pane/help_view.rs b/codex-rs/tui/src/bottom_pane/help_view.rs index 2c1cd7bde0..32ef05237c 100644 --- a/codex-rs/tui/src/bottom_pane/help_view.rs +++ b/codex-rs/tui/src/bottom_pane/help_view.rs @@ -212,7 +212,7 @@ impl SlashHelpView { ]); } - Line::from(vec![ + let mut spans = vec![ key_hint::plain(KeyCode::Up).into(), "/".into(), key_hint::plain(KeyCode::Down).into(), @@ -222,11 +222,16 @@ impl SlashHelpView { key_hint::plain(KeyCode::PageDown).into(), " page ".dim(), "/ search ".dim(), - "n/p match ".dim(), + ]; + if !self.search.active_query.is_empty() { + spans.push("n/p match ".dim()); + } + spans.extend([ "q/".dim(), key_hint::plain(KeyCode::Esc).into(), " close".dim(), - ]) + ]); + Line::from(spans) } fn wrap_rows(rows: &[HelpRow], width: u16) -> (Vec>, Vec, Vec) { @@ -321,7 +326,10 @@ impl BottomPaneView for SlashHelpView { modifiers: KeyModifiers::NONE, .. } => { - self.search.input = Some(self.search.active_query.clone()); + self.search.active_query.clear(); + self.search.selected_match = 0; + self.follow_selected_match.set(false); + self.search.input = Some(String::new()); } KeyEvent { code: KeyCode::Up, .. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_help_output.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_help_output.snap index 9da66934a4..8048721ef2 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_help_output.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_help_output.snap @@ -240,4 +240,4 @@ expression: popup /debug-m-drop /debug-m-update - ↑/↓ scroll pgup/pgdn page / search n/p match q/esc close 1-233/239 + ↑/↓ scroll pgup/pgdn page / search q/esc close 1-233/239 diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index 0c459db9cd..7e8ba646b1 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -6076,6 +6076,28 @@ async fn slash_help_search_navigates_matches_with_n_and_p() { assert!(previous.contains("2/3 |")); } +#[tokio::test] +async fn slash_help_search_restarts_from_empty_input() { + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await; + + chat.dispatch_command(SlashCommand::Help); + chat.handle_key_event(KeyEvent::from(KeyCode::Char('/'))); + for ch in "maintainers".chars() { + chat.handle_key_event(KeyEvent::from(KeyCode::Char(ch))); + } + chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); + + let active = render_bottom_popup(&chat, 100); + assert!(active.contains("1/1 |")); + assert!(active.contains("n/p match")); + + chat.handle_key_event(KeyEvent::from(KeyCode::Char('/'))); + let restarted = render_bottom_popup(&chat, 100); + assert!(restarted.contains("Search: /")); + assert!(!restarted.contains("Search: /maintainers")); + assert!(!restarted.contains("1/1 |")); +} + #[tokio::test] async fn slash_help_esc_dismisses_popup() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;