diff --git a/Cargo.lock b/Cargo.lock index f01022e294..794f5ffd8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4873,6 +4873,7 @@ dependencies = [ name = "project_panel" version = "0.1.0" dependencies = [ + "client", "context_menu", "drag_and_drop", "editor", diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index f1aee9540e..041126271d 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -70,10 +70,14 @@ pub const CONNECTION_TIMEOUT: Duration = Duration::from_secs(5); actions!(client, [SignIn, SignOut]); -pub fn init(client: &Arc, cx: &mut AppContext) { - let client = Arc::downgrade(client); +pub fn init_settings(cx: &mut AppContext) { settings::register_setting::(cx); +} +pub fn init(client: &Arc, cx: &mut AppContext) { + init_settings(cx); + + let client = Arc::downgrade(client); cx.add_global_action({ let client = client.clone(); move |_: &SignIn, cx| { diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index 02e5fa56e4..a69a08fedf 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -186,11 +186,6 @@ impl TestServer { }) }); - cx.update(|cx| { - client::init(&client, cx); - language::init(cx); - }); - let fs = FakeFs::new(cx.background()); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx)); let app_state = Arc::new(workspace::AppState { @@ -205,8 +200,11 @@ impl TestServer { background_actions: || &[], }); - Project::init(&client); cx.update(|cx| { + Project::init(&client); + client::init(&client, cx); + language::init(cx); + editor::init_settings(cx); workspace::init(app_state.clone(), cx); call::init(client.clone(), user_store.clone(), cx); }); diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 2896c47808..5d1a915887 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -27,7 +27,7 @@ use lsp::LanguageServerId; use project::{search::SearchQuery, DiagnosticSummary, HoverBlockKind, Project, ProjectPath}; use rand::prelude::*; use serde_json::json; -use settings::{SettingsStore}; +use settings::SettingsStore; use std::{ cell::{Cell, RefCell}, env, future, mem, @@ -1439,7 +1439,6 @@ async fn test_host_disconnect( cx_b: &mut TestAppContext, cx_c: &mut TestAppContext, ) { - cx_b.update(editor::init); deterministic.forbid_parking(); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; @@ -1449,6 +1448,8 @@ async fn test_host_disconnect( .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)]) .await; + cx_b.update(editor::init); + client_a .fs .insert_tree( @@ -1546,7 +1547,6 @@ async fn test_project_reconnect( cx_a: &mut TestAppContext, cx_b: &mut TestAppContext, ) { - cx_b.update(editor::init); deterministic.forbid_parking(); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; @@ -1555,6 +1555,8 @@ async fn test_project_reconnect( .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)]) .await; + cx_b.update(editor::init); + client_a .fs .insert_tree( @@ -4992,7 +4994,6 @@ async fn test_collaborating_with_code_actions( cx_b: &mut TestAppContext, ) { deterministic.forbid_parking(); - cx_b.update(editor::init); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; let client_b = server.create_client(cx_b, "user_b").await; @@ -5001,6 +5002,8 @@ async fn test_collaborating_with_code_actions( .await; let active_call_a = cx_a.read(ActiveCall::global); + cx_b.update(editor::init); + // Set up a fake language server. let mut language = Language::new( LanguageConfig { @@ -5205,7 +5208,6 @@ async fn test_collaborating_with_renames( cx_b: &mut TestAppContext, ) { deterministic.forbid_parking(); - cx_b.update(editor::init); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; let client_b = server.create_client(cx_b, "user_b").await; @@ -5214,6 +5216,8 @@ async fn test_collaborating_with_renames( .await; let active_call_a = cx_a.read(ActiveCall::global); + cx_b.update(editor::init); + // Set up a fake language server. let mut language = Language::new( LanguageConfig { @@ -5395,8 +5399,6 @@ async fn test_language_server_statuses( cx_b: &mut TestAppContext, ) { deterministic.forbid_parking(); - - cx_b.update(editor::init); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; let client_b = server.create_client(cx_b, "user_b").await; @@ -5405,6 +5407,8 @@ async fn test_language_server_statuses( .await; let active_call_a = cx_a.read(ActiveCall::global); + cx_b.update(editor::init); + // Set up a fake language server. let mut language = Language::new( LanguageConfig { @@ -6112,8 +6116,6 @@ async fn test_basic_following( cx_d: &mut TestAppContext, ) { deterministic.forbid_parking(); - cx_a.update(editor::init); - cx_b.update(editor::init); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; @@ -6131,6 +6133,9 @@ async fn test_basic_following( let active_call_a = cx_a.read(ActiveCall::global); let active_call_b = cx_b.read(ActiveCall::global); + cx_a.update(editor::init); + cx_b.update(editor::init); + client_a .fs .insert_tree( @@ -6709,9 +6714,6 @@ async fn test_following_tab_order( cx_a: &mut TestAppContext, cx_b: &mut TestAppContext, ) { - cx_a.update(editor::init); - cx_b.update(editor::init); - let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; let client_b = server.create_client(cx_b, "user_b").await; @@ -6721,6 +6723,9 @@ async fn test_following_tab_order( let active_call_a = cx_a.read(ActiveCall::global); let active_call_b = cx_b.read(ActiveCall::global); + cx_a.update(editor::init); + cx_b.update(editor::init); + client_a .fs .insert_tree( @@ -6831,9 +6836,6 @@ async fn test_peers_following_each_other( cx_b: &mut TestAppContext, ) { deterministic.forbid_parking(); - cx_a.update(editor::init); - cx_b.update(editor::init); - let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; let client_b = server.create_client(cx_b, "user_b").await; @@ -6843,6 +6845,9 @@ async fn test_peers_following_each_other( let active_call_a = cx_a.read(ActiveCall::global); let active_call_b = cx_b.read(ActiveCall::global); + cx_a.update(editor::init); + cx_b.update(editor::init); + // Client A shares a project. client_a .fs @@ -7002,8 +7007,6 @@ async fn test_auto_unfollowing( cx_b: &mut TestAppContext, ) { deterministic.forbid_parking(); - cx_a.update(editor::init); - cx_b.update(editor::init); // 2 clients connect to a server. let mut server = TestServer::start(&deterministic).await; @@ -7015,6 +7018,9 @@ async fn test_auto_unfollowing( let active_call_a = cx_a.read(ActiveCall::global); let active_call_b = cx_b.read(ActiveCall::global); + cx_a.update(editor::init); + cx_b.update(editor::init); + // Client A shares a project. client_a .fs @@ -7169,8 +7175,6 @@ async fn test_peers_simultaneously_following_each_other( cx_b: &mut TestAppContext, ) { deterministic.forbid_parking(); - cx_a.update(editor::init); - cx_b.update(editor::init); let mut server = TestServer::start(&deterministic).await; let client_a = server.create_client(cx_a, "user_a").await; @@ -7180,6 +7184,9 @@ async fn test_peers_simultaneously_following_each_other( .await; let active_call_a = cx_a.read(ActiveCall::global); + cx_a.update(editor::init); + cx_b.update(editor::init); + client_a.fs.insert_tree("/a", json!({})).await; let (project_a, _) = client_a.build_local_project("/a", cx_a).await; let workspace_a = client_a.build_workspace(&project_a, cx_a); diff --git a/crates/editor/src/blink_manager.rs b/crates/editor/src/blink_manager.rs index 409b6f9b03..303d0960ed 100644 --- a/crates/editor/src/blink_manager.rs +++ b/crates/editor/src/blink_manager.rs @@ -1,8 +1,8 @@ -use std::time::Duration; - +use crate::EditorSettings; use gpui::{Entity, ModelContext}; use settings::Settings; use smol::Timer; +use std::time::Duration; pub struct BlinkManager { blink_interval: Duration, @@ -64,7 +64,7 @@ impl BlinkManager { } fn blink_cursors(&mut self, epoch: usize, cx: &mut ModelContext) { - if cx.global::().cursor_blink { + if settings::get_setting::(None, cx).cursor_blink { if epoch == self.blink_epoch && self.enabled && !self.blinking_paused { self.visible = !self.visible; cx.notify(); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 41087c6eaa..791f67be29 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1,5 +1,6 @@ mod blink_manager; pub mod display_map; +mod editor_settings; mod element; mod git; @@ -28,6 +29,7 @@ use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque}; use copilot::Copilot; pub use display_map::DisplayPoint; use display_map::*; +pub use editor_settings::EditorSettings; pub use element::*; use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; @@ -287,7 +289,12 @@ pub enum Direction { Next, } +pub fn init_settings(cx: &mut AppContext) { + settings::register_setting::(cx); +} + pub fn init(cx: &mut AppContext) { + init_settings(cx); cx.add_action(Editor::new_file); cx.add_action(Editor::cancel); cx.add_action(Editor::newline); @@ -2354,7 +2361,7 @@ impl Editor { } fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext) { - if !cx.global::().show_completions_on_input { + if !settings::get_setting::(None, cx).show_completions_on_input { return; } diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs new file mode 100644 index 0000000000..ed100d0a01 --- /dev/null +++ b/crates/editor/src/editor_settings.rs @@ -0,0 +1,34 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use settings::Setting; + +#[derive(Deserialize)] +pub struct EditorSettings { + pub cursor_blink: bool, + pub hover_popover_enabled: bool, + pub show_completions_on_input: bool, +} + +#[derive(Clone, Serialize, Deserialize, JsonSchema)] +pub struct EditorSettingsContent { + pub cursor_blink: Option, + pub hover_popover_enabled: Option, + pub show_completions_on_input: Option, +} + +impl Setting for EditorSettings { + const KEY: Option<&'static str> = None; + + type FileContent = EditorSettingsContent; + + fn load( + default_value: &Self::FileContent, + user_values: &[&Self::FileContent], + _: &gpui::AppContext, + ) -> anyhow::Result + where + Self: Sized, + { + Self::load_via_json_merge(default_value, user_values) + } +} diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 7ee6a52955..6f40b157a1 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -4697,8 +4697,10 @@ async fn test_completion(cx: &mut gpui::TestAppContext) { apply_additional_edits.await.unwrap(); cx.update(|cx| { - cx.update_global::(|settings, _| { - settings.show_completions_on_input = false; + cx.update_global::(|settings, cx| { + settings.update_user_settings::(cx, |settings| { + settings.show_completions_on_input = Some(false); + }); }) }); cx.set_state("editorĖ‡"); diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index c40cb0fbe3..89626c3ea4 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -1,6 +1,6 @@ use crate::{ - display_map::ToDisplayPoint, Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSnapshot, - EditorStyle, RangeToAnchorExt, + display_map::ToDisplayPoint, Anchor, AnchorRangeExt, DisplayPoint, Editor, EditorSettings, + EditorSnapshot, EditorStyle, RangeToAnchorExt, }; use futures::FutureExt; use gpui::{ @@ -38,7 +38,7 @@ pub fn hover(editor: &mut Editor, _: &Hover, cx: &mut ViewContext) { /// The internal hover action dispatches between `show_hover` or `hide_hover` /// depending on whether a point to hover over is provided. pub fn hover_at(editor: &mut Editor, point: Option, cx: &mut ViewContext) { - if cx.global::().hover_popover_enabled { + if settings::get_setting::(None, cx).hover_popover_enabled { if let Some(point) = point { show_hover(editor, point, false, cx); } else { diff --git a/crates/project_panel/Cargo.toml b/crates/project_panel/Cargo.toml index d52ec403fb..6fcdf06d2c 100644 --- a/crates/project_panel/Cargo.toml +++ b/crates/project_panel/Cargo.toml @@ -24,6 +24,7 @@ futures.workspace = true unicase = "2.6" [dev-dependencies] +client = { path = "../client", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } editor = { path = "../editor", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 97684d874a..d36536f334 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1935,6 +1935,7 @@ mod tests { cx.update(|cx| { cx.set_global(SettingsStore::test(cx)); language::init(cx); + editor::init_settings(cx); }); } } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 4dc947e5f6..e869efcd5c 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -1281,11 +1281,13 @@ pub mod tests { cx.update(|cx| { cx.set_global(SettingsStore::test(cx)); cx.set_global(ActiveSearches::default()); + let mut settings = Settings::test(cx); settings.theme = Arc::new(theme); cx.set_global(settings); language::init(cx); + editor::init_settings(cx); }); } } diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index f5e50aaffb..438dc0d02e 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -38,10 +38,7 @@ pub struct Settings { pub buffer_font_family: FamilyId, pub buffer_font_size: f32, pub active_pane_magnification: f32, - pub cursor_blink: bool, pub confirm_quit: bool, - pub hover_popover_enabled: bool, - pub show_completions_on_input: bool, pub show_call_status_icon: bool, pub autosave: Autosave, pub default_dock_anchor: DockAnchor, @@ -78,9 +75,6 @@ impl Setting for Settings { buffer_font_size: defaults.buffer_font_size.unwrap(), active_pane_magnification: defaults.active_pane_magnification.unwrap(), confirm_quit: defaults.confirm_quit.unwrap(), - cursor_blink: defaults.cursor_blink.unwrap(), - hover_popover_enabled: defaults.hover_popover_enabled.unwrap(), - show_completions_on_input: defaults.show_completions_on_input.unwrap(), show_call_status_icon: defaults.show_call_status_icon.unwrap(), autosave: defaults.autosave.unwrap(), default_dock_anchor: defaults.default_dock_anchor.unwrap(), @@ -341,9 +335,6 @@ impl Settings { buffer_font_size: defaults.buffer_font_size.unwrap(), active_pane_magnification: defaults.active_pane_magnification.unwrap(), confirm_quit: defaults.confirm_quit.unwrap(), - cursor_blink: defaults.cursor_blink.unwrap(), - hover_popover_enabled: defaults.hover_popover_enabled.unwrap(), - show_completions_on_input: defaults.show_completions_on_input.unwrap(), show_call_status_icon: defaults.show_call_status_icon.unwrap(), autosave: defaults.autosave.unwrap(), default_dock_anchor: defaults.default_dock_anchor.unwrap(), @@ -391,13 +382,7 @@ impl Settings { &mut self.active_pane_magnification, data.active_pane_magnification, ); - merge(&mut self.cursor_blink, data.cursor_blink); merge(&mut self.confirm_quit, data.confirm_quit); - merge(&mut self.hover_popover_enabled, data.hover_popover_enabled); - merge( - &mut self.show_completions_on_input, - data.show_completions_on_input, - ); merge(&mut self.autosave, data.autosave); merge(&mut self.default_dock_anchor, data.default_dock_anchor); merge(&mut self.base_keymap, data.base_keymap); @@ -426,9 +411,6 @@ impl Settings { buffer_font_size: 14., active_pane_magnification: 1., confirm_quit: false, - cursor_blink: true, - hover_popover_enabled: true, - show_completions_on_input: true, show_call_status_icon: true, autosave: Autosave::Off, default_dock_anchor: DockAnchor::Bottom,