From 7863ac744d4e25749ea9e25f23522416a3caedea Mon Sep 17 00:00:00 2001 From: Edwin Date: Fri, 3 Jul 2026 08:36:35 +0900 Subject: [PATCH] Add C-k (kill to end of line) to the C-x b search box MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follows up on #692's Emacs cursor motion — C-k truncates the query at the cursor, mirroring readline/Emacs kill-line semantics. --- crates/cli/src/app.rs | 20 ++++++++++++++++++++ crates/cli/src/app/session_picker.rs | 12 ++++++++++++ 2 files changed, 32 insertions(+) diff --git a/crates/cli/src/app.rs b/crates/cli/src/app.rs index c687a73b..8e863f2e 100644 --- a/crates/cli/src/app.rs +++ b/crates/cli/src/app.rs @@ -17984,6 +17984,26 @@ mod tests { server.abort(); } + #[tokio::test] + async fn session_picker_ctrl_k_kills_to_end_of_line() { + let (mut app, _dir, server) = session_picker_app().await; + app.open_session_picker(SessionPickerPurpose::Switch); + picker_type(&mut app, "abcdef"); // cursor at 6, query "abcdef" + app.handle_session_picker_key(KeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL)); + app.handle_session_picker_key(KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL)); + app.handle_session_picker_key(KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL)); + assert_eq!(app.session_picker.as_ref().unwrap().cursor, 2); + app.handle_session_picker_key(KeyEvent::new(KeyCode::Char('k'), KeyModifiers::CONTROL)); + assert_eq!(app.session_picker.as_ref().unwrap().query, "ab"); + // The cursor was already at (the new) end; it doesn't move. + assert_eq!(app.session_picker.as_ref().unwrap().cursor, 2); + // Killing again at the end of the line is a no-op. + app.handle_session_picker_key(KeyEvent::new(KeyCode::Char('k'), KeyModifiers::CONTROL)); + assert_eq!(app.session_picker.as_ref().unwrap().query, "ab"); + assert_eq!(app.session_picker.as_ref().unwrap().cursor, 2); + server.abort(); + } + #[tokio::test] async fn session_picker_open_with_no_sessions_is_noop() { let (mut app, _dir, server) = empty_app().await; diff --git a/crates/cli/src/app/session_picker.rs b/crates/cli/src/app/session_picker.rs index b540dfb1..3b1f7daa 100644 --- a/crates/cli/src/app/session_picker.rs +++ b/crates/cli/src/app/session_picker.rs @@ -381,6 +381,17 @@ impl App { } } + /// `C-k`: kill from the cursor to the end of the query. The cursor itself + /// doesn't move — it's already at the (now shorter) end of the query. + fn session_picker_kill_to_end(&mut self) { + if let Some(dialog) = self.session_picker.as_mut() { + let pos = byte_pos(&dialog.query, dialog.cursor); + dialog.query.truncate(pos); + dialog.cursor = dialog.cursor.min(dialog.query.chars().count()); + } + self.session_picker_reset_selection(); + } + /// Snap the highlight back to the top match. Called after the effective /// query changes (typing/backspace) so navigation resumes from the best hit. fn session_picker_reset_selection(&mut self) { @@ -593,6 +604,7 @@ impl App { KeyCode::Char('b') if ctrl && !to_program => self.session_picker_move_cursor(-1), KeyCode::Char('a') if ctrl && !to_program => self.session_picker_cursor_to_edge(false), KeyCode::Char('e') if ctrl && !to_program => self.session_picker_cursor_to_edge(true), + KeyCode::Char('k') if ctrl && !to_program => self.session_picker_kill_to_end(), KeyCode::Backspace if to_program => self.session_picker_program_backspace(), KeyCode::Backspace => self.session_picker_backspace(), KeyCode::Char(c) if !ctrl && !alt && !super_mod && to_program => {