theme_selector: Don't select last theme when fuzzy searching (#28278)

Hendrik Sollich and Peter Tripp created

The theme selector should select the last match to when opening to keep
the current theme active but it should select the first when searching
to pick the best match.

fixes #28081


https://github.com/user-attachments/assets/b46b9742-4715-4c7a-8f17-2c19a8668333

Release Notes:

- Fixed selecting the correct theme when searching

---------

Co-authored-by: Peter Tripp <peter@zed.dev>

Change summary

crates/theme_selector/src/theme_selector.rs | 40 +++++++++++++++++-----
1 file changed, 31 insertions(+), 9 deletions(-)

Detailed changes

crates/theme_selector/src/theme_selector.rs 🔗

@@ -103,6 +103,7 @@ struct ThemeSelectorDelegate {
     matches: Vec<StringMatch>,
     original_theme: Arc<Theme>,
     selection_completed: bool,
+    selected_theme: Option<Arc<Theme>>,
     selected_index: usize,
     selector: WeakEntity<ThemeSelector>,
 }
@@ -151,6 +152,7 @@ impl ThemeSelectorDelegate {
             original_theme: original_theme.clone(),
             selected_index: 0,
             selection_completed: false,
+            selected_theme: None,
             selector,
         };
 
@@ -158,17 +160,24 @@ impl ThemeSelectorDelegate {
         this
     }
 
-    fn show_selected_theme(&mut self, cx: &mut Context<Picker<ThemeSelectorDelegate>>) {
+    fn show_selected_theme(
+        &mut self,
+        cx: &mut Context<Picker<ThemeSelectorDelegate>>,
+    ) -> Option<Arc<Theme>> {
         if let Some(mat) = self.matches.get(self.selected_index) {
             let registry = ThemeRegistry::global(cx);
             match registry.get(&mat.string) {
                 Ok(theme) => {
-                    Self::set_theme(theme, cx);
+                    Self::set_theme(theme.clone(), cx);
+                    Some(theme)
                 }
                 Err(error) => {
-                    log::error!("error loading theme {}: {}", mat.string, error)
+                    log::error!("error loading theme {}: {}", mat.string, error);
+                    None
                 }
             }
+        } else {
+            None
         }
     }
 
@@ -249,7 +258,7 @@ impl PickerDelegate for ThemeSelectorDelegate {
         cx: &mut Context<Picker<ThemeSelectorDelegate>>,
     ) {
         self.selected_index = ix;
-        self.show_selected_theme(cx);
+        self.selected_theme = self.show_selected_theme(cx);
     }
 
     fn update_matches(
@@ -292,11 +301,24 @@ impl PickerDelegate for ThemeSelectorDelegate {
 
             this.update(cx, |this, cx| {
                 this.delegate.matches = matches;
-                this.delegate.selected_index = this
-                    .delegate
-                    .selected_index
-                    .min(this.delegate.matches.len().saturating_sub(1));
-                this.delegate.show_selected_theme(cx);
+                if query.is_empty() && this.delegate.selected_theme.is_none() {
+                    this.delegate.selected_index = this
+                        .delegate
+                        .selected_index
+                        .min(this.delegate.matches.len().saturating_sub(1));
+                } else if let Some(selected) = this.delegate.selected_theme.as_ref() {
+                    this.delegate.selected_index = this
+                        .delegate
+                        .matches
+                        .iter()
+                        .enumerate()
+                        .find(|(_, mtch)| mtch.string == selected.name)
+                        .map(|(ix, _)| ix)
+                        .unwrap_or_default();
+                } else {
+                    this.delegate.selected_index = 0;
+                }
+                this.delegate.selected_theme = this.delegate.show_selected_theme(cx);
             })
             .log_err();
         })