Automate settings registration (#42238)

Mikayla Maki and Nia created

Release Notes:

- N/A

---------

Co-authored-by: Nia <nia@zed.dev>

Change summary

Cargo.lock                                                        |  4 
crates/acp_thread/src/acp_thread.rs                               |  2 
crates/action_log/src/action_log.rs                               |  2 
crates/agent/Cargo.toml                                           |  1 
crates/agent/src/agent.rs                                         |  4 
crates/agent/src/edit_agent.rs                                    |  2 
crates/agent/src/edit_agent/evals.rs                              |  5 
crates/agent/src/native_agent_server.rs                           |  2 
crates/agent/src/tests/mod.rs                                     |  6 
crates/agent/src/tools/edit_file_tool.rs                          |  5 
crates/agent/src/tools/find_path_tool.rs                          |  2 
crates/agent/src/tools/grep_tool.rs                               |  2 
crates/agent/src/tools/list_directory_tool.rs                     |  2 
crates/agent/src/tools/open_tool.rs                               |  2 
crates/agent/src/tools/read_file_tool.rs                          |  2 
crates/agent_servers/Cargo.toml                                   |  2 
crates/agent_servers/src/e2e_tests.rs                             | 15 
crates/agent_settings/src/agent_settings.rs                       |  8 
crates/agent_ui/src/acp/entry_view_state.rs                       | 10 
crates/agent_ui/src/acp/message_editor.rs                         |  6 
crates/agent_ui/src/acp/thread_view.rs                            |  6 
crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs | 10 
crates/agent_ui/src/agent_diff.rs                                 | 13 
crates/agent_ui/src/agent_ui.rs                                   |  2 
crates/agent_ui/src/buffer_codegen.rs                             |  7 
crates/agent_ui/src/context.rs                                    |  2 
crates/agent_ui/src/context_picker/completion_provider.rs         |  9 
crates/agent_ui/src/text_thread_editor.rs                         |  6 
crates/assistant_slash_commands/src/file_command.rs               |  2 
crates/assistant_text_thread/src/assistant_text_thread_tests.rs   |  4 
crates/audio/src/audio.rs                                         |  1 
crates/audio/src/audio_settings.rs                                |  4 
crates/auto_update/src/auto_update.rs                             |  7 
crates/call/src/call_impl/mod.rs                                  |  4 
crates/call/src/call_settings.rs                                  |  4 
crates/channel/src/channel_store_tests.rs                         |  1 
crates/client/src/client.rs                                       | 15 
crates/client/src/telemetry.rs                                    |  2 
crates/collab/src/tests/debug_panel_tests.rs                      |  3 
crates/collab/src/tests/remote_editing_collaboration_tests.rs     |  5 
crates/collab/src/tests/test_server.rs                            |  3 
crates/collab_ui/src/collab_ui.rs                                 |  4 
crates/collab_ui/src/panel_settings.rs                            |  6 
crates/command_palette/src/command_palette.rs                     |  3 
crates/copilot/Cargo.toml                                         |  1 
crates/copilot/src/copilot_completion_provider.rs                 |  5 
crates/dap/src/client.rs                                          |  5 
crates/dap/src/debugger_settings.rs                               |  3 
crates/debugger_ui/src/debugger_ui.rs                             |  3 
crates/debugger_ui/src/tests.rs                                   |  3 
crates/diagnostics/src/diagnostics_tests.rs                       |  4 
crates/edit_prediction_context/src/edit_prediction_context.rs     |  2 
crates/edit_prediction_context/src/syntax_index.rs                |  2 
crates/editor/benches/editor_render.rs                            |  5 
crates/editor/src/display_map.rs                                  |  5 
crates/editor/src/editor.rs                                       |  6 
crates/editor/src/editor_settings.rs                              |  4 
crates/editor/src/editor_tests.rs                                 |  4 
crates/editor/src/git/blame.rs                                    |  5 
crates/editor/src/inlays/inlay_hints.rs                           |  4 
crates/editor/src/movement.rs                                     |  5 
crates/editor/src/test/editor_lsp_test_context.rs                 |  2 
crates/eval/src/eval.rs                                           |  6 
crates/extension_host/src/extension_host.rs                       |  2 
crates/extension_host/src/extension_settings.rs                   |  4 
crates/extension_host/src/extension_store_test.rs                 |  9 
crates/file_finder/src/file_finder.rs                             |  5 
crates/file_finder/src/file_finder_settings.rs                    |  4 
crates/file_finder/src/file_finder_tests.rs                       |  3 
crates/file_finder/src/open_path_prompt_tests.rs                  |  3 
crates/git_hosting_providers/src/settings.rs                      |  8 
crates/git_ui/src/file_diff_view.rs                               |  4 
crates/git_ui/src/git_panel.rs                                    |  7 
crates/git_ui/src/git_panel_settings.rs                           |  4 
crates/git_ui/src/git_ui.rs                                       |  4 
crates/git_ui/src/project_diff.rs                                 |  3 
crates/git_ui/src/text_diff_view.rs                               |  4 
crates/go_to_line/src/cursor_position.rs                          |  4 
crates/go_to_line/src/go_to_line.rs                               |  7 
crates/image_viewer/src/image_viewer.rs                           |  1 
crates/image_viewer/src/image_viewer_settings.rs                  |  4 
crates/journal/src/journal.rs                                     |  6 
crates/keymap_editor/src/ui_components/keystroke_input.rs         |  3 
crates/language/src/buffer_tests.rs                               |  1 
crates/language/src/language.rs                                   |  7 
crates/language/src/language_settings.rs                          |  9 
crates/language_models/src/language_models.rs                     |  1 
crates/language_models/src/settings.rs                            |  9 
crates/language_tools/src/lsp_log_view_tests.rs                   |  5 
crates/languages/src/bash.rs                                      |  1 
crates/languages/src/c.rs                                         |  1 
crates/languages/src/python.rs                                    |  1 
crates/languages/src/rust.rs                                      |  1 
crates/languages/src/typescript.rs                                |  7 
crates/markdown/examples/markdown.rs                              |  1 
crates/markdown/examples/markdown_as_child.rs                     |  1 
crates/outline/src/outline.rs                                     |  3 
crates/outline_panel/src/outline_panel.rs                         |  9 
crates/outline_panel/src/outline_panel_settings.rs                |  3 
crates/project/src/agent_server_store.rs                          |  4 
crates/project/src/context_server_store.rs                        |  1 
crates/project/src/git_store/conflict_set.rs                      |  9 
crates/project/src/git_store/git_traversal.rs                     |  1 
crates/project/src/image_store.rs                                 |  2 
crates/project/src/project.rs                                     | 14 
crates/project/src/project_settings.rs                            |  6 
crates/project/src/project_tests.rs                               |  2 
crates/project_panel/src/project_panel.rs                         |  6 
crates/project_panel/src/project_panel_settings.rs                |  7 
crates/project_panel/src/project_panel_tests.rs                   |  9 
crates/project_symbols/src/project_symbols.rs                     |  3 
crates/recent_projects/src/recent_projects.rs                     |  9 
crates/recent_projects/src/remote_connections.rs                  |  3 
crates/remote_server/src/headless_project.rs                      |  5 
crates/remote_server/src/remote_editing_tests.rs                  |  8 
crates/remote_server/src/unix.rs                                  |  2 
crates/repl/src/jupyter_settings.rs                               |  4 
crates/repl/src/repl.rs                                           |  4 
crates/repl/src/repl_settings.rs                                  |  4 
crates/search/src/buffer_search.rs                                |  4 
crates/search/src/project_search.rs                               |  4 
crates/settings/Cargo.toml                                        |  2 
crates/settings/src/base_keymap_setting.rs                        |  6 
crates/settings/src/settings.rs                                   |  8 
crates/settings/src/settings_store.rs                             | 59 
crates/settings_macros/src/settings_macros.rs                     | 24 
crates/settings_profile_selector/src/settings_profile_selector.rs |  6 
crates/settings_ui/src/settings_ui.rs                             |  3 
crates/storybook/Cargo.toml                                       |  2 
crates/storybook/src/storybook.rs                                 |  5 
crates/tab_switcher/src/tab_switcher_tests.rs                     |  3 
crates/tasks_ui/src/tasks_ui.rs                                   |  3 
crates/terminal/src/terminal.rs                                   |  4 
crates/terminal/src/terminal_settings.rs                          |  6 
crates/terminal_view/src/terminal_panel.rs                        |  4 
crates/terminal_view/src/terminal_path_like_target.rs             |  3 
crates/terminal_view/src/terminal_view.rs                         |  4 
crates/theme/src/settings.rs                                      |  4 
crates/theme/src/theme.rs                                         |  1 
crates/title_bar/src/title_bar.rs                                 |  1 
crates/title_bar/src/title_bar_settings.rs                        |  4 
crates/vim/src/test/vim_test_context.rs                           |  4 
crates/vim/src/vim.rs                                             |  4 
crates/vim_mode_setting/Cargo.toml                                |  1 
crates/vim_mode_setting/src/vim_mode_setting.rs                   | 11 
crates/workspace/src/item.rs                                      |  5 
crates/workspace/src/pane.rs                                      |  2 
crates/workspace/src/workspace.rs                                 | 13 
crates/workspace/src/workspace_settings.rs                        | 11 
crates/worktree/src/worktree_settings.rs                          |  4 
crates/worktree/src/worktree_tests.rs                             |  8 
crates/worktree_benchmarks/src/main.rs                            |  1 
crates/zed/src/main.rs                                            |  4 
crates/zed/src/zed.rs                                             |  9 
crates/zed/src/zed/open_listener.rs                               |  3 
crates/zeta/src/license_detection.rs                              |  4 
crates/zeta/src/zeta.rs                                           |  3 
crates/zeta2/src/udiff.rs                                         |  2 
crates/zeta2/src/zeta2.rs                                         |  2 
crates/zeta_cli/src/headless.rs                                   |  5 
crates/zlog_settings/src/zlog_settings.rs                         |  6 
161 files changed, 196 insertions(+), 599 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -250,7 +250,6 @@ dependencies = [
  "acp_tools",
  "action_log",
  "agent-client-protocol",
- "agent_settings",
  "anyhow",
  "async-trait",
  "client",
@@ -16218,7 +16217,6 @@ dependencies = [
  "log",
  "menu",
  "picker",
- "project",
  "reqwest_client",
  "rust-embed",
  "settings",
@@ -16228,7 +16226,6 @@ dependencies = [
  "theme",
  "title_bar",
  "ui",
- "workspace",
 ]
 
 [[package]]
@@ -18814,7 +18811,6 @@ dependencies = [
 name = "vim_mode_setting"
 version = "0.1.0"
 dependencies = [
- "gpui",
  "settings",
 ]
 

crates/acp_thread/src/acp_thread.rs 🔗

@@ -2377,8 +2377,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            Project::init_settings(cx);
-            language::init(cx);
         });
     }
 

crates/action_log/src/action_log.rs 🔗

@@ -1013,8 +1013,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/agent/Cargo.toml 🔗

@@ -63,7 +63,6 @@ streaming_diff.workspace = true
 strsim.workspace = true
 task.workspace = true
 telemetry.workspace = true
-terminal.workspace = true
 text.workspace = true
 thiserror.workspace = true
 ui.workspace = true

crates/agent/src/agent.rs 🔗

@@ -1627,9 +1627,7 @@ mod internal_tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            Project::init_settings(cx);
-            agent_settings::init(cx);
-            language::init(cx);
+
             LanguageModelRegistry::test(cx);
         });
     }

crates/agent/src/edit_agent.rs 🔗

