From 41cf114d8a9bef231c257015394c16d3d5e69f5c Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 7 Oct 2025 09:45:20 -0600 Subject: [PATCH] Revert "Remove cx from ThemeSettings (#38836)" (#39691) This reverts commit a2a7bd139a3f94202d2a050a2bc7e50dc139000b. This caused themes to not load correctly on startup, you needed to edit your settings. Release Notes: - N/A --- Cargo.lock | 1 + crates/agent/src/thread.rs | 3 +- crates/agent_settings/src/agent_settings.rs | 2 +- crates/agent_ui/src/acp/entry_view_state.rs | 3 +- crates/agent_ui/src/acp/thread_view.rs | 2 +- crates/agent_ui/src/agent_diff.rs | 5 +- crates/assistant_tools/src/terminal_tool.rs | 3 +- crates/audio/src/audio_settings.rs | 2 +- crates/auto_update/src/auto_update.rs | 2 +- crates/call/src/call_settings.rs | 9 +- crates/client/src/client.rs | 6 +- crates/collab/src/tests/editor_tests.rs | 4 - .../src/tests/randomized_test_helpers.rs | 5 +- crates/collab/src/tests/test_server.rs | 1 - crates/collab_ui/src/panel_settings.rs | 4 +- crates/dap/src/debugger_settings.rs | 3 +- crates/editor/src/editor_settings.rs | 2 +- .../extension_host/src/extension_settings.rs | 3 +- .../file_finder/src/file_finder_settings.rs | 2 +- crates/file_icons/Cargo.toml | 1 + crates/file_icons/src/file_icons.rs | 45 ++-- crates/git_hosting_providers/src/settings.rs | 2 +- crates/git_ui/src/file_diff_view.rs | 4 +- crates/git_ui/src/git_panel_settings.rs | 2 +- crates/git_ui/src/text_diff_view.rs | 4 +- crates/go_to_line/src/cursor_position.rs | 2 +- .../image_viewer/src/image_viewer_settings.rs | 3 +- crates/journal/src/journal.rs | 2 +- crates/language/src/language_settings.rs | 2 +- crates/language_models/src/settings.rs | 2 +- crates/onboarding/src/basics_page.rs | 12 +- .../src/outline_panel_settings.rs | 2 +- crates/project/src/agent_server_store.rs | 8 +- crates/project/src/project.rs | 2 +- crates/project/src/project_settings.rs | 4 +- .../src/project_panel_settings.rs | 2 +- .../recent_projects/src/remote_connections.rs | 2 +- crates/repl/src/jupyter_settings.rs | 2 +- crates/repl/src/repl_settings.rs | 3 +- crates/settings/src/base_keymap_setting.rs | 3 +- crates/settings/src/settings_store.rs | 55 ++--- .../src/settings_profile_selector.rs | 1 + crates/storybook/src/storybook.rs | 6 +- crates/terminal/src/terminal_settings.rs | 4 +- crates/theme/src/fallback_themes.rs | 8 +- crates/theme/src/settings.rs | 210 ++++++++++++++---- crates/theme/src/theme.rs | 137 ++---------- crates/theme_extension/src/theme_extension.rs | 6 +- .../theme_selector/src/icon_theme_selector.rs | 51 +++-- crates/theme_selector/src/theme_selector.rs | 7 +- crates/title_bar/src/title_bar_settings.rs | 3 +- crates/vim/src/vim.rs | 2 +- .../vim_mode_setting/src/vim_mode_setting.rs | 4 +- crates/workspace/src/item.rs | 4 +- crates/workspace/src/workspace.rs | 6 +- crates/workspace/src/workspace_settings.rs | 7 +- crates/worktree/src/worktree_settings.rs | 3 +- crates/zed/src/main.rs | 87 ++++---- crates/zed/src/zed.rs | 9 +- crates/zlog_settings/src/zlog_settings.rs | 2 +- 60 files changed, 423 insertions(+), 360 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b63385619d0c7930f77d3c5a94cd9ec32c1a96b..240ac1cbbb5c34b1f69b206b681d73781632086b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5921,6 +5921,7 @@ version = "0.1.0" dependencies = [ "gpui", "serde", + "settings", "theme", "workspace-hack", "zed-util", diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index d189b7611209d2fbea5c882ea548318f73ddbfb3..9891f66adf34ad531676ca141f2a921e1805aa7f 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -3220,6 +3220,7 @@ mod tests { use settings::{LanguageModelParameters, Settings, SettingsStore}; use std::sync::Arc; use std::time::Duration; + use theme::ThemeSettings; use util::path; use workspace::Workspace; @@ -5280,7 +5281,7 @@ fn main() {{ thread_store::init(fs.clone(), cx); workspace::init_settings(cx); language_model::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); ToolRegistry::default_global(cx); assistant_tool::init(cx); diff --git a/crates/agent_settings/src/agent_settings.rs b/crates/agent_settings/src/agent_settings.rs index ec05c95672fa29b6e4813207e3e592fff9d3be15..d862cacee18ea53f81cdc91981b22f5531f2d75e 100644 --- a/crates/agent_settings/src/agent_settings.rs +++ b/crates/agent_settings/src/agent_settings.rs @@ -151,7 +151,7 @@ impl Default for AgentProfileId { } impl Settings for AgentSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let agent = content.agent.clone().unwrap(); Self { enabled: agent.enabled.unwrap(), diff --git a/crates/agent_ui/src/acp/entry_view_state.rs b/crates/agent_ui/src/acp/entry_view_state.rs index ee506b98810ba51d0fb933a2ca21e650d0cacc0b..340b7f27e911276b4d65fce6124fea14576bda94 100644 --- a/crates/agent_ui/src/acp/entry_view_state.rs +++ b/crates/agent_ui/src/acp/entry_view_state.rs @@ -414,6 +414,7 @@ mod tests { use project::Project; use serde_json::json; use settings::{Settings as _, SettingsStore}; + use theme::ThemeSettings; use util::path; use workspace::Workspace; @@ -543,7 +544,7 @@ mod tests { Project::init_settings(cx); AgentSettings::register(cx); workspace::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); release_channel::init(SemanticVersion::default(), cx); EditorSettings::register(cx); }); diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index 8d698265b9cb9aa92db7b791503cf9f379aa1099..7d8fdcb9368a1c75407eb920cba87838fd9e5d08 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -6086,7 +6086,7 @@ pub(crate) mod tests { Project::init_settings(cx); AgentSettings::register(cx); workspace::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); release_channel::init(SemanticVersion::default(), cx); EditorSettings::register(cx); prompt_store::init(cx) diff --git a/crates/agent_ui/src/agent_diff.rs b/crates/agent_ui/src/agent_diff.rs index 67014e3c3a4c8bd9b43f34d9cad3c23832efdc13..28d54c8fecec1523234e785c8302cf95b769128a 100644 --- a/crates/agent_ui/src/agent_diff.rs +++ b/crates/agent_ui/src/agent_diff.rs @@ -1814,6 +1814,7 @@ mod tests { use serde_json::json; use settings::{Settings, SettingsStore}; use std::{path::Path, rc::Rc}; + use theme::ThemeSettings; use util::path; #[gpui::test] @@ -1826,7 +1827,7 @@ mod tests { AgentSettings::register(cx); prompt_store::init(cx); workspace::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); EditorSettings::register(cx); language_model::init_settings(cx); }); @@ -1978,7 +1979,7 @@ mod tests { AgentSettings::register(cx); prompt_store::init(cx); workspace::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); EditorSettings::register(cx); language_model::init_settings(cx); workspace::register_project_item::(cx); diff --git a/crates/assistant_tools/src/terminal_tool.rs b/crates/assistant_tools/src/terminal_tool.rs index bc6f5f2a612bf17468577624e34d49119f3813c8..db85863f2eca6c9970eecce33e164577007a3100 100644 --- a/crates/assistant_tools/src/terminal_tool.rs +++ b/crates/assistant_tools/src/terminal_tool.rs @@ -704,6 +704,7 @@ mod tests { use serde_json::json; use settings::{Settings, SettingsStore}; use terminal::terminal_settings::TerminalSettings; + use theme::ThemeSettings; use util::{ResultExt as _, test::TempTree}; use super::*; @@ -718,7 +719,7 @@ mod tests { language::init(cx); Project::init_settings(cx); workspace::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); TerminalSettings::register(cx); EditorSettings::register(cx); }); diff --git a/crates/audio/src/audio_settings.rs b/crates/audio/src/audio_settings.rs index 61a993c3358e5e2bf39b626a0764833508bee742..cba7d45c31f4674be6a69c10ab34f00e0b8cbbd1 100644 --- a/crates/audio/src/audio_settings.rs +++ b/crates/audio/src/audio_settings.rs @@ -42,7 +42,7 @@ pub struct AudioSettings { /// Configuration of audio in Zed impl Settings for AudioSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let audio = &content.audio.as_ref().unwrap(); AudioSettings { rodio_audio: audio.rodio_audio.unwrap(), diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 2d1ea7269e2ab102962faeae848d94a8c491d8f2..0d66ddf52fcec527b63f2f57c7a32c62b65bcf3a 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -127,7 +127,7 @@ struct AutoUpdateSetting(bool); /// /// Default: true impl Settings for AutoUpdateSetting { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { Self(content.auto_update.unwrap()) } } diff --git a/crates/call/src/call_settings.rs b/crates/call/src/call_settings.rs index 6c2b25ae60269b7004916cb1ed020cc67006af0b..a97ac682022ef30c603ca94fe60fe78064726f42 100644 --- a/crates/call/src/call_settings.rs +++ b/crates/call/src/call_settings.rs @@ -1,3 +1,4 @@ +use gpui::App; use settings::Settings; #[derive(Debug)] @@ -7,11 +8,17 @@ pub struct CallSettings { } impl Settings for CallSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let call = content.calls.clone().unwrap(); CallSettings { mute_on_join: call.mute_on_join.unwrap(), share_on_join: call.share_on_join.unwrap(), } } + + fn import_from_vscode( + _vscode: &settings::VsCodeSettings, + _current: &mut settings::SettingsContent, + ) { + } } diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 911cada78f14ee587a1b4570c9a35181a2e6fdec..e098e7aed52281605c2882514b23c81d2041c6db 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -101,7 +101,7 @@ pub struct ClientSettings { } impl Settings for ClientSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { if let Some(server_url) = &*ZED_SERVER_URL { return Self { server_url: server_url.clone(), @@ -133,7 +133,7 @@ impl ProxySettings { } impl Settings for ProxySettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { Self { proxy: content.proxy.clone(), } @@ -519,7 +519,7 @@ pub struct TelemetrySettings { } impl settings::Settings for TelemetrySettings { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _cx: &mut App) -> Self { Self { diagnostics: content.telemetry.as_ref().unwrap().diagnostics.unwrap(), metrics: content.telemetry.as_ref().unwrap().metrics.unwrap(), diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs index 8dbefc8714f9797b116551419486507b1a742b5a..5ead2cd1d1b0bd2e224cff8db71fe2908c9da060 100644 --- a/crates/collab/src/tests/editor_tests.rs +++ b/crates/collab/src/tests/editor_tests.rs @@ -2041,10 +2041,6 @@ async fn test_mutual_editor_inlay_hint_cache_update( }); } -// This test started hanging on seed 2 after the theme settings -// PR. The hypothesis is that it's been buggy for a while, but got lucky -// on seeds. -#[ignore] #[gpui::test(iterations = 10)] async fn test_inlay_hint_refresh_is_forwarded( cx_a: &mut TestAppContext, diff --git a/crates/collab/src/tests/randomized_test_helpers.rs b/crates/collab/src/tests/randomized_test_helpers.rs index 11c9f1c338735b7e70b488940647bee5671b3659..9a372017e34f575f780d56f3936fefec832e160c 100644 --- a/crates/collab/src/tests/randomized_test_helpers.rs +++ b/crates/collab/src/tests/randomized_test_helpers.rs @@ -183,10 +183,9 @@ pub async fn run_randomized_test( for (client, cx) in clients { cx.update(|cx| { - let settings = cx.remove_global::(); + let store = cx.remove_global::(); cx.clear_globals(); - cx.set_global(settings); - theme::init(theme::LoadThemes::JustBase, cx); + cx.set_global(store); drop(client); }); } diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index 528253f0dc2e9d4dc8b88a7d8d8c2926be2b2652..fef931c0d8f3f5e8a6a731b4756cad1644b27a8f 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -172,7 +172,6 @@ impl TestServer { } let settings = SettingsStore::test(cx); cx.set_global(settings); - theme::init(theme::LoadThemes::JustBase, cx); release_channel::init(SemanticVersion::default(), cx); client::init_settings(cx); }); diff --git a/crates/collab_ui/src/panel_settings.rs b/crates/collab_ui/src/panel_settings.rs index cd19835c164161543030f552650ec35d7e6e0fe6..58be0c358b2626426bc050b2eb7940f35690b37b 100644 --- a/crates/collab_ui/src/panel_settings.rs +++ b/crates/collab_ui/src/panel_settings.rs @@ -18,7 +18,7 @@ pub struct NotificationPanelSettings { } impl Settings for CollaborationPanelSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self { let panel = content.collaboration_panel.as_ref().unwrap(); Self { @@ -30,7 +30,7 @@ impl Settings for CollaborationPanelSettings { } impl Settings for NotificationPanelSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self { let panel = content.notification_panel.as_ref().unwrap(); return Self { button: panel.button.unwrap(), diff --git a/crates/dap/src/debugger_settings.rs b/crates/dap/src/debugger_settings.rs index dc38c9a0616ff8d37bdfd33f269a4fec9a6395b2..114f858eec5a5660e74b1cf8a80aecf812f17f93 100644 --- a/crates/dap/src/debugger_settings.rs +++ b/crates/dap/src/debugger_settings.rs @@ -1,4 +1,5 @@ use dap_types::SteppingGranularity; +use gpui::App; use settings::{Settings, SettingsContent}; pub struct DebuggerSettings { @@ -33,7 +34,7 @@ pub struct DebuggerSettings { } impl Settings for DebuggerSettings { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _cx: &mut App) -> Self { let content = content.debugger.clone().unwrap(); Self { stepping_granularity: dap_granularity_from_settings( diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 2179f3252d7d5746afb99d1b74c04e6366a928a4..3426171e03f70b18faa71584429a49ea009f73c4 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -176,7 +176,7 @@ impl ScrollbarVisibility for EditorSettings { } impl Settings for EditorSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let editor = content.editor.clone(); let scrollbar = editor.scrollbar.unwrap(); let minimap = editor.minimap.unwrap(); diff --git a/crates/extension_host/src/extension_settings.rs b/crates/extension_host/src/extension_settings.rs index 2f6b66ed0999a541febf368c7f75f22f89fcd6d0..a4af4a1ba3030b54bf14d2b64d8eef3646ae29bf 100644 --- a/crates/extension_host/src/extension_settings.rs +++ b/crates/extension_host/src/extension_settings.rs @@ -2,6 +2,7 @@ use collections::HashMap; use extension::{ DownloadFileCapability, ExtensionCapability, NpmInstallPackageCapability, ProcessExecCapability, }; +use gpui::App; use settings::Settings; use std::sync::Arc; @@ -36,7 +37,7 @@ impl ExtensionSettings { } impl Settings for ExtensionSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { Self { auto_install_extensions: content.extension.auto_install_extensions.clone(), auto_update_extensions: content.extension.auto_update_extensions.clone(), diff --git a/crates/file_finder/src/file_finder_settings.rs b/crates/file_finder/src/file_finder_settings.rs index 8689e0ad1e3df2c90c2c033953f08eb31aff052d..cf2b4f4bfb87f7a71c2dcc2a1d0a2218131c988a 100644 --- a/crates/file_finder/src/file_finder_settings.rs +++ b/crates/file_finder/src/file_finder_settings.rs @@ -11,7 +11,7 @@ pub struct FileFinderSettings { } impl Settings for FileFinderSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self { let file_finder = content.file_finder.as_ref().unwrap(); Self { diff --git a/crates/file_icons/Cargo.toml b/crates/file_icons/Cargo.toml index b87827618e8a927f882f177854c41fa90eeebd0b..1c271f4132a5a2083cc0072367a32c9850f83802 100644 --- a/crates/file_icons/Cargo.toml +++ b/crates/file_icons/Cargo.toml @@ -15,6 +15,7 @@ doctest = false [dependencies] gpui.workspace = true serde.workspace = true +settings.workspace = true theme.workspace = true util.workspace = true workspace-hack.workspace = true diff --git a/crates/file_icons/src/file_icons.rs b/crates/file_icons/src/file_icons.rs index e8650a83b920142a3b6ab2f69bdc6e2eca6b7470..b7322a717d20f232cad7b9239a46a5eb0e124abd 100644 --- a/crates/file_icons/src/file_icons.rs +++ b/crates/file_icons/src/file_icons.rs @@ -2,7 +2,8 @@ use std::sync::Arc; use std::{path::Path, str}; use gpui::{App, SharedString}; -use theme::{GlobalTheme, IconTheme, ThemeRegistry}; +use settings::Settings; +use theme::{IconTheme, ThemeRegistry, ThemeSettings}; use util::paths::PathExt; #[derive(Debug)] @@ -12,8 +13,10 @@ pub struct FileIcons { impl FileIcons { pub fn get(cx: &App) -> Self { + let theme_settings = ThemeSettings::get_global(cx); + Self { - icon_theme: GlobalTheme::icon_theme(cx).clone(), + icon_theme: theme_settings.active_icon_theme.clone(), } } @@ -94,7 +97,7 @@ impl FileIcons { .map(|icon_definition| icon_definition.path.clone()) } - get_icon_for_type(GlobalTheme::icon_theme(cx), typ).or_else(|| { + get_icon_for_type(&ThemeSettings::get_global(cx).active_icon_theme, typ).or_else(|| { Self::default_icon_theme(cx).and_then(|icon_theme| get_icon_for_type(&icon_theme, typ)) }) } @@ -119,16 +122,20 @@ impl FileIcons { } } - get_folder_icon(GlobalTheme::icon_theme(cx), path, expanded) - .or_else(|| { - Self::default_icon_theme(cx) - .and_then(|icon_theme| get_folder_icon(&icon_theme, path, expanded)) - }) - .or_else(|| { - // If we can't find a specific folder icon for the folder at the given path, fall back to the generic folder - // icon. - Self::get_generic_folder_icon(expanded, cx) - }) + get_folder_icon( + &ThemeSettings::get_global(cx).active_icon_theme, + path, + expanded, + ) + .or_else(|| { + Self::default_icon_theme(cx) + .and_then(|icon_theme| get_folder_icon(&icon_theme, path, expanded)) + }) + .or_else(|| { + // If we can't find a specific folder icon for the folder at the given path, fall back to the generic folder + // icon. + Self::get_generic_folder_icon(expanded, cx) + }) } fn get_generic_folder_icon(expanded: bool, cx: &App) -> Option { @@ -143,10 +150,12 @@ impl FileIcons { } } - get_generic_folder_icon(GlobalTheme::icon_theme(cx), expanded).or_else(|| { - Self::default_icon_theme(cx) - .and_then(|icon_theme| get_generic_folder_icon(&icon_theme, expanded)) - }) + get_generic_folder_icon(&ThemeSettings::get_global(cx).active_icon_theme, expanded).or_else( + || { + Self::default_icon_theme(cx) + .and_then(|icon_theme| get_generic_folder_icon(&icon_theme, expanded)) + }, + ) } pub fn get_chevron_icon(expanded: bool, cx: &App) -> Option { @@ -158,7 +167,7 @@ impl FileIcons { } } - get_chevron_icon(GlobalTheme::icon_theme(cx), expanded).or_else(|| { + get_chevron_icon(&ThemeSettings::get_global(cx).active_icon_theme, expanded).or_else(|| { Self::default_icon_theme(cx) .and_then(|icon_theme| get_chevron_icon(&icon_theme, expanded)) }) diff --git a/crates/git_hosting_providers/src/settings.rs b/crates/git_hosting_providers/src/settings.rs index 9a1625c8debac5fc83004eae26e6b9673a17290c..e045fae08b7a4dc019177361d7365f286c95518c 100644 --- a/crates/git_hosting_providers/src/settings.rs +++ b/crates/git_hosting_providers/src/settings.rs @@ -58,7 +58,7 @@ pub struct GitHostingProviderSettings { } impl Settings for GitHostingProviderSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { Self { git_hosting_providers: content .project diff --git a/crates/git_ui/src/file_diff_view.rs b/crates/git_ui/src/file_diff_view.rs index 387bda808708cf38beded2fe17edd92466885672..b13ce28b8aa18f5f2af4722f06518a42dfea2563 100644 --- a/crates/git_ui/src/file_diff_view.rs +++ b/crates/git_ui/src/file_diff_view.rs @@ -360,7 +360,7 @@ mod tests { use editor::test::editor_test_context::assert_state_with_diff; use gpui::TestAppContext; use project::{FakeFs, Fs, Project}; - use settings::SettingsStore; + use settings::{Settings, SettingsStore}; use std::path::PathBuf; use unindent::unindent; use util::path; @@ -374,7 +374,7 @@ mod tests { Project::init_settings(cx); workspace::init_settings(cx); editor::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + theme::ThemeSettings::register(cx) }); } diff --git a/crates/git_ui/src/git_panel_settings.rs b/crates/git_ui/src/git_panel_settings.rs index f98493d1d9ef4bcf9b53393671091c8b72dcd998..342b0105cd5f92b8228572391cd4ddac7256a7a7 100644 --- a/crates/git_ui/src/git_panel_settings.rs +++ b/crates/git_ui/src/git_panel_settings.rs @@ -43,7 +43,7 @@ impl ScrollbarVisibility for GitPanelSettings { } impl Settings for GitPanelSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self { let git_panel = content.git_panel.clone().unwrap(); Self { button: git_panel.button.unwrap(), diff --git a/crates/git_ui/src/text_diff_view.rs b/crates/git_ui/src/text_diff_view.rs index 8f7dac4e4049a65dbd630966cea249664d22ba61..3cafcd43d0c0593ef38e0e4d40c099594d7499fd 100644 --- a/crates/git_ui/src/text_diff_view.rs +++ b/crates/git_ui/src/text_diff_view.rs @@ -450,7 +450,7 @@ mod tests { use gpui::{TestAppContext, VisualContext}; use project::{FakeFs, Project}; use serde_json::json; - use settings::SettingsStore; + use settings::{Settings, SettingsStore}; use unindent::unindent; use util::{path, test::marked_text_ranges}; @@ -462,7 +462,7 @@ mod tests { Project::init_settings(cx); workspace::init_settings(cx); editor::init_settings(cx); - theme::init(theme::LoadThemes::JustBase, cx); + theme::ThemeSettings::register(cx) }); } diff --git a/crates/go_to_line/src/cursor_position.rs b/crates/go_to_line/src/cursor_position.rs index ee95d1181d1f61fb95a9bbff5c7402aa2c9a1694..b722777262be078858959ae8fbd95528f8e0f986 100644 --- a/crates/go_to_line/src/cursor_position.rs +++ b/crates/go_to_line/src/cursor_position.rs @@ -304,7 +304,7 @@ impl From for LineIndicatorFormat { } impl Settings for LineIndicatorFormat { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { content.line_indicator_format.unwrap().into() } } diff --git a/crates/image_viewer/src/image_viewer_settings.rs b/crates/image_viewer/src/image_viewer_settings.rs index 839d5fbfe44fc624351953018c1437e9fa2c32e0..64f2e4948284265c1f348cb90be85d18d8c22d8e 100644 --- a/crates/image_viewer/src/image_viewer_settings.rs +++ b/crates/image_viewer/src/image_viewer_settings.rs @@ -1,3 +1,4 @@ +use gpui::App; pub use settings::ImageFileSizeUnit; use settings::Settings; @@ -11,7 +12,7 @@ pub struct ImageViewerSettings { } impl Settings for ImageViewerSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { Self { unit: content.image_viewer.clone().unwrap().unit.unwrap(), } diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index 9062081f66da0e920b99af8816432b4f006d2295..9dc724f1234d79619ea1347e6747ce286aa42ca3 100644 --- a/crates/journal/src/journal.rs +++ b/crates/journal/src/journal.rs @@ -33,7 +33,7 @@ pub struct JournalSettings { } impl settings::Settings for JournalSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let journal = content.journal.clone().unwrap(); Self { diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index f815ecc8517d1e3e83f8614c21786e7b1a6cbfd0..fba5888e16b493b0c587bef42899b179317c3d9b 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -500,7 +500,7 @@ fn merge_with_editorconfig(settings: &mut LanguageSettings, cfg: &EditorconfigPr } impl settings::Settings for AllLanguageSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let all_languages = &content.project.all_languages; fn load_from_content(settings: LanguageSettingsContent) -> LanguageSettings { diff --git a/crates/language_models/src/settings.rs b/crates/language_models/src/settings.rs index ce29be38431055ddce992552607259066ab9f3cb..178703bd93d0d2cf0ece2e82ed26cedb49a38196 100644 --- a/crates/language_models/src/settings.rs +++ b/crates/language_models/src/settings.rs @@ -36,7 +36,7 @@ pub struct AllLanguageModelSettings { impl settings::Settings for AllLanguageModelSettings { const PRESERVED_KEYS: Option<&'static [&'static str]> = Some(&["version"]); - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let language_models = content.language_models.clone().unwrap(); let anthropic = language_models.anthropic.unwrap(); let bedrock = language_models.bedrock.unwrap(); diff --git a/crates/onboarding/src/basics_page.rs b/crates/onboarding/src/basics_page.rs index 8c8c8051a33f1c18d1f9084be898560d3177054a..99af251dfefcab5fd4dba6f82e02531d3c849433 100644 --- a/crates/onboarding/src/basics_page.rs +++ b/crates/onboarding/src/basics_page.rs @@ -34,8 +34,16 @@ fn get_theme_family_themes(theme_name: &str) -> Option<(&'static str, &'static s } fn render_theme_section(tab_index: &mut isize, cx: &mut App) -> impl IntoElement { - let theme_selection = ThemeSettings::get_global(cx).theme.clone(); + let theme_selection = ThemeSettings::get_global(cx).theme_selection.clone(); let system_appearance = theme::SystemAppearance::global(cx); + let theme_selection = theme_selection.unwrap_or_else(|| ThemeSelection::Dynamic { + mode: match *system_appearance { + Appearance::Light => ThemeMode::Light, + Appearance::Dark => ThemeMode::Dark, + }, + light: ThemeName("One Light".into()), + dark: ThemeName("One Dark".into()), + }); let theme_mode = theme_selection .mode() @@ -103,7 +111,7 @@ fn render_theme_section(tab_index: &mut isize, cx: &mut App) -> impl IntoElement ThemeMode::Dark => Appearance::Dark, ThemeMode::System => *system_appearance, }; - let current_theme_name: SharedString = theme_selection.name(appearance).0.into(); + let current_theme_name = SharedString::new(theme_selection.theme(appearance)); let theme_names = match appearance { Appearance::Light => LIGHT_THEMES, diff --git a/crates/outline_panel/src/outline_panel_settings.rs b/crates/outline_panel/src/outline_panel_settings.rs index 58598bdb4f9089e2c6284976869b82be600825ae..7e09e21c2311780ec23f24b9616270c4a1f24854 100644 --- a/crates/outline_panel/src/outline_panel_settings.rs +++ b/crates/outline_panel/src/outline_panel_settings.rs @@ -41,7 +41,7 @@ impl ScrollbarVisibility for OutlinePanelSettings { } impl Settings for OutlinePanelSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let panel = content.outline_panel.as_ref().unwrap(); Self { button: panel.button.unwrap(), diff --git a/crates/project/src/agent_server_store.rs b/crates/project/src/agent_server_store.rs index 4618ea049dc08bb29749dd7bd77a7bd07fa87eaa..19d62f019ec80a380508fc342d16fd09cafc8cd6 100644 --- a/crates/project/src/agent_server_store.rs +++ b/crates/project/src/agent_server_store.rs @@ -14,7 +14,7 @@ use feature_flags::FeatureFlagAppExt as _; use fs::{Fs, RemoveOptions, RenameOptions}; use futures::StreamExt as _; use gpui::{ - AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, Task, + App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, Task, }; use http_client::github::AssetKind; use node_runtime::NodeRuntime; @@ -22,7 +22,7 @@ use remote::RemoteClient; use rpc::{AnyProtoClient, TypedEnvelope, proto}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use settings::SettingsStore; +use settings::{SettingsContent, SettingsStore}; use util::{ResultExt as _, debug_panic}; use crate::ProjectEnvironment; @@ -1294,7 +1294,7 @@ impl From for CustomAgentServerSettings { } impl settings::Settings for AllAgentServersSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let agent_settings = content.agent_servers.clone().unwrap(); Self { gemini: agent_settings.gemini.map(Into::into), @@ -1307,4 +1307,6 @@ impl settings::Settings for AllAgentServersSettings { .collect(), } } + + fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut SettingsContent) {} } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index c4c6e5f3658f16a55e7401b721568b4326bf072a..7e6bb35c0ead718d61aba2dae73999f54c0498ce 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -980,7 +980,7 @@ pub struct DisableAiSettings { } impl settings::Settings for DisableAiSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { Self { disable_ai: content.disable_ai.unwrap().0, } diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index fc09f9f296147fda96a5e0c21089356420a62546..5bae7b05773afb71ae9bcb541ef140cda29464ca 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -4,7 +4,7 @@ use context_server::ContextServerCommand; use dap::adapters::DebugAdapterName; use fs::Fs; use futures::StreamExt as _; -use gpui::{AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Subscription, Task}; +use gpui::{App, AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Subscription, Task}; use lsp::LanguageServerName; use paths::{ EDITORCONFIG_NAME, local_debug_file_relative_path, local_settings_file_relative_path, @@ -437,7 +437,7 @@ pub struct LspPullDiagnosticsSettings { } impl Settings for ProjectSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let project = &content.project.clone(); let diagnostics = content.diagnostics.as_ref().unwrap(); let lsp_pull_diagnostics = diagnostics.lsp_pull_diagnostics.as_ref().unwrap(); diff --git a/crates/project_panel/src/project_panel_settings.rs b/crates/project_panel/src/project_panel_settings.rs index c8bd287c33c9ddf131369897d0897e9edf5311c3..0f5f2e5b53a7a856b9e6bff136a1b1cc5af3e293 100644 --- a/crates/project_panel/src/project_panel_settings.rs +++ b/crates/project_panel/src/project_panel_settings.rs @@ -55,7 +55,7 @@ impl ScrollbarVisibility for ProjectPanelSettings { } impl Settings for ProjectPanelSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self { let project_panel = content.project_panel.clone().unwrap(); Self { button: project_panel.button.unwrap(), diff --git a/crates/recent_projects/src/remote_connections.rs b/crates/recent_projects/src/remote_connections.rs index 4431c49a2d28ccfc5d799f3646cb9f46714183f1..2e0358d0fcbf0e655698761894345499b9587942 100644 --- a/crates/recent_projects/src/remote_connections.rs +++ b/crates/recent_projects/src/remote_connections.rs @@ -104,7 +104,7 @@ impl From for Connection { } impl Settings for SshSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let remote = &content.remote; Self { ssh_connections: remote.ssh_connections.clone().unwrap_or_default().into(), diff --git a/crates/repl/src/jupyter_settings.rs b/crates/repl/src/jupyter_settings.rs index 9b3dc014f21443cc6112a864badc3a8d36ac90ed..830e6032147cbc96bb46b240651167402db427f1 100644 --- a/crates/repl/src/jupyter_settings.rs +++ b/crates/repl/src/jupyter_settings.rs @@ -19,7 +19,7 @@ impl JupyterSettings { } impl Settings for JupyterSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let jupyter = content.editor.jupyter.clone().unwrap(); Self { kernel_selections: jupyter.kernel_selections.unwrap_or_default(), diff --git a/crates/repl/src/repl_settings.rs b/crates/repl/src/repl_settings.rs index 1cd96ca47705e90c56fb1b3e25e41eb8edce0c87..ee18c89d67a0f1da55acaee89cfaa0b03dc80f87 100644 --- a/crates/repl/src/repl_settings.rs +++ b/crates/repl/src/repl_settings.rs @@ -1,3 +1,4 @@ +use gpui::App; use settings::Settings; /// Settings for configuring REPL display and behavior. @@ -16,7 +17,7 @@ pub struct ReplSettings { } impl Settings for ReplSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let repl = content.repl.as_ref().unwrap(); Self { diff --git a/crates/settings/src/base_keymap_setting.rs b/crates/settings/src/base_keymap_setting.rs index b2b19864256704fe1a8e1eb929743d37b7ba4407..1b41dc0d4f7db6a907de9586d5c4ceb796d00165 100644 --- a/crates/settings/src/base_keymap_setting.rs +++ b/crates/settings/src/base_keymap_setting.rs @@ -4,6 +4,7 @@ use crate::{ self as settings, settings_content::{BaseKeymapContent, SettingsContent}, }; +use gpui::App; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{Settings, VsCodeSettings}; @@ -130,7 +131,7 @@ impl BaseKeymap { } impl Settings for BaseKeymap { - fn from_settings(s: &crate::settings_content::SettingsContent) -> Self { + fn from_settings(s: &crate::settings_content::SettingsContent, _cx: &mut App) -> Self { s.base_keymap.unwrap().into() } diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index a5773ba25f5447946e18e65a97104d08394a35b1..b94a24866c76a57328f3b1ebf6a688b2fa4b3820 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -67,7 +67,11 @@ pub trait Settings: 'static + Send + Sync + Sized { /// /// This function *should* panic if default values are missing, /// and you should add a default to default.json for documentation. - fn from_settings(content: &SettingsContent) -> Self; + fn from_settings(content: &SettingsContent, cx: &mut App) -> Self; + + fn missing_default() -> anyhow::Error { + anyhow::anyhow!("missing default for: {}", std::any::type_name::()) + } /// Use [the helpers in the vscode_import module](crate::vscode_import) to apply known /// equivalent settings from a vscode config to our config @@ -78,8 +82,8 @@ pub trait Settings: 'static + Send + Sync + Sized { where Self: Sized, { - SettingsStore::update_global(cx, |store, _| { - store.register_setting::(); + SettingsStore::update_global(cx, |store, cx| { + store.register_setting::(cx); }); } @@ -201,7 +205,7 @@ struct SettingValue { trait AnySettingValue: 'static + Send + Sync { fn setting_type_name(&self) -> &'static str; - fn from_settings(&self, s: &SettingsContent) -> Box; + fn from_settings(&self, s: &SettingsContent, cx: &mut App) -> Box; fn value_for_path(&self, path: Option) -> &dyn Any; fn all_local_values(&self) -> Vec<(WorktreeId, Arc, &dyn Any)>; @@ -255,7 +259,7 @@ impl SettingsStore { } /// Add a new type of setting to the store. - pub fn register_setting(&mut self) { + pub fn register_setting(&mut self, cx: &mut App) { let setting_type_id = TypeId::of::(); let entry = self.setting_values.entry(setting_type_id); @@ -267,7 +271,7 @@ impl SettingsStore { global_value: None, local_values: Vec::new(), })); - let value = T::from_settings(&self.merged_settings); + let value = T::from_settings(&self.merged_settings, cx); setting_value.set_global_value(Box::new(value)); } @@ -940,7 +944,7 @@ impl SettingsStore { self.merged_settings = Rc::new(merged); for setting_value in self.setting_values.values_mut() { - let value = setting_value.from_settings(&self.merged_settings); + let value = setting_value.from_settings(&self.merged_settings, cx); setting_value.set_global_value(value); } } @@ -977,7 +981,8 @@ impl SettingsStore { } for setting_value in self.setting_values.values_mut() { - let value = setting_value.from_settings(&project_settings_stack.last().unwrap()); + let value = + setting_value.from_settings(&project_settings_stack.last().unwrap(), cx); setting_value.set_local_value(*root_id, directory_path.clone(), value); } } @@ -1061,8 +1066,8 @@ impl Debug for SettingsStore { } impl AnySettingValue for SettingValue { - fn from_settings(&self, s: &SettingsContent) -> Box { - Box::new(T::from_settings(s)) as _ + fn from_settings(&self, s: &SettingsContent, cx: &mut App) -> Box { + Box::new(T::from_settings(s, cx)) as _ } fn setting_type_name(&self) -> &'static str { @@ -1133,7 +1138,7 @@ mod tests { } impl Settings for AutoUpdateSetting { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _: &mut App) -> Self { AutoUpdateSetting { auto_update: content.auto_update.unwrap(), } @@ -1147,7 +1152,7 @@ mod tests { } impl Settings for ItemSettings { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _: &mut App) -> Self { let content = content.tabs.clone().unwrap(); ItemSettings { close_position: content.close_position.unwrap(), @@ -1176,7 +1181,7 @@ mod tests { } impl Settings for DefaultLanguageSettings { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _: &mut App) -> Self { let content = &content.project.all_languages.defaults; DefaultLanguageSettings { tab_size: content.tab_size.unwrap(), @@ -1200,9 +1205,9 @@ mod tests { #[gpui::test] fn test_settings_store_basic(cx: &mut App) { let mut store = SettingsStore::new(cx, &default_settings()); - store.register_setting::(); - store.register_setting::(); - store.register_setting::(); + store.register_setting::(cx); + store.register_setting::(cx); + store.register_setting::(cx); assert_eq!( store.get::(None), @@ -1308,7 +1313,7 @@ mod tests { store .set_user_settings(r#"{ "auto_update": false }"#, cx) .unwrap(); - store.register_setting::(); + store.register_setting::(cx); assert_eq!( store.get::(None), @@ -1516,9 +1521,9 @@ mod tests { #[gpui::test] fn test_vscode_import(cx: &mut App) { let mut store = SettingsStore::new(cx, &test_settings()); - store.register_setting::(); - store.register_setting::(); - store.register_setting::(); + store.register_setting::(cx); + store.register_setting::(cx); + store.register_setting::(cx); // create settings that werent present check_vscode_import( @@ -1637,7 +1642,7 @@ mod tests { #[gpui::test] fn test_global_settings(cx: &mut App) { let mut store = SettingsStore::new(cx, &test_settings()); - store.register_setting::(); + store.register_setting::(cx); // Set global settings - these should override defaults but not user settings store @@ -1686,7 +1691,7 @@ mod tests { #[gpui::test] fn test_get_value_for_field_basic(cx: &mut App) { let mut store = SettingsStore::new(cx, &test_settings()); - store.register_setting::(); + store.register_setting::(cx); store .set_user_settings(r#"{"preferred_line_length": 0}"#, cx) @@ -1743,8 +1748,8 @@ mod tests { #[gpui::test] fn test_get_value_for_field_local_worktrees_dont_interfere(cx: &mut App) { let mut store = SettingsStore::new(cx, &test_settings()); - store.register_setting::(); - store.register_setting::(); + store.register_setting::(cx); + store.register_setting::(cx); let local_1 = (WorktreeId::from_usize(0), RelPath::empty().into_arc()); @@ -1872,7 +1877,7 @@ mod tests { #[gpui::test] fn test_get_overrides_for_field(cx: &mut App) { let mut store = SettingsStore::new(cx, &test_settings()); - store.register_setting::(); + store.register_setting::(cx); let wt0_root = (WorktreeId::from_usize(0), RelPath::empty().into_arc()); let wt0_child1 = (WorktreeId::from_usize(0), rel_path("child1").into_arc()); diff --git a/crates/settings_profile_selector/src/settings_profile_selector.rs b/crates/settings_profile_selector/src/settings_profile_selector.rs index 4eecf3b290d37548d4fe3a1312f5572164b89907..11a25c553aab0021970f8fa9f721cb021139a2a2 100644 --- a/crates/settings_profile_selector/src/settings_profile_selector.rs +++ b/crates/settings_profile_selector/src/settings_profile_selector.rs @@ -302,6 +302,7 @@ mod tests { cx.set_global(settings_store); settings::init(cx); theme::init(theme::LoadThemes::JustBase, cx); + ThemeSettings::register(cx); client::init_settings(cx); language::init(cx); super::init(cx); diff --git a/crates/storybook/src/storybook.rs b/crates/storybook/src/storybook.rs index 592ee7bc7ac5cc92125fc7b4aa5846b4338884d7..ac01e6c5c88d042353a17f18281cd4d467c7c491 100644 --- a/crates/storybook/src/storybook.rs +++ b/crates/storybook/src/storybook.rs @@ -19,7 +19,7 @@ use reqwest_client::ReqwestClient; use settings::{KeymapFile, Settings}; use simplelog::SimpleLogger; use strum::IntoEnumIterator; -use theme::ThemeSettings; +use theme::{ThemeRegistry, ThemeSettings}; use ui::prelude::*; use workspace; @@ -80,9 +80,9 @@ fn main() { let selector = story_selector; + let theme_registry = ThemeRegistry::global(cx); let mut theme_settings = ThemeSettings::get_global(cx).clone(); - theme_settings.theme = - theme::ThemeSelection::Static(settings::ThemeName(theme_name.into())); + theme_settings.active_theme = theme_registry.get(&theme_name).unwrap(); ThemeSettings::override_global(theme_settings, cx); language::init(cx); diff --git a/crates/terminal/src/terminal_settings.rs b/crates/terminal/src/terminal_settings.rs index e3ef3960a9c6a37c6596c0804c2f58ca273216d0..91a65f386fdb21556ea7fac8c2c3d26187f162c8 100644 --- a/crates/terminal/src/terminal_settings.rs +++ b/crates/terminal/src/terminal_settings.rs @@ -2,7 +2,7 @@ use alacritty_terminal::vte::ansi::{ CursorShape as AlacCursorShape, CursorStyle as AlacCursorStyle, }; use collections::HashMap; -use gpui::{FontFallbacks, FontFeatures, FontWeight, Pixels, px}; +use gpui::{App, FontFallbacks, FontFeatures, FontWeight, Pixels, px}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -72,7 +72,7 @@ fn settings_shell_to_task_shell(shell: settings::Shell) -> Shell { } impl settings::Settings for TerminalSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let content = content.terminal.clone().unwrap(); TerminalSettings { shell: settings_shell_to_task_shell(content.shell.unwrap()), diff --git a/crates/theme/src/fallback_themes.rs b/crates/theme/src/fallback_themes.rs index 4fb8069bc16d1967dfe10b2e6a577b990d942db7..13786aca57aab50b503da48d0d4f54fdd78b88c2 100644 --- a/crates/theme/src/fallback_themes.rs +++ b/crates/theme/src/fallback_themes.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use gpui::{FontStyle, FontWeight, HighlightStyle, Hsla, WindowBackgroundAppearance, hsla}; use crate::{ - AccentColors, Appearance, DEFAULT_DARK_THEME, PlayerColors, StatusColors, - StatusColorsRefinement, SyntaxTheme, SystemColors, Theme, ThemeColors, ThemeColorsRefinement, - ThemeFamily, ThemeStyles, default_color_scales, + AccentColors, Appearance, PlayerColors, StatusColors, StatusColorsRefinement, SyntaxTheme, + SystemColors, Theme, ThemeColors, ThemeColorsRefinement, ThemeFamily, ThemeStyles, + default_color_scales, }; /// The default theme family for Zed. @@ -92,7 +92,7 @@ pub(crate) fn zed_default_dark() -> Theme { let player = PlayerColors::dark(); Theme { id: "one_dark".to_string(), - name: DEFAULT_DARK_THEME.into(), + name: "One Dark".into(), appearance: Appearance::Dark, styles: ThemeStyles { window_background_appearance: WindowBackgroundAppearance::Opaque, diff --git a/crates/theme/src/settings.rs b/crates/theme/src/settings.rs index 01676bccc9b1f0d47b871623f61c76f085b250e4..83cd7f9f2e55bc0a510d8653f397fbfc994c18e7 100644 --- a/crates/theme/src/settings.rs +++ b/crates/theme/src/settings.rs @@ -1,6 +1,8 @@ +use crate::fallback_themes::zed_default_dark; use crate::{ - Appearance, DEFAULT_ICON_THEME_NAME, SyntaxTheme, Theme, status_colors_refinement, - syntax_overrides, theme_colors_refinement, + Appearance, DEFAULT_ICON_THEME_NAME, IconTheme, IconThemeNotFoundError, SyntaxTheme, Theme, + ThemeNotFoundError, ThemeRegistry, status_colors_refinement, syntax_overrides, + theme_colors_refinement, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -14,6 +16,7 @@ use serde::{Deserialize, Serialize}; pub use settings::{FontFamilyName, IconThemeName, ThemeMode, ThemeName}; use settings::{Settings, SettingsContent}; use std::sync::Arc; +use util::ResultExt as _; const MIN_FONT_SIZE: Pixels = px(6.0); const MAX_FONT_SIZE: Pixels = px(100.0); @@ -122,7 +125,9 @@ pub struct ThemeSettings { /// The terminal font family can be overridden using it's own setting. pub buffer_line_height: BufferLineHeight, /// The current theme selection. - pub theme: ThemeSelection, + pub theme_selection: Option, + /// The active theme. + pub active_theme: Arc, /// Manual overrides for the active theme. /// /// Note: This setting is still experimental. See [this tracking issue](https://github.com/zed-industries/zed/issues/18078) @@ -130,7 +135,9 @@ pub struct ThemeSettings { /// Manual overrides per theme pub theme_overrides: HashMap, /// The current icon theme selection. - pub icon_theme: IconThemeSelection, + pub icon_theme_selection: Option, + /// The active icon theme. + pub active_icon_theme: Arc, /// The density of the UI. /// Note: This setting is still experimental. See [this tracking issue]( pub ui_density: UiDensity, @@ -138,14 +145,73 @@ pub struct ThemeSettings { pub unnecessary_code_fade: f32, } -pub(crate) const DEFAULT_LIGHT_THEME: &'static str = "One Light"; -pub(crate) const DEFAULT_DARK_THEME: &'static str = "One Dark"; +impl ThemeSettings { + const DEFAULT_LIGHT_THEME: &'static str = "One Light"; + const DEFAULT_DARK_THEME: &'static str = "One Dark"; + + /// Returns the name of the default theme for the given [`Appearance`]. + pub fn default_theme(appearance: Appearance) -> &'static str { + match appearance { + Appearance::Light => Self::DEFAULT_LIGHT_THEME, + Appearance::Dark => Self::DEFAULT_DARK_THEME, + } + } -/// Returns the name of the default theme for the given [`Appearance`]. -pub fn default_theme(appearance: Appearance) -> &'static str { - match appearance { - Appearance::Light => DEFAULT_LIGHT_THEME, - Appearance::Dark => DEFAULT_DARK_THEME, + /// Reloads the current theme. + /// + /// Reads the [`ThemeSettings`] to know which theme should be loaded, + /// taking into account the current [`SystemAppearance`]. + pub fn reload_current_theme(cx: &mut App) { + let mut theme_settings = ThemeSettings::get_global(cx).clone(); + let system_appearance = SystemAppearance::global(cx); + + if let Some(theme_selection) = theme_settings.theme_selection.clone() { + let mut theme_name = theme_selection.theme(*system_appearance); + + // If the selected theme doesn't exist, fall back to a default theme + // based on the system appearance. + let theme_registry = ThemeRegistry::global(cx); + if let Err(err @ ThemeNotFoundError(_)) = theme_registry.get(theme_name) { + if theme_registry.extensions_loaded() { + log::error!("{err}"); + } + + theme_name = Self::default_theme(*system_appearance); + }; + + if let Some(_theme) = theme_settings.switch_theme(theme_name, cx) { + ThemeSettings::override_global(theme_settings, cx); + } + } + } + + /// Reloads the current icon theme. + /// + /// Reads the [`ThemeSettings`] to know which icon theme should be loaded, + /// taking into account the current [`SystemAppearance`]. + pub fn reload_current_icon_theme(cx: &mut App) { + let mut theme_settings = ThemeSettings::get_global(cx).clone(); + let system_appearance = SystemAppearance::global(cx); + + if let Some(icon_theme_selection) = theme_settings.icon_theme_selection.clone() { + let mut icon_theme_name = icon_theme_selection.icon_theme(*system_appearance); + + // If the selected icon theme doesn't exist, fall back to the default theme. + let theme_registry = ThemeRegistry::global(cx); + if let Err(err @ IconThemeNotFoundError(_)) = + theme_registry.get_icon_theme(icon_theme_name) + { + if theme_registry.extensions_loaded() { + log::error!("{err}"); + } + + icon_theme_name = DEFAULT_ICON_THEME_NAME; + }; + + if let Some(_theme) = theme_settings.switch_icon_theme(icon_theme_name, cx) { + ThemeSettings::override_global(theme_settings, cx); + } + } } } @@ -171,6 +237,13 @@ impl SystemAppearance { GlobalSystemAppearance(SystemAppearance(cx.window_appearance().into())); } + /// Returns the global [`SystemAppearance`]. + /// + /// Inserts a default [`SystemAppearance`] if one does not yet exist. + pub(crate) fn default_global(cx: &mut App) -> Self { + cx.default_global::().0 + } + /// Returns the global [`SystemAppearance`]. pub fn global(cx: &App) -> Self { cx.global::().0 @@ -229,15 +302,15 @@ impl From for ThemeSelection { impl ThemeSelection { /// Returns the theme name for the selected [ThemeMode]. - pub fn name(&self, system_appearance: Appearance) -> ThemeName { + pub fn theme(&self, system_appearance: Appearance) -> &str { match self { - Self::Static(theme) => theme.clone(), + Self::Static(theme) => &theme.0, Self::Dynamic { mode, light, dark } => match mode { - ThemeMode::Light => light.clone(), - ThemeMode::Dark => dark.clone(), + ThemeMode::Light => &light.0, + ThemeMode::Dark => &dark.0, ThemeMode::System => match system_appearance { - Appearance::Light => light.clone(), - Appearance::Dark => dark.clone(), + Appearance::Light => &light.0, + Appearance::Dark => &dark.0, }, }, } @@ -281,15 +354,15 @@ impl From for IconThemeSelection { impl IconThemeSelection { /// Returns the icon theme name based on the given [`Appearance`]. - pub fn name(&self, system_appearance: Appearance) -> IconThemeName { + pub fn icon_theme(&self, system_appearance: Appearance) -> &str { match self { - Self::Static(theme) => theme.clone(), + Self::Static(theme) => &theme.0, Self::Dynamic { mode, light, dark } => match mode { - ThemeMode::Light => light.clone(), - ThemeMode::Dark => dark.clone(), + ThemeMode::Light => &light.0, + ThemeMode::Dark => &dark.0, ThemeMode::System => match system_appearance { - Appearance::Light => light.clone(), - Appearance::Dark => dark.clone(), + Appearance::Light => &light.0, + Appearance::Dark => &dark.0, }, }, } @@ -335,7 +408,7 @@ pub fn set_theme( /// Sets the icon theme for the given appearance to the icon theme with the specified name. pub fn set_icon_theme( current: &mut SettingsContent, - icon_theme_name: IconThemeName, + icon_theme_name: String, appearance: Appearance, ) { if let Some(selection) = current.theme.icon_theme.as_mut() { @@ -351,9 +424,11 @@ pub fn set_icon_theme( }, }; - *icon_theme_to_update = icon_theme_name; + *icon_theme_to_update = IconThemeName(icon_theme_name.into()); } else { - current.theme.icon_theme = Some(settings::IconThemeSelection::Static(icon_theme_name)); + current.theme.icon_theme = Some(settings::IconThemeSelection::Static(IconThemeName( + icon_theme_name.into(), + ))); } } @@ -381,8 +456,8 @@ pub fn set_mode(content: &mut SettingsContent, mode: ThemeMode) { } else { theme.theme = Some(settings::ThemeSelection::Dynamic { mode, - light: ThemeName(DEFAULT_LIGHT_THEME.into()), - dark: ThemeName(DEFAULT_DARK_THEME.into()), + light: ThemeName(ThemeSettings::DEFAULT_LIGHT_THEME.into()), + dark: ThemeName(ThemeSettings::DEFAULT_DARK_THEME.into()), }); } @@ -521,22 +596,44 @@ impl ThemeSettings { f32::max(self.buffer_line_height.value(), MIN_LINE_HEIGHT) } + /// Switches to the theme with the given name, if it exists. + /// + /// Returns a `Some` containing the new theme if it was successful. + /// Returns `None` otherwise. + pub fn switch_theme(&mut self, theme: &str, cx: &mut App) -> Option> { + let themes = ThemeRegistry::default_global(cx); + + let mut new_theme = None; + + match themes.get(theme) { + Ok(theme) => { + self.active_theme = theme.clone(); + new_theme = Some(theme); + } + Err(err @ ThemeNotFoundError(_)) => { + log::error!("{err}"); + } + } + + self.apply_theme_overrides(); + + new_theme + } + /// Applies the theme overrides, if there are any, to the current theme. - pub fn apply_theme_overrides(&self, mut arc_theme: Arc) -> Arc { + pub fn apply_theme_overrides(&mut self) { // Apply the old overrides setting first, so that the new setting can override those. if let Some(experimental_theme_overrides) = &self.experimental_theme_overrides { - let mut theme = (*arc_theme).clone(); + let mut theme = (*self.active_theme).clone(); ThemeSettings::modify_theme(&mut theme, experimental_theme_overrides); - arc_theme = Arc::new(theme); + self.active_theme = Arc::new(theme); } - if let Some(theme_overrides) = self.theme_overrides.get(arc_theme.name.as_ref()) { - let mut theme = (*arc_theme).clone(); + if let Some(theme_overrides) = self.theme_overrides.get(self.active_theme.name.as_ref()) { + let mut theme = (*self.active_theme).clone(); ThemeSettings::modify_theme(&mut theme, theme_overrides); - arc_theme = Arc::new(theme); + self.active_theme = Arc::new(theme); } - - arc_theme } fn modify_theme(base_theme: &mut Theme, theme_overrides: &settings::ThemeStyleContent) { @@ -557,6 +654,24 @@ impl ThemeSettings { syntax_overrides(&theme_overrides), ); } + + /// Switches to the icon theme with the given name, if it exists. + /// + /// Returns a `Some` containing the new icon theme if it was successful. + /// Returns `None` otherwise. + pub fn switch_icon_theme(&mut self, icon_theme: &str, cx: &mut App) -> Option> { + let themes = ThemeRegistry::default_global(cx); + + let mut new_icon_theme = None; + + if let Some(icon_theme) = themes.get_icon_theme(icon_theme).log_err() { + self.active_icon_theme = icon_theme.clone(); + new_icon_theme = Some(icon_theme); + cx.refresh_windows(); + } + + new_icon_theme + } } /// Observe changes to the adjusted buffer font size. @@ -689,11 +804,14 @@ pub fn font_fallbacks_from_settings( } impl settings::Settings for ThemeSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, cx: &mut App) -> Self { let content = &content.theme; + // todo(settings_refactor). This should *not* require cx... + let themes = ThemeRegistry::default_global(cx); + let system_appearance = SystemAppearance::default_global(cx); let theme_selection: ThemeSelection = content.theme.clone().unwrap().into(); let icon_theme_selection: IconThemeSelection = content.icon_theme.clone().unwrap().into(); - Self { + let mut this = Self { ui_font_size: clamp_font_size(content.ui_font_size.unwrap().into()), ui_font: Font { family: content.ui_font_family.as_ref().unwrap().0.clone().into(), @@ -719,13 +837,23 @@ impl settings::Settings for ThemeSettings { buffer_line_height: content.buffer_line_height.unwrap().into(), agent_ui_font_size: content.agent_ui_font_size.map(Into::into), agent_buffer_font_size: content.agent_buffer_font_size.map(Into::into), - theme: theme_selection, + active_theme: themes + .get(theme_selection.theme(*system_appearance)) + .or(themes.get(&zed_default_dark().name)) + .unwrap(), + theme_selection: Some(theme_selection), experimental_theme_overrides: content.experimental_theme_overrides.clone(), theme_overrides: content.theme_overrides.clone(), - icon_theme: icon_theme_selection, + active_icon_theme: themes + .get_icon_theme(icon_theme_selection.icon_theme(*system_appearance)) + .or_else(|_| themes.default_icon_theme()) + .unwrap(), + icon_theme_selection: Some(icon_theme_selection), ui_density: content.ui_density.unwrap_or_default().into(), unnecessary_code_fade: content.unnecessary_code_fade.unwrap().0.clamp(0.0, 0.9), - } + }; + this.apply_theme_overrides(); + this } fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) { diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index c18719efe0d2665928bb0c6003cc69a85da49b83..5b12e4d33bd5f2eb7ad3500e9194363de47b356f 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -27,8 +27,6 @@ use ::settings::SettingsStore; use anyhow::Result; use fallback_themes::apply_status_color_defaults; use fs::Fs; -use gpui::BorrowAppContext; -use gpui::Global; use gpui::{ App, AssetSource, HighlightStyle, Hsla, Pixels, Refineable, SharedString, WindowAppearance, WindowBackgroundAppearance, px, @@ -97,7 +95,6 @@ pub enum LoadThemes { /// Initialize the theme system. pub fn init(themes_to_load: LoadThemes, cx: &mut App) { - SystemAppearance::init(cx); let (assets, load_user_themes) = match themes_to_load { LoadThemes::JustBase => (Box::new(()) as Box, false), LoadThemes::All(assets) => (assets, true), @@ -111,67 +108,40 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut App) { ThemeSettings::register(cx); FontFamilyCache::init_global(cx); - let theme = GlobalTheme::configured_theme(cx); - let icon_theme = GlobalTheme::configured_icon_theme(cx); - cx.set_global(GlobalTheme { theme, icon_theme }); - - let settings = ThemeSettings::get_global(cx); - - let mut prev_buffer_font_size_settings = settings.buffer_font_size_settings(); - let mut prev_ui_font_size_settings = settings.ui_font_size_settings(); - let mut prev_agent_ui_font_size_settings = settings.agent_ui_font_size_settings(); - let mut prev_agent_buffer_font_size_settings = settings.agent_buffer_font_size_settings(); - let mut prev_theme_name = settings.theme.name(SystemAppearance::global(cx).0); - let mut prev_icon_theme_name = settings.icon_theme.name(SystemAppearance::global(cx).0); - let mut prev_theme_overrides = ( - settings.experimental_theme_overrides.clone(), - settings.theme_overrides.clone(), - ); + let mut prev_buffer_font_size_settings = + ThemeSettings::get_global(cx).buffer_font_size_settings(); + let mut prev_ui_font_size_settings = ThemeSettings::get_global(cx).ui_font_size_settings(); + let mut prev_agent_ui_font_size_settings = + ThemeSettings::get_global(cx).agent_ui_font_size_settings(); + let mut prev_agent_buffer_font_size_settings = + ThemeSettings::get_global(cx).agent_buffer_font_size_settings(); cx.observe_global::(move |cx| { - let settings = ThemeSettings::get_global(cx); - - let buffer_font_size_settings = settings.buffer_font_size_settings(); - let ui_font_size_settings = settings.ui_font_size_settings(); - let agent_ui_font_size_settings = settings.agent_ui_font_size_settings(); - let agent_buffer_font_size_settings = settings.agent_buffer_font_size_settings(); - let theme_name = settings.theme.name(SystemAppearance::global(cx).0); - let icon_theme_name = settings.icon_theme.name(SystemAppearance::global(cx).0); - let theme_overrides = ( - settings.experimental_theme_overrides.clone(), - settings.theme_overrides.clone(), - ); - + let buffer_font_size_settings = ThemeSettings::get_global(cx).buffer_font_size_settings(); if buffer_font_size_settings != prev_buffer_font_size_settings { prev_buffer_font_size_settings = buffer_font_size_settings; reset_buffer_font_size(cx); } + let ui_font_size_settings = ThemeSettings::get_global(cx).ui_font_size_settings(); if ui_font_size_settings != prev_ui_font_size_settings { prev_ui_font_size_settings = ui_font_size_settings; reset_ui_font_size(cx); } + let agent_ui_font_size_settings = + ThemeSettings::get_global(cx).agent_ui_font_size_settings(); if agent_ui_font_size_settings != prev_agent_ui_font_size_settings { prev_agent_ui_font_size_settings = agent_ui_font_size_settings; reset_agent_ui_font_size(cx); } + let agent_buffer_font_size_settings = + ThemeSettings::get_global(cx).agent_buffer_font_size_settings(); if agent_buffer_font_size_settings != prev_agent_buffer_font_size_settings { prev_agent_buffer_font_size_settings = agent_buffer_font_size_settings; reset_agent_buffer_font_size(cx); } - - if theme_name != prev_theme_name || theme_overrides != prev_theme_overrides { - prev_theme_name = theme_name; - prev_theme_overrides = theme_overrides; - GlobalTheme::reload_theme(cx); - } - - if icon_theme_name != prev_icon_theme_name { - prev_icon_theme_name = icon_theme_name; - GlobalTheme::reload_icon_theme(cx); - } }) .detach(); } @@ -184,7 +154,7 @@ pub trait ActiveTheme { impl ActiveTheme for App { fn theme(&self) -> &Arc { - GlobalTheme::theme(self) + &ThemeSettings::get_global(self).active_theme } } @@ -438,82 +408,3 @@ pub async fn read_icon_theme( Ok(icon_theme_family) } - -/// The active theme -pub struct GlobalTheme { - theme: Arc, - icon_theme: Arc, -} -impl Global for GlobalTheme {} - -impl GlobalTheme { - fn configured_theme(cx: &mut App) -> Arc { - let themes = ThemeRegistry::default_global(cx); - let theme_settings = ThemeSettings::get_global(cx); - let system_appearance = SystemAppearance::global(cx); - - let theme_name = theme_settings.theme.name(*system_appearance); - - let theme = match themes.get(&theme_name.0) { - Ok(theme) => theme, - Err(err) => { - if themes.extensions_loaded() { - log::error!("{err}"); - } - themes - .get(default_theme(*system_appearance)) - // fallback for tests. - .unwrap_or_else(|_| themes.get(DEFAULT_DARK_THEME).unwrap()) - } - }; - theme_settings.apply_theme_overrides(theme) - } - - /// Reloads the current theme. - /// - /// Reads the [`ThemeSettings`] to know which theme should be loaded, - /// taking into account the current [`SystemAppearance`]. - pub fn reload_theme(cx: &mut App) { - let theme = Self::configured_theme(cx); - cx.update_global::(|this, _| this.theme = theme); - cx.refresh_windows(); - } - - fn configured_icon_theme(cx: &mut App) -> Arc { - let themes = ThemeRegistry::default_global(cx); - let theme_settings = ThemeSettings::get_global(cx); - let system_appearance = SystemAppearance::global(cx); - - let icon_theme_name = theme_settings.icon_theme.name(*system_appearance); - - match themes.get_icon_theme(&icon_theme_name.0) { - Ok(theme) => theme, - Err(err) => { - if themes.extensions_loaded() { - log::error!("{err}"); - } - themes.get_icon_theme(DEFAULT_ICON_THEME_NAME).unwrap() - } - } - } - - /// Reloads the current icon theme. - /// - /// Reads the [`ThemeSettings`] to know which icon theme should be loaded, - /// taking into account the current [`SystemAppearance`]. - pub fn reload_icon_theme(cx: &mut App) { - let icon_theme = Self::configured_icon_theme(cx); - cx.update_global::(|this, _| this.icon_theme = icon_theme); - cx.refresh_windows(); - } - - /// the active theme - pub fn theme(cx: &App) -> &Arc { - &cx.global::().theme - } - - /// the active icon theme - pub fn icon_theme(cx: &App) -> &Arc { - &cx.global::().icon_theme - } -} diff --git a/crates/theme_extension/src/theme_extension.rs b/crates/theme_extension/src/theme_extension.rs index 10df2349c86decbadaa010778a95d04af36a6aab..b9c6ed6d4b9c5b1ddf5ce0066e1b6b729ba7ee7f 100644 --- a/crates/theme_extension/src/theme_extension.rs +++ b/crates/theme_extension/src/theme_extension.rs @@ -5,7 +5,7 @@ use anyhow::Result; use extension::{ExtensionHostProxy, ExtensionThemeProxy}; use fs::Fs; use gpui::{App, BackgroundExecutor, SharedString, Task}; -use theme::{GlobalTheme, ThemeRegistry}; +use theme::{ThemeRegistry, ThemeSettings}; pub fn init( extension_host_proxy: Arc, @@ -46,7 +46,7 @@ impl ExtensionThemeProxy for ThemeRegistryProxy { } fn reload_current_theme(&self, cx: &mut App) { - GlobalTheme::reload_theme(cx) + ThemeSettings::reload_current_theme(cx) } fn list_icon_theme_names( @@ -83,6 +83,6 @@ impl ExtensionThemeProxy for ThemeRegistryProxy { } fn reload_current_icon_theme(&self, cx: &mut App) { - GlobalTheme::reload_icon_theme(cx) + ThemeSettings::reload_current_icon_theme(cx) } } diff --git a/crates/theme_selector/src/icon_theme_selector.rs b/crates/theme_selector/src/icon_theme_selector.rs index 2ea3436d43cd2d2a4bda392384ff51f962824143..5cd04aa8951dff890c68e8512e8082e5288f0f63 100644 --- a/crates/theme_selector/src/icon_theme_selector.rs +++ b/crates/theme_selector/src/icon_theme_selector.rs @@ -7,10 +7,7 @@ use gpui::{ use picker::{Picker, PickerDelegate}; use settings::{Settings as _, SettingsStore, update_settings_file}; use std::sync::Arc; -use theme::{ - Appearance, IconThemeName, IconThemeSelection, SystemAppearance, ThemeMeta, ThemeRegistry, - ThemeSettings, -}; +use theme::{Appearance, IconTheme, ThemeMeta, ThemeRegistry, ThemeSettings}; use ui::{ListItem, ListItemSpacing, prelude::*, v_flex}; use util::ResultExt; use workspace::{ModalView, ui::HighlightedLabel}; @@ -54,9 +51,9 @@ pub(crate) struct IconThemeSelectorDelegate { fs: Arc, themes: Vec, matches: Vec, - original_theme: IconThemeName, + original_theme: Arc, selection_completed: bool, - selected_theme: Option, + selected_theme: Option>, selected_index: usize, selector: WeakEntity, } @@ -69,9 +66,7 @@ impl IconThemeSelectorDelegate { cx: &mut Context, ) -> Self { let theme_settings = ThemeSettings::get_global(cx); - let original_theme = theme_settings - .icon_theme - .name(SystemAppearance::global(cx).0); + let original_theme = theme_settings.active_icon_theme.clone(); let registry = ThemeRegistry::global(cx); let mut themes = registry @@ -112,18 +107,29 @@ impl IconThemeSelectorDelegate { selector, }; - this.select_if_matching(&original_theme.0); + this.select_if_matching(&original_theme.name); this } fn show_selected_theme( &mut self, cx: &mut Context>, - ) -> Option { - let mat = self.matches.get(self.selected_index)?; - let name = IconThemeName(mat.string.clone().into()); - Self::set_icon_theme(name.clone(), cx); - Some(name) + ) -> Option> { + if let Some(mat) = self.matches.get(self.selected_index) { + let registry = ThemeRegistry::global(cx); + match registry.get_icon_theme(&mat.string) { + Ok(theme) => { + Self::set_icon_theme(theme.clone(), cx); + Some(theme) + } + Err(err) => { + log::error!("error loading icon theme {}: {err}", mat.string); + None + } + } + } else { + None + } } fn select_if_matching(&mut self, theme_name: &str) { @@ -134,11 +140,12 @@ impl IconThemeSelectorDelegate { .unwrap_or(self.selected_index); } - fn set_icon_theme(name: IconThemeName, cx: &mut App) { - SettingsStore::update_global(cx, |store, _| { + fn set_icon_theme(theme: Arc, cx: &mut App) { + SettingsStore::update_global(cx, |store, cx| { let mut theme_settings = store.get::(None).clone(); - theme_settings.icon_theme = IconThemeSelection::Static(name); + theme_settings.active_icon_theme = theme; store.override_global(theme_settings); + cx.refresh_windows(); }); } } @@ -163,9 +170,7 @@ impl PickerDelegate for IconThemeSelectorDelegate { self.selection_completed = true; let theme_settings = ThemeSettings::get_global(cx); - let theme_name = theme_settings - .icon_theme - .name(SystemAppearance::global(cx).0); + let theme_name = theme_settings.active_icon_theme.name.clone(); telemetry::event!( "Settings Changed", @@ -176,7 +181,7 @@ impl PickerDelegate for IconThemeSelectorDelegate { let appearance = Appearance::from(window.appearance()); update_settings_file(self.fs.clone(), cx, move |settings, _| { - theme::set_icon_theme(settings, theme_name, appearance); + theme::set_icon_theme(settings, theme_name.to_string(), appearance); }); self.selector @@ -263,7 +268,7 @@ impl PickerDelegate for IconThemeSelectorDelegate { .matches .iter() .enumerate() - .find(|(_, mtch)| mtch.string.as_str() == selected.0.as_ref()) + .find(|(_, mtch)| mtch.string == selected.name) .map(|(ix, _)| ix) .unwrap_or_default(); } else { diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index d3e21d5bd51613ef496fa9dbea52502688fc1f16..de41f3155f3c86cc5144c54c2b187ad0fd217b1c 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -203,11 +203,12 @@ impl ThemeSelectorDelegate { } fn set_theme(theme: Arc, cx: &mut App) { - SettingsStore::update_global(cx, |store, _| { + SettingsStore::update_global(cx, |store, cx| { let mut theme_settings = store.get::(None).clone(); - let name = theme.as_ref().name.clone().into(); - theme_settings.theme = theme::ThemeSelection::Static(theme::ThemeName(name)); + theme_settings.active_theme = theme; + theme_settings.apply_theme_overrides(); store.override_global(theme_settings); + cx.refresh_windows(); }); } } diff --git a/crates/title_bar/src/title_bar_settings.rs b/crates/title_bar/src/title_bar_settings.rs index bc9b1acbaa06cf60396e61ff68470c8a544e3f5d..712346abfb633f987458ed7b5978e35648569d6b 100644 --- a/crates/title_bar/src/title_bar_settings.rs +++ b/crates/title_bar/src/title_bar_settings.rs @@ -1,4 +1,5 @@ use settings::{Settings, SettingsContent}; +use ui::App; #[derive(Copy, Clone, Debug)] pub struct TitleBarSettings { @@ -12,7 +13,7 @@ pub struct TitleBarSettings { } impl Settings for TitleBarSettings { - fn from_settings(s: &SettingsContent) -> Self { + fn from_settings(s: &SettingsContent, _: &mut App) -> Self { let content = s.title_bar.clone().unwrap(); TitleBarSettings { show_branch_icon: content.show_branch_icon.unwrap(), diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index e01d1065b99aa6791bf79d8df26fe354c562284c..c9ca7cb325a99b376eafa36f46011fde80f465f0 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -1913,7 +1913,7 @@ impl From for Mode { } impl Settings for VimSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let vim = content.vim.clone().unwrap(); Self { default_mode: vim.default_mode.unwrap().into(), diff --git a/crates/vim_mode_setting/src/vim_mode_setting.rs b/crates/vim_mode_setting/src/vim_mode_setting.rs index d9495c556646f9b9f12dc0b52b9530796a5ad5e3..c82109f6b1f653c29942430fbf1fc557c09270fd 100644 --- a/crates/vim_mode_setting/src/vim_mode_setting.rs +++ b/crates/vim_mode_setting/src/vim_mode_setting.rs @@ -16,7 +16,7 @@ pub fn init(cx: &mut App) { pub struct VimModeSetting(pub bool); impl Settings for VimModeSetting { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _cx: &mut App) -> Self { Self(content.vim_mode.unwrap()) } @@ -28,7 +28,7 @@ impl Settings for VimModeSetting { pub struct HelixModeSetting(pub bool); impl Settings for HelixModeSetting { - fn from_settings(content: &SettingsContent) -> Self { + fn from_settings(content: &SettingsContent, _cx: &mut App) -> Self { Self(content.helix_mode.unwrap()) } diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index f868547dbf1da85bce8cf90c4bca266f941f78d9..572dd26cd779b974412cbf0476f9b9de11fb6315 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -65,7 +65,7 @@ pub struct PreviewTabsSettings { } impl Settings for ItemSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let tabs = content.tabs.as_ref().unwrap(); Self { git_status: tabs.git_status.unwrap(), @@ -113,7 +113,7 @@ impl Settings for ItemSettings { } impl Settings for PreviewTabsSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let preview_tabs = content.preview_tabs.as_ref().unwrap(); Self { enabled: preview_tabs.enabled.unwrap(), diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f7a48999d24dba04b34b87236e3674b3076218fa..c1271ea0e15fdd4a0bae3ad31c51de7468d2cd2b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -103,7 +103,7 @@ use std::{ time::Duration, }; use task::{DebugScenario, SpawnInTerminal, TaskContext}; -use theme::{ActiveTheme, GlobalTheme, SystemAppearance, ThemeSettings}; +use theme::{ActiveTheme, SystemAppearance, ThemeSettings}; pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; pub use ui; use ui::{Window, prelude::*}; @@ -1435,8 +1435,8 @@ impl Workspace { *SystemAppearance::global_mut(cx) = SystemAppearance(window_appearance.into()); - GlobalTheme::reload_theme(cx); - GlobalTheme::reload_icon_theme(cx); + ThemeSettings::reload_current_theme(cx); + ThemeSettings::reload_current_icon_theme(cx); }), cx.on_release(move |this, cx| { this.app_state.workspace_store.update(cx, move |store, _| { diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 541194b0044dd897723c89763abc7d3a2abc20f3..963fd6de58c2a722c0592cb911dbabaf87dafa0f 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -2,6 +2,7 @@ use std::num::NonZeroUsize; use crate::DockPosition; use collections::HashMap; +use gpui::App; use serde::Deserialize; pub use settings::AutosaveSetting; use settings::Settings; @@ -61,7 +62,7 @@ pub struct TabBarSettings { } impl Settings for WorkspaceSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let workspace = &content.workspace; Self { active_pane_modifiers: ActivePanelModifiers { @@ -196,7 +197,7 @@ impl Settings for WorkspaceSettings { } impl Settings for TabBarSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let tab_bar = content.tab_bar.clone().unwrap(); TabBarSettings { show: tab_bar.show.unwrap(), @@ -230,7 +231,7 @@ pub struct StatusBarSettings { } impl Settings for StatusBarSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let status_bar = content.status_bar.clone().unwrap(); StatusBarSettings { show: status_bar.show.unwrap(), diff --git a/crates/worktree/src/worktree_settings.rs b/crates/worktree/src/worktree_settings.rs index a9fcbf0909617986dd2d1d816ed513dd281f2940..3e8fc6114a7ac0ca10fbe823fff9ab3a7115b3c4 100644 --- a/crates/worktree/src/worktree_settings.rs +++ b/crates/worktree/src/worktree_settings.rs @@ -1,6 +1,7 @@ use std::path::Path; use anyhow::Context as _; +use gpui::App; use settings::{Settings, SettingsContent}; use util::{ ResultExt, @@ -34,7 +35,7 @@ impl WorktreeSettings { } impl Settings for WorktreeSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _cx: &mut App) -> Self { let worktree = content.project.worktree.clone(); let file_scan_exclusions = worktree.file_scan_exclusions.unwrap(); let file_scan_inclusions = worktree.file_scan_inclusions.unwrap(); diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index e90d8823907e91874b1d1a9dadcea978a1f7fd7e..db8d8736bd77de3367291dfb7e263012d2baa53d 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -41,8 +41,8 @@ use std::{ sync::Arc, }; use theme::{ - ActiveTheme, GlobalTheme, IconThemeNotFoundError, SystemAppearance, ThemeNotFoundError, - ThemeRegistry, ThemeSettings, + ActiveTheme, IconThemeNotFoundError, SystemAppearance, ThemeNotFoundError, ThemeRegistry, + ThemeSettings, }; use util::{ResultExt, TryFutureExt, maybe}; use uuid::Uuid; @@ -542,6 +542,7 @@ pub fn main() { cx, ); + SystemAppearance::init(cx); theme::init(theme::LoadThemes::All(Box::new(Assets)), cx); theme_extension::init( extension_host_proxy.clone(), @@ -1362,49 +1363,49 @@ fn eager_load_active_theme_and_icon_theme(fs: Arc, cx: &App) { 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) - { - cx.spawn({ - let theme_registry = theme_registry.clone(); - let fs = fs.clone(); - async move |cx| { - theme_registry.load_user_theme(&theme_path, fs).await?; + 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| { - GlobalTheme::reload_theme(cx); - }) - } - }) - .detach_and_log_err(cx); + cx.update(|cx| { + ThemeSettings::reload_current_theme(cx); + }) + } + }) + .detach_and_log_err(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) - { - cx.spawn({ - let fs = fs.clone(); - async move |cx| { - theme_registry - .load_icon_theme(&icon_theme_path, &icons_root_path, fs) - .await?; + 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| { - GlobalTheme::reload_icon_theme(cx); - }) - } - }) - .detach_and_log_err(cx); + cx.update(|cx| { + ThemeSettings::reload_current_icon_theme(cx); + }) + } + }) + .detach_and_log_err(cx); + } } } @@ -1432,7 +1433,7 @@ fn load_user_themes_in_background(fs: Arc, cx: &mut App) { } } theme_registry.load_user_themes(themes_dir, fs).await?; - cx.update(GlobalTheme::reload_theme)?; + cx.update(ThemeSettings::reload_current_theme)?; } anyhow::Ok(()) } @@ -1458,7 +1459,7 @@ fn watch_themes(fs: Arc, cx: &mut App) { .await .log_err() { - cx.update(GlobalTheme::reload_theme).log_err(); + cx.update(ThemeSettings::reload_current_theme).log_err(); } } } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index f439ccf7ef267c21d6ecdbad2c22c5dcd9a83866..4585877bdcedf7f6d3b32e4d40c1707f3ca96f7d 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1997,11 +1997,8 @@ mod tests { path::{Path, PathBuf}, time::Duration, }; - use theme::ThemeRegistry; - use util::{ - path, - rel_path::{RelPath, rel_path}, - }; + use theme::{ThemeRegistry, ThemeSettings}; + use util::{path, rel_path::rel_path}; use workspace::{ NewFile, OpenOptions, OpenVisible, SERIALIZATION_THROTTLE_TIME, SaveIntent, SplitDirection, WorkspaceHandle, @@ -4599,7 +4596,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.as_ref() == "One Dark" { + if theme.name == ThemeSettings::get(None, cx).active_theme.name { has_default_theme = true; } } diff --git a/crates/zlog_settings/src/zlog_settings.rs b/crates/zlog_settings/src/zlog_settings.rs index 1f695aa8ff5f8eb09d4cc0c2ae04282c469fb29c..cb564fcff3f024d37f0126c8870b436e449a0e1d 100644 --- a/crates/zlog_settings/src/zlog_settings.rs +++ b/crates/zlog_settings/src/zlog_settings.rs @@ -24,7 +24,7 @@ pub struct ZlogSettings { } impl Settings for ZlogSettings { - fn from_settings(content: &settings::SettingsContent) -> Self { + fn from_settings(content: &settings::SettingsContent, _: &mut App) -> Self { ZlogSettings { scopes: content.log.clone().unwrap(), }