Reland "Remove cx from ThemeSettings" (#39720)

- **Reapply "Remove cx from ThemeSettings (#38836)" (#39691)**
- **Fix theme loading races**

Closes #ISSUE

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin
2025-10-08 17:36:52 +02:00
committed by GitHub
parent 70af11ef2a
commit 1d1c799b4b
60 changed files with 395 additions and 462 deletions
+23 -82
View File
@@ -12,7 +12,6 @@ use crashes::InitCrashHandler;
use db::kvp::{GLOBAL_KEY_VALUE_STORE, KEY_VALUE_STORE};
use editor::Editor;
use extension::ExtensionHostProxy;
use extension_host::ExtensionStore;
use fs::{Fs, RealFs};
use futures::{StreamExt, channel::oneshot, future};
use git::GitHostingProviderRegistry;
@@ -40,10 +39,7 @@ use std::{
process,
sync::Arc,
};
use theme::{
ActiveTheme, IconThemeNotFoundError, SystemAppearance, ThemeNotFoundError, ThemeRegistry,
ThemeSettings,
};
use theme::{ActiveTheme, GlobalTheme, ThemeRegistry};
use util::{ResultExt, TryFutureExt, maybe};
use uuid::Uuid;
use workspace::{
@@ -57,7 +53,7 @@ use zed::{
initialize_workspace, open_paths_with_positions,
};
use crate::zed::OpenRequestKind;
use crate::zed::{OpenRequestKind, eager_load_active_theme_and_icon_theme};
#[cfg(feature = "mimalloc")]
#[global_allocator]
@@ -543,11 +539,18 @@ pub fn main() {
system_id.as_ref().map(|id| id.to_string()),
cx,
);
SystemAppearance::init(cx);
theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
theme_extension::init(
extension_host::init(
extension_host_proxy.clone(),
app_state.fs.clone(),
app_state.client.clone(),
app_state.node_runtime.clone(),
cx,
);
theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
eager_load_active_theme_and_icon_theme(fs.clone(), cx);
theme_extension::init(
extension_host_proxy,
ThemeRegistry::global(cx),
cx.background_executor().clone(),
);
@@ -581,18 +584,10 @@ pub fn main() {
);
assistant_tools::init(app_state.client.http_client(), cx);
repl::init(app_state.fs.clone(), cx);
extension_host::init(
extension_host_proxy,
app_state.fs.clone(),
app_state.client.clone(),
app_state.node_runtime.clone(),
cx,
);
recent_projects::init(cx);
load_embedded_fonts(cx);
app_state.languages.set_theme(cx.theme().clone());
editor::init(cx);
image_viewer::init(cx);
repl::notebook::init(cx);
@@ -638,8 +633,6 @@ pub fn main() {
json_schema_store::init(cx);
cx.observe_global::<SettingsStore>({
let fs = fs.clone();
let languages = app_state.languages.clone();
let http = app_state.client.http_client();
let client = app_state.client.clone();
move |cx| {
@@ -652,9 +645,6 @@ pub fn main() {
.ok();
}
eager_load_active_theme_and_icon_theme(fs.clone(), cx);
languages.set_theme(cx.theme().clone());
let new_host = &client::ClientSettings::get_global(cx).server_url;
if &http.base_url() != new_host {
http.set_base_url(new_host);
@@ -665,6 +655,14 @@ pub fn main() {
}
})
.detach();
app_state.languages.set_theme(cx.theme().clone());
cx.observe_global::<GlobalTheme>({
let languages = app_state.languages.clone();
move |cx| {
languages.set_theme(cx.theme().clone());
}
})
.detach();
telemetry::event!(
"Settings Changed",
setting = "theme",
@@ -1354,63 +1352,6 @@ fn load_embedded_fonts(cx: &App) {
.unwrap();
}
/// Eagerly loads the active theme and icon theme based on the selections in the
/// theme settings.
///
/// This fast path exists to load these themes as soon as possible so the user
/// doesn't see the default themes while waiting on extensions to load.
fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &App) {
let extension_store = ExtensionStore::global(cx);
let theme_registry = ThemeRegistry::global(cx);
let theme_settings = ThemeSettings::get_global(cx);
let appearance = SystemAppearance::global(cx).0;
if let Some(theme_selection) = theme_settings.theme_selection.as_ref() {
let theme_name = theme_selection.theme(appearance);
if matches!(theme_registry.get(theme_name), Err(ThemeNotFoundError(_)))
&& let Some(theme_path) = extension_store.read(cx).path_to_extension_theme(theme_name)
{
cx.spawn({
let theme_registry = theme_registry.clone();
let fs = fs.clone();
async move |cx| {
theme_registry.load_user_theme(&theme_path, fs).await?;
cx.update(|cx| {
ThemeSettings::reload_current_theme(cx);
})
}
})
.detach_and_log_err(cx);
}
}
if let Some(icon_theme_selection) = theme_settings.icon_theme_selection.as_ref() {
let icon_theme_name = icon_theme_selection.icon_theme(appearance);
if matches!(
theme_registry.get_icon_theme(icon_theme_name),
Err(IconThemeNotFoundError(_))
) && let Some((icon_theme_path, icons_root_path)) = extension_store
.read(cx)
.path_to_extension_icon_theme(icon_theme_name)
{
cx.spawn({
let fs = fs.clone();
async move |cx| {
theme_registry
.load_icon_theme(&icon_theme_path, &icons_root_path, fs)
.await?;
cx.update(|cx| {
ThemeSettings::reload_current_icon_theme(cx);
})
}
})
.detach_and_log_err(cx);
}
}
}
/// Spawns a background task to load the user themes from the themes directory.
fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut App) {
cx.spawn({
@@ -1435,7 +1376,7 @@ fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut App) {
}
}
theme_registry.load_user_themes(themes_dir, fs).await?;
cx.update(ThemeSettings::reload_current_theme)?;
cx.update(GlobalTheme::reload_theme)?;
}
anyhow::Ok(())
}
@@ -1461,7 +1402,7 @@ fn watch_themes(fs: Arc<dyn fs::Fs>, cx: &mut App) {
.await
.log_err()
{
cx.update(ThemeSettings::reload_current_theme).log_err();
cx.update(GlobalTheme::reload_theme).log_err();
}
}
}
+61 -4
View File
@@ -20,7 +20,9 @@ use collections::VecDeque;
use debugger_ui::debugger_panel::DebugPanel;
use editor::ProposedChangesEditorToolbar;
use editor::{Editor, MultiBuffer};
use extension_host::ExtensionStore;
use feature_flags::{FeatureFlagAppExt, PanicFeatureFlag};
use fs::Fs;
use futures::future::Either;
use futures::{StreamExt, channel::mpsc, select_biased};
use git_ui::git_panel::GitPanel;
@@ -68,7 +70,10 @@ use std::{
sync::atomic::{self, AtomicBool},
};
use terminal_view::terminal_panel::{self, TerminalPanel};
use theme::{ActiveTheme, ThemeSettings};
use theme::{
ActiveTheme, GlobalTheme, IconThemeNotFoundError, SystemAppearance, ThemeNotFoundError,
ThemeRegistry, ThemeSettings,
};
use ui::{PopoverMenuHandle, prelude::*};
use util::markdown::MarkdownString;
use util::rel_path::RelPath;
@@ -2012,6 +2017,55 @@ fn capture_recent_audio(workspace: &mut Workspace, _: &mut Window, cx: &mut Cont
);
}
/// Eagerly loads the active theme and icon theme based on the selections in the
/// theme settings.
///
/// This fast path exists to load these themes as soon as possible so the user
/// doesn't see the default themes while waiting on extensions to load.
pub(crate) fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &mut App) {
let extension_store = ExtensionStore::global(cx);
let theme_registry = ThemeRegistry::global(cx);
let theme_settings = ThemeSettings::get_global(cx);
let appearance = SystemAppearance::global(cx).0;
let theme_name = theme_settings.theme.name(appearance);
if matches!(
theme_registry.get(&theme_name.0),
Err(ThemeNotFoundError(_))
) && let Some(theme_path) = extension_store
.read(cx)
.path_to_extension_theme(&theme_name.0)
{
if cx
.background_executor()
.block(theme_registry.load_user_theme(&theme_path, fs.clone()))
.log_err()
.is_some()
{
GlobalTheme::reload_theme(cx);
}
}
let theme_settings = ThemeSettings::get_global(cx);
let icon_theme_name = theme_settings.icon_theme.name(appearance);
if matches!(
theme_registry.get_icon_theme(&icon_theme_name.0),
Err(IconThemeNotFoundError(_))
) && let Some((icon_theme_path, icons_root_path)) = extension_store
.read(cx)
.path_to_extension_icon_theme(&icon_theme_name.0)
{
if cx
.background_executor()
.block(theme_registry.load_icon_theme(&icon_theme_path, &icons_root_path, fs))
.log_err()
.is_some()
{
GlobalTheme::reload_icon_theme(cx);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -2031,8 +2085,11 @@ mod tests {
path::{Path, PathBuf},
time::Duration,
};
use theme::{ThemeRegistry, ThemeSettings};
use util::{path, rel_path::rel_path};
use theme::ThemeRegistry;
use util::{
path,
rel_path::{RelPath, rel_path},
};
use workspace::{
NewFile, OpenOptions, OpenVisible, SERIALIZATION_THROTTLE_TIME, SaveIntent, SplitDirection,
WorkspaceHandle,
@@ -4632,7 +4689,7 @@ mod tests {
for theme_name in themes.list().into_iter().map(|meta| meta.name) {
let theme = themes.get(&theme_name).unwrap();
assert_eq!(theme.name, theme_name);
if theme.name == ThemeSettings::get(None, cx).active_theme.name {
if theme.name.as_ref() == "One Dark" {
has_default_theme = true;
}
}