Merge pull request #1551 from zed-industries/settings-changes

Mikayla Maki created

Basic feature flag implementation

Change summary

assets/keymaps/default.json        |  7 -------
crates/settings/src/keymap_file.rs | 14 ++++++++------
crates/settings/src/settings.rs    | 12 +++++++++++-
crates/terminal/src/terminal.rs    |  5 ++++-
crates/zed/src/main.rs             |  9 ++++++---
5 files changed, 29 insertions(+), 18 deletions(-)

Detailed changes

assets/keymaps/default.json 🔗

@@ -425,12 +425,5 @@
             "cmd-v": "terminal::Paste",
             "cmd-k": "terminal::Clear"
         }
-    },
-    {
-        "context": "ModalTerminal",
-        "bindings": {
-            "ctrl-cmd-space": "terminal::ShowCharacterPalette",
-            "shift-escape": "terminal::DeployModal"
-        }
     }
 ]

crates/settings/src/keymap_file.rs 🔗

@@ -10,6 +10,7 @@ use schemars::{
 };
 use serde::Deserialize;
 use serde_json::{value::RawValue, Value};
+use util::ResultExt;
 
 #[derive(Deserialize, Default, Clone, JsonSchema)]
 #[serde(transparent)]
@@ -56,26 +57,27 @@ impl KeymapFileContent {
         for KeymapBlock { context, bindings } in self.0 {
             let bindings = bindings
                 .into_iter()
-                .map(|(keystroke, action)| {
+                .filter_map(|(keystroke, action)| {
                     let action = action.0.get();
 
                     // This is a workaround for a limitation in serde: serde-rs/json#497
                     // We want to deserialize the action data as a `RawValue` so that we can
                     // deserialize the action itself dynamically directly from the JSON
                     // string. But `RawValue` currently does not work inside of an untagged enum.
-                    let action = if action.starts_with('[') {
-                        let ActionWithData(name, data) = serde_json::from_str(action)?;
+                    if action.starts_with('[') {
+                        let ActionWithData(name, data) = serde_json::from_str(action).log_err()?;
                         cx.deserialize_action(&name, Some(data.get()))
                     } else {
-                        let name = serde_json::from_str(action)?;
+                        let name = serde_json::from_str(action).log_err()?;
                         cx.deserialize_action(name, None)
                     }
                     .with_context(|| {
                         format!(
                             "invalid binding value for keystroke {keystroke}, context {context:?}"
                         )
-                    })?;
-                    Binding::load(&keystroke, action, context.as_deref())
+                    })
+                    .log_err()
+                    .map(|action| Binding::load(&keystroke, action, context.as_deref()))
                 })
                 .collect::<Result<Vec<_>>>()?;
 

crates/settings/src/settings.rs 🔗

@@ -20,6 +20,7 @@ pub use keymap_file::{keymap_file_json_schema, KeymapFileContent};
 
 #[derive(Clone)]
 pub struct Settings {
+    pub experiments: FeatureFlags,
     pub projects_online_by_default: bool,
     pub buffer_font_family: FamilyId,
     pub default_buffer_font_size: f32,
@@ -38,6 +39,11 @@ pub struct Settings {
     pub theme: Arc<Theme>,
 }
 
+#[derive(Copy, Clone, Debug, Default, Deserialize, JsonSchema)]
+pub struct FeatureFlags {
+    pub modal_terminal: bool,
+}
+
 #[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
 pub struct EditorSettings {
     pub tab_size: Option<NonZeroU32>,
@@ -139,6 +145,8 @@ pub enum WorkingDirectory {
 
 #[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
 pub struct SettingsFileContent {
+    #[serde(default)]
+    pub experiments: Option<FeatureFlags>,
     #[serde(default)]
     pub projects_online_by_default: Option<bool>,
     #[serde(default)]
@@ -189,6 +197,7 @@ impl Settings {
         .unwrap();
 
         Self {
+            experiments: FeatureFlags::default(),
             buffer_font_family: font_cache
                 .load_family(&[defaults.buffer_font_family.as_ref().unwrap()])
                 .unwrap(),
@@ -247,7 +256,7 @@ impl Settings {
         );
         merge(&mut self.vim_mode, data.vim_mode);
         merge(&mut self.autosave, data.autosave);
-
+        merge(&mut self.experiments, data.experiments);
         // Ensure terminal font is loaded, so we can request it in terminal_element layout
         if let Some(terminal_font) = &data.terminal.font_family {
             font_cache.load_family(&[terminal_font]).log_err();
@@ -308,6 +317,7 @@ impl Settings {
     #[cfg(any(test, feature = "test-support"))]
     pub fn test(cx: &gpui::AppContext) -> Settings {
         Settings {
+            experiments: FeatureFlags::default(),
             buffer_font_family: cx.font_cache().load_family(&["Monaco"]).unwrap(),
             buffer_font_size: 14.,
             default_buffer_font_size: 14.,

crates/terminal/src/terminal.rs 🔗

@@ -46,7 +46,10 @@ use crate::mappings::{
 
 ///Initialize and register all of our action handlers
 pub fn init(cx: &mut MutableAppContext) {
-    cx.add_action(deploy_modal);
+    let settings = cx.global::<Settings>();
+    if settings.experiments.modal_terminal {
+        cx.add_action(deploy_modal);
+    }
 
     terminal_view::init(cx);
     connected_view::init(cx);

crates/zed/src/main.rs 🔗

@@ -95,6 +95,12 @@ fn main() {
             .spawn(languages::init(languages.clone(), cx.background().clone()));
         let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
 
+        let (settings_file, keymap_file) = cx.background().block(config_files).unwrap();
+
+        //Make sure to load settings before initialization, so we know what features to toggle
+        watch_settings_file(default_settings, settings_file, themes.clone(), cx);
+        watch_keymap_file(keymap_file, cx);
+
         context_menu::init(cx);
         project::Project::init(&client);
         client::Channel::init(&client);
@@ -114,10 +120,7 @@ fn main() {
         terminal::init(cx);
 
         let db = cx.background().block(db);
-        let (settings_file, keymap_file) = cx.background().block(config_files).unwrap();
 
-        watch_settings_file(default_settings, settings_file, themes.clone(), cx);
-        watch_keymap_file(keymap_file, cx);
         cx.spawn(|cx| watch_themes(fs.clone(), themes.clone(), cx))
             .detach();