Add a newtype wrapper around the global `ThemeRegistry` (#7025)

Marshall Bowers created

This PR adds a newtype wrapper around the global `ThemeRegistry`.

This allows us to limit where the `ThemeRegistry` can be accessed
directly via `cx.global` et al., without going through the dedicated
methods on the `ThemeRegistry`.

Release Notes:

- N/A

Change summary

Cargo.lock                   |  1 +
crates/theme/Cargo.toml      |  1 +
crates/theme/src/registry.rs | 21 ++++++++++++++++++---
crates/theme/src/theme.rs    |  2 +-
4 files changed, 21 insertions(+), 4 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -7920,6 +7920,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "color",
+ "derive_more",
  "fs",
  "gpui",
  "indexmap 1.9.3",

crates/theme/Cargo.toml 🔗

@@ -21,6 +21,7 @@ doctest = false
 
 [dependencies]
 anyhow.workspace = true
+derive_more.workspace = true
 fs = { path = "../fs" }
 gpui = { path = "../gpui" }
 indexmap = { version = "1.6.2", features = ["serde"] }

crates/theme/src/registry.rs 🔗

@@ -2,6 +2,7 @@ use std::collections::HashMap;
 use std::sync::Arc;
 
 use anyhow::{anyhow, Context, Result};
+use derive_more::{Deref, DerefMut};
 use gpui::{AppContext, AssetSource, HighlightStyle, SharedString};
 use refineable::Refineable;
 use util::ResultExt;
@@ -18,6 +19,20 @@ pub struct ThemeMeta {
     pub appearance: Appearance,
 }
 
+/// The global [`ThemeRegistry`].
+///
+/// This newtype exists for obtaining a unique [`TypeId`](std::any::TypeId) when
+/// inserting the [`ThemeRegistry`] into the context as a global.
+///
+/// This should not be exposed outside of this module.
+#[derive(Default, Deref, DerefMut)]
+struct GlobalThemeRegistry(ThemeRegistry);
+
+/// Initializes the theme registry.
+pub fn init(assets: Box<dyn AssetSource>, cx: &mut AppContext) {
+    cx.set_global(GlobalThemeRegistry(ThemeRegistry::new(assets)));
+}
+
 pub struct ThemeRegistry {
     assets: Box<dyn AssetSource>,
     themes: HashMap<SharedString, Arc<Theme>>,
@@ -26,19 +41,19 @@ pub struct ThemeRegistry {
 impl ThemeRegistry {
     /// Returns the global [`ThemeRegistry`].
     pub fn global(cx: &AppContext) -> &Self {
-        cx.global::<ThemeRegistry>()
+        cx.global::<GlobalThemeRegistry>()
     }
 
     /// Returns a mutable reference to the global [`ThemeRegistry`].
     pub fn global_mut(cx: &mut AppContext) -> &mut Self {
-        cx.global_mut::<ThemeRegistry>()
+        cx.global_mut::<GlobalThemeRegistry>()
     }
 
     /// Returns a mutable reference to the global [`ThemeRegistry`].
     ///
     /// Inserts a default [`ThemeRegistry`] if one does not yet exist.
     pub fn default_global(cx: &mut AppContext) -> &mut Self {
-        cx.default_global::<ThemeRegistry>()
+        cx.default_global::<GlobalThemeRegistry>()
     }
 
     pub fn new(assets: Box<dyn AssetSource>) -> Self {

crates/theme/src/theme.rs 🔗

@@ -60,7 +60,7 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut AppContext) {
         LoadThemes::JustBase => (Box::new(()) as Box<dyn AssetSource>, false),
         LoadThemes::All(assets) => (assets, true),
     };
-    cx.set_global(ThemeRegistry::new(assets));
+    registry::init(assets, cx);
 
     if load_user_themes {
         ThemeRegistry::global_mut(cx).load_user_themes();