Define project settings in project crate

Max Brunsfeld created

Change summary

Cargo.lock                                        |  1 
Cargo.toml                                        |  1 
crates/collab/Cargo.toml                          |  2 
crates/collab/src/tests.rs                        |  2 
crates/editor/src/editor_settings.rs              |  5 --
crates/editor/src/editor_tests.rs                 |  1 
crates/editor/src/test/editor_lsp_test_context.rs |  1 
crates/project/Cargo.toml                         |  3 +
crates/project/src/project.rs                     | 14 ++++++-
crates/project/src/project_settings.rs            | 31 +++++++++++++++++
crates/project/src/project_tests.rs               |  1 
crates/project_symbols/src/project_symbols.rs     |  1 
crates/settings/Cargo.toml                        |  2 
crates/settings/src/settings.rs                   | 15 -------
crates/theme/Cargo.toml                           |  2 
crates/zed/Cargo.toml                             |  2 
crates/zed/src/main.rs                            |  2 
17 files changed, 59 insertions(+), 27 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -4852,6 +4852,7 @@ dependencies = [
  "rand 0.8.5",
  "regex",
  "rpc",
+ "schemars",
  "serde",
  "serde_derive",
  "serde_json",

Cargo.toml 🔗

@@ -94,6 +94,7 @@ smol = { version = "1.2" }
 tempdir = { version = "0.3.7" }
 thiserror = { version = "1.0.29" }
 time = { version = "0.3", features = ["serde", "serde-well-known"] }
+toml = { version = "0.5" }
 unindent = { version = "0.1.7" }
 
 [patch.crates-io]

crates/collab/Cargo.toml 🔗

@@ -51,7 +51,7 @@ tokio = { version = "1", features = ["full"] }
 tokio-tungstenite = "0.17"
 tonic = "0.6"
 tower = "0.4"
-toml = "0.5.8"
+toml.workspace = true
 tracing = "0.1.34"
 tracing-log = "0.1.3"
 tracing-subscriber = { version = "0.3.11", features = ["env-filter", "json"] }

crates/collab/src/tests.rs 🔗

@@ -201,7 +201,7 @@ impl TestServer {
         });
 
         cx.update(|cx| {
-            Project::init(&client);
+            Project::init(&client, cx);
             client::init(&client, cx);
             language::init(cx);
             editor::init_settings(cx);

crates/editor/src/editor_settings.rs 🔗

@@ -25,10 +25,7 @@ impl Setting for EditorSettings {
         default_value: &Self::FileContent,
         user_values: &[&Self::FileContent],
         _: &gpui::AppContext,
-    ) -> anyhow::Result<Self>
-    where
-        Self: Sized,
-    {
+    ) -> anyhow::Result<Self> {
         Self::load_via_json_merge(default_value, user_values)
     }
 }

crates/editor/src/editor_tests.rs 🔗

@@ -6684,6 +6684,7 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
         cx.set_global(Settings::test(cx));
         language::init(cx);
         crate::init(cx);
+        Project::init_settings(cx);
     });
 
     update_test_settings(cx, f);

crates/project/Cargo.toml 🔗

@@ -50,6 +50,7 @@ parking_lot.workspace = true
 postage.workspace = true
 rand.workspace = true
 regex.workspace = true
+schemars.workspace = true
 serde.workspace = true
 serde_derive.workspace = true
 serde_json.workspace = true
@@ -57,7 +58,7 @@ sha2 = "0.10"
 similar = "1.3"
 smol.workspace = true
 thiserror.workspace = true
-toml = "0.5"
+toml.workspace = true
 itertools = "0.10"
 
 [dev-dependencies]

crates/project/src/project.rs 🔗

@@ -1,6 +1,7 @@
 mod ignore;
 mod lsp_command;
 mod lsp_glob_set;
+mod project_settings;
 pub mod search;
 pub mod terminals;
 pub mod worktree;
