Restore theme sorting in Zed2 (#3563)

Marshall Bowers created

This PR restores the sorting of themes in the theme selector in Zed2.

Release Notes:

- N/A

Change summary

crates/theme2/src/registry.rs                | 13 ++++++++-
crates/theme2/src/theme2.rs                  |  9 ++++++
crates/theme_selector2/src/theme_selector.rs | 30 ++++++++++++---------
3 files changed, 37 insertions(+), 15 deletions(-)

Detailed changes

crates/theme2/src/registry.rs 🔗

@@ -10,6 +10,12 @@ use crate::{
     SystemColors, Theme, ThemeColors, ThemeFamily, ThemeStyles, UserTheme, UserThemeFamily,
 };
 
+#[derive(Debug, Clone)]
+pub struct ThemeMeta {
+    pub name: SharedString,
+    pub appearance: Appearance,
+}
+
 pub struct ThemeRegistry {
     themes: HashMap<SharedString, Arc<Theme>>,
 }
@@ -94,8 +100,11 @@ impl ThemeRegistry {
         self.themes.keys().cloned()
     }
 
-    pub fn list(&self, _staff: bool) -> impl Iterator<Item = SharedString> + '_ {
-        self.themes.values().map(|theme| theme.name.clone())
+    pub fn list(&self, _staff: bool) -> impl Iterator<Item = ThemeMeta> + '_ {
+        self.themes.values().map(|theme| ThemeMeta {
+            name: theme.name.clone(),
+            appearance: theme.appearance(),
+        })
     }
 
     pub fn get(&self, name: &str) -> Result<Arc<Theme>> {

crates/theme2/src/theme2.rs 🔗

@@ -31,6 +31,15 @@ pub enum Appearance {
     Dark,
 }
 
+impl Appearance {
+    pub fn is_light(&self) -> bool {
+        match self {
+            Self::Light => true,
+            Self::Dark => false,
+        }
+    }
+}
+
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 pub enum LoadThemes {
     /// Only load the base theme.

crates/theme_selector2/src/theme_selector.rs 🔗

@@ -2,13 +2,13 @@ use feature_flags::FeatureFlagAppExt;
 use fs::Fs;
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, AppContext, DismissEvent, Div, EventEmitter, FocusableView, Render, SharedString,
-    View, ViewContext, VisualContext, WeakView,
+    actions, AppContext, DismissEvent, Div, EventEmitter, FocusableView, Render, View, ViewContext,
+    VisualContext, WeakView,
 };
 use picker::{Picker, PickerDelegate};
 use settings::{update_settings_file, SettingsStore};
 use std::sync::Arc;
-use theme::{Theme, ThemeRegistry, ThemeSettings};
+use theme::{Theme, ThemeMeta, ThemeRegistry, ThemeSettings};
 use ui::{prelude::*, v_stack, ListItem};
 use util::ResultExt;
 use workspace::{ui::HighlightedLabel, Workspace};
@@ -81,7 +81,7 @@ impl ThemeSelector {
 
 pub struct ThemeSelectorDelegate {
     fs: Arc<dyn Fs>,
-    theme_names: Vec<SharedString>,
+    themes: Vec<ThemeMeta>,
     matches: Vec<StringMatch>,
     original_theme: Arc<Theme>,
     selection_completed: bool,
@@ -99,21 +99,25 @@ impl ThemeSelectorDelegate {
 
         let staff_mode = cx.is_staff();
         let registry = cx.global::<ThemeRegistry>();
-        let theme_names = registry.list(staff_mode).collect::<Vec<_>>();
-        //todo!(theme sorting)
-        // theme_names.sort_unstable_by(|a, b| a.is_light.cmp(&b.is_light).then(a.name.cmp(&b.name)));
-        let matches = theme_names
+        let mut themes = registry.list(staff_mode).collect::<Vec<_>>();
+        themes.sort_unstable_by(|a, b| {
+            a.appearance
+                .is_light()
+                .cmp(&b.appearance.is_light())
+                .then(a.name.cmp(&b.name))
+        });
+        let matches = themes
             .iter()
             .map(|meta| StringMatch {
                 candidate_id: 0,
                 score: 0.0,
                 positions: Default::default(),
-                string: meta.to_string(),
+                string: meta.name.to_string(),
             })
             .collect();
         let mut this = Self {
             fs,
-            theme_names,
+            themes,
             matches,
             original_theme: original_theme.clone(),
             selected_index: 0,
@@ -213,13 +217,13 @@ impl PickerDelegate for ThemeSelectorDelegate {
     ) -> gpui::Task<()> {
         let background = cx.background_executor().clone();
         let candidates = self
-            .theme_names
+            .themes
             .iter()
             .enumerate()
             .map(|(id, meta)| StringMatchCandidate {
                 id,
-                char_bag: meta.as_ref().into(),
-                string: meta.to_string(),
+                char_bag: meta.name.as_ref().into(),
+                string: meta.name.to_string(),
             })
             .collect::<Vec<_>>();