From b366f8e9d3d374333b89667a2e7de2256b3c1d27 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 21 Apr 2026 11:20:40 -0600 Subject: [PATCH] Fix vim mode in thread sidebar (#54381) Release Notes: - vim: Removed normal mode from the agent sidebar search --------- Co-authored-by: cameron --- Cargo.lock | 1 - crates/sidebar/Cargo.toml | 1 - crates/sidebar/src/sidebar.rs | 27 +++++++++++++++++---------- crates/sidebar/src/sidebar_tests.rs | 23 ++++++++++++++++++----- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b9676d92f98a61c6b24ac75128383e08c739592..553c936cd0ac262ade247c17f47517dc9533f9a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16169,7 +16169,6 @@ dependencies = [ "theme_settings", "ui", "util", - "vim_mode_setting", "workspace", "zed_actions", ] diff --git a/crates/sidebar/Cargo.toml b/crates/sidebar/Cargo.toml index c0c0b26e1dfe2daa8bfa6f2cc7445def417ff177..97e0943980006757d96f97dee68597ef7adfb714 100644 --- a/crates/sidebar/Cargo.toml +++ b/crates/sidebar/Cargo.toml @@ -44,7 +44,6 @@ theme.workspace = true theme_settings.workspace = true ui.workspace = true util.workspace = true -vim_mode_setting.workspace = true workspace.workspace = true zed_actions.workspace = true diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index 4491c1693d6936db35a5a7c4c8cfa7db8f89f1cf..55e9b2ddae188d53d719edd84f2ef307f38c6bb2 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -505,7 +505,6 @@ impl Sidebar { let filter_editor = cx.new(|cx| { let mut editor = Editor::single_line(window, cx); - editor.set_use_modal_editing(true); editor.set_placeholder_text("Search…", window, cx); editor }); @@ -2222,6 +2221,23 @@ impl Sidebar { } fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context) { + if self.filter_editor.read(cx).is_focused(window) { + if self.reset_filter_editor_text(window, cx) { + self.selection = None; + self.update_entries(cx); + return; + } + + if self.selection.is_none() { + self.select_first_entry(); + } + if self.selection.is_some() { + self.focus_handle.focus(window, cx); + cx.notify(); + } + return; + } + if self.reset_filter_editor_text(window, cx) { self.update_entries(cx); } else { @@ -2247,15 +2263,6 @@ impl Sidebar { self.filter_editor.focus_handle(cx).focus(window, cx); } - // When vim mode is active, the editor defaults to normal mode which - // blocks text input. Switch to insert mode so the user can type - // immediately. - if vim_mode_setting::VimModeSetting::get_global(cx).0 { - if let Ok(action) = cx.build_action("vim::SwitchToInsertMode", None) { - window.dispatch_action(action, cx); - } - } - cx.notify(); } diff --git a/crates/sidebar/src/sidebar_tests.rs b/crates/sidebar/src/sidebar_tests.rs index 7600793dff500cde8d8e54d86186e26e3816a923..2de895114d1ca3082592a6a8359951d69f180a61 100644 --- a/crates/sidebar/src/sidebar_tests.rs +++ b/crates/sidebar/src/sidebar_tests.rs @@ -1679,9 +1679,9 @@ async fn test_search_matches_regardless_of_case(cx: &mut TestAppContext) { } #[gpui::test] -async fn test_escape_clears_search_and_restores_full_list(cx: &mut TestAppContext) { +async fn test_escape_from_search_focuses_first_thread(cx: &mut TestAppContext) { // Scenario: A user searches, finds what they need, then presses Escape - // to dismiss the filter and see the full list again. + // in the search field to hand keyboard control back to the thread list. let project = init_test_project("/my-project", cx).await; let (multi_workspace, cx) = cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); @@ -1723,8 +1723,8 @@ async fn test_escape_clears_search_and_restores_full_list(cx: &mut TestAppContex ] ); - // User presses Escape — filter clears, full list is restored. - // The selection index (1) now points at the first thread entry. + // First Escape clears the search text, restoring the full list. + // Focus stays on the filter editor. cx.dispatch_action(Cancel); cx.run_until_parked(); assert_eq!( @@ -1732,10 +1732,23 @@ async fn test_escape_clears_search_and_restores_full_list(cx: &mut TestAppContex vec![ // "v [my-project]", - " Alpha thread <== selected", + " Alpha thread", " Beta thread", ] ); + sidebar.update_in(cx, |sidebar, window, cx| { + assert!(sidebar.filter_editor.read(cx).is_focused(window)); + assert!(!sidebar.focus_handle.is_focused(window)); + }); + + // Second Escape moves focus from the empty search field to the thread list. + cx.dispatch_action(Cancel); + cx.run_until_parked(); + sidebar.update_in(cx, |sidebar, window, cx| { + assert_eq!(sidebar.selection, Some(1)); + assert!(sidebar.focus_handle.is_focused(window)); + assert!(!sidebar.filter_editor.read(cx).is_focused(window)); + }); } #[gpui::test]