From dae8d9efd2618668c957d223ceccf1d29629d644 Mon Sep 17 00:00:00 2001 From: Matei Oprea Date: Wed, 3 Jun 2026 13:08:08 +0300 Subject: [PATCH 1/4] theme_selector: Mark the active theme with a check icon While browsing themes in theme selector, the currently active theme will always be marked with a check icon so you can always have a reference of where you started from. --- crates/theme_selector/src/theme_selector.rs | 33 +++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index c60218003dff62..8ba37f8d422f6a 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -3,8 +3,8 @@ mod icon_theme_selector; use fs::Fs; use fuzzy::{StringMatch, StringMatchCandidate, match_strings}; use gpui::{ - App, Context, DismissEvent, Entity, EventEmitter, Focusable, Render, UpdateGlobal, WeakEntity, - Window, actions, + App, Context, DismissEvent, Entity, EventEmitter, Focusable, Render, SharedString, + UpdateGlobal, WeakEntity, Window, actions, }; use picker::{Picker, PickerDelegate}; use settings::{Settings, SettingsStore, update_settings_file}; @@ -134,6 +134,8 @@ struct ThemeSelectorDelegate { original_theme_settings: ThemeSettings, /// The current system appearance. original_system_appearance: Appearance, + /// The name of the original theme. + original_theme_name: SharedString, /// The currently selected new theme. new_theme: Arc, selection_completed: bool, @@ -196,6 +198,7 @@ impl ThemeSelectorDelegate { matches, original_theme_settings, original_system_appearance, + original_theme_name: original_theme.name.clone(), new_theme: original_theme, // Start with the original theme. selected_index, selection_completed: false, @@ -204,6 +207,12 @@ impl ThemeSelectorDelegate { } } + fn is_original_theme(&self, index: usize) -> bool { + self.matches + .get(index) + .is_some_and(|mat| mat.string == self.original_theme_name) + } + fn show_selected_theme( &mut self, cx: &mut Context>, @@ -487,16 +496,28 @@ impl PickerDelegate for ThemeSelectorDelegate { _cx: &mut Context>, ) -> Option { let theme_match = &self.matches.get(ix)?; + let is_original_theme = self.is_original_theme(ix); Some( ListItem::new(ix) .inset(true) .spacing(ListItemSpacing::Sparse) .toggle_state(selected) - .child(HighlightedLabel::new( - theme_match.string.clone(), - theme_match.positions.clone(), - )), + .child( + div() + .flex() + .flex_row() + .w_full() + .justify_between() + .items_center() + .child(HighlightedLabel::new( + theme_match.string.clone(), + theme_match.positions.clone(), + )) + .when(is_original_theme, |this| { + this.child(Icon::new(IconName::Check).color(Color::Selected)) + }), + ), ) } From 86674cca331638d7dfc935ad2082f4a44f05db87 Mon Sep 17 00:00:00 2001 From: dino Date: Wed, 3 Jun 2026 13:56:35 +0100 Subject: [PATCH 2/4] refactor(theme_selector): use end slot, muted icon color and id * Refactor how tracking and comparing the original theme is done in order to use its id instead of string comparison * Refactor how the check icon is used for the active theme in order to leverage `ListItem::end_slot` * Use `Color::Muted` for the check icon, similar to what we're doing for `line ending selector: toggle` --- crates/theme_selector/src/theme_selector.rs | 50 +++++++++++---------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 8ba37f8d422f6a..82bff3853db7fa 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -3,8 +3,8 @@ mod icon_theme_selector; use fs::Fs; use fuzzy::{StringMatch, StringMatchCandidate, match_strings}; use gpui::{ - App, Context, DismissEvent, Entity, EventEmitter, Focusable, Render, SharedString, - UpdateGlobal, WeakEntity, Window, actions, + App, Context, DismissEvent, Entity, EventEmitter, Focusable, Render, UpdateGlobal, WeakEntity, + Window, actions, }; use picker::{Picker, PickerDelegate}; use settings::{Settings, SettingsStore, update_settings_file}; @@ -134,8 +134,14 @@ struct ThemeSelectorDelegate { original_theme_settings: ThemeSettings, /// The current system appearance. original_system_appearance: Appearance, - /// The name of the original theme. - original_theme_name: SharedString, + /// The index of the original theme in the list of themes. + /// Using `Option` instead of `usize` because it's possible that the + /// original theme is not present in the list of themes when it is first + /// built, depending on the provided `themes_filter`. For example, when a + /// theme is installed, the `themes_filter` is set to the new theme names + /// and, if we used `unwrap_or(0)` as a fallback, the first theme in the + /// list would be shown as "active". + original_theme_id: Option, /// The currently selected new theme. new_theme: Arc, selection_completed: bool, @@ -176,10 +182,15 @@ impl ThemeSelectorDelegate { .then(a.name.cmp(&b.name)) }); + let original_theme_id = themes + .iter() + .position(|meta| meta.name == original_theme.name); + let matches: Vec = themes .iter() - .map(|meta| StringMatch { - candidate_id: 0, + .enumerate() + .map(|(id, meta)| StringMatch { + candidate_id: id, score: 0.0, positions: Default::default(), string: meta.name.to_string(), @@ -198,7 +209,7 @@ impl ThemeSelectorDelegate { matches, original_theme_settings, original_system_appearance, - original_theme_name: original_theme.name.clone(), + original_theme_id, new_theme: original_theme, // Start with the original theme. selected_index, selection_completed: false, @@ -210,7 +221,8 @@ impl ThemeSelectorDelegate { fn is_original_theme(&self, index: usize) -> bool { self.matches .get(index) - .is_some_and(|mat| mat.string == self.original_theme_name) + .zip(self.original_theme_id) + .is_some_and(|(mat, original_theme_id)| mat.candidate_id == original_theme_id) } fn show_selected_theme( @@ -503,21 +515,13 @@ impl PickerDelegate for ThemeSelectorDelegate { .inset(true) .spacing(ListItemSpacing::Sparse) .toggle_state(selected) - .child( - div() - .flex() - .flex_row() - .w_full() - .justify_between() - .items_center() - .child(HighlightedLabel::new( - theme_match.string.clone(), - theme_match.positions.clone(), - )) - .when(is_original_theme, |this| { - this.child(Icon::new(IconName::Check).color(Color::Selected)) - }), - ), + .child(HighlightedLabel::new( + theme_match.string.clone(), + theme_match.positions.clone(), + )) + .when(is_original_theme, |this| { + this.end_slot(Icon::new(IconName::Check).color(Color::Muted)) + }), ) } From f031c6070d47da85fd817bc60c9644cdebfb38d6 Mon Sep 17 00:00:00 2001 From: dino Date: Wed, 3 Jun 2026 14:43:59 +0100 Subject: [PATCH 3/4] feat(theme_selector): show check next to original icon theme --- crates/theme_selector/src/icon_theme_selector.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/theme_selector/src/icon_theme_selector.rs b/crates/theme_selector/src/icon_theme_selector.rs index 725881f8cc16e7..9abcd9a40cf08e 100644 --- a/crates/theme_selector/src/icon_theme_selector.rs +++ b/crates/theme_selector/src/icon_theme_selector.rs @@ -299,6 +299,7 @@ impl PickerDelegate for IconThemeSelectorDelegate { _cx: &mut Context>, ) -> Option { let theme_match = &self.matches.get(ix)?; + let is_original_theme = theme_match.string.as_str() == self.original_theme.0.as_ref(); Some( ListItem::new(ix) @@ -308,7 +309,10 @@ impl PickerDelegate for IconThemeSelectorDelegate { .child(HighlightedLabel::new( theme_match.string.clone(), theme_match.positions.clone(), - )), + )) + .when(is_original_theme, |this| { + this.end_slot(Icon::new(IconName::Check).color(Color::Muted)) + }), ) } From 272fe30601cf52b21abd103ef0a7aa9f452b0f9a Mon Sep 17 00:00:00 2001 From: dino Date: Wed, 3 Jun 2026 14:49:20 +0100 Subject: [PATCH 4/4] docs(theme_selector): fix field documentation --- crates/theme_selector/src/theme_selector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 82bff3853db7fa..5fc3217f63f4bb 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -134,7 +134,7 @@ struct ThemeSelectorDelegate { original_theme_settings: ThemeSettings, /// The current system appearance. original_system_appearance: Appearance, - /// The index of the original theme in the list of themes. + /// The id of the original theme in the list of themes. /// Using `Option` instead of `usize` because it's possible that the /// original theme is not present in the list of themes when it is first /// built, depending on the provided `themes_filter`. For example, when a