Allow dynamic set_theme based on Appearance (#42812)
Tracking Issue (does not close): https://github.com/zed-industries/zed/issues/35552 This is somewhat of a blocker for https://github.com/zed-industries/zed/pull/40035 (but also the current behavior doesn't really make sense). The current behavior of `ThemeSelectorDelegate::set_theme` (the theme selector menu) is to simply set the in-memory settings to `Static`, regardless of if it is currently `Dynamic`. The reason this doesn't matter now is that the `theme::set_theme` function that updates the user's settings file _will_ make this check, so dynamic settings stay dynamic in `settings.json`, but not in memory. But this is also sort of strange, because `theme::set_theme` will set the setting of whatever the old appearance was to the new theme name. In other words, if I am currently on a light mode theme and I change my theme to a dark mode theme using the theme selector, the `light` field of `theme` in `settings.json` is set to a dark mode theme! _I think this is because displaying the new theme in the theme selector does not update the global context, so `ThemeSettings::get_global(cx).theme.name(appearance).0` returns the original theme appearance, not the new one._ --- This PR makes `ThemeSelectorDelegate::set_theme` keep the current `ThemeSelection`, as well as changes the behavior of the `theme::set_theme` call to always choose the correct setting to update. One edge case that might be slightly strange now is that if the user has specified the mode as `System`, this will now override that with the appearance of the new theme. I think this is fine, as otherwise a user might set a dark theme and nothing will change because the `ThemeAppearanceMode` is set to `light` or `system` (where `system` is also light). I also have an `unreachable!` in there that I'm pretty sure is true but I don't really know how to formally prove that... Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
This commit is contained in:
@@ -304,31 +304,50 @@ impl IconThemeSelection {
|
||||
}
|
||||
}
|
||||
|
||||
// impl ThemeSettingsContent {
|
||||
/// Sets the theme for the given appearance to the theme with the specified name.
|
||||
///
|
||||
/// The caller should make sure that the [`Appearance`] matches the theme associated with the name.
|
||||
///
|
||||
/// If the current [`ThemeAppearanceMode`] is set to [`System`] and the user's system [`Appearance`]
|
||||
/// is different than the new theme's [`Appearance`], this function will update the
|
||||
/// [`ThemeAppearanceMode`] to the new theme's appearance in order to display the new theme.
|
||||
///
|
||||
/// [`System`]: ThemeAppearanceMode::System
|
||||
pub fn set_theme(
|
||||
current: &mut SettingsContent,
|
||||
theme_name: impl Into<Arc<str>>,
|
||||
appearance: Appearance,
|
||||
theme_appearance: Appearance,
|
||||
system_appearance: Appearance,
|
||||
) {
|
||||
if let Some(selection) = current.theme.theme.as_mut() {
|
||||
let theme_to_update = match selection {
|
||||
settings::ThemeSelection::Static(theme) => theme,
|
||||
settings::ThemeSelection::Dynamic { mode, light, dark } => match mode {
|
||||
ThemeAppearanceMode::Light => light,
|
||||
ThemeAppearanceMode::Dark => dark,
|
||||
ThemeAppearanceMode::System => match appearance {
|
||||
Appearance::Light => light,
|
||||
Appearance::Dark => dark,
|
||||
},
|
||||
},
|
||||
};
|
||||
let theme_name = ThemeName(theme_name.into());
|
||||
|
||||
*theme_to_update = ThemeName(theme_name.into());
|
||||
} else {
|
||||
current.theme.theme = Some(settings::ThemeSelection::Static(ThemeName(
|
||||
theme_name.into(),
|
||||
)));
|
||||
let Some(selection) = current.theme.theme.as_mut() else {
|
||||
current.theme.theme = Some(settings::ThemeSelection::Static(theme_name));
|
||||
return;
|
||||
};
|
||||
|
||||
match selection {
|
||||
settings::ThemeSelection::Static(theme) => {
|
||||
*theme = theme_name;
|
||||
}
|
||||
settings::ThemeSelection::Dynamic { mode, light, dark } => {
|
||||
// Update the appropriate theme slot based on appearance.
|
||||
match theme_appearance {
|
||||
Appearance::Light => *light = theme_name,
|
||||
Appearance::Dark => *dark = theme_name,
|
||||
}
|
||||
|
||||
// Don't update the theme mode if it is set to system and the new theme has the same
|
||||
// appearance.
|
||||
let should_update_mode =
|
||||
!(mode == &ThemeAppearanceMode::System && theme_appearance == system_appearance);
|
||||
|
||||
if should_update_mode {
|
||||
// Update the mode to the specified appearance (otherwise we might set the theme and
|
||||
// nothing gets updated because the system specified the other mode appearance).
|
||||
*mode = ThemeAppearanceMode::from(theme_appearance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,15 @@ impl From<WindowAppearance> for Appearance {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Appearance> for ThemeAppearanceMode {
|
||||
fn from(value: Appearance) -> Self {
|
||||
match value {
|
||||
Appearance::Light => Self::Light,
|
||||
Appearance::Dark => Self::Dark,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Which themes should be loaded. This is used primarily for testing.
|
||||
pub enum LoadThemes {
|
||||
/// Only load the base theme.
|
||||
|
||||
Reference in New Issue
Block a user