Fix vim mode in thread sidebar (#54381) (cherry-pick to preview) (#54437)

zed-zippy[bot] , Conrad Irwin , and cameron created

Cherry-pick of #54381 to preview

----
Release Notes:

- vim: Removed normal mode from the agent sidebar search

---------

Co-authored-by: cameron <cameron.studdstreet@gmail.com>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: cameron <cameron.studdstreet@gmail.com>

Change summary

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(-)

Detailed changes

Cargo.lock πŸ”—

@@ -16092,7 +16092,6 @@ dependencies = [
  "theme_settings",
  "ui",
  "util",
- "vim_mode_setting",
  "workspace",
  "zed_actions",
 ]

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
 

crates/sidebar/src/sidebar.rs πŸ”—

@@ -485,7 +485,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
         });
@@ -2213,6 +2212,23 @@ impl Sidebar {
     }
 
     fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
+        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 {
@@ -2238,15 +2254,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();
     }
 

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]