@@ -255,16 +255,20 @@ impl ThemeRegistry {
continue;
};
- let Some(reader) = fs.open_sync(&theme_path).await.log_err() else {
- continue;
- };
+ self.load_user_theme(&theme_path, fs.clone())
+ .await
+ .log_err();
+ }
- let Some(theme) = serde_json_lenient::from_reader(reader).log_err() else {
- continue;
- };
+ Ok(())
+ }
- self.insert_user_theme_families([theme]);
- }
+ /// Loads the user theme from the specified path and adds it to the registry.
+ pub async fn load_user_theme(&self, theme_path: &Path, fs: Arc<dyn Fs>) -> Result<()> {
+ let reader = fs.open_sync(&theme_path).await?;
+ let theme = serde_json_lenient::from_reader(reader)?;
+
+ self.insert_user_theme_families([theme]);
Ok(())
}
@@ -11,6 +11,7 @@ use db::kvp::KEY_VALUE_STORE;
use editor::Editor;
use env_logger::Builder;
use fs::RealFs;
+use fsevent::StreamFlags;
use futures::StreamExt;
use gpui::{App, AppContext, AsyncAppContext, Context, SemanticVersion, Task};
use isahc::{prelude::Configurable, Request};
@@ -171,35 +172,8 @@ fn main() {
);
assistant::init(cx);
- // TODO: Should we be loading the themes in a different spot?
- cx.spawn({
- let fs = fs.clone();
- |cx| async move {
- if let Some(theme_registry) =
- cx.update(|cx| ThemeRegistry::global(cx).clone()).log_err()
- {
- if let Some(()) = theme_registry
- .load_user_themes(&paths::THEMES_DIR.clone(), fs)
- .await
- .log_err()
- {
- cx.update(|cx| {
- let mut theme_settings = ThemeSettings::get_global(cx).clone();
-
- if let Some(requested_theme) = theme_settings.requested_theme.clone() {
- if let Some(_theme) =
- theme_settings.switch_theme(&requested_theme, cx)
- {
- ThemeSettings::override_global(theme_settings, cx);
- }
- }
- })
- .log_err();
- }
- }
- }
- })
- .detach();
+ load_user_themes_in_background(fs.clone(), cx);
+ watch_themes(fs.clone(), cx);
cx.spawn(|_| watch_languages(fs.clone(), languages.clone()))
.detach();
@@ -903,6 +877,81 @@ fn load_embedded_fonts(cx: &AppContext) {
.unwrap();
}
+/// Spawns a background task to load the user themes from the themes directory.
+fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
+ cx.spawn({
+ let fs = fs.clone();
+ |cx| async move {
+ if let Some(theme_registry) =
+ cx.update(|cx| ThemeRegistry::global(cx).clone()).log_err()
+ {
+ if let Some(()) = theme_registry
+ .load_user_themes(&paths::THEMES_DIR.clone(), fs)
+ .await
+ .log_err()
+ {
+ cx.update(|cx| {
+ let mut theme_settings = ThemeSettings::get_global(cx).clone();
+
+ if let Some(requested_theme) = theme_settings.requested_theme.clone() {
+ if let Some(_theme) = theme_settings.switch_theme(&requested_theme, cx)
+ {
+ ThemeSettings::override_global(theme_settings, cx);
+ }
+ }
+ })
+ .log_err();
+ }
+ }
+ }
+ })
+ .detach();
+}
+
+/// Spawns a background task to watch the themes directory for changes.
+fn watch_themes(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
+ cx.spawn(|cx| async move {
+ let mut events = fs
+ .watch(&paths::THEMES_DIR.clone(), Duration::from_millis(100))
+ .await;
+
+ while let Some(events) = events.next().await {
+ for event in events {
+ if event.flags.contains(StreamFlags::ITEM_REMOVED) {
+ // Theme was removed, don't need to reload.
+ // We may want to remove the theme from the registry, in this case.
+ } else {
+ if let Some(theme_registry) =
+ cx.update(|cx| ThemeRegistry::global(cx).clone()).log_err()
+ {
+ if let Some(()) = theme_registry
+ .load_user_theme(&event.path, fs.clone())
+ .await
+ .log_err()
+ {
+ cx.update(|cx| {
+ let mut theme_settings = ThemeSettings::get_global(cx).clone();
+
+ if let Some(requested_theme) =
+ theme_settings.requested_theme.clone()
+ {
+ if let Some(_theme) =
+ theme_settings.switch_theme(&requested_theme, cx)
+ {
+ ThemeSettings::override_global(theme_settings, cx);
+ }
+ }
+ })
+ .log_err();
+ }
+ }
+ }
+ }
+ }
+ })
+ .detach()
+}
+
async fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>) {
let reload_debounce = Duration::from_millis(250);