@@ -1394,7 +1394,7 @@ mod tests {
 
     async fn init_test(cx: &mut TestAppContext) -> EditAgent {
         cx.update(settings::init);
-        cx.update(Project::init_settings);
+
         let project = Project::test(FakeFs::new(cx.executor()), [], cx).await;
         let model = Arc::new(FakeLanguageModel::default());
         let action_log = cx.new(|_| ActionLog::new(project.clone()));

crates/agent/src/edit_agent/evals.rs 🔗

@@ -1468,14 +1468,9 @@ impl EditAgentTest {
             gpui_tokio::init(cx);
             let http_client = Arc::new(ReqwestClient::user_agent("agent tests").unwrap());
             cx.set_http_client(http_client);
-
-            client::init_settings(cx);
             let client = Client::production(cx);
             let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
-
             settings::init(cx);
-            Project::init_settings(cx);
-            language::init(cx);
             language_model::init(client.clone(), cx);
             language_models::init(user_store, client.clone(), cx);
         });

crates/agent/src/native_agent_server.rs 🔗

@@ -88,8 +88,6 @@ mod tests {
         async |fs, project, cx| {
             let auth = cx.update(|cx| {
                 prompt_store::init(cx);
-                terminal::init(cx);
-
                 let registry = language_model::LanguageModelRegistry::read_global(cx);
                 let auth = registry
                     .provider(&language_model::ANTHROPIC_PROVIDER_ID)

crates/agent/src/tests/mod.rs 🔗

@@ -1851,7 +1851,6 @@ async fn test_agent_connection(cx: &mut TestAppContext) {
     // Initialize language model system with test provider
     cx.update(|cx| {
         gpui_tokio::init(cx);
-        client::init_settings(cx);
 
         let http_client = FakeHttpClient::with_404_response();
         let clock = Arc::new(clock::FakeSystemClock::new());
@@ -1859,9 +1858,7 @@ async fn test_agent_connection(cx: &mut TestAppContext) {
         let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
         language_model::init(client.clone(), cx);
         language_models::init(user_store, client.clone(), cx);
-        Project::init_settings(cx);
         LanguageModelRegistry::test(cx);
-        agent_settings::init(cx);
     });
     cx.executor().forbid_parking();
 
@@ -2395,8 +2392,6 @@ async fn setup(cx: &mut TestAppContext, model: TestModel) -> ThreadTest {
 
     cx.update(|cx| {
         settings::init(cx);
-        Project::init_settings(cx);
-        agent_settings::init(cx);
 
         match model {
             TestModel::Fake => {}
@@ -2404,7 +2399,6 @@ async fn setup(cx: &mut TestAppContext, model: TestModel) -> ThreadTest {
                 gpui_tokio::init(cx);
                 let http_client = ReqwestClient::user_agent("agent tests").unwrap();
                 cx.set_http_client(Arc::new(http_client));
-                client::init_settings(cx);
                 let client = Client::production(cx);
                 let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
                 language_model::init(client.clone(), cx);

crates/agent/src/tools/edit_file_tool.rs 🔗

@@ -562,7 +562,6 @@ fn resolve_path(
 mod tests {
     use super::*;
     use crate::{ContextServerRegistry, Templates};
-    use client::TelemetrySettings;
     use fs::Fs;
     use gpui::{TestAppContext, UpdateGlobal};
     use language_model::fake_provider::FakeLanguageModel;
@@ -1753,10 +1752,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            TelemetrySettings::register(cx);
-            agent_settings::AgentSettings::register(cx);
-            Project::init_settings(cx);
         });
     }
 }

crates/agent/src/tools/find_path_tool.rs 🔗

@@ -246,8 +246,6 @@ mod test {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 }

crates/agent/src/tools/grep_tool.rs 🔗

@@ -778,8 +778,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/agent/src/tools/open_tool.rs 🔗

@@ -163,8 +163,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 }

crates/agent/src/tools/read_file_tool.rs 🔗

@@ -509,8 +509,6 @@ mod test {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/agent_servers/Cargo.toml 🔗

@@ -21,7 +21,6 @@ acp_tools.workspace = true
 acp_thread.workspace = true
 action_log.workspace = true
 agent-client-protocol.workspace = true
-agent_settings.workspace = true
 anyhow.workspace = true
 async-trait.workspace = true
 client.workspace = true
@@ -33,7 +32,6 @@ gpui.workspace = true
 gpui_tokio = { workspace = true, optional = true }
 http_client.workspace = true
 indoc.workspace = true
-language.workspace = true
 language_model.workspace = true
 language_models.workspace = true
 log.workspace = true

crates/agent_servers/src/e2e_tests.rs 🔗

@@ -6,7 +6,9 @@ use gpui::{AppContext, Entity, TestAppContext};
 use indoc::indoc;
 #[cfg(test)]
 use project::agent_server_store::BuiltinAgentServerSettings;
-use project::{FakeFs, Project, agent_server_store::AllAgentServersSettings};
+use project::{FakeFs, Project};
+#[cfg(test)]
+use settings::Settings;
 use std::{
     path::{Path, PathBuf},
     sync::Arc,
@@ -452,29 +454,22 @@ pub use common_e2e_tests;
 // Helpers
 
 pub async fn init_test(cx: &mut TestAppContext) -> Arc<FakeFs> {
-    use settings::Settings;
-
     env_logger::try_init().ok();
 
     cx.update(|cx| {
         let settings_store = settings::SettingsStore::test(cx);
         cx.set_global(settings_store);
-        Project::init_settings(cx);
-        language::init(cx);
         gpui_tokio::init(cx);
         let http_client = reqwest_client::ReqwestClient::user_agent("agent tests").unwrap();
         cx.set_http_client(Arc::new(http_client));
-        client::init_settings(cx);
         let client = client::Client::production(cx);
         let user_store = cx.new(|cx| client::UserStore::new(client.clone(), cx));
         language_model::init(client.clone(), cx);
         language_models::init(user_store, client, cx);
-        agent_settings::init(cx);
-        AllAgentServersSettings::register(cx);
 
         #[cfg(test)]
-        AllAgentServersSettings::override_global(
-            AllAgentServersSettings {
+        project::agent_server_store::AllAgentServersSettings::override_global(
+            project::agent_server_store::AllAgentServersSettings {
                 claude: Some(BuiltinAgentServerSettings {
                     path: Some("claude-code-acp".into()),
                     args: None,

crates/agent_settings/src/agent_settings.rs 🔗

@@ -10,7 +10,7 @@ use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::{
     DefaultAgentView, DockPosition, LanguageModelParameters, LanguageModelSelection,
-    NotifyWhenAgentWaiting, Settings,
+    NotifyWhenAgentWaiting, RegisterSetting, Settings,
 };
 
 pub use crate::agent_profile::*;
@@ -19,11 +19,7 @@ pub const SUMMARIZE_THREAD_PROMPT: &str = include_str!("prompts/summarize_thread
 pub const SUMMARIZE_THREAD_DETAILED_PROMPT: &str =
     include_str!("prompts/summarize_thread_detailed_prompt.txt");
 
-pub fn init(cx: &mut App) {
-    AgentSettings::register(cx);
-}
-
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RegisterSetting)]
 pub struct AgentSettings {
     pub enabled: bool,
     pub button: bool,

crates/agent_ui/src/acp/entry_view_state.rs 🔗

@@ -401,10 +401,9 @@ mod tests {
     use acp_thread::{AgentConnection, StubAgentConnection};
     use agent::HistoryStore;
     use agent_client_protocol as acp;
-    use agent_settings::AgentSettings;
     use assistant_text_thread::TextThreadStore;
     use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
-    use editor::{EditorSettings, RowInfo};
+    use editor::RowInfo;
     use fs::FakeFs;
     use gpui::{AppContext as _, SemanticVersion, TestAppContext};
 
@@ -413,7 +412,7 @@ mod tests {
     use pretty_assertions::assert_matches;
     use project::Project;
     use serde_json::json;
-    use settings::{Settings as _, SettingsStore};
+    use settings::SettingsStore;
     use util::path;
     use workspace::Workspace;
 
@@ -539,13 +538,8 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
-            AgentSettings::register(cx);
-            workspace::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
             release_channel::init(SemanticVersion::default(), cx);
-            EditorSettings::register(cx);
         });
     }
 }

crates/agent_ui/src/acp/message_editor.rs 🔗

@@ -1901,10 +1901,8 @@ mod tests {
         let app_state = cx.update(AppState::test);
 
         cx.update(|cx| {
-            language::init(cx);
             editor::init(cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
         });
 
         let project = Project::test(app_state.fs.clone(), [path!("/dir").as_ref()], cx).await;
@@ -2077,10 +2075,8 @@ mod tests {
         let app_state = cx.update(AppState::test);
 
         cx.update(|cx| {
-            language::init(cx);
             editor::init(cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
         });
 
         app_state
@@ -2907,10 +2903,8 @@ mod tests {
         let app_state = cx.update(AppState::test);
 
         cx.update(|cx| {
-            language::init(cx);
             editor::init(cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
         });
 
         app_state

crates/agent_ui/src/acp/thread_view.rs 🔗

@@ -5993,7 +5993,6 @@ pub(crate) mod tests {
     use acp_thread::StubAgentConnection;
     use agent_client_protocol::SessionId;
     use assistant_text_thread::TextThreadStore;
-    use editor::EditorSettings;
     use fs::FakeFs;
     use gpui::{EventEmitter, SemanticVersion, TestAppContext, VisualTestContext};
     use project::Project;
@@ -6511,13 +6510,8 @@ pub(crate) mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
-            AgentSettings::register(cx);
-            workspace::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
             release_channel::init(SemanticVersion::default(), cx);
-            EditorSettings::register(cx);
             prompt_store::init(cx)
         });
     }

crates/agent_ui/src/agent_configuration/add_llm_provider_modal.rs 🔗

@@ -515,16 +515,14 @@ impl Render for AddLlmProviderModal {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use editor::EditorSettings;
     use fs::FakeFs;
     use gpui::{TestAppContext, VisualTestContext};
-    use language::language_settings;
     use language_model::{
         LanguageModelProviderId, LanguageModelProviderName,
         fake_provider::FakeLanguageModelProvider,
     };
     use project::Project;
-    use settings::{Settings as _, SettingsStore};
+    use settings::SettingsStore;
     use util::path;
 
     #[gpui::test]
@@ -730,13 +728,9 @@ mod tests {
         cx.update(|cx| {
             let store = SettingsStore::test(cx);
             cx.set_global(store);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            language_settings::init(cx);
-            EditorSettings::register(cx);
+
             language_model::init_settings(cx);
-            language_models::init_settings(cx);
         });
 
         let fs = FakeFs::new(cx.executor());

crates/agent_ui/src/agent_diff.rs 🔗

@@ -1717,12 +1717,11 @@ mod tests {
     use super::*;
     use crate::Keep;
     use acp_thread::AgentConnection as _;
-    use agent_settings::AgentSettings;
     use editor::EditorSettings;
     use gpui::{TestAppContext, UpdateGlobal, VisualTestContext};
     use project::{FakeFs, Project};
     use serde_json::json;
-    use settings::{Settings, SettingsStore};
+    use settings::SettingsStore;
     use std::{path::Path, rc::Rc};
     use util::path;
 
@@ -1731,13 +1730,8 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
-            AgentSettings::register(cx);
             prompt_store::init(cx);
-            workspace::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            EditorSettings::register(cx);
             language_model::init_settings(cx);
         });
 
@@ -1890,13 +1884,8 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
-            AgentSettings::register(cx);
             prompt_store::init(cx);
-            workspace::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            EditorSettings::register(cx);
             language_model::init_settings(cx);
             workspace::register_project_item::<Editor>(cx);
         });

crates/agent_ui/src/agent_ui.rs 🔗

@@ -247,8 +247,6 @@ pub fn init(
     is_eval: bool,
     cx: &mut App,
 ) {
-    AgentSettings::register(cx);
-
     assistant_text_thread::init(client.clone(), cx);
     rules_library::init(cx);
     if !is_eval {

crates/agent_ui/src/buffer_codegen.rs 🔗

@@ -1082,10 +1082,7 @@ mod tests {
     };
     use gpui::TestAppContext;
     use indoc::indoc;
-    use language::{
-        Buffer, Language, LanguageConfig, LanguageMatcher, Point, language_settings,
-        tree_sitter_rust,
-    };
+    use language::{Buffer, Language, LanguageConfig, LanguageMatcher, Point, tree_sitter_rust};
     use language_model::{LanguageModelRegistry, TokenUsage};
     use rand::prelude::*;
     use settings::SettingsStore;
@@ -1465,8 +1462,6 @@ mod tests {
     fn init_test(cx: &mut TestAppContext) {
         cx.update(LanguageModelRegistry::test);
         cx.set_global(cx.update(SettingsStore::test));
-        cx.update(Project::init_settings);
-        cx.update(language_settings::init);
     }
 
     fn simulate_response_stream(

crates/agent_ui/src/context.rs 🔗

@@ -1075,8 +1075,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/agent_ui/src/context_picker/completion_provider.rs 🔗

@@ -1182,10 +1182,8 @@ mod tests {
         let app_state = cx.update(AppState::test);
 
         cx.update(|cx| {
-            language::init(cx);
             editor::init(cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
         });
 
         app_state
@@ -1486,10 +1484,8 @@ mod tests {
         let app_state = cx.update(AppState::test);
 
         cx.update(|cx| {
-            language::init(cx);
             editor::init(cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
         });
 
         app_state
@@ -1686,11 +1682,6 @@ mod tests {
             let store = SettingsStore::test(cx);
             cx.set_global(store);
             theme::init(theme::LoadThemes::JustBase, cx);
-            client::init_settings(cx);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
-            editor::init_settings(cx);
         });
     }
 }

crates/agent_ui/src/text_thread_editor.rs 🔗

@@ -3223,11 +3223,7 @@ mod tests {
         prompt_store::init(cx);
         LanguageModelRegistry::test(cx);
         cx.set_global(settings_store);
-        language::init(cx);
-        agent_settings::init(cx);
-        Project::init_settings(cx);
+
         theme::init(theme::LoadThemes::JustBase, cx);
-        workspace::init_settings(cx);
-        editor::init_settings(cx);
     }
 }

crates/assistant_slash_commands/src/file_command.rs 🔗

@@ -577,8 +577,6 @@ mod test {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
             // release_channel::init(SemanticVersion::default(), cx);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/assistant_text_thread/src/assistant_text_thread_tests.rs 🔗

@@ -22,7 +22,6 @@ use language_model::{
 };
 use parking_lot::Mutex;
 use pretty_assertions::assert_eq;
-use project::Project;
 use prompt_store::PromptBuilder;
 use rand::prelude::*;
 use serde_json::json;
@@ -1411,9 +1410,6 @@ fn init_test(cx: &mut App) {
     prompt_store::init(cx);
     LanguageModelRegistry::test(cx);
     cx.set_global(settings_store);
-    language::init(cx);
-    agent_settings::init(cx);
-    Project::init_settings(cx);
 }
 
 #[derive(Clone)]

crates/audio/src/audio.rs 🔗

@@ -48,7 +48,6 @@ pub const LEGACY_CHANNEL_COUNT: NonZero<u16> = nz!(2);
 pub const REPLAY_DURATION: Duration = Duration::from_secs(30);
 
 pub fn init(cx: &mut App) {
-    AudioSettings::register(cx);
     LIVE_SETTINGS.initialize(cx);
 }
 

crates/audio/src/audio_settings.rs 🔗

@@ -1,9 +1,9 @@
 use std::sync::atomic::{AtomicBool, Ordering};
 
 use gpui::App;
-use settings::{Settings, SettingsStore};
+use settings::{RegisterSetting, Settings, SettingsStore};
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RegisterSetting)]
 pub struct AudioSettings {
     /// Opt into the new audio system.
     ///

crates/auto_update/src/auto_update.rs 🔗

@@ -10,7 +10,7 @@ use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
 use paths::remote_servers_dir;
 use release_channel::{AppCommitSha, ReleaseChannel};
 use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsStore};
+use settings::{RegisterSetting, Settings, SettingsStore};
 use smol::{fs, io::AsyncReadExt};
 use smol::{fs::File, process::Command};
 use std::mem;
@@ -120,7 +120,7 @@ impl Drop for MacOsUnmounter<'_> {
     }
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, RegisterSetting)]
 struct AutoUpdateSetting(bool);
 
 /// Whether or not to automatically check for updates.
@@ -138,8 +138,6 @@ struct GlobalAutoUpdate(Option<Entity<AutoUpdater>>);
 impl Global for GlobalAutoUpdate {}
 
 pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
-    AutoUpdateSetting::register(cx);
-
     cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
         workspace.register_action(|_, action, window, cx| check(action, window, cx));
 
@@ -1028,7 +1026,6 @@ mod tests {
                 .set_user_settings("{}", cx)
                 .expect("Unable to set user settings");
             cx.set_global(store);
-            AutoUpdateSetting::register(cx);
             assert!(AutoUpdateSetting::get_global(cx).0);
         });
     }

crates/call/src/call_impl/mod.rs 🔗

@@ -1,7 +1,6 @@
 pub mod participant;
 pub mod room;
 
-use crate::call_settings::CallSettings;
 use anyhow::{Context as _, Result, anyhow};
 use audio::Audio;
 use client::{ChannelId, Client, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE, proto};
@@ -14,7 +13,6 @@ use gpui::{
 use postage::watch;
 use project::Project;
 use room::Event;
-use settings::Settings;
 use std::sync::Arc;
 
 pub use livekit_client::{RemoteVideoTrack, RemoteVideoTrackView, RemoteVideoTrackViewEvent};
@@ -26,8 +24,6 @@ struct GlobalActiveCall(Entity<ActiveCall>);
 impl Global for GlobalActiveCall {}
 
 pub fn init(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut App) {
-    CallSettings::register(cx);
-
     let active_call = cx.new(|cx| ActiveCall::new(client, user_store, cx));
     cx.set_global(GlobalActiveCall(active_call));
 }

crates/call/src/call_settings.rs 🔗

@@ -1,6 +1,6 @@
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 
-#[derive(Debug)]
+#[derive(Debug, RegisterSetting)]
 pub struct CallSettings {
     pub mute_on_join: bool,
     pub share_on_join: bool,

crates/channel/src/channel_store_tests.rs 🔗

@@ -237,7 +237,6 @@ fn init_test(cx: &mut App) -> Entity<ChannelStore> {
     let settings_store = SettingsStore::test(cx);
     cx.set_global(settings_store);
     release_channel::init(SemanticVersion::default(), cx);
-    client::init_settings(cx);
 
     let clock = Arc::new(FakeSystemClock::new());
     let http = FakeHttpClient::with_404_response();

crates/client/src/client.rs 🔗

@@ -30,7 +30,7 @@ use rand::prelude::*;
 use release_channel::{AppVersion, ReleaseChannel};
 use rpc::proto::{AnyTypedEnvelope, EnvelopedMessage, PeerId, RequestMessage};
 use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsContent};
+use settings::{RegisterSetting, Settings, SettingsContent};
 use std::{
     any::TypeId,
     convert::TryFrom,
@@ -95,7 +95,7 @@ actions!(
     ]
 );
 
-#[derive(Deserialize)]
+#[derive(Deserialize, RegisterSetting)]
 pub struct ClientSettings {
     pub server_url: String,
 }
@@ -113,7 +113,7 @@ impl Settings for ClientSettings {
     }
 }
 
-#[derive(Deserialize, Default)]
+#[derive(Deserialize, Default, RegisterSetting)]
 pub struct ProxySettings {
     pub proxy: Option<String>,
 }
@@ -140,12 +140,6 @@ impl Settings for ProxySettings {
     }
 }
 
-pub fn init_settings(cx: &mut App) {
-    TelemetrySettings::register(cx);
-    ClientSettings::register(cx);
-    ProxySettings::register(cx);
-}
-
 pub fn init(client: &Arc<Client>, cx: &mut App) {
     let client = Arc::downgrade(client);
     cx.on_action({
@@ -508,7 +502,7 @@ impl<T: 'static> Drop for PendingEntitySubscription<T> {
     }
 }
 
-#[derive(Copy, Clone, Deserialize, Debug)]
+#[derive(Copy, Clone, Deserialize, Debug, RegisterSetting)]
 pub struct TelemetrySettings {
     pub diagnostics: bool,
     pub metrics: bool,
@@ -2177,7 +2171,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            init_settings(cx);
         });
     }
 }

crates/client/src/telemetry.rs 🔗

@@ -179,8 +179,6 @@ impl Telemetry {
         let release_channel =
             ReleaseChannel::try_global(cx).map(|release_channel| release_channel.display_name());
 
-        TelemetrySettings::register(cx);
-
         let state = Arc::new(Mutex::new(TelemetryState {
             settings: *TelemetrySettings::get_global(cx),
             architecture: env::consts::ARCH,

crates/collab/src/tests/debug_panel_tests.rs 🔗

@@ -23,9 +23,6 @@ pub fn init_test(cx: &mut gpui::TestAppContext) {
     cx.update(|cx| {
         theme::init(theme::LoadThemes::JustBase, cx);
         command_palette_hooks::init(cx);
-        language::init(cx);
-        workspace::init_settings(cx);
-        project::Project::init_settings(cx);
         debugger_ui::init(cx);
         editor::init(cx);
     });

crates/collab/src/tests/remote_editing_collaboration_tests.rs 🔗

@@ -84,7 +84,6 @@ async fn test_sharing_an_ssh_remote_project(
     let node = NodeRuntime::unavailable();
     let languages = Arc::new(LanguageRegistry::new(server_cx.executor()));
     let _headless_project = server_cx.new(|cx| {
-        client::init_settings(cx);
         HeadlessProject::new(
             HeadlessAppState {
                 session: server_ssh,
@@ -245,7 +244,6 @@ async fn test_ssh_collaboration_git_branches(
     let node = NodeRuntime::unavailable();
     let languages = Arc::new(LanguageRegistry::new(server_cx.executor()));
     let headless_project = server_cx.new(|cx| {
-        client::init_settings(cx);
         HeadlessProject::new(
             HeadlessAppState {
                 session: server_ssh,
@@ -450,7 +448,6 @@ async fn test_ssh_collaboration_formatting_with_prettier(
     server_cx.update(HeadlessProject::init);
     let remote_http_client = Arc::new(BlockedHttpClient);
     let _headless_project = server_cx.new(|cx| {
-        client::init_settings(cx);
         HeadlessProject::new(
             HeadlessAppState {
                 session: server_ssh,
@@ -612,7 +609,6 @@ async fn test_remote_server_debugger(
     let node = NodeRuntime::unavailable();
     let languages = Arc::new(LanguageRegistry::new(server_cx.executor()));
     let _headless_project = server_cx.new(|cx| {
-        client::init_settings(cx);
         HeadlessProject::new(
             HeadlessAppState {
                 session: server_ssh,
@@ -721,7 +717,6 @@ async fn test_slow_adapter_startup_retries(
     let node = NodeRuntime::unavailable();
     let languages = Arc::new(LanguageRegistry::new(server_cx.executor()));
     let _headless_project = server_cx.new(|cx| {
-        client::init_settings(cx);
         HeadlessProject::new(
             HeadlessAppState {
                 session: server_ssh,

crates/collab/src/tests/test_server.rs 🔗

@@ -174,7 +174,6 @@ impl TestServer {
             cx.set_global(settings);
             theme::init(theme::LoadThemes::JustBase, cx);
             release_channel::init(SemanticVersion::default(), cx);
-            client::init_settings(cx);
         });
 
         let clock = Arc::new(FakeSystemClock::new());
@@ -345,7 +344,6 @@ impl TestServer {
             theme::init(theme::LoadThemes::JustBase, cx);
             Project::init(&client, cx);
             client::init(&client, cx);
-            language::init(cx);
             editor::init(cx);
             workspace::init(app_state.clone(), cx);
             call::init(client.clone(), user_store.clone(), cx);
@@ -359,7 +357,6 @@ impl TestServer {
             );
             language_model::LanguageModelRegistry::test(cx);
             assistant_text_thread::init(client.clone(), cx);
-            agent_settings::init(cx);
         });
 
         client

crates/collab_ui/src/collab_ui.rs 🔗

@@ -13,14 +13,10 @@ use gpui::{
 };
 pub use panel_settings::{CollaborationPanelSettings, NotificationPanelSettings};
 use release_channel::ReleaseChannel;
-use settings::Settings;
 use ui::px;
 use workspace::AppState;
 
 pub fn init(app_state: &Arc<AppState>, cx: &mut App) {
-    CollaborationPanelSettings::register(cx);
-    NotificationPanelSettings::register(cx);
-
     channel_view::init(cx);
     collab_panel::init(cx);
     notification_panel::init(cx);

crates/collab_ui/src/panel_settings.rs 🔗

@@ -1,16 +1,16 @@
 use gpui::Pixels;
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 use ui::px;
 use workspace::dock::DockPosition;
 
-#[derive(Debug)]
+#[derive(Debug, RegisterSetting)]
 pub struct CollaborationPanelSettings {
     pub button: bool,
     pub dock: DockPosition,
     pub default_width: Pixels,
 }
 
-#[derive(Debug)]
+#[derive(Debug, RegisterSetting)]
 pub struct NotificationPanelSettings {
     pub button: bool,
     pub dock: DockPosition,

crates/command_palette/src/command_palette.rs 🔗

@@ -28,7 +28,6 @@ use workspace::{ModalView, Workspace, WorkspaceSettings};
 use zed_actions::{OpenZedUrl, command_palette::Toggle};
 
 pub fn init(cx: &mut App) {
-    client::init_settings(cx);
     command_palette_hooks::init(cx);
     cx.observe_new(CommandPalette::register).detach();
 }
@@ -789,13 +788,11 @@ mod tests {
         cx.update(|cx| {
             let app_state = AppState::test(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            language::init(cx);
             editor::init(cx);
             menu::init();
             go_to_line::init(cx);
             workspace::init(app_state.clone(), cx);
             init(cx);
-            Project::init_settings(cx);
             cx.bind_keys(KeymapFile::load_panic_on_failure(
                 r#"[
                     {

crates/copilot/Cargo.toml 🔗

@@ -26,7 +26,6 @@ test-support = [
 [dependencies]
 anyhow.workspace = true
 chrono.workspace = true
-client.workspace = true
 collections.workspace = true
 command_palette_hooks.workspace = true
 dirs.workspace = true

crates/copilot/src/copilot_completion_provider.rs 🔗

@@ -1115,11 +1115,6 @@ mod tests {
             let store = SettingsStore::test(cx);
             cx.set_global(store);
             theme::init(theme::LoadThemes::JustBase, cx);
-            client::init_settings(cx);
-            language::init(cx);
-            editor::init_settings(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
             SettingsStore::update_global(cx, |store: &mut SettingsStore, cx| {
                 store.update_user_settings(cx, |settings| f(&mut settings.project.all_languages));
             });

crates/dap/src/client.rs 🔗

@@ -256,7 +256,7 @@ impl DebugAdapterClient {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{client::DebugAdapterClient, debugger_settings::DebuggerSettings};
+    use crate::client::DebugAdapterClient;
     use dap_types::{
         Capabilities, InitializeRequestArguments, InitializeRequestArgumentsPathFormat,
         RunInTerminalRequestArguments, StartDebuggingRequestArguments,
@@ -265,7 +265,7 @@ mod tests {
     };
     use gpui::TestAppContext;
     use serde_json::json;
-    use settings::{Settings, SettingsStore};
+    use settings::SettingsStore;
     use std::sync::{
         Arc,
         atomic::{AtomicBool, Ordering},
@@ -277,7 +277,6 @@ mod tests {
         cx.update(|cx| {
             let settings = SettingsStore::test(cx);
             cx.set_global(settings);
-            DebuggerSettings::register(cx);
         });
     }
 

crates/dap/src/debugger_settings.rs 🔗

@@ -1,6 +1,7 @@
 use dap_types::SteppingGranularity;
-use settings::{Settings, SettingsContent};
+use settings::{RegisterSetting, Settings, SettingsContent};
 
+#[derive(Debug, RegisterSetting)]
 pub struct DebuggerSettings {
     /// Determines the stepping granularity.
     ///

crates/debugger_ui/src/debugger_ui.rs 🔗

@@ -1,6 +1,5 @@
 use std::any::TypeId;
 
-use dap::debugger_settings::DebuggerSettings;
 use debugger_panel::DebugPanel;
 use editor::Editor;
 use gpui::{Action, App, DispatchPhase, EntityInputHandler, actions};
@@ -10,7 +9,6 @@ use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::Threa
 use schemars::JsonSchema;
 use serde::Deserialize;
 use session::DebugSession;
-use settings::Settings;
 use stack_trace_view::StackTraceView;
 use tasks_ui::{Spawn, TaskOverrides};
 use ui::{FluentBuilder, InteractiveElement};
@@ -115,7 +113,6 @@ actions!(
 );
 
 pub fn init(cx: &mut App) {
-    DebuggerSettings::register(cx);
     workspace::FollowableViewRegistry::register::<DebugSession>(cx);
 
     cx.observe_new(|workspace: &mut Workspace, _, _| {

crates/debugger_ui/src/tests.rs 🔗

@@ -43,9 +43,6 @@ pub fn init_test(cx: &mut gpui::TestAppContext) {
         terminal_view::init(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
         command_palette_hooks::init(cx);
-        language::init(cx);
-        workspace::init_settings(cx);
-        Project::init_settings(cx);
         editor::init(cx);
         crate::init(cx);
         dap_adapters::init(cx);

crates/diagnostics/src/diagnostics_tests.rs 🔗

@@ -2021,10 +2021,6 @@ fn init_test(cx: &mut TestAppContext) {
         let settings = SettingsStore::test(cx);
         cx.set_global(settings);
         theme::init(theme::LoadThemes::JustBase, cx);
-        language::init(cx);
-        client::init_settings(cx);
-        workspace::init_settings(cx);
-        Project::init_settings(cx);
         crate::init(cx);
         editor::init(cx);
     });

crates/edit_prediction_context/src/syntax_index.rs 🔗

@@ -972,8 +972,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
 
         let fs = FakeFs::new(cx.executor());

crates/editor/benches/editor_render.rs 🔗

@@ -4,7 +4,6 @@ use editor::{
     actions::{DeleteToPreviousWordStart, SelectAll, SplitSelectionIntoLines},
 };
 use gpui::{AppContext, Focusable as _, TestAppContext, TestDispatcher};
-use project::Project;
 use rand::{Rng as _, SeedableRng as _, rngs::StdRng};
 use settings::SettingsStore;
 use ui::IntoElement;
@@ -125,10 +124,6 @@ pub fn benches() {
         assets::Assets.load_test_fonts(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
         // release_channel::init(SemanticVersion::default(), cx);
-        client::init_settings(cx);
-        language::init(cx);
-        workspace::init_settings(cx);
-        Project::init_settings(cx);
         editor::init(cx);
     });
 

crates/editor/src/display_map.rs 🔗

@@ -1577,7 +1577,7 @@ pub mod tests {
         LanguageMatcher,
     };
     use lsp::LanguageServerId;
-    use project::Project;
+
     use rand::{Rng, prelude::*};
     use settings::{SettingsContent, SettingsStore};
     use smol::stream::StreamExt;
@@ -2966,10 +2966,7 @@ pub mod tests {
     fn init_test(cx: &mut App, f: impl Fn(&mut SettingsContent)) {
         let settings = SettingsStore::test(cx);
         cx.set_global(settings);
-        workspace::init_settings(cx);
-        language::init(cx);
         crate::init(cx);
-        Project::init_settings(cx);
         theme::init(LoadThemes::JustBase, cx);
         cx.update_global::<SettingsStore, _>(|store, cx| {
             store.update_user_settings(cx, f);

crates/editor/src/editor.rs 🔗

@@ -310,13 +310,7 @@ pub enum HideMouseCursorOrigin {
     MovementAction,
 }
 
-pub fn init_settings(cx: &mut App) {
-    EditorSettings::register(cx);
-}
-
 pub fn init(cx: &mut App) {
-    init_settings(cx);
-
     cx.set_global(GlobalBlameRenderer(Arc::new(())));
 
     workspace::register_project_item::<Editor>(cx);

crates/editor/src/editor_settings.rs 🔗

@@ -8,12 +8,12 @@ pub use settings::{
     GoToDefinitionFallback, HideMouseMode, MinimapThumb, MinimapThumbBorder, MultiCursorModifier,
     ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder,
 };
-use settings::{RelativeLineNumbers, Settings};
+use settings::{RegisterSetting, RelativeLineNumbers, Settings};
 use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
 
 /// Imports from the VSCode settings at
 /// https://code.visualstudio.com/docs/reference/default-settings
-#[derive(Clone)]
+#[derive(Clone, RegisterSetting)]
 pub struct EditorSettings {
     pub cursor_blink: bool,
     pub cursor_shape: Option<CursorShape>,

crates/editor/src/editor_tests.rs 🔗

@@ -25700,10 +25700,6 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
         cx.set_global(store);
         theme::init(theme::LoadThemes::JustBase, cx);
         release_channel::init(SemanticVersion::default(), cx);
-        client::init_settings(cx);
-        language::init(cx);
-        Project::init_settings(cx);
-        workspace::init_settings(cx);
         crate::init(cx);
     });
     zlog::init_test();

crates/editor/src/git/blame.rs 🔗

@@ -764,11 +764,6 @@ mod tests {
 
             theme::init(theme::LoadThemes::JustBase, cx);
 
-            language::init(cx);
-            client::init_settings(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
-
             crate::init(cx);
         });
     }

crates/editor/src/inlays/inlay_hints.rs 🔗

@@ -3951,10 +3951,6 @@ let c = 3;"#
             cx.set_global(settings_store);
             theme::init(theme::LoadThemes::JustBase, cx);
             release_channel::init(SemanticVersion::default(), cx);
-            client::init_settings(cx);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
             crate::init(cx);
         });
 

crates/editor/src/movement.rs 🔗

@@ -877,7 +877,7 @@ mod tests {
     };
     use gpui::{AppContext as _, font, px};
     use language::Capability;
-    use project::{Project, project_settings::DiagnosticSeverity};
+    use project::project_settings::DiagnosticSeverity;
     use settings::SettingsStore;
     use util::post_inc;
 
@@ -1346,10 +1346,7 @@ mod tests {
     fn init_test(cx: &mut gpui::App) {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
-        workspace::init_settings(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        language::init(cx);
         crate::init(cx);
-        Project::init_settings(cx);
     }
 }

crates/editor/src/test/editor_lsp_test_context.rs 🔗

@@ -54,10 +54,8 @@ impl EditorLspTestContext {
 
         cx.update(|cx| {
             assets::Assets.load_test_fonts(cx);
-            language::init(cx);
             crate::init(cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
         });
 
         let file_name = format!(

crates/eval/src/eval.rs 🔗

@@ -23,7 +23,6 @@ use gpui_tokio::Tokio;
 use language::LanguageRegistry;
 use language_model::{ConfiguredModel, LanguageModel, LanguageModelRegistry, SelectedModel};
 use node_runtime::{NodeBinaryOptions, NodeRuntime};
-use project::Project;
 use project::project_settings::ProjectSettings;
 use prompt_store::PromptBuilder;
 use release_channel::AppVersion;
@@ -354,7 +353,6 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
 
     let settings_store = SettingsStore::new(cx, &settings::default_settings());
     cx.set_global(settings_store);
-    client::init_settings(cx);
 
     // Set User-Agent so we can download language servers from GitHub
     let user_agent = format!(
@@ -376,8 +374,6 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
     };
     cx.set_http_client(Arc::new(http));
 
-    Project::init_settings(cx);
-
     let client = Client::production(cx);
     cx.set_http_client(client.http_client());
 
@@ -422,8 +418,6 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
     let node_runtime = NodeRuntime::new(client.http_client(), None, rx);
 
     let extension_host_proxy = ExtensionHostProxy::global(cx);
-
-    language::init(cx);
     debug_adapter_extension::init(extension_host_proxy.clone(), cx);
     language_extension::init(LspAccess::Noop, extension_host_proxy, languages.clone());
     language_model::init(client.clone(), cx);

crates/extension_host/src/extension_host.rs 🔗

@@ -200,8 +200,6 @@ pub fn init(
     node_runtime: NodeRuntime,
     cx: &mut App,
 ) {
-    ExtensionSettings::register(cx);
-
     let store = cx.new(move |cx| {
         ExtensionStore::new(
             paths::extensions_dir().clone(),

crates/extension_host/src/extension_settings.rs 🔗

@@ -2,10 +2,10 @@ use collections::HashMap;
 use extension::{
     DownloadFileCapability, ExtensionCapability, NpmInstallPackageCapability, ProcessExecCapability,
 };
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 use std::sync::Arc;
 
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default, Clone, RegisterSetting)]
 pub struct ExtensionSettings {
     /// The extensions that should be automatically installed by Zed.
     ///

crates/extension_host/src/extension_store_test.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
     Event, ExtensionIndex, ExtensionIndexEntry, ExtensionIndexLanguageEntry,
-    ExtensionIndexThemeEntry, ExtensionManifest, ExtensionSettings, ExtensionStore,
-    GrammarManifestEntry, RELOAD_DEBOUNCE_DURATION, SchemaVersion,
+    ExtensionIndexThemeEntry, ExtensionManifest, ExtensionStore, GrammarManifestEntry,
+    RELOAD_DEBOUNCE_DURATION, SchemaVersion,
 };
 use async_compression::futures::bufread::GzipEncoder;
 use collections::{BTreeMap, HashSet};
@@ -19,7 +19,7 @@ use project::{DEFAULT_COMPLETION_CONTEXT, Project};
 use release_channel::AppVersion;
 use reqwest_client::ReqwestClient;
 use serde_json::json;
-use settings::{Settings as _, SettingsStore};
+use settings::SettingsStore;
 use std::{
     ffi::OsString,
     path::{Path, PathBuf},
@@ -865,9 +865,6 @@ fn init_test(cx: &mut TestAppContext) {
         release_channel::init(SemanticVersion::default(), cx);
         extension::init(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        Project::init_settings(cx);
-        ExtensionSettings::register(cx);
-        language::init(cx);
         gpui_tokio::init(cx);
     });
 }

crates/file_finder/src/file_finder.rs 🔗

@@ -90,12 +90,7 @@ pub struct FileFinder {
     init_modifiers: Option<Modifiers>,
 }
 
-pub fn init_settings(cx: &mut App) {
-    FileFinderSettings::register(cx);
-}
-
 pub fn init(cx: &mut App) {
-    init_settings(cx);
     cx.observe_new(FileFinder::register).detach();
     cx.observe_new(OpenPathPrompt::register).detach();
     cx.observe_new(OpenPathPrompt::register_new_path).detach();

crates/file_finder/src/file_finder_settings.rs 🔗

@@ -1,8 +1,8 @@
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 
-#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
+#[derive(Deserialize, Debug, Clone, Copy, PartialEq, RegisterSetting)]
 pub struct FileFinderSettings {
     pub file_icons: bool,
     pub modal_max_width: FileFinderWidth,

crates/file_finder/src/file_finder_tests.rs 🔗

@@ -3206,11 +3206,8 @@ fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
     cx.update(|cx| {
         let state = AppState::test(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        language::init(cx);
         super::init(cx);
         editor::init(cx);
-        workspace::init_settings(cx);
-        Project::init_settings(cx);
         state
     })
 }

crates/file_finder/src/open_path_prompt_tests.rs 🔗

@@ -397,11 +397,8 @@ fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
     cx.update(|cx| {
         let state = AppState::test(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        language::init(cx);
         super::init(cx);
         editor::init(cx);
-        workspace::init_settings(cx);
-        Project::init_settings(cx);
         state
     })
 }

crates/git_hosting_providers/src/settings.rs 🔗

@@ -2,15 +2,15 @@ use std::sync::Arc;
 
 use git::GitHostingProviderRegistry;
 use gpui::App;
-use settings::{GitHostingProviderConfig, GitHostingProviderKind, Settings, SettingsStore};
+use settings::{
+    GitHostingProviderConfig, GitHostingProviderKind, RegisterSetting, Settings, SettingsStore,
+};
 use url::Url;
 use util::ResultExt as _;
 
 use crate::{Bitbucket, Github, Gitlab};
 
 pub(crate) fn init(cx: &mut App) {
-    GitHostingProviderSettings::register(cx);
-
     init_git_hosting_provider_settings(cx);
 }
 
@@ -52,7 +52,7 @@ fn update_git_hosting_providers_from_settings(cx: &mut App) {
     provider_registry.set_setting_providers(iter);
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, RegisterSetting)]
 pub struct GitHostingProviderSettings {
     pub git_hosting_providers: Vec<GitHostingProviderConfig>,
 }

crates/git_ui/src/file_diff_view.rs 🔗

@@ -370,10 +370,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
-            editor::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
         });
     }

crates/git_ui/src/git_panel.rs 🔗

@@ -4955,7 +4955,7 @@ mod tests {
         status::{StatusCode, UnmergedStatus, UnmergedStatusCode},
     };
     use gpui::{TestAppContext, UpdateGlobal, VisualTestContext};
-    use project::{FakeFs, WorktreeSettings};
+    use project::FakeFs;
     use serde_json::json;
     use settings::SettingsStore;
     use theme::LoadThemes;
@@ -4970,13 +4970,8 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            AgentSettings::register(cx);
-            WorktreeSettings::register(cx);
-            workspace::init_settings(cx);
             theme::init(LoadThemes::JustBase, cx);
-            language::init(cx);
             editor::init(cx);
-            Project::init_settings(cx);
             crate::init(cx);
         });
     }

crates/git_ui/src/git_panel_settings.rs 🔗

@@ -2,7 +2,7 @@ use editor::EditorSettings;
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::{Settings, StatusStyle};
+use settings::{RegisterSetting, Settings, StatusStyle};
 use ui::{
     px,
     scrollbars::{ScrollbarVisibility, ShowScrollbar},
@@ -14,7 +14,7 @@ pub struct ScrollbarSettings {
     pub show: Option<ShowScrollbar>,
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, RegisterSetting)]
 pub struct GitPanelSettings {
     pub button: bool,
     pub dock: DockPosition,

crates/git_ui/src/git_ui.rs 🔗

@@ -1,6 +1,5 @@
 use std::any::Any;
 
-use ::settings::Settings;
 use command_palette_hooks::CommandPaletteFilter;
 use commit_modal::CommitModal;
 use editor::{Editor, actions::DiffClipboardWithSelectionData};
@@ -15,7 +14,6 @@ use git::{
     repository::{Branch, Upstream, UpstreamTracking, UpstreamTrackingStatus},
     status::{FileStatus, StatusCode, UnmergedStatus, UnmergedStatusCode},
 };
-use git_panel_settings::GitPanelSettings;
 use gpui::{
     Action, App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, SharedString,
     Window, actions,
@@ -57,8 +55,6 @@ actions!(
 );
 
 pub fn init(cx: &mut App) {
-    GitPanelSettings::register(cx);
-
     editor::set_blame_renderer(blame_ui::GitBlameRenderer, cx);
     commit_view::init(cx);
 

crates/git_ui/src/project_diff.rs 🔗

@@ -1587,9 +1587,6 @@ mod tests {
             let store = SettingsStore::test(cx);
             cx.set_global(store);
             theme::init(theme::LoadThemes::JustBase, cx);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
             editor::init(cx);
             crate::init(cx);
         });

crates/git_ui/src/text_diff_view.rs 🔗

@@ -458,10 +458,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
-            editor::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
         });
     }

crates/go_to_line/src/cursor_position.rs 🔗

@@ -1,6 +1,6 @@
 use editor::{Editor, EditorEvent, MultiBufferSnapshot};
 use gpui::{App, Entity, FocusHandle, Focusable, Styled, Subscription, Task, WeakEntity};
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 use std::{fmt::Write, num::NonZeroU32, time::Duration};
 use text::{Point, Selection};
 use ui::{
@@ -293,7 +293,7 @@ impl StatusItemView for CursorPosition {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, RegisterSetting)]
 pub enum LineIndicatorFormat {
     Short,
     Long,

crates/go_to_line/src/go_to_line.rs 🔗

@@ -1,6 +1,6 @@
 pub mod cursor_position;
 
-use cursor_position::{LineIndicatorFormat, UserCaretPosition};
+use cursor_position::UserCaretPosition;
 use editor::{
     Anchor, Editor, MultiBufferSnapshot, RowHighlightOptions, SelectionEffects, ToOffset, ToPoint,
     actions::Tab,
@@ -11,7 +11,6 @@ use gpui::{
     Subscription, div, prelude::*,
 };
 use language::Buffer;
-use settings::Settings;
 use text::{Bias, Point};
 use theme::ActiveTheme;
 use ui::prelude::*;
@@ -19,7 +18,6 @@ use util::paths::FILE_ROW_COLUMN_DELIMITER;
 use workspace::{DismissDecision, ModalView};
 
 pub fn init(cx: &mut App) {
-    LineIndicatorFormat::register(cx);
     cx.observe_new(GoToLine::register).detach();
 }
 
@@ -770,11 +768,8 @@ mod tests {
     fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
         cx.update(|cx| {
             let state = AppState::test(cx);
-            language::init(cx);
             crate::init(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             state
         })
     }

crates/image_viewer/src/image_viewer.rs 🔗

@@ -412,7 +412,6 @@ impl ProjectItem for ImageView {
 }
 
 pub fn init(cx: &mut App) {
-    ImageViewerSettings::register(cx);
     workspace::register_project_item::<ImageView>(cx);
     workspace::register_serializable_item::<ImageView>(cx);
 }

crates/image_viewer/src/image_viewer_settings.rs 🔗

@@ -1,8 +1,8 @@
 pub use settings::ImageFileSizeUnit;
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 
 /// The settings for the image viewer.
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug, Default, RegisterSetting)]
 pub struct ImageViewerSettings {
     /// The unit to use for displaying image file sizes.
     ///

crates/journal/src/journal.rs 🔗

@@ -3,7 +3,7 @@ use editor::scroll::Autoscroll;
 use editor::{Editor, SelectionEffects};
 use gpui::{App, AppContext as _, Context, Window, actions};
 pub use settings::HourFormat;
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 use std::{
     fs::OpenOptions,
     path::{Path, PathBuf},
@@ -20,7 +20,7 @@ actions!(
 );
 
 /// Settings specific to journaling
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RegisterSetting)]
 pub struct JournalSettings {
     /// The path of the directory where journal entries are stored.
     ///
@@ -44,8 +44,6 @@ impl settings::Settings for JournalSettings {
 }
 
 pub fn init(_: Arc<AppState>, cx: &mut App) {
-    JournalSettings::register(cx);
-
     cx.observe_new(
         |workspace: &mut Workspace, _window, _cx: &mut Context<Workspace>| {
             workspace.register_action(|workspace, _: &NewJournalEntry, window, cx| {

crates/keymap_editor/src/ui_components/keystroke_input.rs 🔗

@@ -1102,9 +1102,6 @@ mod tests {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
             theme::init(theme::LoadThemes::JustBase, cx);
-            language::init(cx);
-            project::Project::init_settings(cx);
-            workspace::init_settings(cx);
         });
 
         let fs = FakeFs::new(cx.executor());

crates/language/src/buffer_tests.rs 🔗

@@ -3922,7 +3922,6 @@ fn assert_bracket_pairs(
 fn init_settings(cx: &mut App, f: fn(&mut AllLanguageSettingsContent)) {
     let settings_store = SettingsStore::test(cx);
     cx.set_global(settings_store);
-    crate::init(cx);
     cx.update_global::<SettingsStore, _>(|settings, cx| {
         settings.update_user_settings(cx, |content| f(&mut content.project.all_languages));
     });

crates/language/src/language.rs 🔗

@@ -88,13 +88,6 @@ pub use syntax_map::{
 pub use text::{AnchorRangeExt, LineEnding};
 pub use tree_sitter::{Node, Parser, Tree, TreeCursor};
 
-/// Initializes the `language` crate.
-///
-/// This should be called before making use of items from the create.
-pub fn init(cx: &mut App) {
-    language_settings::init(cx);
-}
-
 static QUERY_CURSORS: Mutex<Vec<QueryCursor>> = Mutex::new(vec![]);
 static PARSERS: Mutex<Vec<Parser>> = Mutex::new(vec![]);
 

crates/language/src/language_settings.rs 🔗

@@ -15,15 +15,10 @@ pub use settings::{
     Formatter, FormatterList, InlayHintKind, LanguageSettingsContent, LspInsertMode,
     RewrapBehavior, ShowWhitespaceSetting, SoftWrap, WordsCompletionMode,
 };
-use settings::{Settings, SettingsLocation, SettingsStore};
+use settings::{RegisterSetting, Settings, SettingsLocation, SettingsStore};
 use shellexpand;
 use std::{borrow::Cow, num::NonZeroU32, path::Path, sync::Arc};
 
-/// Initializes the language settings.
-pub fn init(cx: &mut App) {
-    AllLanguageSettings::register(cx);
-}
-
 /// Returns the settings for the specified language from the provided file.
 pub fn language_settings<'a>(
     language: Option<LanguageName>,
@@ -50,7 +45,7 @@ pub fn all_language_settings<'a>(
 }
 
 /// The settings for all languages.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, RegisterSetting)]
 pub struct AllLanguageSettings {
     /// The edit prediction settings.
     pub edit_predictions: EditPredictionSettings,

crates/language_models/src/language_models.rs 🔗

@@ -28,7 +28,6 @@ use crate::provider::x_ai::XAiLanguageModelProvider;
 pub use crate::settings::*;
 
 pub fn init(user_store: Entity<UserStore>, client: Arc<Client>, cx: &mut App) {
-    crate::settings::init_settings(cx);
     let registry = LanguageModelRegistry::global(cx);
     registry.update(cx, |registry, cx| {
         register_language_model_providers(registry, user_store, client.clone(), cx);

crates/language_models/src/settings.rs 🔗

@@ -1,8 +1,7 @@
 use std::sync::Arc;
 
 use collections::HashMap;
-use gpui::App;
-use settings::Settings;
+use settings::RegisterSetting;
 
 use crate::provider::{
     anthropic::AnthropicSettings, bedrock::AmazonBedrockSettings, cloud::ZedDotDevSettings,
@@ -12,11 +11,7 @@ use crate::provider::{
     vercel::VercelSettings, x_ai::XAiSettings,
 };
 
-/// Initializes the language model settings.
-pub fn init_settings(cx: &mut App) {
-    AllLanguageModelSettings::register(cx);
-}
-
+#[derive(Debug, RegisterSetting)]
 pub struct AllLanguageModelSettings {
     pub anthropic: AnthropicSettings,
     pub bedrock: AmazonBedrockSettings,

crates/language_tools/src/lsp_log_view_tests.rs 🔗

@@ -109,12 +109,7 @@ fn init_test(cx: &mut gpui::TestAppContext) {
     cx.update(|cx| {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
-        workspace::init_settings(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
         release_channel::init(SemanticVersion::default(), cx);
-        language::init(cx);
-        client::init_settings(cx);
-        Project::init_settings(cx);
-        editor::init_settings(cx);
     });
 }

crates/languages/src/bash.rs 🔗

@@ -32,7 +32,6 @@ mod tests {
         cx.update(|cx| {
             let test_settings = SettingsStore::test(cx);
             cx.set_global(test_settings);
-            language::init(cx);
             cx.update_global::<SettingsStore, _>(|store, cx| {
                 store.update_user_settings(cx, |s| {
                     s.project.all_languages.defaults.tab_size = NonZeroU32::new(2)

crates/languages/src/c.rs 🔗

@@ -402,7 +402,6 @@ mod tests {
         cx.update(|cx| {
             let test_settings = SettingsStore::test(cx);
             cx.set_global(test_settings);
-            language::init(cx);
             cx.update_global::<SettingsStore, _>(|store, cx| {
                 store.update_user_settings(cx, |s| {
                     s.project.all_languages.defaults.tab_size = NonZeroU32::new(2);

crates/languages/src/python.rs 🔗

@@ -2271,7 +2271,6 @@ mod tests {
         cx.update(|cx| {
             let test_settings = SettingsStore::test(cx);
             cx.set_global(test_settings);
-            language::init(cx);
             cx.update_global::<SettingsStore, _>(|store, cx| {
                 store.update_user_settings(cx, |s| {
                     s.project.all_languages.defaults.tab_size = NonZeroU32::new(2);

crates/languages/src/rust.rs 🔗

@@ -1445,7 +1445,6 @@ mod tests {
         cx.update(|cx| {
             let test_settings = SettingsStore::test(cx);
             cx.set_global(test_settings);
-            language::init(cx);
             cx.update_global::<SettingsStore, _>(|store, cx| {
                 store.update_user_settings(cx, |s| {
                     s.project.all_languages.defaults.tab_size = NonZeroU32::new(2);

crates/languages/src/typescript.rs 🔗

@@ -1091,8 +1091,7 @@ mod tests {
     use std::path::Path;
 
     use gpui::{AppContext as _, BackgroundExecutor, TestAppContext};
-    use language::language_settings;
-    use project::{FakeFs, Project};
+    use project::FakeFs;
     use serde_json::json;
     use task::TaskTemplates;
     use unindent::Unindent;
@@ -1432,8 +1431,6 @@ mod tests {
     async fn test_package_json_discovery(executor: BackgroundExecutor, cx: &mut TestAppContext) {
         cx.update(|cx| {
             settings::init(cx);
-            Project::init_settings(cx);
-            language_settings::init(cx);
         });
 
         let package_json_1 = json!({
@@ -1593,8 +1590,6 @@ mod tests {
     ) {
         cx.update(|cx| {
             settings::init(cx);
-            Project::init_settings(cx);
-            language_settings::init(cx);
         });
 
         // Test case with all test runners present

crates/markdown/examples/markdown.rs 🔗

@@ -38,7 +38,6 @@ pub fn main() {
     Application::new().with_assets(Assets).run(|cx| {
         let store = SettingsStore::test(cx);
         cx.set_global(store);
-        language::init(cx);
         cx.bind_keys([KeyBinding::new("cmd-c", markdown::Copy, None)]);
 
         let node_runtime = NodeRuntime::unavailable();

crates/markdown/examples/markdown_as_child.rs 🔗

@@ -22,7 +22,6 @@ pub fn main() {
     Application::new().with_assets(Assets).run(|cx| {
         let store = SettingsStore::test(cx);
         cx.set_global(store);
-        language::init(cx);
         cx.bind_keys([KeyBinding::new("cmd-c", markdown::Copy, None)]);
 
         let node_runtime = NodeRuntime::unavailable();

crates/outline/src/outline.rs 🔗

@@ -575,11 +575,8 @@ mod tests {
     fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
         cx.update(|cx| {
             let state = AppState::test(cx);
-            language::init(cx);
             crate::init(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             state
         })
     }

crates/outline_panel/src/outline_panel.rs 🔗

@@ -656,13 +656,7 @@ struct SerializedOutlinePanel {
     active: Option<bool>,
 }
 
-pub fn init_settings(cx: &mut App) {
-    OutlinePanelSettings::register(cx);
-}
-
 pub fn init(cx: &mut App) {
-    init_settings(cx);
-
     cx.observe_new(|workspace: &mut Workspace, _, _| {
         workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
             workspace.toggle_panel_focus::<OutlinePanel>(window, cx);
@@ -6823,10 +6817,7 @@ outline: struct OutlineEntryExcerpt
 
             theme::init(theme::LoadThemes::JustBase, cx);
 
-            language::init(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             project_search::init(cx);
             buffer_search::init(cx);
             super::init(cx);

crates/outline_panel/src/outline_panel_settings.rs 🔗

@@ -1,9 +1,10 @@
 use editor::EditorSettings;
 use gpui::{App, Pixels};
+use settings::RegisterSetting;
 pub use settings::{DockSide, Settings, ShowIndentGuides};
 use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
 
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, RegisterSetting)]
 pub struct OutlinePanelSettings {
     pub button: bool,
     pub default_width: Pixels,

crates/project/src/agent_server_store.rs 🔗

@@ -20,7 +20,7 @@ use remote::RemoteClient;
 use rpc::{AnyProtoClient, TypedEnvelope, proto};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::SettingsStore;
+use settings::{RegisterSetting, SettingsStore};
 use task::Shell;
 use util::{ResultExt as _, debug_panic};
 
@@ -1618,7 +1618,7 @@ pub const GEMINI_NAME: &'static str = "gemini";
 pub const CLAUDE_CODE_NAME: &'static str = "claude";
 pub const CODEX_NAME: &'static str = "codex";
 
-#[derive(Default, Clone, JsonSchema, Debug, PartialEq)]
+#[derive(Default, Clone, JsonSchema, Debug, PartialEq, RegisterSetting)]
 pub struct AllAgentServersSettings {
     pub gemini: Option<BuiltinAgentServerSettings>,
     pub claude: Option<BuiltinAgentServerSettings>,

crates/project/src/context_server_store.rs 🔗

@@ -1307,7 +1307,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            Project::init_settings(cx);
             let mut settings = ProjectSettings::get_global(cx).clone();
             for (id, config) in context_server_configurations {
                 settings.context_servers.insert(id, config);

crates/project/src/git_store/conflict_set.rs 🔗

@@ -268,13 +268,10 @@ mod tests {
         status::{UnmergedStatus, UnmergedStatusCode},
     };
     use gpui::{BackgroundExecutor, TestAppContext};
-    use language::language_settings::AllLanguageSettings;
     use serde_json::json;
-    use settings::Settings as _;
     use text::{Buffer, BufferId, Point, ReplicaId, ToOffset as _};
     use unindent::Unindent as _;
     use util::{path, rel_path::rel_path};
-    use worktree::WorktreeSettings;
 
     #[test]
     fn test_parse_conflicts_in_buffer() {
@@ -488,9 +485,6 @@ mod tests {
         zlog::init_test();
         cx.update(|cx| {
             settings::init(cx);
-            WorktreeSettings::register(cx);
-            Project::init_settings(cx);
-            AllLanguageSettings::register(cx);
         });
         let initial_text = "
             one
@@ -589,9 +583,6 @@ mod tests {
         zlog::init_test();
         cx.update(|cx| {
             settings::init(cx);
-            WorktreeSettings::register(cx);
-            Project::init_settings(cx);
-            AllLanguageSettings::register(cx);
         });
 
         let initial_text = "

crates/project/src/image_store.rs 🔗

@@ -920,8 +920,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/project/src/project.rs 🔗

@@ -35,7 +35,6 @@ mod yarn;
 use dap::inline_value::{InlineValueLocation, VariableLookupKind, VariableScope};
 
 use crate::{
-    agent_server_store::AllAgentServersSettings,
     git_store::GitStore,
     lsp_store::{SymbolLocation, log_store::LogKind},
 };
@@ -101,7 +100,7 @@ use rpc::{
 };
 use search::{SearchInputKind, SearchQuery, SearchResult};
 use search_history::SearchHistory;
-use settings::{InvalidSettingsError, Settings, SettingsLocation, SettingsStore};
+use settings::{InvalidSettingsError, RegisterSetting, Settings, SettingsLocation, SettingsStore};
 use smol::channel::Receiver;
 use snippet::Snippet;
 use snippet_provider::SnippetProvider;
@@ -996,7 +995,7 @@ pub enum PulledDiagnostics {
 /// Whether to disable all AI features in Zed.
 ///
 /// Default: false
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, RegisterSetting)]
 pub struct DisableAiSettings {
     pub disable_ai: bool,
 }
@@ -1010,16 +1009,8 @@ impl settings::Settings for DisableAiSettings {
 }
 
 impl Project {
-    pub fn init_settings(cx: &mut App) {
-        WorktreeSettings::register(cx);
-        ProjectSettings::register(cx);
-        DisableAiSettings::register(cx);
-        AllAgentServersSettings::register(cx);
-    }
-
     pub fn init(client: &Arc<Client>, cx: &mut App) {
         connection_manager::init(client.clone(), cx);
-        Self::init_settings(cx);
 
         let client: AnyProtoClient = client.clone().into();
         client.add_entity_message_handler(Self::handle_add_collaborator);
@@ -5759,7 +5750,6 @@ mod disable_ai_settings_tests {
     async fn test_disable_ai_settings_security(cx: &mut TestAppContext) {
         cx.update(|cx| {
             settings::init(cx);
-            Project::init_settings(cx);
 
             // Test 1: Default is false (AI enabled)
             assert!(

crates/project/src/project_settings.rs 🔗

@@ -20,8 +20,8 @@ use serde::{Deserialize, Serialize};
 pub use settings::DirenvSettings;
 pub use settings::LspSettings;
 use settings::{
-    DapSettingsContent, InvalidSettingsError, LocalSettingsKind, Settings, SettingsLocation,
-    SettingsStore, parse_json_with_comments, watch_config_file,
+    DapSettingsContent, InvalidSettingsError, LocalSettingsKind, RegisterSetting, Settings,
+    SettingsLocation, SettingsStore, parse_json_with_comments, watch_config_file,
 };
 use std::{path::PathBuf, sync::Arc, time::Duration};
 use task::{DebugTaskFile, TaskTemplates, VsCodeDebugTaskFile, VsCodeTaskFile};
@@ -33,7 +33,7 @@ use crate::{
     worktree_store::{WorktreeStore, WorktreeStoreEvent},
 };
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, RegisterSetting)]
 pub struct ProjectSettings {
     /// Configuration for language servers.
     ///

crates/project/src/project_tests.rs 🔗

@@ -10091,8 +10091,6 @@ pub fn init_test(cx: &mut gpui::TestAppContext) {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
         release_channel::init(SemanticVersion::default(), cx);
-        language::init(cx);
-        Project::init_settings(cx);
     });
 }
 

crates/project_panel/src/project_panel.rs 🔗

@@ -360,13 +360,7 @@ impl FoldedAncestors {
     }
 }
 
-pub fn init_settings(cx: &mut App) {
-    ProjectPanelSettings::register(cx);
-}
-
 pub fn init(cx: &mut App) {
-    init_settings(cx);
-
     cx.observe_new(|workspace: &mut Workspace, _, _| {
         workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
             workspace.toggle_panel_focus::<ProjectPanel>(window, cx);

crates/project_panel/src/project_panel_settings.rs 🔗

@@ -2,13 +2,16 @@ use editor::EditorSettings;
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::{DockSide, ProjectPanelEntrySpacing, Settings, ShowDiagnostics, ShowIndentGuides};
+use settings::{
+    DockSide, ProjectPanelEntrySpacing, RegisterSetting, Settings, ShowDiagnostics,
+    ShowIndentGuides,
+};
 use ui::{
     px,
     scrollbars::{ScrollbarVisibility, ShowScrollbar},
 };
 
-#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
+#[derive(Deserialize, Debug, Clone, Copy, PartialEq, RegisterSetting)]
 pub struct ProjectPanelSettings {
     pub button: bool,
     pub hide_gitignore: bool,

crates/project_panel/src/project_panel_tests.rs 🔗

@@ -7333,14 +7333,8 @@ fn init_test(cx: &mut TestAppContext) {
     cx.update(|cx| {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
-        init_settings(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        language::init(cx);
-        editor::init_settings(cx);
         crate::init(cx);
-        workspace::init_settings(cx);
-        client::init_settings(cx);
-        Project::init_settings(cx);
 
         cx.update_global::<SettingsStore, _>(|store, cx| {
             store.update_user_settings(cx, |settings| {
@@ -7358,12 +7352,9 @@ fn init_test_with_editor(cx: &mut TestAppContext) {
     cx.update(|cx| {
         let app_state = AppState::test(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        init_settings(cx);
-        language::init(cx);
         editor::init(cx);
         crate::init(cx);
         workspace::init(app_state, cx);
-        Project::init_settings(cx);
 
         cx.update_global::<SettingsStore, _>(|store, cx| {
             store.update_user_settings(cx, |settings| {

crates/project_symbols/src/project_symbols.rs 🔗

@@ -439,9 +439,6 @@ mod tests {
             cx.set_global(store);
             theme::init(theme::LoadThemes::JustBase, cx);
             release_channel::init(SemanticVersion::default(), cx);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
             editor::init(cx);
         });
     }

crates/recent_projects/src/recent_projects.rs 🔗

@@ -34,8 +34,6 @@ use workspace::{
 use zed_actions::{OpenRecent, OpenRemote};
 
 pub fn init(cx: &mut App) {
-    SshSettings::register(cx);
-
     #[cfg(target_os = "windows")]
     cx.on_action(|open_wsl: &zed_actions::wsl_actions::OpenFolderInWsl, cx| {
         let create_new_window = open_wsl.create_new_window;
@@ -762,10 +760,9 @@ impl Render for MatchTooltip {
 mod tests {
     use std::path::PathBuf;
 
-    use dap::debugger_settings::DebuggerSettings;
     use editor::Editor;
     use gpui::{TestAppContext, UpdateGlobal, WindowHandle};
-    use project::Project;
+
     use serde_json::json;
     use settings::SettingsStore;
     use util::path;
@@ -911,12 +908,8 @@ mod tests {
     fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
         cx.update(|cx| {
             let state = AppState::test(cx);
-            language::init(cx);
             crate::init(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            DebuggerSettings::register(cx);
-            Project::init_settings(cx);
             state
         })
     }

crates/recent_projects/src/remote_connections.rs 🔗

@@ -23,7 +23,7 @@ use remote::{
     SshConnectionOptions,
 };
 pub use settings::SshConnection;
-use settings::{ExtendingVec, Settings, WslConnection};
+use settings::{ExtendingVec, RegisterSetting, Settings, WslConnection};
 use theme::ThemeSettings;
 use ui::{
     ActiveTheme, Color, CommonAnimationExt, Context, Icon, IconName, IconSize, InteractiveElement,
@@ -32,6 +32,7 @@ use ui::{
 use util::paths::PathWithPosition;
 use workspace::{AppState, ModalView, Workspace};
 
+#[derive(RegisterSetting)]
 pub struct SshSettings {
     pub ssh_connections: ExtendingVec<SshConnection>,
     pub wsl_connections: ExtendingVec<WslConnection>,

crates/remote_server/src/headless_project.rs 🔗

@@ -28,7 +28,7 @@ use rpc::{
     proto::{self, REMOTE_SERVER_PEER_ID, REMOTE_SERVER_PROJECT_ID},
 };
 
-use settings::{Settings as _, initial_server_settings_content};
+use settings::initial_server_settings_content;
 use smol::stream::StreamExt;
 use std::{
     num::NonZeroU64,
@@ -74,9 +74,6 @@ pub struct HeadlessAppState {
 impl HeadlessProject {
     pub fn init(cx: &mut App) {
         settings::init(cx);
-        language::init(cx);
-        project::Project::init_settings(cx);
-        extension_host::ExtensionSettings::register(cx);
         log_store::init(true, cx);
     }
 

crates/remote_server/src/remote_editing_tests.rs 🔗

@@ -1493,10 +1493,7 @@ async fn test_remote_git_diffs_when_recv_update_repository_delay(
         .await
         .unwrap();
     let buffer_id = cx.update(|cx| buffer.read(cx).remote_id());
-    cx.update(|cx| {
-        workspace::init_settings(cx);
-        editor::init_settings(cx);
-    });
+
     let cx = cx.add_empty_window();
     let editor = cx.new_window_entity(|window, cx| {
         Editor::for_buffer(buffer, Some(project.clone()), window, cx)
@@ -1853,8 +1850,6 @@ pub async fn init_test(
     let proxy = Arc::new(ExtensionHostProxy::new());
     server_cx.update(HeadlessProject::init);
     let headless = server_cx.new(|cx| {
-        client::init_settings(cx);
-
         HeadlessProject::new(
             crate::HeadlessAppState {
                 session: ssh_server_client,
@@ -1906,7 +1901,6 @@ fn build_project(ssh: Entity<RemoteClient>, cx: &mut TestAppContext) -> Entity<P
 
     cx.update(|cx| {
         Project::init(&client, cx);
-        language::init(cx);
     });
 
     cx.update(|cx| Project::remote(ssh, client, node, user_store, languages, fs, cx))

crates/remote_server/src/unix.rs 🔗

@@ -397,8 +397,6 @@ pub fn execute_run(
         log::info!("gpui app started, initializing server");
         let session = start_server(listeners, log_rx, cx);
 
-        client::init_settings(cx);
-
         GitHostingProviderRegistry::set_global(git_hosting_provider_registry, cx);
         git_hosting_providers::init(cx);
         dap_adapters::init(cx);

crates/repl/src/jupyter_settings.rs 🔗

@@ -2,9 +2,9 @@ use collections::HashMap;
 
 use editor::EditorSettings;
 use gpui::App;
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 
-#[derive(Debug, Default)]
+#[derive(Debug, Default, RegisterSetting)]
 pub struct JupyterSettings {
     pub kernel_selections: HashMap<String, String>,
 }

crates/repl/src/repl.rs 🔗

@@ -15,7 +15,6 @@ use async_dispatcher::{Dispatcher, Runnable, set_dispatcher};
 use gpui::{App, PlatformDispatcher};
 use project::Fs;
 pub use runtimelib::ExecutionState;
-use settings::Settings as _;
 
 pub use crate::jupyter_settings::JupyterSettings;
 pub use crate::kernels::{Kernel, KernelSpecification, KernelStatus};
@@ -31,9 +30,6 @@ pub const KERNEL_DOCS_URL: &str = "https://zed.dev/docs/repl#changing-kernels";
 
 pub fn init(fs: Arc<dyn Fs>, cx: &mut App) {
     set_dispatcher(zed_dispatcher(cx));
-    JupyterSettings::register(cx);
-    ::editor::init_settings(cx);
-    ReplSettings::register(cx);
     repl_sessions_ui::init(cx);
     ReplStore::init(fs, cx);
 }

crates/repl/src/repl_settings.rs 🔗

@@ -1,7 +1,7 @@
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 
 /// Settings for configuring REPL display and behavior.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RegisterSetting)]
 pub struct ReplSettings {
     /// Maximum number of lines to keep in REPL's scrollback buffer.
     /// Clamped with [4, 256] range.

crates/search/src/buffer_search.rs 🔗

@@ -1532,7 +1532,6 @@ mod tests {
     };
     use gpui::{Hsla, TestAppContext, UpdateGlobal, VisualTestContext};
     use language::{Buffer, Point};
-    use project::Project;
     use settings::{SearchSettingsContent, SettingsStore};
     use smol::stream::StreamExt as _;
     use unindent::Unindent as _;
@@ -1542,11 +1541,8 @@ mod tests {
         cx.update(|cx| {
             let store = settings::SettingsStore::test(cx);
             cx.set_global(store);
-            workspace::init_settings(cx);
             editor::init(cx);
 
-            language::init(cx);
-            Project::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
             crate::init(cx);
         });

crates/search/src/project_search.rs 🔗

@@ -4547,11 +4547,7 @@ pub mod tests {
 
             theme::init(theme::LoadThemes::JustBase, cx);
 
-            language::init(cx);
-            client::init_settings(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             crate::init(cx);
         });
     }

crates/settings/Cargo.toml 🔗

@@ -25,6 +25,7 @@ futures.workspace = true
 gpui.workspace = true
 inventory.workspace = true
 log.workspace = true
+migrator.workspace = true
 paths.workspace = true
 release_channel.workspace = true
 rust-embed.workspace = true
@@ -40,7 +41,6 @@ smallvec.workspace = true
 strum.workspace = true
 util.workspace = true
 zlog.workspace = true
-migrator.workspace = true
 
 [dev-dependencies]
 fs = { workspace = true, features = ["test-support"] }

crates/settings/src/base_keymap_setting.rs 🔗

@@ -3,12 +3,14 @@ use std::fmt::{Display, Formatter};
 use crate::{self as settings, settings_content::BaseKeymapContent};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 
 /// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
 ///
 /// Default: VSCode
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
+#[derive(
+    Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default, RegisterSetting,
+)]
 pub enum BaseKeymap {
     #[default]
     VSCode,

crates/settings/src/settings.rs 🔗

@@ -9,6 +9,13 @@ mod settings_store;
 mod vscode_import;
 
 pub use settings_content::*;
+pub use settings_macros::RegisterSetting;
+
+#[doc(hidden)]
+pub mod private {
+    pub use crate::settings_store::{RegisteredSetting, SettingValue};
+    pub use inventory;
+}
 
 use gpui::{App, Global};
 use rust_embed::RustEmbed;
@@ -81,7 +88,6 @@ pub struct SettingsAssets;
 pub fn init(cx: &mut App) {
     let settings = SettingsStore::new(cx, &default_settings());
     cx.set_global(settings);
-    BaseKeymap::register(cx);
     SettingsStore::observe_active_settings_profile_name(cx).detach();
 }
 

crates/settings/src/settings_store.rs 🔗

@@ -124,6 +124,14 @@ pub trait Settings: 'static + Send + Sync + Sized {
     }
 }
 
+pub struct RegisteredSetting {
+    pub settings_value: fn() -> Box<dyn AnySettingValue>,
+    pub from_settings: fn(&SettingsContent) -> Box<dyn Any>,
+    pub id: fn() -> TypeId,
+}
+
+inventory::collect!(RegisteredSetting);
+
 #[derive(Clone, Copy, Debug)]
 pub struct SettingsLocation<'a> {
     pub worktree_id: WorktreeId,
@@ -220,13 +228,17 @@ pub enum LocalSettingsKind {
 
 impl Global for SettingsStore {}
 
+#[doc(hidden)]
 #[derive(Debug)]
-struct SettingValue<T> {
-    global_value: Option<T>,
-    local_values: Vec<(WorktreeId, Arc<RelPath>, T)>,
+pub struct SettingValue<T> {
+    #[doc(hidden)]
+    pub global_value: Option<T>,
+    #[doc(hidden)]
+    pub local_values: Vec<(WorktreeId, Arc<RelPath>, T)>,
 }
 
-trait AnySettingValue: 'static + Send + Sync {
+#[doc(hidden)]
+pub trait AnySettingValue: 'static + Send + Sync {
     fn setting_type_name(&self) -> &'static str;
 
     fn from_settings(&self, s: &SettingsContent) -> Box<dyn Any>;
@@ -250,7 +262,7 @@ impl SettingsStore {
         let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
         let default_settings: Rc<SettingsContent> =
             parse_json_with_comments(default_settings).unwrap();
-        Self {
+        let mut this = Self {
             setting_values: Default::default(),
             default_settings: default_settings.clone(),
             global_settings: None,
@@ -268,7 +280,11 @@ impl SettingsStore {
                 }
             }),
             file_errors: BTreeMap::default(),
-        }
+        };
+
+        this.load_settings_types();
+
+        this
     }
 
     pub fn observe_active_settings_profile_name(cx: &mut App) -> gpui::Subscription {
@@ -288,19 +304,34 @@ impl SettingsStore {
 
     /// Add a new type of setting to the store.
     pub fn register_setting<T: Settings>(&mut self) {
-        let setting_type_id = TypeId::of::<T>();
-        let entry = self.setting_values.entry(setting_type_id);
+        self.register_setting_internal(&RegisteredSetting {
+            settings_value: || {
+                Box::new(SettingValue::<T> {
+                    global_value: None,
+                    local_values: Vec::new(),
+                })
+            },
+            from_settings: |content| Box::new(T::from_settings(content)),
+            id: || TypeId::of::<T>(),
+        });
+    }
+
+    fn load_settings_types(&mut self) {
+        for registered_setting in inventory::iter::<RegisteredSetting>() {
+            self.register_setting_internal(registered_setting);
+        }
+    }
+
+    fn register_setting_internal(&mut self, registered_setting: &RegisteredSetting) {
+        let entry = self.setting_values.entry((registered_setting.id)());
 
         if matches!(entry, hash_map::Entry::Occupied(_)) {
             return;
         }
 
-        let setting_value = entry.or_insert(Box::new(SettingValue::<T> {
-            global_value: None,
-            local_values: Vec::new(),
-        }));
-        let value = T::from_settings(&self.merged_settings);
-        setting_value.set_global_value(Box::new(value));
+        let setting_value = entry.or_insert((registered_setting.settings_value)());
+        let value = (registered_setting.from_settings)(&self.merged_settings);
+        setting_value.set_global_value(value);
     }
 
     /// Get the value of a setting.

crates/settings_macros/src/settings_macros.rs 🔗

@@ -76,3 +76,27 @@ pub fn derive_merge_from(input: TokenStream) -> TokenStream {
 
     TokenStream::from(expanded)
 }
+
+/// Registers the setting type with the SettingsStore. Note that you need to
+/// have `gpui` in your dependencies for this to work.
+#[proc_macro_derive(RegisterSetting)]
+pub fn derive_register_setting(input: TokenStream) -> TokenStream {
+    let input = syn::parse_macro_input!(input as DeriveInput);
+    let type_name = &input.ident;
+
+    quote! {
+        settings::private::inventory::submit! {
+            settings::private::RegisteredSetting {
+                settings_value: || {
+                    Box::new(settings::private::SettingValue::<#type_name> {
+                        global_value: None,
+                        local_values: Vec::new(),
+                    })
+                },
+                from_settings: |content| Box::new(<#type_name as settings::Settings>::from_settings(content)),
+                id: || std::any::TypeId::of::<#type_name>(),
+            }
+        }
+    }
+    .into()
+}

crates/settings_profile_selector/src/settings_profile_selector.rs 🔗

@@ -280,10 +280,8 @@ fn display_name(profile_name: &Option<String>) -> String {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use client;
     use editor;
     use gpui::{TestAppContext, UpdateGlobal, VisualTestContext};
-    use language;
     use menu::{Cancel, Confirm, SelectNext, SelectPrevious};
     use project::{FakeFs, Project};
     use serde_json::json;
@@ -302,12 +300,8 @@ mod tests {
             cx.set_global(settings_store);
             settings::init(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            client::init_settings(cx);
-            language::init(cx);
             super::init(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             state
         });
 

crates/settings_ui/src/settings_ui.rs 🔗

@@ -3651,9 +3651,6 @@ pub mod test {
     pub fn register_settings(cx: &mut App) {
         settings::init(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        workspace::init_settings(cx);
-        project::Project::init_settings(cx);
-        language::init(cx);
         editor::init(cx);
         menu::init();
     }

crates/storybook/Cargo.toml 🔗

@@ -26,7 +26,6 @@ language.workspace = true
 log.workspace = true
 menu.workspace = true
 picker.workspace = true
-project.workspace = true
 reqwest_client.workspace = true
 rust-embed.workspace = true
 settings.workspace = true
@@ -36,7 +35,6 @@ strum = { workspace = true, features = ["derive"] }
 theme.workspace = true
 title_bar = { workspace = true, features = ["stories"] }
 ui = { workspace = true, features = ["stories"] }
-workspace.workspace = true
 
 [dev-dependencies]
 gpui = { workspace = true, features = ["test-support"] }

crates/storybook/src/storybook.rs 🔗

@@ -14,14 +14,12 @@ use gpui::{
     div, px, size,
 };
 use log::LevelFilter;
-use project::Project;
 use reqwest_client::ReqwestClient;
 use settings::{KeymapFile, Settings};
 use simplelog::SimpleLogger;
 use strum::IntoEnumIterator;
 use theme::ThemeSettings;
 use ui::prelude::*;
-use workspace;
 
 use crate::app_menus::app_menus;
 use crate::assets::Assets;
@@ -85,10 +83,7 @@ fn main() {
             theme::ThemeSelection::Static(settings::ThemeName(theme_name.into()));
         ThemeSettings::override_global(theme_settings, cx);
 
-        language::init(cx);
         editor::init(cx);
-        Project::init_settings(cx);
-        workspace::init_settings(cx);
         init(cx);
         load_storybook_keymap(cx);
         cx.set_menus(app_menus());

crates/tab_switcher/src/tab_switcher_tests.rs 🔗

@@ -284,11 +284,8 @@ fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
     cx.update(|cx| {
         let state = AppState::test(cx);
         theme::init(theme::LoadThemes::JustBase, cx);
-        language::init(cx);
         super::init(cx);
         editor::init(cx);
-        workspace::init_settings(cx);
-        Project::init_settings(cx);
         state
     })
 }

crates/tasks_ui/src/tasks_ui.rs 🔗

@@ -602,11 +602,8 @@ mod tests {
     pub(crate) fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
         cx.update(|cx| {
             let state = AppState::test(cx);
-            language::init(cx);
             crate::init(cx);
             editor::init(cx);
-            workspace::init_settings(cx);
-            Project::init_settings(cx);
             TaskStore::init(None);
             state
         })

crates/terminal/src/terminal.rs 🔗

@@ -182,10 +182,6 @@ impl EventListener for ZedListener {
     }
 }
 
-pub fn init(cx: &mut App) {
-    TerminalSettings::register(cx);
-}
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub struct TerminalBounds {
     pub cell_width: Pixels,

crates/terminal/src/terminal_settings.rs 🔗

@@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
 
 pub use settings::AlternateScroll;
 use settings::{
-    ShowScrollbar, TerminalBlink, TerminalDockPosition, TerminalLineHeight, VenvSettings,
-    WorkingDirectory, merge_from::MergeFrom,
+    RegisterSetting, ShowScrollbar, TerminalBlink, TerminalDockPosition, TerminalLineHeight,
+    VenvSettings, WorkingDirectory, merge_from::MergeFrom,
 };
 use task::Shell;
 use theme::FontFamilyName;
@@ -19,7 +19,7 @@ pub struct Toolbar {
     pub breadcrumbs: bool,
 }
 
-#[derive(Clone, Debug, Deserialize)]
+#[derive(Clone, Debug, Deserialize, RegisterSetting)]
 pub struct TerminalSettings {
     pub shell: Shell,
     pub working_directory: WorkingDirectory,

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -1971,10 +1971,6 @@ mod tests {
             let store = SettingsStore::test(cx);
             cx.set_global(store);
             theme::init(theme::LoadThemes::JustBase, cx);
-            client::init_settings(cx);
-            language::init(cx);
-            Project::init_settings(cx);
-            workspace::init_settings(cx);
             editor::init(cx);
             crate::init(cx);
         });

crates/terminal_view/src/terminal_path_like_target.rs 🔗

@@ -534,10 +534,7 @@ mod tests {
         let fs = app_cx.update(AppState::test).fs.as_fake().clone();
 
         app_cx.update(|cx| {
-            terminal::init(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            Project::init_settings(cx);
-            language::init(cx);
             editor::init(cx);
         });
 

crates/terminal_view/src/terminal_view.rs 🔗

@@ -95,7 +95,6 @@ actions!(
 pub fn init(cx: &mut App) {
     assistant_slash_command::init(cx);
     terminal_panel::init(cx);
-    terminal::init(cx);
 
     register_serializable_item::<TerminalView>(cx);
 
@@ -1692,10 +1691,7 @@ mod tests {
     pub async fn init_test(cx: &mut TestAppContext) -> (Entity<Project>, Entity<Workspace>) {
         let params = cx.update(AppState::test);
         cx.update(|cx| {
-            terminal::init(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
-            Project::init_settings(cx);
-            language::init(cx);
         });
 
         let project = Project::test(params.fs.clone(), [], cx).await;

crates/theme/src/settings.rs 🔗

@@ -12,7 +12,7 @@ use refineable::Refineable;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 pub use settings::{FontFamilyName, IconThemeName, ThemeMode, ThemeName};
-use settings::{Settings, SettingsContent};
+use settings::{RegisterSetting, Settings, SettingsContent};
 use std::sync::Arc;
 
 const MIN_FONT_SIZE: Pixels = px(6.0);
@@ -94,7 +94,7 @@ impl From<settings::UiDensity> for UiDensity {
 }
 
 /// Customizable settings for the UI and theme system.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, PartialEq, RegisterSetting)]
 pub struct ThemeSettings {
     /// The UI font size. Determines the size of text in the UI,
     /// as well as the size of a [gpui::Rems] unit.

crates/theme/src/theme.rs 🔗

@@ -108,7 +108,6 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut App) {
         ThemeRegistry::global(cx).load_bundled_themes();
     }
 
-    ThemeSettings::register(cx);
     FontFamilyCache::init_global(cx);
 
     let theme = GlobalTheme::configured_theme(cx);

crates/title_bar/src/title_bar.rs 🔗

@@ -66,7 +66,6 @@ actions!(
 );
 
 pub fn init(cx: &mut App) {
-    TitleBarSettings::register(cx);
     SystemWindowTabs::init(cx);
 
     cx.observe_new(|workspace: &mut Workspace, window, cx| {

crates/title_bar/src/title_bar_settings.rs 🔗

@@ -1,6 +1,6 @@
-use settings::{Settings, SettingsContent};
+use settings::{RegisterSetting, Settings, SettingsContent};
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, RegisterSetting)]
 pub struct TitleBarSettings {
     pub show_branch_icon: bool,
     pub show_onboarding_banner: bool,

crates/vim/src/test/vim_test_context.rs 🔗

@@ -25,10 +25,6 @@ impl VimTestContext {
             git_ui::init(cx);
             crate::init(cx);
             search::init(cx);
-            workspace::init_settings(cx);
-            language::init(cx);
-            editor::init_settings(cx);
-            project::Project::init_settings(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
             settings_ui::init(cx);
         });

crates/vim/src/vim.rs 🔗

@@ -40,6 +40,7 @@ use normal::search::SearchSubmit;
 use object::Object;
 use schemars::JsonSchema;
 use serde::Deserialize;
+use settings::RegisterSetting;
 pub use settings::{
     ModeContent, Settings, SettingsStore, UseSystemClipboard, update_settings_file,
 };
@@ -268,8 +269,6 @@ actions!(
 
 /// Initializes the `vim` crate.
 pub fn init(cx: &mut App) {
-    vim_mode_setting::init(cx);
-    VimSettings::register(cx);
     VimGlobals::register(cx);
 
     cx.observe_new(Vim::register).detach();
@@ -1943,6 +1942,7 @@ impl Vim {
     }
 }
 
+#[derive(RegisterSetting)]
 struct VimSettings {
     pub default_mode: Mode,
     pub toggle_relative_line_numbers: bool,

crates/vim_mode_setting/src/vim_mode_setting.rs 🔗

@@ -4,15 +4,9 @@
 //! disable Vim/Helix modes without having to depend on the `vim` crate in its
 //! entirety.
 
-use gpui::App;
-use settings::{Settings, SettingsContent};
-
-/// Initializes the `vim_mode_setting` crate.
-pub fn init(cx: &mut App) {
-    VimModeSetting::register(cx);
-    HelixModeSetting::register(cx);
-}
+use settings::{RegisterSetting, Settings, SettingsContent};
 
+#[derive(RegisterSetting)]
 pub struct VimModeSetting(pub bool);
 
 impl Settings for VimModeSetting {
@@ -21,6 +15,7 @@ impl Settings for VimModeSetting {
     }
 }
 
+#[derive(RegisterSetting)]
 pub struct HelixModeSetting(pub bool);
 
 impl Settings for HelixModeSetting {

crates/workspace/src/item.rs 🔗

@@ -17,7 +17,8 @@ use gpui::{
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 pub use settings::{
-    ActivateOnClose, ClosePosition, Settings, SettingsLocation, ShowCloseButton, ShowDiagnostics,
+    ActivateOnClose, ClosePosition, RegisterSetting, Settings, SettingsLocation, ShowCloseButton,
+    ShowDiagnostics,
 };
 use smallvec::SmallVec;
 use std::{
@@ -50,6 +51,7 @@ impl Default for SaveOptions {
     }
 }
 
+#[derive(RegisterSetting)]
 pub struct ItemSettings {
     pub git_status: bool,
     pub close_position: ClosePosition,
@@ -59,6 +61,7 @@ pub struct ItemSettings {
     pub show_close_button: ShowCloseButton,
 }
 
+#[derive(RegisterSetting)]
 pub struct PreviewTabsSettings {
     pub enabled: bool,
     pub enable_preview_from_file_finder: bool,

crates/workspace/src/pane.rs 🔗

@@ -6873,8 +6873,6 @@ mod tests {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
             theme::init(LoadThemes::JustBase, cx);
-            crate::init_settings(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/workspace/src/workspace.rs 🔗

@@ -527,14 +527,6 @@ impl From<WorkspaceId> for i64 {
     }
 }
 
-pub fn init_settings(cx: &mut App) {
-    WorkspaceSettings::register(cx);
-    ItemSettings::register(cx);
-    PreviewTabsSettings::register(cx);
-    TabBarSettings::register(cx);
-    StatusBarSettings::register(cx);
-}
-
 fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, cx: &mut App) {
     let paths = cx.prompt_for_paths(options);
     cx.spawn(
@@ -568,7 +560,6 @@ fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, c
 }
 
 pub fn init(app_state: Arc<AppState>, cx: &mut App) {
-    init_settings(cx);
     component::init();
     theme_preview::init(cx);
     toast_layer::init(cx);
@@ -987,7 +978,6 @@ impl AppState {
 
         theme::init(theme::LoadThemes::JustBase, cx);
         client::init(&client, cx);
-        crate::init_settings(cx);
 
         Arc::new(Self {
             client,
@@ -11341,9 +11331,6 @@ mod tests {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
             theme::init(theme::LoadThemes::JustBase, cx);
-            language::init(cx);
-            crate::init_settings(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/workspace/src/workspace_settings.rs 🔗

@@ -3,13 +3,12 @@ use std::num::NonZeroUsize;
 use crate::DockPosition;
 use collections::HashMap;
 use serde::Deserialize;
-pub use settings::AutosaveSetting;
 pub use settings::{
-    BottomDockLayout, PaneSplitDirectionHorizontal, PaneSplitDirectionVertical,
-    RestoreOnStartupBehavior,
+    AutosaveSetting, BottomDockLayout, InactiveOpacity, PaneSplitDirectionHorizontal,
+    PaneSplitDirectionVertical, RegisterSetting, RestoreOnStartupBehavior, Settings,
 };
-use settings::{InactiveOpacity, Settings};
 
+#[derive(RegisterSetting)]
 pub struct WorkspaceSettings {
     pub active_pane_modifiers: ActivePanelModifiers,
     pub bottom_dock_layout: settings::BottomDockLayout,
@@ -53,7 +52,7 @@ pub struct ActivePanelModifiers {
     pub inactive_opacity: Option<InactiveOpacity>,
 }
 
-#[derive(Deserialize)]
+#[derive(Deserialize, RegisterSetting)]
 pub struct TabBarSettings {
     pub show: bool,
     pub show_nav_history_buttons: bool,
@@ -121,7 +120,7 @@ impl Settings for TabBarSettings {
     }
 }
 
-#[derive(Deserialize)]
+#[derive(Deserialize, RegisterSetting)]
 pub struct StatusBarSettings {
     pub show: bool,
     pub active_language_button: bool,

crates/worktree/src/worktree_settings.rs 🔗

@@ -1,14 +1,14 @@
 use std::path::Path;
 
 use anyhow::Context as _;
-use settings::Settings;
+use settings::{RegisterSetting, Settings};
 use util::{
     ResultExt,
     paths::{PathMatcher, PathStyle},
     rel_path::RelPath,
 };
 
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, RegisterSetting)]
 pub struct WorktreeSettings {
     pub project_name: Option<String>,
     /// Whether to prevent this project from being shared in public channels.

crates/worktree/src/worktree_tests.rs 🔗

@@ -1,7 +1,4 @@
-use crate::{
-    Entry, EntryKind, Event, PathChange, Worktree, WorktreeModelHandle,
-    worktree_settings::WorktreeSettings,
-};
+use crate::{Entry, EntryKind, Event, PathChange, Worktree, WorktreeModelHandle};
 use anyhow::Result;
 use fs::{FakeFs, Fs, RealFs, RemoveOptions};
 use git::GITIGNORE;
@@ -12,7 +9,7 @@ use pretty_assertions::assert_eq;
 use rand::prelude::*;
 
 use serde_json::json;
-use settings::{Settings, SettingsStore};
+use settings::SettingsStore;
 use std::{
     env,
     fmt::Write,
@@ -2269,6 +2266,5 @@ fn init_test(cx: &mut gpui::TestAppContext) {
     cx.update(|cx| {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
-        WorktreeSettings::register(cx);
     });
 }

crates/worktree_benchmarks/src/main.rs 🔗

@@ -19,7 +19,6 @@ fn main() {
 
     app.run(|cx| {
         settings::init(cx);
-        WorktreeSettings::register(cx);
         let fs = Arc::new(RealFs::new(None, cx.background_executor().clone()));
 
         cx.spawn(async move |cx| {

crates/zed/src/main.rs 🔗

@@ -409,7 +409,7 @@ pub fn main() {
             handle_settings_changed,
         );
         handle_keymap_file_changes(user_keymap_file_rx, cx);
-        client::init_settings(cx);
+
         let user_agent = format!(
             "Zed/{} ({}; {})",
             AppVersion::global(cx),
@@ -468,7 +468,6 @@ pub fn main() {
         let node_runtime = NodeRuntime::new(client.http_client(), Some(shell_env_loaded_rx), rx);
 
         debug_adapter_extension::init(extension_host_proxy.clone(), cx);
-        language::init(cx);
         languages::init(languages.clone(), fs.clone(), node_runtime.clone(), cx);
         let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
         let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx));
@@ -573,7 +572,6 @@ pub fn main() {
         supermaven::init(app_state.client.clone(), cx);
         language_model::init(app_state.client.clone(), cx);
         language_models::init(app_state.user_store.clone(), app_state.client.clone(), cx);
-        agent_settings::init(cx);
         acp_tools::init(cx);
         zeta2_tools::init(cx);
         web_search::init(cx);

crates/zed/src/zed.rs 🔗

@@ -1408,9 +1408,6 @@ pub fn handle_keymap_file_changes(
     mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
     cx: &mut App,
 ) {
-    BaseKeymap::register(cx);
-    vim_mode_setting::init(cx);
-
     let (base_keymap_tx, mut base_keymap_rx) = mpsc::unbounded();
     let (keyboard_layout_tx, mut keyboard_layout_rx) = mpsc::unbounded();
     let mut old_base_keymap = *BaseKeymap::get_global(cx);
@@ -4331,10 +4328,8 @@ mod tests {
 
             theme::init(theme::LoadThemes::JustBase, cx);
             client::init(&app_state.client, cx);
-            language::init(cx);
             workspace::init(app_state.clone(), cx);
             onboarding::init(cx);
-            Project::init_settings(cx);
             app_state
         })
     }
@@ -4797,21 +4792,17 @@ mod tests {
 
             let state = Arc::get_mut(&mut app_state).unwrap();
             state.build_window_options = build_window_options;
-
             app_state.languages.add(markdown_language());
 
             gpui_tokio::init(cx);
-            vim_mode_setting::init(cx);
             theme::init(theme::LoadThemes::JustBase, cx);
             audio::init(cx);
             channel::init(&app_state.client, app_state.user_store.clone(), cx);
             call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
             notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx);
             workspace::init(app_state.clone(), cx);
-            Project::init_settings(cx);
             release_channel::init(SemanticVersion::default(), cx);
             command_palette::init(cx);
-            language::init(cx);
             editor::init(cx);
             collab_ui::init(&app_state, cx);
             git_ui::init(cx);

crates/zed/src/zed/open_listener.rs 🔗

@@ -665,9 +665,6 @@ mod tests {
     #[gpui::test]
     fn test_parse_ssh_url(cx: &mut TestAppContext) {
         let _app_state = init_test(cx);
-        cx.update(|cx| {
-            SshSettings::register(cx);
-        });
         let request = cx.update(|cx| {
             OpenRequest::parse(
                 RawOpenRequest {

crates/zeta/src/license_detection.rs 🔗

@@ -390,8 +390,7 @@ mod tests {
     use gpui::TestAppContext;
     use rand::Rng as _;
     use serde_json::json;
-    use settings::{Settings as _, SettingsStore};
-    use worktree::WorktreeSettings;
+    use settings::SettingsStore;
 
     use super::*;
 
@@ -720,7 +719,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            WorktreeSettings::register(cx);
         });
     }
 

crates/zeta/src/zeta.rs 🔗

@@ -2079,9 +2079,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            client::init_settings(cx);
-            Project::init_settings(cx);
         });
     }
 

crates/zeta2/src/udiff.rs 🔗

@@ -1015,8 +1015,6 @@ mod tests {
         cx.update(|cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            Project::init_settings(cx);
-            language::init(cx);
         });
 
         FakeFs::new(cx.background_executor.clone())

crates/zeta2/src/zeta2.rs 🔗

@@ -2095,8 +2095,6 @@ mod tests {
         cx.update(move |cx| {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
-            language::init(cx);
-            Project::init_settings(cx);
             zlog::init_test();
 
             let (req_tx, req_rx) = mpsc::unbounded();

crates/zeta_cli/src/headless.rs 🔗

@@ -7,7 +7,6 @@ use gpui_tokio::Tokio;
 use language::LanguageRegistry;
 use language_extension::LspAccess;
 use node_runtime::{NodeBinaryOptions, NodeRuntime};
-use project::Project;
 use project::project_settings::ProjectSettings;
 use release_channel::AppVersion;
 use reqwest_client::ReqwestClient;
@@ -33,7 +32,6 @@ pub fn init(cx: &mut App) -> ZetaCliAppState {
 
     let settings_store = SettingsStore::new(cx, &settings::default_settings());
     cx.set_global(settings_store);
-    client::init_settings(cx);
 
     // Set User-Agent so we can download language servers from GitHub
     let user_agent = format!(
@@ -55,8 +53,6 @@ pub fn init(cx: &mut App) -> ZetaCliAppState {
     };
     cx.set_http_client(Arc::new(http));
 
-    Project::init_settings(cx);
-
     let client = Client::production(cx);
     cx.set_http_client(client.http_client());
 
@@ -102,7 +98,6 @@ pub fn init(cx: &mut App) -> ZetaCliAppState {
 
     let extension_host_proxy = ExtensionHostProxy::global(cx);
 
-    language::init(cx);
     debug_adapter_extension::init(extension_host_proxy.clone(), cx);
     language_extension::init(LspAccess::Noop, extension_host_proxy, languages.clone());
     language_model::init(client.clone(), cx);

crates/zlog_settings/src/zlog_settings.rs 🔗

@@ -2,11 +2,9 @@
 use collections::HashMap;
 
 use gpui::App;
-use settings::{Settings, SettingsStore};
+use settings::{RegisterSetting, Settings, SettingsStore};
 
 pub fn init(cx: &mut App) {
-    ZlogSettings::register(cx);
-
     cx.observe_global::<SettingsStore>(|cx| {
         let zlog_settings = ZlogSettings::get_global(cx);
         zlog::filter::refresh_from_settings(&zlog_settings.scopes);
@@ -14,7 +12,7 @@ pub fn init(cx: &mut App) {
     .detach();
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RegisterSetting)]
 pub struct ZlogSettings {
     /// A map of log scopes to the desired log level.
     /// Useful for filtering out noisy logs or enabling more verbose logging.