diff --git a/Cargo.lock b/Cargo.lock index 270f2971a8..fe82fa06c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8089,7 +8089,7 @@ dependencies = [ "log", "rust-embed", "serde", - "settings", + "settings2", "simplelog", "smallvec", "strum", @@ -10753,6 +10753,7 @@ dependencies = [ "sum_tree", "tempdir", "text", + "theme2", "thiserror", "tiny_http", "toml 0.5.11", diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 92b0fbfe57..6072f47397 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -24,6 +24,7 @@ use rand::prelude::*; use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use settings2::Settings; use std::{ any::TypeId, collections::HashMap, @@ -78,7 +79,7 @@ pub struct SignOut; pub struct Reconnect; pub fn init_settings(cx: &mut AppContext) { - settings2::register::(cx); + TelemetrySettings::register(cx); } pub fn init(client: &Arc, cx: &mut AppContext) { @@ -371,7 +372,7 @@ pub struct TelemetrySettingsContent { pub metrics: Option, } -impl settings2::Setting for TelemetrySettings { +impl settings2::Settings for TelemetrySettings { const KEY: Option<&'static str> = Some("telemetry"); type FileContent = TelemetrySettingsContent; diff --git a/crates/client2/src/telemetry.rs b/crates/client2/src/telemetry.rs index acb129ea33..1b64e94107 100644 --- a/crates/client2/src/telemetry.rs +++ b/crates/client2/src/telemetry.rs @@ -3,6 +3,7 @@ use gpui2::{serde_json, AppContext, AppMetadata, Executor, Task}; use lazy_static::lazy_static; use parking_lot::Mutex; use serde::Serialize; +use settings2::Settings; use std::{env, io::Write, mem, path::PathBuf, sync::Arc, time::Duration}; use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt}; use tempfile::NamedTempFile; @@ -191,7 +192,7 @@ impl Telemetry { }; let telemetry_settings = if let Ok(telemetry_settings) = - cx.update(|cx| *settings2::get::(cx)) + cx.update(|cx| *TelemetrySettings::get_global(cx)) { telemetry_settings } else { @@ -211,7 +212,7 @@ impl Telemetry { is_staff: bool, cx: &AppContext, ) { - if !settings2::get::(cx).metrics { + if !TelemetrySettings::get_global(cx).metrics { return; } diff --git a/crates/language2/src/language_settings.rs b/crates/language2/src/language_settings.rs index 26af176353..4816e506db 100644 --- a/crates/language2/src/language_settings.rs +++ b/crates/language2/src/language_settings.rs @@ -8,10 +8,11 @@ use schemars::{ JsonSchema, }; use serde::{Deserialize, Serialize}; +use settings2::Settings; use std::{num::NonZeroU32, path::Path, sync::Arc}; pub fn init(cx: &mut AppContext) { - settings2::register::(cx); + AllLanguageSettings::register(cx); } pub fn language_settings<'a>( @@ -28,7 +29,7 @@ pub fn all_language_settings<'a>( cx: &'a AppContext, ) -> &'a AllLanguageSettings { let location = file.map(|f| (f.worktree_id(), f.path().as_ref())); - settings2::get_local(location, cx) + AllLanguageSettings::get(location, cx) } #[derive(Debug, Clone)] @@ -254,7 +255,7 @@ impl InlayHintKind { } } -impl settings2::Setting for AllLanguageSettings { +impl settings2::Settings for AllLanguageSettings { const KEY: Option<&'static str> = None; type FileContent = AllLanguageSettingsContent; diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 4b8f061a4d..93081c5e31 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -58,7 +58,7 @@ use project_settings::{LspSettings, ProjectSettings}; use rand::prelude::*; use search::SearchQuery; use serde::Serialize; -use settings2::SettingsStore; +use settings2::{SettingsStore, Settings}; use sha2::{Digest, Sha256}; use similar::{ChangeTag, TextDiff}; use smol::channel::{Receiver, Sender}; @@ -562,7 +562,7 @@ impl SearchMatchCandidate { impl Project { pub fn init_settings(cx: &mut AppContext) { - settings2::register::(cx); + ProjectSettings::register(cx); } pub fn init(client: &Arc, cx: &mut AppContext) { @@ -674,7 +674,7 @@ impl Project { }, copilot_lsp_subscription, copilot_log_subscription: None, - current_lsp_settings: settings2::get::(cx).lsp.clone(), + current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(), node: Some(node), prettier_instances: HashMap::default(), } @@ -775,7 +775,7 @@ impl Project { }, copilot_lsp_subscription, copilot_log_subscription: None, - current_lsp_settings: settings2::get::(cx).lsp.clone(), + current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(), node: None, prettier_instances: HashMap::default(), }; @@ -914,7 +914,7 @@ impl Project { let mut language_servers_to_restart = Vec::new(); let languages = self.languages.to_vec(); - let new_lsp_settings = settings2::get::(cx).lsp.clone(); + let new_lsp_settings = ProjectSettings::get_global(cx).lsp.clone(); let current_lsp_settings = &self.current_lsp_settings; for (worktree_id, started_lsp_name) in self.language_server_ids.keys() { let language = languages.iter().find_map(|l| { @@ -2493,7 +2493,7 @@ impl Project { self.buffers_needing_diff.insert(buffer.downgrade()); let first_insertion = self.buffers_needing_diff.len() == 1; - let settings = settings2::get::(cx); + let settings = ProjectSettings::get_global(cx); let delay = if let Some(delay) = settings.git.gutter_debounce { delay } else { @@ -2789,7 +2789,7 @@ impl Project { None => return, }; - let project_settings = settings2::get::(cx); + let project_settings = ProjectSettings::get_global(cx); let lsp = project_settings.lsp.get(&adapter.name.0); let override_options = lsp.map(|s| s.initialization_options.clone()).flatten(); diff --git a/crates/project2/src/project_settings.rs b/crates/project2/src/project_settings.rs index c739d96a6f..b85226f7cc 100644 --- a/crates/project2/src/project_settings.rs +++ b/crates/project2/src/project_settings.rs @@ -2,7 +2,7 @@ use collections::HashMap; use gpui2::AppContext; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use settings2::Setting; +use settings2::Settings; use std::sync::Arc; #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] @@ -33,7 +33,7 @@ pub struct LspSettings { pub initialization_options: Option, } -impl Setting for ProjectSettings { +impl Settings for ProjectSettings { const KEY: Option<&'static str> = None; type FileContent = Self; diff --git a/crates/project2/src/terminals.rs b/crates/project2/src/terminals.rs index 6945433fb9..a0f59c4bc1 100644 --- a/crates/project2/src/terminals.rs +++ b/crates/project2/src/terminals.rs @@ -1,5 +1,6 @@ use crate::Project; use gpui2::{AnyWindowHandle, Context, Handle, ModelContext, WeakHandle}; +use settings2::Settings; use std::path::{Path, PathBuf}; use terminal2::{ terminal_settings::{self, TerminalSettings, VenvSettingsContent}, @@ -25,7 +26,7 @@ impl Project { "creating terminals as a guest is not supported yet" )); } else { - let settings = settings2::get::(cx); + let settings = TerminalSettings::get_global(cx); let python_settings = settings.detect_venv.clone(); let shell = settings.shell.clone(); diff --git a/crates/settings2/src/settings2.rs b/crates/settings2/src/settings2.rs index 8c3587d942..a8fa37c77e 100644 --- a/crates/settings2/src/settings2.rs +++ b/crates/settings2/src/settings2.rs @@ -8,7 +8,7 @@ use util::asset_str; pub use keymap_file::KeymapFile; pub use settings_file::*; -pub use settings_store::{Setting, SettingsJsonSchemaParams, SettingsStore}; +pub use settings_store::{Settings, SettingsJsonSchemaParams, SettingsStore}; #[derive(RustEmbed)] #[folder = "../../assets"] diff --git a/crates/settings2/src/settings_file.rs b/crates/settings2/src/settings_file.rs index 56b75cc26d..eff236d375 100644 --- a/crates/settings2/src/settings_file.rs +++ b/crates/settings2/src/settings_file.rs @@ -1,31 +1,11 @@ -use crate::{settings_store::SettingsStore, Setting}; +use crate::{settings_store::SettingsStore, Settings}; use anyhow::Result; use fs::Fs; use futures::{channel::mpsc, StreamExt}; use gpui2::{AppContext, Executor}; -use std::{ - io::ErrorKind, - path::{Path, PathBuf}, - str, - sync::Arc, - time::Duration, -}; +use std::{io::ErrorKind, path::PathBuf, str, sync::Arc, time::Duration}; use util::{paths, ResultExt}; -pub fn register(cx: &mut AppContext) { - cx.update_global(|store: &mut SettingsStore, cx| { - store.register_setting::(cx); - }); -} - -pub fn get<'a, T: Setting>(cx: &'a AppContext) -> &'a T { - cx.global::().get(None) -} - -pub fn get_local<'a, T: Setting>(location: Option<(usize, &Path)>, cx: &'a AppContext) -> &'a T { - cx.global::().get(location) -} - pub const EMPTY_THEME_NAME: &'static str = "empty-theme"; #[cfg(any(test, feature = "test-support"))] @@ -119,7 +99,7 @@ async fn load_settings(fs: &Arc) -> Result { } } -pub fn update_settings_file( +pub fn update_settings_file( fs: Arc, cx: &mut AppContext, update: impl 'static + Send + FnOnce(&mut T::FileContent), diff --git a/crates/settings2/src/settings_store.rs b/crates/settings2/src/settings_store.rs index bd3c96de69..91dc104c99 100644 --- a/crates/settings2/src/settings_store.rs +++ b/crates/settings2/src/settings_store.rs @@ -18,7 +18,7 @@ use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _}; /// A value that can be defined as a user setting. /// /// Settings can be loaded from a combination of multiple JSON files. -pub trait Setting: 'static + Send + Sync { +pub trait Settings: 'static + Send + Sync { /// The name of a key within the JSON file from which this setting should /// be deserialized. If this is `None`, then the setting will be deserialized /// from the root object. @@ -76,6 +76,36 @@ pub trait Setting: 'static + Send + Sync { fn missing_default() -> anyhow::Error { anyhow::anyhow!("missing default") } + + fn register(cx: &mut AppContext) + where + Self: Sized, + { + cx.update_global(|store: &mut SettingsStore, cx| { + store.register_setting::(cx); + }); + } + + fn get<'a>(path: Option<(usize, &Path)>, cx: &'a AppContext) -> &'a Self + where + Self: Sized, + { + cx.global::().get(path) + } + + fn get_global<'a>(cx: &'a AppContext) -> &'a Self + where + Self: Sized, + { + cx.global::().get(None) + } + + fn override_global<'a>(settings: Self, cx: &'a mut AppContext) + where + Self: Sized, + { + cx.global_mut::().override_global(settings) + } } pub struct SettingsJsonSchemaParams<'a> { @@ -138,7 +168,7 @@ struct DeserializedSetting(Box); impl SettingsStore { /// Add a new type of setting to the store. - pub fn register_setting(&mut self, cx: &mut AppContext) { + pub fn register_setting(&mut self, cx: &mut AppContext) { let setting_type_id = TypeId::of::(); let entry = self.setting_values.entry(setting_type_id); if matches!(entry, hash_map::Entry::Occupied(_)) { @@ -177,7 +207,7 @@ impl SettingsStore { /// /// Panics if the given setting type has not been registered, or if there is no /// value for this setting. - pub fn get(&self, path: Option<(usize, &Path)>) -> &T { + pub fn get(&self, path: Option<(usize, &Path)>) -> &T { self.setting_values .get(&TypeId::of::()) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::())) @@ -189,7 +219,7 @@ impl SettingsStore { /// Override the global value for a setting. /// /// The given value will be overwritten if the user settings file changes. - pub fn override_global(&mut self, value: T) { + pub fn override_global(&mut self, value: T) { self.setting_values .get_mut(&TypeId::of::()) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::())) @@ -218,7 +248,7 @@ impl SettingsStore { /// This is only for tests. Normally, settings are only loaded from /// JSON files. #[cfg(any(test, feature = "test-support"))] - pub fn update_user_settings( + pub fn update_user_settings( &mut self, cx: &mut AppContext, update: impl FnOnce(&mut T::FileContent), @@ -230,7 +260,7 @@ impl SettingsStore { /// Update the value of a setting in a JSON file, returning the new text /// for that JSON file. - pub fn new_text_for_update( + pub fn new_text_for_update( &self, old_text: String, update: impl FnOnce(&mut T::FileContent), @@ -245,7 +275,7 @@ impl SettingsStore { /// Update the value of a setting in a JSON file, returning a list /// of edits to apply to the JSON file. - pub fn edits_for_update( + pub fn edits_for_update( &self, text: &str, update: impl FnOnce(&mut T::FileContent), @@ -287,7 +317,7 @@ impl SettingsStore { } /// Configure the tab sized when updating JSON files. - pub fn set_json_tab_size_callback( + pub fn set_json_tab_size_callback( &mut self, get_tab_size: fn(&T) -> Option, ) { @@ -544,7 +574,7 @@ impl Debug for SettingsStore { } } -impl AnySettingValue for SettingValue { +impl AnySettingValue for SettingValue { fn key(&self) -> Option<&'static str> { T::KEY } diff --git a/crates/storybook2/Cargo.toml b/crates/storybook2/Cargo.toml index 76c814cd77..0f335ae984 100644 --- a/crates/storybook2/Cargo.toml +++ b/crates/storybook2/Cargo.toml @@ -19,7 +19,7 @@ itertools = "0.11.0" log.workspace = true rust-embed.workspace = true serde.workspace = true -settings = { path = "../settings" } +settings2 = { path = "../settings2" } simplelog = "0.9" smallvec.workspace = true strum = { version = "0.25.0", features = ["derive"] } diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 7f7cbfa150..c6d71f079d 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -14,11 +14,11 @@ use gpui2::{ WindowOptions, }; use log::LevelFilter; +use settings2::{default_settings, Settings, SettingsStore}; use simplelog::SimpleLogger; use story_selector::ComponentStory; -use theme2::ThemeRegistry; +use theme2::{ThemeRegistry, ThemeSettings}; use ui::{prelude::*, themed}; -use util::ResultExt; use crate::assets::Assets; use crate::story_selector::StorySelector; @@ -56,14 +56,22 @@ fn main() { gpui2::App::production(asset_source).run(move |cx| { load_embedded_fonts(cx).unwrap(); + let mut store = SettingsStore::default(); + store + .set_default_settings(default_settings().as_ref(), cx) + .unwrap(); + cx.set_global(store); + + theme2::init(cx); + let selector = story_selector.unwrap_or(StorySelector::Component(ComponentStory::Workspace)); - let theme_registry = cx.default_global::(); + let theme_registry = cx.global::(); - if let Some(new_theme) = theme_registry.get(&theme_name).log_err() { - cx.set_global(new_theme); - } + let mut theme_settings = ThemeSettings::get_global(cx).clone(); + theme_settings.active_theme = theme_registry.get(&theme_name).unwrap(); + ThemeSettings::override_global(theme_settings, cx); cx.set_global(theme.clone()); ui::settings::init(cx); diff --git a/crates/terminal2/src/terminal2.rs b/crates/terminal2/src/terminal2.rs index 4496e3df23..5cf73576bc 100644 --- a/crates/terminal2/src/terminal2.rs +++ b/crates/terminal2/src/terminal2.rs @@ -33,6 +33,7 @@ use mappings::mouse::{ use procinfo::LocalProcessInfo; use serde::{Deserialize, Serialize}; +use settings2::Settings; use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings}; use util::truncate_and_trailoff; @@ -126,7 +127,7 @@ impl EventListener for ZedListener { } pub fn init(cx: &mut AppContext) { - settings2::register::(cx); + TerminalSettings::register(cx); } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] @@ -1190,7 +1191,7 @@ impl Terminal { origin: Point, cx: &mut MainThread>, ) { - let setting = settings2::get::(cx); + let setting = TerminalSettings::get_global(cx); let position = e.position - origin; if self.mouse_mode(e.modifiers.shift) { diff --git a/crates/terminal2/src/terminal_settings.rs b/crates/terminal2/src/terminal_settings.rs index 208c480f10..1be9ac5000 100644 --- a/crates/terminal2/src/terminal_settings.rs +++ b/crates/terminal2/src/terminal_settings.rs @@ -98,7 +98,7 @@ impl TerminalSettings { // } } -impl settings2::Setting for TerminalSettings { +impl settings2::Settings for TerminalSettings { const KEY: Option<&'static str> = Some("terminal"); type FileContent = TerminalSettingsContent; diff --git a/crates/theme2/src/settings.rs b/crates/theme2/src/settings.rs index b658465ec5..379b01dd4b 100644 --- a/crates/theme2/src/settings.rs +++ b/crates/theme2/src/settings.rs @@ -8,7 +8,7 @@ use schemars::{ }; use serde::{Deserialize, Serialize}; use serde_json::Value; -use settings2::SettingsJsonSchemaParams; +use settings2::{Settings, SettingsJsonSchemaParams}; use std::sync::Arc; use util::ResultExt as _; @@ -20,7 +20,7 @@ pub struct ThemeSettings { pub buffer_font: Font, pub buffer_font_size: Pixels, pub buffer_line_height: BufferLineHeight, - pub theme: Arc, + pub active_theme: Arc, } #[derive(Default)] @@ -75,7 +75,7 @@ impl ThemeSettings { pub fn adjusted_font_size(size: Pixels, cx: &mut AppContext) -> Pixels { if let Some(adjusted_size) = cx.default_global::().0 { - let buffer_font_size = settings2::get::(cx).buffer_font_size; + let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size; let delta = adjusted_size - buffer_font_size; size + delta } else { @@ -85,7 +85,7 @@ pub fn adjusted_font_size(size: Pixels, cx: &mut AppContext) -> Pixels { } pub fn adjust_font_size(cx: &mut AppContext, f: fn(&mut Pixels)) { - let buffer_font_size = settings2::get::(cx).buffer_font_size; + let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size; let adjusted_size = cx .default_global::() .0 @@ -102,7 +102,7 @@ pub fn reset_font_size(cx: &mut AppContext) { } } -impl settings2::Setting for ThemeSettings { +impl settings2::Settings for ThemeSettings { const KEY: Option<&'static str> = None; type FileContent = ThemeSettingsContent; @@ -123,7 +123,7 @@ impl settings2::Setting for ThemeSettings { }, buffer_font_size: defaults.buffer_font_size.unwrap().into(), buffer_line_height: defaults.buffer_line_height.unwrap(), - theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(), + active_theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(), }; for value in user_values.into_iter().copied().cloned() { @@ -136,11 +136,14 @@ impl settings2::Setting for ThemeSettings { if let Some(value) = &value.theme { if let Some(theme) = themes.get(value).log_err() { - this.theme = theme; + this.active_theme = theme; } } - merge(&mut this.buffer_font_size, value.buffer_font_size.map(Into::into)); + merge( + &mut this.buffer_font_size, + value.buffer_font_size.map(Into::into), + ); merge(&mut this.buffer_line_height, value.buffer_line_height); } diff --git a/crates/theme2/src/theme2.rs b/crates/theme2/src/theme2.rs index e02a73c528..b2f116deb9 100644 --- a/crates/theme2/src/theme2.rs +++ b/crates/theme2/src/theme2.rs @@ -5,9 +5,19 @@ mod themes; pub use registry::*; pub use settings::*; -use gpui2::{HighlightStyle, Hsla, SharedString}; +use gpui2::{AppContext, HighlightStyle, Hsla, SharedString}; +use settings2::Settings; use std::sync::Arc; +pub fn init(cx: &mut AppContext) { + cx.set_global(ThemeRegistry::default()); + ThemeSettings::register(cx); +} + +pub fn active_theme<'a>(cx: &'a AppContext) -> &'a Arc { + &ThemeSettings::get_global(cx).active_theme +} + pub struct Theme { pub metadata: ThemeMetadata, @@ -102,14 +112,3 @@ pub struct ThemeMetadata { pub struct Editor { pub syntax: Arc, } - -// #[derive(Default)] -// pub struct SyntaxTheme { -// pub highlights: Vec<(String, HighlightStyle)>, -// } - -// impl SyntaxTheme { -// pub fn new(highlights: Vec<(String, HighlightStyle)>) -> Self { -// Self { highlights } -// } -// } diff --git a/crates/ui2/src/theme.rs b/crates/ui2/src/theme.rs index e772fb2061..00f20f5967 100644 --- a/crates/ui2/src/theme.rs +++ b/crates/ui2/src/theme.rs @@ -219,5 +219,5 @@ pub fn old_theme(cx: &WindowContext) -> Arc { } pub fn theme(cx: &WindowContext) -> Arc { - cx.global::>().clone() + theme2::active_theme(cx).clone() } diff --git a/crates/zed2/Cargo.toml b/crates/zed2/Cargo.toml index 19da608b78..06804253b8 100644 --- a/crates/zed2/Cargo.toml +++ b/crates/zed2/Cargo.toml @@ -64,7 +64,7 @@ sum_tree = { path = "../sum_tree" } shellexpand = "2.1.0" text = { path = "../text" } # terminal_view = { path = "../terminal_view" } -# theme = { path = "../theme" } +theme2 = { path = "../theme2" } # theme_selector = { path = "../theme_selector" } util = { path = "../util" } # semantic_index = { path = "../semantic_index" } diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 14d91c0f1e..fff3b5eae1 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -19,7 +19,9 @@ use log::LevelFilter; use node_runtime::RealNodeRuntime; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; -use settings2::{default_settings, handle_settings_file_changes, watch_config_file, SettingsStore}; +use settings2::{ + default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore, +}; use simplelog::ConfigBuilder; use smol::process::Command; use std::{ @@ -123,7 +125,7 @@ fn main() { // cx.set_global(client.clone()); - // theme::init(Assets, cx); + theme2::init(cx); // context_menu::init(cx); // project::Project::init(&client, cx); // client::init(&client, cx); @@ -506,7 +508,7 @@ fn init_panic_hook(app: &App, installation_id: Option, session_id: Strin } fn upload_previous_panics(http: Arc, cx: &mut AppContext) { - let telemetry_settings = *settings2::get::(cx); + let telemetry_settings = *client2::TelemetrySettings::get_global(cx); cx.executor() .spawn(async move {