Added experimental themes flag

Mikayla Maki created

Change summary

.gitignore                                        |  3 +
crates/collab/src/integration_tests.rs            |  2 
crates/settings/src/settings.rs                   |  4 +
crates/theme/src/theme_registry.rs                | 22 +++++++++----
crates/theme_selector/src/theme_selector.rs       | 16 ++++++---
crates/workspace/src/workspace.rs                 |  2 
crates/zed/src/main.rs                            | 12 ++++---
crates/zed/src/settings_file.rs                   |  2 
crates/zed/src/zed.rs                             | 12 +++++-
styles/src/buildThemes.ts                         |  5 ++
styles/src/themes.ts                              |  6 +++
styles/src/themes/experiments/cave-experiments.ts | 28 +++++++++++++++++
12 files changed, 87 insertions(+), 27 deletions(-)

Detailed changes

.gitignore 🔗

@@ -7,4 +7,5 @@
 /crates/collab/static/styles.css
 /vendor/bin
 /assets/themes/*.json
-/assets/themes/internal/*.json
+/assets/themes/internal/*.json
+/assets/themes/experiments/*.json

crates/collab/src/integration_tests.rs 🔗

@@ -5220,7 +5220,7 @@ impl TestServer {
             user_store: user_store.clone(),
             project_store: project_store.clone(),
             languages: Arc::new(LanguageRegistry::new(Task::ready(()))),
-            themes: ThemeRegistry::new((), cx.font_cache(), false),
+            themes: ThemeRegistry::new((), cx.font_cache()),
             fs: fs.clone(),
             build_window_options: Default::default,
             initialize_workspace: |_, _, _| unimplemented!(),

crates/settings/src/settings.rs 🔗

@@ -41,7 +41,9 @@ pub struct Settings {
 }
 
 #[derive(Copy, Clone, Debug, Default, Deserialize, JsonSchema)]
-pub struct FeatureFlags {}
+pub struct FeatureFlags {
+    pub experimental_themes: bool,
+}
 
 impl FeatureFlags {
     pub fn keymap_files(&self) -> Vec<&'static str> {

crates/theme/src/theme_registry.rs 🔗

@@ -10,26 +10,34 @@ pub struct ThemeRegistry {
     themes: Mutex<HashMap<String, Arc<Theme>>>,
     theme_data: Mutex<HashMap<String, Arc<Value>>>,
     font_cache: Arc<FontCache>,
-    internal: bool,
 }
 
 impl ThemeRegistry {
-    pub fn new(source: impl AssetSource, font_cache: Arc<FontCache>, internal: bool) -> Arc<Self> {
+    pub fn new(source: impl AssetSource, font_cache: Arc<FontCache>) -> Arc<Self> {
         Arc::new(Self {
             assets: Box::new(source),
             themes: Default::default(),
             theme_data: Default::default(),
             font_cache,
-            internal,
         })
     }
 
-    pub fn list(&self) -> impl Iterator<Item = ThemeMeta> + '_ {
+    pub fn list(&self, internal: bool, experiments: bool) -> impl Iterator<Item = ThemeMeta> + '_ {
         let mut dirs = self.assets.list("themes/");
 
-        if self.internal {
-            dirs.extend(self.assets.list("themes/internal/"))
-        };
+        if !internal {
+            dirs = dirs
+                .into_iter()
+                .filter(|path| !path.starts_with("themes/internal"))
+                .collect()
+        }
+
+        if !experiments {
+            dirs = dirs
+                .into_iter()
+                .filter(|path| !path.starts_with("themes/experiments"))
+                .collect()
+        }
 
         dirs.into_iter().filter_map(|path| {
             let filename = path.strip_prefix("themes/")?;

crates/theme_selector/src/theme_selector.rs 🔗

@@ -39,13 +39,17 @@ impl ThemeSelector {
     fn new(registry: Arc<ThemeRegistry>, cx: &mut ViewContext<Self>) -> Self {
         let handle = cx.weak_handle();
         let picker = cx.add_view(|cx| Picker::new(handle, cx));
-        let original_theme = cx.global::<Settings>().theme.clone();
-        let mut theme_names = registry.list().collect::<Vec<_>>();
+        let settings = cx.global::<Settings>();
+        let original_theme = settings.theme.clone();
+
+        let mut theme_names = registry
+            .list(settings.internal, settings.experiments.experimental_themes)
+            .collect::<Vec<_>>();
         theme_names.sort_unstable_by(|a, b| {
-            a.is_light.cmp(&b.is_light).reverse()
-            // a.ends_with("dark")
-            //     .cmp(&b.ends_with("dark"))
-            //     .then_with(|| a.cmp(b))
+            a.is_light
+                .cmp(&b.is_light)
+                .reverse()
+                .then(a.name.cmp(&b.name))
         });
         let matches = theme_names
             .iter()

crates/workspace/src/workspace.rs 🔗

@@ -860,7 +860,7 @@ impl AppState {
         let client = Client::new(http_client.clone());
         let project_store = cx.add_model(|_| ProjectStore::new(project::Db::open_fake()));
         let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
-        let themes = ThemeRegistry::new((), cx.font_cache().clone(), false);
+        let themes = ThemeRegistry::new((), cx.font_cache().clone());
         Arc::new(Self {
             client,
             themes,

crates/zed/src/main.rs 🔗

@@ -70,7 +70,6 @@ fn main() {
                 .await
                 .map(|github| {
                     &github == "as-cii"
-                        || &github == "ForLoveOfCats"
                         || &github == "ForLoveOfCats"
                         || &github == "gibusu"
                         || &github == "iamnbutler"
@@ -85,7 +84,7 @@ fn main() {
         }
     });
 
-    let themes = ThemeRegistry::new(Assets, app.font_cache(), internal);
+    let themes = ThemeRegistry::new(Assets, app.font_cache());
     let default_settings = Settings::defaults(Assets, &app.font_cache(), &themes);
 
     let config_files = load_config_files(&app, fs.clone());
@@ -127,9 +126,12 @@ fn main() {
                 let fs = fs.clone();
                 async move {
                     while let Some(user) = current_user.recv().await {
-                        let user_name = user
-                            .map(|user| user.github_login.clone())
-                            .unwrap_or_else(|| String::new());
+                        // When the user logs out, `user` is None.
+                        if user.is_none() {
+                            continue;
+                        }
+
+                        let user_name = user.unwrap().github_login.clone();
 
                         fs.save(
                             &*zed::paths::LAST_USERNAME,

crates/zed/src/settings_file.rs 🔗

@@ -153,7 +153,7 @@ mod tests {
             watch_settings_file(
                 default_settings.clone(),
                 source,
-                ThemeRegistry::new((), font_cache, false),
+                ThemeRegistry::new((), font_cache),
                 false,
                 cx,
             )

crates/zed/src/zed.rs 🔗

@@ -244,7 +244,13 @@ pub fn initialize_workspace(
 
     cx.emit(workspace::Event::PaneAdded(workspace.active_pane().clone()));
 
-    let theme_names = app_state.themes.list().map(|meta| meta.name).collect();
+    let settings = cx.global::<Settings>();
+
+    let theme_names = app_state
+        .themes
+        .list(settings.internal, settings.experiments.experimental_themes)
+        .map(|meta| meta.name)
+        .collect();
     let language_names = &languages::LANGUAGE_NAMES;
 
     workspace.project().update(cx, |project, cx| {
@@ -1664,11 +1670,11 @@ mod tests {
                     .into(),
             ])
             .unwrap();
-        let themes = ThemeRegistry::new(Assets, cx.font_cache().clone(), false);
+        let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
         let settings = Settings::defaults(Assets, cx.font_cache(), &themes);
 
         let mut has_default_theme = false;
-        for theme_name in themes.list().map(|meta| meta.name) {
+        for theme_name in themes.list(false, false).map(|meta| meta.name) {
             let theme = themes.get(&theme_name).unwrap();
             if theme.meta.name == settings.theme.meta.name {
                 has_default_theme = true;

styles/src/buildThemes.ts 🔗

@@ -2,12 +2,13 @@ import * as fs from "fs";
 import * as path from "path";
 import { tmpdir } from "os";
 import app from "./styleTree/app";
-import themes, { internalThemes } from "./themes";
+import themes, { internalThemes, experimentalThemes } from "./themes";
 import snakeCase from "./utils/snakeCase";
 import Theme from "./themes/common/theme";
 
 const themeDirectory = `${__dirname}/../../assets/themes`;
 const internalDirectory = `${themeDirectory}/internal`;
+const experimentsDirectory = `${themeDirectory}/experiments`;
 const tempDirectory = fs.mkdtempSync(path.join(tmpdir(), "build-themes"));
 
 // Clear existing themes
@@ -24,6 +25,7 @@ function clearThemes(themeDirectory: string) {
 
 clearThemes(themeDirectory);
 clearThemes(internalDirectory);
+clearThemes(experimentsDirectory);
 
 function writeThemes(themes: Theme[], outputDirectory: string) {
   for (let theme of themes) {
@@ -40,3 +42,4 @@ function writeThemes(themes: Theme[], outputDirectory: string) {
 // Write new themes to theme directory
 writeThemes(themes, themeDirectory);
 writeThemes(internalThemes, internalDirectory);
+writeThemes(experimentalThemes, experimentsDirectory);

styles/src/themes.ts 🔗

@@ -8,6 +8,10 @@ export default themes;
 const internalThemes: Theme[] = [];
 export { internalThemes }
 
+const experimentalThemes: Theme[] = [];
+export { experimentalThemes }
+
+
 function fillThemes(themesPath: string, themes: Theme[]) {
   for (const fileName of fs.readdirSync(themesPath)) {
     if (fileName == "template.ts") continue;
@@ -23,3 +27,5 @@ function fillThemes(themesPath: string, themes: Theme[]) {
 
 fillThemes(path.resolve(`${__dirname}/themes`), themes)
 fillThemes(path.resolve(`${__dirname}/themes/internal`), internalThemes)
+fillThemes(path.resolve(`${__dirname}/themes/experiments`), experimentalThemes)
+

styles/src/themes/experiments/cave-experiments.ts 🔗

@@ -0,0 +1,28 @@
+import chroma from "chroma-js";
+import { colorRamp, createTheme } from "../common/base16";
+
+const name = "cave-experiments";
+
+const ramps = {
+  neutral: chroma.scale([
+    "#555555",
+    "#555555",
+    "#555555",
+    "#555555",
+    "#555555",
+    "#555555",
+    "#555555",
+    "#555555",
+  ]),
+  red: colorRamp(chroma("#555555")),
+  orange: colorRamp(chroma("#555555")),
+  yellow: colorRamp(chroma("#555555")),
+  green: colorRamp(chroma("#555555")),
+  cyan: colorRamp(chroma("#555555")),
+  blue: colorRamp(chroma("#555555")),
+  violet: colorRamp(chroma("#555555")),
+  magenta: colorRamp(chroma("#555555")),
+};
+
+export const dark = createTheme(`${name}-dark`, false, ramps);
+export const light = createTheme(`${name}-light`, true, ramps);