@@ -42,6 +43,7 @@ use lsp::{
 use lsp_command::*;
 use lsp_glob_set::LspGlobSet;
 use postage::watch;
+use project_settings::ProjectSettings;
 use rand::prelude::*;
 use search::SearchQuery;
 use serde::Serialize;
@@ -385,7 +387,13 @@ impl FormatTrigger {
 }
 
 impl Project {
-    pub fn init(client: &Arc<Client>) {
+    pub fn init_settings(cx: &mut AppContext) {
+        settings::register_setting::<ProjectSettings>(cx);
+    }
+
+    pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
+        Self::init_settings(cx);
+
         client.add_model_message_handler(Self::handle_add_collaborator);
         client.add_model_message_handler(Self::handle_update_project_collaborator);
         client.add_model_message_handler(Self::handle_remove_collaborator);
@@ -2206,7 +2214,9 @@ impl Project {
                 None => continue,
             };
 
-            let lsp = &cx.global::<Settings>().lsp.get(&adapter.name.0);
+            let lsp = settings::get_setting::<ProjectSettings>(None, cx)
+                .lsp
+                .get(&adapter.name.0);
             let override_options = lsp.map(|s| s.initialization_options.clone()).flatten();
 
             let mut initialization_options = adapter.initialization_options.clone();

crates/project/src/project_settings.rs 🔗

@@ -0,0 +1,31 @@
+use collections::HashMap;
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use settings::Setting;
+use std::sync::Arc;
+
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+pub struct ProjectSettings {
+    #[serde(default)]
+    pub lsp: HashMap<Arc<str>, LspSettings>,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub struct LspSettings {
+    pub initialization_options: Option<serde_json::Value>,
+}
+
+impl Setting for ProjectSettings {
+    const KEY: Option<&'static str> = None;
+
+    type FileContent = Self;
+
+    fn load(
+        default_value: &Self::FileContent,
+        user_values: &[&Self::FileContent],
+        _: &gpui::AppContext,
+    ) -> anyhow::Result<Self> {
+        Self::load_via_json_merge(default_value, user_values)
+    }
+}

crates/project/src/project_tests.rs 🔗

@@ -3723,5 +3723,6 @@ fn init_test(cx: &mut gpui::TestAppContext) {
     cx.update(|cx| {
         cx.set_global(SettingsStore::test(cx));
         language::init(cx);
+        Project::init_settings(cx);
     });
 }

crates/settings/Cargo.toml 🔗

@@ -32,7 +32,7 @@ serde.workspace = true
 serde_derive.workspace = true
 serde_json.workspace = true
 smallvec.workspace = true
-toml = "0.5"
+toml.workspace = true
 tree-sitter = "*"
 tree-sitter-json = "*"
 

crates/settings/src/settings.rs 🔗

@@ -19,7 +19,7 @@ use sqlez::{
     bindable::{Bind, Column, StaticColumnCount},
     statement::Statement,
 };
-use std::{borrow::Cow, collections::HashMap, str, sync::Arc};
+use std::{borrow::Cow, str, sync::Arc};
 use theme::{Theme, ThemeRegistry};
 use util::ResultExt as _;
 
@@ -44,7 +44,6 @@ pub struct Settings {
     pub default_dock_anchor: DockAnchor,
     pub git: GitSettings,
     pub git_overrides: GitSettings,
-    pub lsp: HashMap<Arc<str>, LspSettings>,
     pub theme: Arc<Theme>,
     pub base_keymap: BaseKeymap,
 }
@@ -80,7 +79,6 @@ impl Setting for Settings {
             default_dock_anchor: defaults.default_dock_anchor.unwrap(),
             git: defaults.git.unwrap(),
             git_overrides: Default::default(),
-            lsp: defaults.lsp.clone(),
             theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(),
             base_keymap: Default::default(),
         };
@@ -290,19 +288,11 @@ pub struct SettingsFileContent {
     #[serde(default)]
     pub git: Option<GitSettings>,
     #[serde(default)]
-    pub lsp: HashMap<Arc<str>, LspSettings>,
-    #[serde(default)]
     pub theme: Option<String>,
     #[serde(default)]
     pub base_keymap: Option<BaseKeymap>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub struct LspSettings {
-    pub initialization_options: Option<Value>,
-}
-
 impl Settings {
     pub fn initial_user_settings_content(assets: &'static impl AssetSource) -> Cow<'static, str> {
         match assets.load(INITIAL_USER_SETTINGS_ASSET_PATH).unwrap() {
@@ -340,7 +330,6 @@ impl Settings {
             default_dock_anchor: defaults.default_dock_anchor.unwrap(),
             git: defaults.git.unwrap(),
             git_overrides: Default::default(),
-            lsp: defaults.lsp.clone(),
             theme: themes.get(&defaults.theme.unwrap()).unwrap(),
             base_keymap: Default::default(),
         }
@@ -388,7 +377,6 @@ impl Settings {
         merge(&mut self.base_keymap, data.base_keymap);
 
         self.git_overrides = data.git.unwrap_or_default();
-        self.lsp = data.lsp;
     }
 
     pub fn git_gutter(&self) -> GitGutter {
@@ -416,7 +404,6 @@ impl Settings {
             default_dock_anchor: DockAnchor::Bottom,
             git: Default::default(),
             git_overrides: Default::default(),
-            lsp: Default::default(),
             theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), Default::default),
             base_keymap: Default::default(),
         }

crates/theme/Cargo.toml 🔗

@@ -19,4 +19,4 @@ parking_lot.workspace = true
 serde.workspace = true
 serde_derive.workspace = true
 serde_json.workspace = true
-toml = "0.5"
+toml.workspace = true

crates/zed/Cargo.toml 🔗

@@ -101,7 +101,7 @@ smol.workspace = true
 tempdir.workspace = true
 thiserror.workspace = true
 tiny_http = "0.8"
-toml = "0.5"
+toml.workspace = true
 tree-sitter = "0.20"
 tree-sitter-c = "0.20.1"
 tree-sitter-cpp = "0.20.0"

crates/zed/src/main.rs 🔗

@@ -157,7 +157,7 @@ fn main() {
         cx.set_global(client.clone());
 
         context_menu::init(cx);
-        project::Project::init(&client);
+        project::Project::init(&client, cx);
         client::init(&client, cx);
         command_palette::init(cx);
         editor::init(cx);