diff --git a/Cargo.lock b/Cargo.lock index b76445011cbb70b0e0fe88c83471be58714cb65d..d380fa4306560cf0aa9014e544d4e76f54ca98f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,6 +729,7 @@ dependencies = [ "language", "project", "search", + "settings", "theme", "workspace", ] @@ -881,6 +882,7 @@ dependencies = [ "editor", "gpui", "postage", + "settings", "theme", "time 0.3.7", "util", @@ -1131,6 +1133,7 @@ dependencies = [ "client", "gpui", "postage", + "settings", "theme", "workspace", ] @@ -1480,6 +1483,7 @@ dependencies = [ "postage", "project", "serde_json", + "settings", "theme", "unindent", "util", @@ -1646,6 +1650,7 @@ dependencies = [ "rand 0.8.3", "rpc", "serde", + "settings", "smallvec", "smol", "snippet", @@ -1806,6 +1811,7 @@ dependencies = [ "postage", "project", "serde_json", + "settings", "theme", "util", "workspace", @@ -2206,6 +2212,7 @@ dependencies = [ "editor", "gpui", "postage", + "settings", "text", "workspace", ] @@ -3255,6 +3262,7 @@ dependencies = [ "language", "ordered-float", "postage", + "settings", "smol", "text", "workspace", @@ -3643,6 +3651,7 @@ dependencies = [ "postage", "project", "serde_json", + "settings", "theme", "util", "workspace", @@ -3659,6 +3668,7 @@ dependencies = [ "ordered-float", "postage", "project", + "settings", "smol", "text", "util", @@ -4258,6 +4268,7 @@ dependencies = [ "postage", "project", "serde_json", + "settings", "theme", "unindent", "util", @@ -4406,6 +4417,21 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "settings" +version = "0.1.0" +dependencies = [ + "anyhow", + "gpui", + "schemars", + "serde", + "serde_json", + "serde_path_to_error", + "theme", + "toml", + "util", +] + [[package]] name = "sha-1" version = "0.8.2" @@ -5142,6 +5168,7 @@ dependencies = [ "log", "parking_lot", "postage", + "settings", "smol", "theme", "workspace", @@ -5719,6 +5746,7 @@ dependencies = [ "language", "log", "project", + "settings", "util", "workspace", ] @@ -5948,9 +5976,9 @@ dependencies = [ "parking_lot", "postage", "project", - "schemars", "serde", "serde_json", + "settings", "smallvec", "theme", "util", @@ -6034,6 +6062,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", + "settings", "simplelog", "smallvec", "smol", @@ -6099,6 +6128,7 @@ dependencies = [ "scrypt", "serde", "serde_json", + "settings", "sha-1 0.9.6", "sqlx 0.5.5", "surf", diff --git a/crates/breadcrumbs/Cargo.toml b/crates/breadcrumbs/Cargo.toml index 7dbafdb3be560805d18df4fe47a4c0b7c605b95a..88fd614a893e0badaa5800a9c9eef6d75b4da374 100644 --- a/crates/breadcrumbs/Cargo.toml +++ b/crates/breadcrumbs/Cargo.toml @@ -14,6 +14,7 @@ gpui = { path = "../gpui" } language = { path = "../language" } project = { path = "../project" } search = { path = "../search" } +settings = { path = "../settings" } theme = { path = "../theme" } workspace = { path = "../workspace" } diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs index 59c8b08b685270576967492f3f0c87d659a5799b..b2bba37e38fb591e20561b5edb34912e9c4c5c18 100644 --- a/crates/breadcrumbs/src/breadcrumbs.rs +++ b/crates/breadcrumbs/src/breadcrumbs.rs @@ -6,8 +6,9 @@ use gpui::{ use language::{Buffer, OutlineItem}; use project::Project; use search::ProjectSearchView; +use settings::Settings; use theme::SyntaxTheme; -use workspace::{ItemHandle, Settings, ToolbarItemLocation, ToolbarItemView}; +use workspace::{ItemHandle, ToolbarItemLocation, ToolbarItemView}; pub enum Event { UpdateLocation, diff --git a/crates/chat_panel/Cargo.toml b/crates/chat_panel/Cargo.toml index a64ecc8b7b8d2b8bfc474c42d830f1feec017021..95426517d7f7cd4f216ef806aeab151dba2bf68d 100644 --- a/crates/chat_panel/Cargo.toml +++ b/crates/chat_panel/Cargo.toml @@ -11,6 +11,7 @@ doctest = false client = { path = "../client" } editor = { path = "../editor" } gpui = { path = "../gpui" } +settings = { path = "../settings" } theme = { path = "../theme" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/chat_panel/src/chat_panel.rs b/crates/chat_panel/src/chat_panel.rs index a7c912389479460c618d0570ee17ef9c4d6abedc..9d575768a6385e106f484fde00a5a68d54d6be0f 100644 --- a/crates/chat_panel/src/chat_panel.rs +++ b/crates/chat_panel/src/chat_panel.rs @@ -13,10 +13,10 @@ use gpui::{ ViewContext, ViewHandle, }; use postage::prelude::Stream; +use settings::{Settings, SoftWrap}; use std::sync::Arc; use time::{OffsetDateTime, UtcOffset}; use util::{ResultExt, TryFutureExt}; -use workspace::{settings::SoftWrap, Settings}; const MESSAGE_LOADING_THRESHOLD: usize = 50; diff --git a/crates/contacts_panel/Cargo.toml b/crates/contacts_panel/Cargo.toml index 43bd2548a8d0cd5c835ca645f787c56e16efa733..6a4dbf653dbb1751ca1a41303cf2fec08fb6f09e 100644 --- a/crates/contacts_panel/Cargo.toml +++ b/crates/contacts_panel/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] client = { path = "../client" } gpui = { path = "../gpui" } +settings = { path = "../settings" } theme = { path = "../theme" } workspace = { path = "../workspace" } postage = { version = "0.4.1", features = ["futures-traits"] } diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index 06c6b8f1bb648b7978f7896f7fcf48fffd256412..deb6f8e4a32919270342d420e8006da510d79fc4 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -8,7 +8,8 @@ use gpui::{ Element, ElementBox, Entity, LayoutContext, ModelHandle, RenderContext, Subscription, View, ViewContext, }; -use workspace::{AppState, JoinProject, JoinProjectParams, Settings}; +use workspace::{AppState, JoinProject, JoinProjectParams}; +use settings::Settings; pub struct ContactsPanel { contacts: ListState, diff --git a/crates/diagnostics/Cargo.toml b/crates/diagnostics/Cargo.toml index 4cf45041e9049a39c8d55ddf813562ad506b79fc..4f59ffc68c64cb313360056a09ca176117769eaa 100644 --- a/crates/diagnostics/Cargo.toml +++ b/crates/diagnostics/Cargo.toml @@ -14,6 +14,7 @@ editor = { path = "../editor" } language = { path = "../language" } gpui = { path = "../gpui" } project = { path = "../project" } +settings = { path = "../settings" } theme = { path = "../theme" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index da50e99f1e5175d04900c4d0a4839479e1dd82c7..1d317278a6ab90bb47c5d53b6235d555a13fb1ea 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -25,7 +25,8 @@ use std::{ sync::Arc, }; use util::TryFutureExt; -use workspace::{ItemHandle as _, ItemNavHistory, Settings, Workspace}; +use workspace::{ItemHandle as _, ItemNavHistory, Workspace}; +use settings::Settings; action!(Deploy); diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 690c5100ecf9ec3a8edf89414a2ef545f868201a..41826017cdd1a0742265d5884a22e72d8af0f6fa 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -3,7 +3,8 @@ use gpui::{ elements::*, platform::CursorStyle, Entity, ModelHandle, RenderContext, View, ViewContext, }; use project::Project; -use workspace::{Settings, StatusItemView}; +use workspace::{StatusItemView}; +use settings::Settings; pub struct DiagnosticSummary { summary: project::DiagnosticSummary, diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 77e169b91b2e03648402687722b29ea045c7822b..4664d9c52e674fa0786bdd1de501d20cecf99ee9 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -28,6 +28,7 @@ language = { path = "../language" } lsp = { path = "../lsp" } project = { path = "../project" } rpc = { path = "../rpc" } +settings = { path = "../settings" } snippet = { path = "../snippet" } sum_tree = { path = "../sum_tree" } theme = { path = "../theme" } @@ -54,6 +55,7 @@ lsp = { path = "../lsp", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } +settings = { path = "../settings", features = ["test-support"] } workspace = { path = "../workspace", features = ["test-support"] } ctor = "0.1" env_logger = "0.8" diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 2bea851ec2fa92605aa32b9f2a2c584a649e7305..27db9a8de51ae343002ed445dd24c5c43ee7199a 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -46,6 +46,7 @@ impl Entity for DisplayMap { impl DisplayMap { pub fn new( buffer: ModelHandle, + // TODO - remove. read tab_size from settings inside tab_size: usize, font_id: FontId, font_size: f32, @@ -76,6 +77,8 @@ impl DisplayMap { let buffer_snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (folds_snapshot, edits) = self.fold_map.read(buffer_snapshot, edits); + + // TODO: Pull tabsize out of cx and pass it to sync let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits); let (wraps_snapshot, edits) = self .wrap_map diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0a019e1701aa6b4a8cb82e29f431eeb5145486c0..46d71ebeae2e00d43e9fc0cf70690b03f907b7d1 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -41,6 +41,7 @@ pub use multi_buffer::{ use ordered_float::OrderedFloat; use project::{Project, ProjectTransaction}; use serde::{Deserialize, Serialize}; +use settings::Settings; use smallvec::SmallVec; use smol::Timer; use snippet::Snippet; @@ -57,7 +58,7 @@ pub use sum_tree::Bias; use text::rope::TextDimension; use theme::DiagnosticStyle; use util::{post_inc, ResultExt, TryFutureExt}; -use workspace::{settings, ItemNavHistory, Settings, Workspace}; +use workspace::{ItemNavHistory, Workspace}; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); const MAX_LINE_LEN: usize = 1024; @@ -5669,16 +5670,16 @@ impl Editor { } pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { - let language = self.language(cx); + let language = self.language(cx).map(|language| language.name()); let settings = cx.global::(); let mode = self .soft_wrap_mode_override - .unwrap_or_else(|| settings.soft_wrap(language)); + .unwrap_or_else(|| settings.soft_wrap(language.as_deref())); match mode { settings::SoftWrap::None => SoftWrap::None, settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth, settings::SoftWrap::PreferredLineLength => { - SoftWrap::Column(settings.preferred_line_length(language)) + SoftWrap::Column(settings.preferred_line_length(language.as_deref())) } } } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 18f780dacc1ad68d28814a92241163f3fcf27748..0ffe3feb6d43cb1ffd0b6eea1c5812f61f41d85c 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1494,8 +1494,8 @@ mod tests { display_map::{BlockDisposition, BlockProperties}, Editor, MultiBuffer, }; + use settings::Settings; use util::test::sample_text; - use workspace::Settings; #[gpui::test] fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) { diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 67d5aee7731d9e23934849a8ee638de034bc82f6..9a102dd5ce66661f6b1b4c5e37d2ecafa98393b1 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -8,12 +8,11 @@ use gpui::{ use language::{Bias, Buffer, Diagnostic, File as _, SelectionGoal}; use project::{File, Project, ProjectEntryId, ProjectPath}; use rpc::proto::{self, update_view}; +use settings::Settings; use std::{fmt::Write, path::PathBuf, time::Duration}; use text::{Point, Selection}; use util::TryFutureExt; -use workspace::{ - FollowableItem, Item, ItemHandle, ItemNavHistory, ProjectItem, Settings, StatusItemView, -}; +use workspace::{FollowableItem, Item, ItemHandle, ItemNavHistory, ProjectItem, StatusItemView}; pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2); diff --git a/crates/file_finder/Cargo.toml b/crates/file_finder/Cargo.toml index b946ea48fbbf58a7196f56949ececfe23fa1fd75..47dd9b15bc07423c9cb4a86ef493f41ba7bf4c9b 100644 --- a/crates/file_finder/Cargo.toml +++ b/crates/file_finder/Cargo.toml @@ -12,6 +12,7 @@ editor = { path = "../editor" } fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } project = { path = "../project" } +settings = { path = "../settings" } util = { path = "../util" } theme = { path = "../theme" } workspace = { path = "../workspace" } diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 471e43a0edcb4e95011fd07a280ab6f3b835f223..7dfe9a54deabce916e496b77a9e46fa2dede6840 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -19,8 +19,9 @@ use std::{ use util::post_inc; use workspace::{ menu::{Confirm, SelectNext, SelectPrev}, - Settings, Workspace, + Workspace, }; +use settings::Settings; pub struct FileFinder { handle: WeakViewHandle, diff --git a/crates/go_to_line/Cargo.toml b/crates/go_to_line/Cargo.toml index eaad41e0802ef0caecbc807a373eea8131ff6ec8..76744274c7ed704d3af71498fe1aa1869ab8823e 100644 --- a/crates/go_to_line/Cargo.toml +++ b/crates/go_to_line/Cargo.toml @@ -11,5 +11,6 @@ doctest = false text = { path = "../text" } editor = { path = "../editor" } gpui = { path = "../gpui" } +settings = { path = "../settings" } workspace = { path = "../workspace" } postage = { version = "0.4", features = ["futures-traits"] } diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 109d33097d69cf5f4d251451aa634887774145de..19b43d572148b8f0c13534bd4ae11fb784cdbe88 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -3,8 +3,9 @@ use gpui::{ action, elements::*, geometry::vector::Vector2F, keymap::Binding, Axis, Entity, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, }; +use settings::Settings; use text::{Bias, Point}; -use workspace::{Settings, Workspace}; +use workspace::Workspace; action!(Toggle); action!(Confirm); diff --git a/crates/outline/Cargo.toml b/crates/outline/Cargo.toml index e5ed300dc75e68ff5f9e09f9822078b3fa65e854..fc9444a14c705b9fdd6aeb5a1bb1b8b0f6e6c851 100644 --- a/crates/outline/Cargo.toml +++ b/crates/outline/Cargo.toml @@ -12,6 +12,7 @@ editor = { path = "../editor" } fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } language = { path = "../language" } +settings = { path = "../settings" } text = { path = "../text" } workspace = { path = "../workspace" } ordered-float = "2.1.1" diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index c33cb60b3e36456c9557536ed77ea166bb5dd668..14b57f2d132314d189d0fa3c94d840c27e49c007 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -13,10 +13,11 @@ use gpui::{ }; use language::Outline; use ordered_float::OrderedFloat; +use settings::Settings; use std::cmp::{self, Reverse}; use workspace::{ menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev}, - Settings, Workspace, + Workspace, }; action!(Toggle); diff --git a/crates/project_panel/Cargo.toml b/crates/project_panel/Cargo.toml index 2e501780365fbb0ce3d942c9dd3fce71dccc4493..81e975cc73ded8026c597e88e202c57a6c86ec55 100644 --- a/crates/project_panel/Cargo.toml +++ b/crates/project_panel/Cargo.toml @@ -10,6 +10,7 @@ doctest = false [dependencies] gpui = { path = "../gpui" } project = { path = "../project" } +settings = { path = "../settings" } theme = { path = "../theme" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 0dd6b08bacc68bf888e9348636ec0b66669a509c..6ae81fcb5e608fc6709ce1e7e38d3c8369955be9 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -10,6 +10,7 @@ use gpui::{ ViewHandle, WeakViewHandle, }; use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId}; +use settings::Settings; use std::{ collections::{hash_map, HashMap}, ffi::OsStr, @@ -17,7 +18,7 @@ use std::{ }; use workspace::{ menu::{SelectNext, SelectPrev}, - Settings, Workspace, + Workspace, }; pub struct ProjectPanel { diff --git a/crates/project_symbols/Cargo.toml b/crates/project_symbols/Cargo.toml index cdaedf109c3b3501a58dd14c6460e5e3519193ce..de22c0eda027a4a3ec1e0a6c0f0bc4024fb58747 100644 --- a/crates/project_symbols/Cargo.toml +++ b/crates/project_symbols/Cargo.toml @@ -13,6 +13,7 @@ fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } project = { path = "../project" } text = { path = "../text" } +settings = { path = "../settings" } workspace = { path = "../workspace" } util = { path = "../util" } anyhow = "1.0.38" diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 74e7d90d689f8fadfd06763feaa366ffeab3f61a..f707aa30f71dd1e354a2fc079caaa2ac489d3774 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -11,6 +11,7 @@ use gpui::{ }; use ordered_float::OrderedFloat; use project::{Project, Symbol}; +use settings::Settings; use std::{ borrow::Cow, cmp::{self, Reverse}, @@ -18,7 +19,7 @@ use std::{ use util::ResultExt; use workspace::{ menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev}, - Settings, Workspace, + Workspace, }; action!(Toggle); diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 5553e3b9a281eb2e0a5c811155436d94d092e60c..77961de01f3efdee86603d01b99c259509d04c9e 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -13,6 +13,7 @@ editor = { path = "../editor" } gpui = { path = "../gpui" } language = { path = "../language" } project = { path = "../project" } +settings = { path = "../settings" } theme = { path = "../theme" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index b5f8eedf8023828baba389b14d385b0e5184c273..5dc93245b97739e35ca1bf5ef5b216d6432aed99 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -9,7 +9,8 @@ use gpui::{ use language::OffsetRangeExt; use project::search::SearchQuery; use std::ops::Range; -use workspace::{ItemHandle, Pane, Settings, ToolbarItemLocation, ToolbarItemView}; +use workspace::{ItemHandle, Pane, ToolbarItemLocation, ToolbarItemView}; +use settings::Settings; action!(Deploy, bool); action!(Dismiss); diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 745f23154fd98a77b3f20e79f1f4d513f235ebc5..9009dfee79493b493868b6ba930fe0186709b99e 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -10,15 +10,14 @@ use gpui::{ ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle, }; use project::{search::SearchQuery, Project}; +use settings::Settings; use std::{ any::{Any, TypeId}, ops::Range, path::PathBuf, }; use util::ResultExt as _; -use workspace::{ - Item, ItemNavHistory, Pane, Settings, ToolbarItemLocation, ToolbarItemView, Workspace, -}; +use workspace::{Item, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace}; action!(Deploy); action!(Search); diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index c39fb2f10b22cebaa4053c64609d14e21fba0416..6e27fa16c523cf0908f10fff8cdf772c54269b84 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -14,6 +14,7 @@ required-features = ["seed-support"] [dependencies] collections = { path = "../collections" } +settings = { path = "../settings" } rpc = { path = "../rpc" } anyhow = "1.0.40" async-io = "1.3" diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index eb12de9b727bb6ea9c6b87047ffeab23372221ea..51c7807660708ea47209a5d133d2f7128e33b4f7 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1104,6 +1104,7 @@ mod tests { use rand::prelude::*; use rpc::PeerId; use serde_json::json; + use settings::Settings; use sqlx::types::time::OffsetDateTime; use std::{ cell::Cell, @@ -1117,7 +1118,7 @@ mod tests { }, time::Duration, }; - use workspace::{Item, Settings, SplitDirection, Workspace, WorkspaceParams}; + use workspace::{Item, SplitDirection, Workspace, WorkspaceParams}; #[cfg(test)] #[ctor::ctor] diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..baaf787bee4dc43530d8185864bcf5ea732e0722 --- /dev/null +++ b/crates/settings/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "settings" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/settings.rs" +doctest = false + +[features] +test-support = [] + +[dependencies] +gpui = { path = "../gpui" } +theme = { path = "../theme" } +util = { path = "../util" } +anyhow = "1.0.38" +schemars = "0.8" +serde = { version = "1", features = ["derive", "rc"] } +serde_json = { version = "1.0.64", features = ["preserve_order"] } +serde_path_to_error = "0.1.4" +toml = "0.5" diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs new file mode 100644 index 0000000000000000000000000000000000000000..467456b2fc2d15a7daa6f394bc843ffa177c9e22 --- /dev/null +++ b/crates/settings/src/settings.rs @@ -0,0 +1,171 @@ +use anyhow::Result; +use gpui::font_cache::{FamilyId, FontCache}; +use schemars::{schema_for, JsonSchema}; +use serde::Deserialize; +use std::{collections::HashMap, sync::Arc}; +use theme::{Theme, ThemeRegistry}; +use util::ResultExt as _; + +#[derive(Clone)] +pub struct Settings { + pub buffer_font_family: FamilyId, + pub buffer_font_size: f32, + pub vim_mode: bool, + pub tab_size: usize, + pub soft_wrap: SoftWrap, + pub preferred_line_length: u32, + pub language_overrides: HashMap, LanguageOverride>, + pub theme: Arc, +} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema)] +pub struct LanguageOverride { + pub tab_size: Option, + pub soft_wrap: Option, + pub preferred_line_length: Option, +} + +#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum SoftWrap { + None, + EditorWidth, + PreferredLineLength, +} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema)] +pub struct SettingsFileContent { + #[serde(default)] + pub buffer_font_family: Option, + #[serde(default)] + pub buffer_font_size: Option, + #[serde(default)] + pub vim_mode: Option, + #[serde(flatten)] + pub editor: LanguageOverride, + #[serde(default)] + pub language_overrides: HashMap, LanguageOverride>, + #[serde(default)] + pub theme: Option, +} + +impl Settings { + pub fn new( + buffer_font_family: &str, + font_cache: &FontCache, + theme: Arc, + ) -> Result { + Ok(Self { + buffer_font_family: font_cache.load_family(&[buffer_font_family])?, + buffer_font_size: 15., + vim_mode: false, + tab_size: 4, + soft_wrap: SoftWrap::None, + preferred_line_length: 80, + language_overrides: Default::default(), + theme, + }) + } + + pub fn file_json_schema() -> serde_json::Value { + serde_json::to_value(schema_for!(SettingsFileContent)).unwrap() + } + + pub fn with_overrides( + mut self, + language_name: impl Into>, + overrides: LanguageOverride, + ) -> Self { + self.language_overrides + .insert(language_name.into(), overrides); + self + } + + pub fn tab_size(&self, language: Option<&str>) -> usize { + language + .and_then(|language| self.language_overrides.get(language)) + .and_then(|settings| settings.tab_size) + .unwrap_or(self.tab_size) + } + + pub fn soft_wrap(&self, language: Option<&str>) -> SoftWrap { + language + .and_then(|language| self.language_overrides.get(language)) + .and_then(|settings| settings.soft_wrap) + .unwrap_or(self.soft_wrap) + } + + pub fn preferred_line_length(&self, language: Option<&str>) -> u32 { + language + .and_then(|language| self.language_overrides.get(language)) + .and_then(|settings| settings.preferred_line_length) + .unwrap_or(self.preferred_line_length) + } + + #[cfg(any(test, feature = "test-support"))] + pub fn test(cx: &gpui::AppContext) -> Settings { + Settings { + buffer_font_family: cx.font_cache().load_family(&["Monaco"]).unwrap(), + buffer_font_size: 14., + vim_mode: false, + tab_size: 4, + soft_wrap: SoftWrap::None, + preferred_line_length: 80, + language_overrides: Default::default(), + theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), || Default::default()), + } + } + + pub fn merge( + &mut self, + data: &SettingsFileContent, + theme_registry: &ThemeRegistry, + font_cache: &FontCache, + ) { + if let Some(value) = &data.buffer_font_family { + if let Some(id) = font_cache.load_family(&[value]).log_err() { + self.buffer_font_family = id; + } + } + if let Some(value) = &data.theme { + if let Some(theme) = theme_registry.get(value).log_err() { + self.theme = theme; + } + } + + merge(&mut self.buffer_font_size, data.buffer_font_size); + merge(&mut self.vim_mode, data.vim_mode); + merge(&mut self.soft_wrap, data.editor.soft_wrap); + merge(&mut self.tab_size, data.editor.tab_size); + merge( + &mut self.preferred_line_length, + data.editor.preferred_line_length, + ); + + for (language_name, settings) in &data.language_overrides { + let target = self + .language_overrides + .entry(language_name.clone()) + .or_default(); + + merge_option(&mut target.tab_size, settings.tab_size); + merge_option(&mut target.soft_wrap, settings.soft_wrap); + merge_option( + &mut target.preferred_line_length, + settings.preferred_line_length, + ); + } + } +} + +fn merge(target: &mut T, value: Option) { + if let Some(value) = value { + *target = value; + } +} + +fn merge_option(target: &mut Option, value: Option) { + if value.is_some() { + *target = value; + } +} diff --git a/crates/theme_selector/Cargo.toml b/crates/theme_selector/Cargo.toml index ff3d50454f8997b1eeb86283d926bedb1b26b9ba..585d10d563c9919deb8a878576a14c9b09f35e72 100644 --- a/crates/theme_selector/Cargo.toml +++ b/crates/theme_selector/Cargo.toml @@ -12,6 +12,7 @@ editor = { path = "../editor" } fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } theme = { path = "../theme" } +settings = { path = "../settings" } workspace = { path = "../workspace" } log = "0.4" parking_lot = "0.11.1" diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index d61cac1c4428ae1e481f8548fa207f976f96e783..5bcbd62e09578c1210d32a4be10b435c8f695a04 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -9,9 +9,10 @@ use gpui::{ }; use std::{cmp, sync::Arc}; use theme::{Theme, ThemeRegistry}; +use settings::Settings; use workspace::{ menu::{Confirm, SelectNext, SelectPrev}, - Settings, Workspace, + Workspace, }; pub struct ThemeSelector { diff --git a/crates/vim/Cargo.toml b/crates/vim/Cargo.toml index 28ee7de8729f5fc5a8ba4bba2032ffa9d38ee99e..4ffa6a4363c5e08e17899db49d20a46a568dcca9 100644 --- a/crates/vim/Cargo.toml +++ b/crates/vim/Cargo.toml @@ -12,6 +12,7 @@ collections = { path = "../collections" } editor = { path = "../editor" } gpui = { path = "../gpui" } language = { path = "../language" } +settings = { path = "../settings" } workspace = { path = "../workspace" } log = "0.4" @@ -19,7 +20,8 @@ log = "0.4" indoc = "1.0.4" editor = { path = "../editor", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } -project = { path = "../project", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } +project = { path = "../project", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } +settings = { path = "../settings" } workspace = { path = "../workspace", features = ["test-support"] } \ No newline at end of file diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 609843d9696c215037cb9bef05cde9bc5c28ac14..16ee1612d58a8e0720f92821af6a8621f0ec9ec0 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -10,7 +10,8 @@ use editor::{CursorShape, Editor}; use gpui::{action, MutableAppContext, ViewContext, WeakViewHandle}; use mode::Mode; -use workspace::{self, Settings, Workspace}; +use settings::Settings; +use workspace::{self, Workspace}; action!(SwitchMode, Mode); diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index 7ef0bd85439b74c9739814a2480584b3496918b9..75d1b1b8f2667ab111278d2efa6979c66e7d50bd 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -17,6 +17,7 @@ collections = { path = "../collections" } gpui = { path = "../gpui" } language = { path = "../language" } project = { path = "../project" } +settings = { path = "../settings" } theme = { path = "../theme" } util = { path = "../util" } anyhow = "1.0.38" @@ -24,7 +25,6 @@ futures = "0.3" log = "0.4" parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } -schemars = "0.8" serde = { version = "1", features = ["derive", "rc"] } serde_json = { version = "1", features = ["preserve_order"] } smallvec = { version = "1.6", features = ["union"] } @@ -33,3 +33,4 @@ smallvec = { version = "1.6", features = ["union"] } client = { path = "../client", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } +settings = { path = "../settings", features = ["test-support"] } \ No newline at end of file diff --git a/crates/workspace/src/lsp_status.rs b/crates/workspace/src/lsp_status.rs index a12f81857f1d1b2ed4d44aa01c6283da67f2c8c2..cf920b108d1e6d1a8828642b70b10bbda45d4847 100644 --- a/crates/workspace/src/lsp_status.rs +++ b/crates/workspace/src/lsp_status.rs @@ -1,4 +1,4 @@ -use crate::{ItemHandle, Settings, StatusItemView}; +use crate::{ItemHandle, StatusItemView}; use futures::StreamExt; use gpui::AppContext; use gpui::{ @@ -7,6 +7,7 @@ use gpui::{ }; use language::{LanguageRegistry, LanguageServerBinaryStatus}; use project::{LanguageServerProgress, Project}; +use settings::Settings; use smallvec::SmallVec; use std::cmp::Reverse; use std::fmt::Write; diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index fb13ef2fd0e89dda0e38e00f0c39cecce0c4abd1..d3fa9dbfbf75d2ef26cf6384ff1cce11b8ff6614 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1,5 +1,5 @@ use super::{ItemHandle, SplitDirection}; -use crate::{toolbar::Toolbar, Item, Settings, WeakItemHandle, Workspace}; +use crate::{toolbar::Toolbar, Item, WeakItemHandle, Workspace}; use anyhow::Result; use collections::{HashMap, VecDeque}; use futures::StreamExt; @@ -12,7 +12,8 @@ use gpui::{ AppContext, Entity, MutableAppContext, PromptLevel, Quad, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; -use project::{ProjectEntryId, ProjectPath}; +use project::{Project, ProjectEntryId, ProjectPath}; +use settings::Settings; use std::{any::Any, cell::RefCell, cmp, mem, path::Path, rc::Rc}; use util::ResultExt; diff --git a/crates/workspace/src/settings.rs b/crates/workspace/src/settings.rs deleted file mode 100644 index 5ccf8056e674b98953a340645677606bae80cfaf..0000000000000000000000000000000000000000 --- a/crates/workspace/src/settings.rs +++ /dev/null @@ -1,325 +0,0 @@ -use anyhow::Result; -use futures::{stream, SinkExt, StreamExt as _}; -use gpui::{ - executor, - font_cache::{FamilyId, FontCache}, -}; -use language::Language; -use postage::{prelude::Stream, watch}; -use project::Fs; -use schemars::{schema_for, JsonSchema}; -use serde::Deserialize; -use std::{collections::HashMap, path::Path, sync::Arc, time::Duration}; -use theme::{Theme, ThemeRegistry}; -use util::ResultExt; - -#[derive(Clone)] -pub struct Settings { - pub buffer_font_family: FamilyId, - pub buffer_font_size: f32, - pub vim_mode: bool, - pub tab_size: usize, - pub soft_wrap: SoftWrap, - pub preferred_line_length: u32, - pub language_overrides: HashMap, LanguageOverride>, - pub theme: Arc, -} - -#[derive(Clone, Debug, Default, Deserialize, JsonSchema)] -pub struct LanguageOverride { - pub tab_size: Option, - pub soft_wrap: Option, - pub preferred_line_length: Option, -} - -#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum SoftWrap { - None, - EditorWidth, - PreferredLineLength, -} - -#[derive(Clone)] -pub struct SettingsFile(watch::Receiver); - -#[derive(Clone, Debug, Default, Deserialize, JsonSchema)] -struct SettingsFileContent { - #[serde(default)] - buffer_font_family: Option, - #[serde(default)] - buffer_font_size: Option, - #[serde(default)] - vim_mode: Option, - #[serde(flatten)] - editor: LanguageOverride, - #[serde(default)] - language_overrides: HashMap, LanguageOverride>, - #[serde(default)] - theme: Option, -} - -impl SettingsFile { - pub async fn new( - fs: Arc, - executor: &executor::Background, - path: impl Into>, - ) -> Self { - let path = path.into(); - let settings = Self::load(fs.clone(), &path).await.unwrap_or_default(); - let mut events = fs.watch(&path, Duration::from_millis(500)).await; - let (mut tx, rx) = watch::channel_with(settings); - executor - .spawn(async move { - while events.next().await.is_some() { - if let Some(settings) = Self::load(fs.clone(), &path).await { - if tx.send(settings).await.is_err() { - break; - } - } - } - }) - .detach(); - Self(rx) - } - - async fn load(fs: Arc, path: &Path) -> Option { - if fs.is_file(&path).await { - fs.load(&path) - .await - .log_err() - .and_then(|data| serde_json::from_str(&data).log_err()) - } else { - Some(SettingsFileContent::default()) - } - } -} - -impl Settings { - pub fn file_json_schema() -> serde_json::Value { - serde_json::to_value(schema_for!(SettingsFileContent)).unwrap() - } - - pub fn from_files( - defaults: Self, - sources: Vec, - theme_registry: Arc, - font_cache: Arc, - ) -> impl futures::stream::Stream { - stream::select_all(sources.iter().enumerate().map(|(i, source)| { - let mut rx = source.0.clone(); - // Consume the initial item from all of the constituent file watches but one. - // This way, the stream will yield exactly one item for the files' initial - // state, and won't return any more items until the files change. - if i > 0 { - rx.try_recv().ok(); - } - rx - })) - .map(move |_| { - let mut settings = defaults.clone(); - for source in &sources { - settings.merge(&*source.0.borrow(), &theme_registry, &font_cache); - } - settings - }) - } - - pub fn new( - buffer_font_family: &str, - font_cache: &FontCache, - theme: Arc, - ) -> Result { - Ok(Self { - buffer_font_family: font_cache.load_family(&[buffer_font_family])?, - buffer_font_size: 15., - vim_mode: false, - tab_size: 4, - soft_wrap: SoftWrap::None, - preferred_line_length: 80, - language_overrides: Default::default(), - theme, - }) - } - - pub fn with_overrides( - mut self, - language_name: impl Into>, - overrides: LanguageOverride, - ) -> Self { - self.language_overrides - .insert(language_name.into(), overrides); - self - } - - pub fn tab_size(&self, language: Option<&Arc>) -> usize { - language - .and_then(|language| self.language_overrides.get(language.name().as_ref())) - .and_then(|settings| settings.tab_size) - .unwrap_or(self.tab_size) - } - - pub fn soft_wrap(&self, language: Option<&Arc>) -> SoftWrap { - language - .and_then(|language| self.language_overrides.get(language.name().as_ref())) - .and_then(|settings| settings.soft_wrap) - .unwrap_or(self.soft_wrap) - } - - pub fn preferred_line_length(&self, language: Option<&Arc>) -> u32 { - language - .and_then(|language| self.language_overrides.get(language.name().as_ref())) - .and_then(|settings| settings.preferred_line_length) - .unwrap_or(self.preferred_line_length) - } - - #[cfg(any(test, feature = "test-support"))] - pub fn test(cx: &gpui::AppContext) -> Settings { - Settings { - buffer_font_family: cx.font_cache().load_family(&["Monaco"]).unwrap(), - buffer_font_size: 14., - vim_mode: false, - tab_size: 4, - soft_wrap: SoftWrap::None, - preferred_line_length: 80, - language_overrides: Default::default(), - theme: gpui::fonts::with_font_cache(cx.font_cache().clone(), || Default::default()), - } - } - - fn merge( - &mut self, - data: &SettingsFileContent, - theme_registry: &ThemeRegistry, - font_cache: &FontCache, - ) { - if let Some(value) = &data.buffer_font_family { - if let Some(id) = font_cache.load_family(&[value]).log_err() { - self.buffer_font_family = id; - } - } - if let Some(value) = &data.theme { - if let Some(theme) = theme_registry.get(value).log_err() { - self.theme = theme; - } - } - - merge(&mut self.buffer_font_size, data.buffer_font_size); - merge(&mut self.vim_mode, data.vim_mode); - merge(&mut self.soft_wrap, data.editor.soft_wrap); - merge(&mut self.tab_size, data.editor.tab_size); - merge( - &mut self.preferred_line_length, - data.editor.preferred_line_length, - ); - - for (language_name, settings) in &data.language_overrides { - let target = self - .language_overrides - .entry(language_name.clone()) - .or_default(); - - merge_option(&mut target.tab_size, settings.tab_size); - merge_option(&mut target.soft_wrap, settings.soft_wrap); - merge_option( - &mut target.preferred_line_length, - settings.preferred_line_length, - ); - } - } -} - -fn merge(target: &mut T, value: Option) { - if let Some(value) = value { - *target = value; - } -} - -fn merge_option(target: &mut Option, value: Option) { - if value.is_some() { - *target = value; - } -} - -#[cfg(test)] -mod tests { - use super::*; - use project::FakeFs; - - #[gpui::test] - async fn test_settings_from_files(cx: &mut gpui::TestAppContext) { - let executor = cx.background(); - let fs = FakeFs::new(executor.clone()); - - fs.save( - "/settings1.json".as_ref(), - &r#" - { - "buffer_font_size": 24, - "soft_wrap": "editor_width", - "language_overrides": { - "Markdown": { - "preferred_line_length": 100, - "soft_wrap": "preferred_line_length" - } - } - } - "# - .into(), - ) - .await - .unwrap(); - - let source1 = SettingsFile::new(fs.clone(), &executor, "/settings1.json".as_ref()).await; - let source2 = SettingsFile::new(fs.clone(), &executor, "/settings2.json".as_ref()).await; - let source3 = SettingsFile::new(fs.clone(), &executor, "/settings3.json".as_ref()).await; - - let mut settings_rx = Settings::from_files( - cx.read(Settings::test), - vec![source1, source2, source3], - ThemeRegistry::new((), cx.font_cache()), - cx.font_cache(), - ); - - let settings = settings_rx.next().await.unwrap(); - let md_settings = settings.language_overrides.get("Markdown").unwrap(); - assert_eq!(settings.soft_wrap, SoftWrap::EditorWidth); - assert_eq!(settings.buffer_font_size, 24.0); - assert_eq!(settings.tab_size, 4); - assert_eq!(md_settings.soft_wrap, Some(SoftWrap::PreferredLineLength)); - assert_eq!(md_settings.preferred_line_length, Some(100)); - - fs.save( - "/settings2.json".as_ref(), - &r#" - { - "tab_size": 2, - "soft_wrap": "none", - "language_overrides": { - "Markdown": { - "preferred_line_length": 120 - } - } - } - "# - .into(), - ) - .await - .unwrap(); - - let settings = settings_rx.next().await.unwrap(); - let md_settings = settings.language_overrides.get("Markdown").unwrap(); - assert_eq!(settings.soft_wrap, SoftWrap::None); - assert_eq!(settings.buffer_font_size, 24.0); - assert_eq!(settings.tab_size, 2); - assert_eq!(md_settings.soft_wrap, Some(SoftWrap::PreferredLineLength)); - assert_eq!(md_settings.preferred_line_length, Some(120)); - - fs.remove_file("/settings2.json".as_ref(), Default::default()) - .await - .unwrap(); - - let settings = settings_rx.next().await.unwrap(); - assert_eq!(settings.tab_size, 4); - } -} diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index a91dd645a067465ab13a9e304ece9d55448285d0..c9a2c819e2ca59f6d7f6c47453ae6a5dfc8eb6f2 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -1,4 +1,5 @@ -use crate::{ItemHandle, Pane, Settings}; +use crate::{ItemHandle, Pane}; +use settings::Settings; use gpui::{ elements::*, AnyViewHandle, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 8212b2508282daf6eb4c0088263089bd7c5f71af..e9b20bf3a04e5876a7a6e202f06b3b78c8727a68 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -1,8 +1,9 @@ -use crate::{ItemHandle, Settings}; +use crate::ItemHandle; use gpui::{ elements::*, AnyViewHandle, AppContext, ElementBox, Entity, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, }; +use settings::Settings; pub trait ToolbarItemView: View { fn set_active_pane_item( diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cd3e0e7b30e7c4427e168e401b4447c2e8b48c03..7ee7d5cf44ae7e84d04cfd2293ed2f1ffa8e2c7c 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2,7 +2,6 @@ pub mod lsp_status; pub mod menu; pub mod pane; pub mod pane_group; -pub mod settings; pub mod sidebar; mod status_bar; mod toolbar; @@ -31,7 +30,7 @@ pub use pane::*; pub use pane_group::*; use postage::prelude::Stream; use project::{fs, Fs, Project, ProjectEntryId, ProjectPath, Worktree}; -pub use settings::Settings; +use settings::Settings; use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus}; use status_bar::StatusBar; pub use status_bar::StatusItemView; diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 86011fdb46b5a556163d80437e78045b7f0d64d1..25f45b9cc03333f247ade91f23febc5893d0b3b7 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -51,6 +51,7 @@ project = { path = "../project" } project_panel = { path = "../project_panel" } project_symbols = { path = "../project_symbols" } rpc = { path = "../rpc" } +settings = { path = "../settings" } sum_tree = { path = "../sum_tree" } text = { path = "../text" } theme = { path = "../theme" } @@ -111,6 +112,7 @@ lsp = { path = "../lsp", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } rpc = { path = "../rpc", features = ["test-support"] } client = { path = "../client", features = ["test-support"] } +settings = { path = "../settings", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } workspace = { path = "../workspace", features = ["test-support"] } env_logger = "0.8" diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 49efc9ade2af2749cca42cc20362a1c174dea833..a13cbe86f9fda295155688fe5de324a6d1082fb8 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -9,17 +9,19 @@ use gpui::{App, AssetSource, Task}; use log::LevelFilter; use parking_lot::Mutex; use project::Fs; +use settings::{self, Settings}; use smol::process::Command; use std::{env, fs, path::PathBuf, sync::Arc}; use theme::{ThemeRegistry, DEFAULT_THEME_NAME}; use util::ResultExt; -use workspace::{ - self, - settings::{self, SettingsFile}, - AppState, OpenNew, OpenParams, OpenPaths, Settings, -}; +use workspace::{self, AppState, OpenNew, OpenParams, OpenPaths}; use zed::{ - self, assets::Assets, build_window_options, build_workspace, fs::RealFs, languages, menus, + self, + assets::Assets, + build_window_options, build_workspace, + fs::RealFs, + languages, menus, + settings_file::{settings_from_files, SettingsFile}, }; fn main() { @@ -97,7 +99,7 @@ fn main() { .detach_and_log_err(cx); let settings_file = cx.background().block(settings_file).unwrap(); - let mut settings_rx = Settings::from_files( + let mut settings_rx = settings_from_files( default_settings, vec![settings_file], themes.clone(), diff --git a/crates/zed/src/settings_file.rs b/crates/zed/src/settings_file.rs new file mode 100644 index 0000000000000000000000000000000000000000..46a3d41eb14c1cf2ede1a951de494014e0977fa1 --- /dev/null +++ b/crates/zed/src/settings_file.rs @@ -0,0 +1,157 @@ +use futures::{stream, StreamExt}; +use gpui::{executor, FontCache}; +use postage::sink::Sink as _; +use postage::{prelude::Stream, watch}; +use project::Fs; +use settings::{Settings, SettingsFileContent}; +use std::{path::Path, sync::Arc, time::Duration}; +use theme::ThemeRegistry; +use util::ResultExt; + +#[derive(Clone)] +pub struct SettingsFile(watch::Receiver); + +impl SettingsFile { + pub async fn new( + fs: Arc, + executor: &executor::Background, + path: impl Into>, + ) -> Self { + let path = path.into(); + let settings = Self::load(fs.clone(), &path).await.unwrap_or_default(); + let mut events = fs.watch(&path, Duration::from_millis(500)).await; + let (mut tx, rx) = watch::channel_with(settings); + executor + .spawn(async move { + while events.next().await.is_some() { + if let Some(settings) = Self::load(fs.clone(), &path).await { + if tx.send(settings).await.is_err() { + break; + } + } + } + }) + .detach(); + Self(rx) + } + + async fn load(fs: Arc, path: &Path) -> Option { + if fs.is_file(&path).await { + fs.load(&path) + .await + .log_err() + .and_then(|data| serde_json::from_str(&data).log_err()) + } else { + Some(SettingsFileContent::default()) + } + } +} + +pub fn settings_from_files( + defaults: Settings, + sources: Vec, + theme_registry: Arc, + font_cache: Arc, +) -> impl futures::stream::Stream { + stream::select_all(sources.iter().enumerate().map(|(i, source)| { + let mut rx = source.0.clone(); + // Consume the initial item from all of the constituent file watches but one. + // This way, the stream will yield exactly one item for the files' initial + // state, and won't return any more items until the files change. + if i > 0 { + rx.try_recv().ok(); + } + rx + })) + .map(move |_| { + let mut settings = defaults.clone(); + for source in &sources { + settings.merge(&*source.0.borrow(), &theme_registry, &font_cache); + } + settings + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use project::FakeFs; + use settings::SoftWrap; + + #[gpui::test] + async fn test_settings_from_files(cx: &mut gpui::TestAppContext) { + let executor = cx.background(); + let fs = FakeFs::new(executor.clone()); + + fs.save( + "/settings1.json".as_ref(), + &r#" + { + "buffer_font_size": 24, + "soft_wrap": "editor_width", + "language_overrides": { + "Markdown": { + "preferred_line_length": 100, + "soft_wrap": "preferred_line_length" + } + } + } + "# + .into(), + ) + .await + .unwrap(); + + let source1 = SettingsFile::new(fs.clone(), &executor, "/settings1.json".as_ref()).await; + let source2 = SettingsFile::new(fs.clone(), &executor, "/settings2.json".as_ref()).await; + let source3 = SettingsFile::new(fs.clone(), &executor, "/settings3.json".as_ref()).await; + + let mut settings_rx = settings_from_files( + cx.read(Settings::test), + vec![source1, source2, source3], + ThemeRegistry::new((), cx.font_cache()), + cx.font_cache(), + ); + + let settings = settings_rx.next().await.unwrap(); + let md_settings = settings.language_overrides.get("Markdown").unwrap(); + assert_eq!(settings.soft_wrap, SoftWrap::EditorWidth); + assert_eq!(settings.buffer_font_size, 24.0); + assert_eq!(settings.tab_size, 4); + assert_eq!(md_settings.soft_wrap, Some(SoftWrap::PreferredLineLength)); + assert_eq!(md_settings.preferred_line_length, Some(100)); + + fs.save( + "/settings2.json".as_ref(), + &r#" + { + "tab_size": 2, + "soft_wrap": "none", + "language_overrides": { + "Markdown": { + "preferred_line_length": 120 + } + } + } + "# + .into(), + ) + .await + .unwrap(); + + let settings = settings_rx.next().await.unwrap(); + let md_settings = settings.language_overrides.get("Markdown").unwrap(); + assert_eq!(settings.soft_wrap, SoftWrap::None); + assert_eq!(settings.buffer_font_size, 24.0); + assert_eq!(settings.tab_size, 2); + assert_eq!(md_settings.soft_wrap, Some(SoftWrap::PreferredLineLength)); + assert_eq!(md_settings.preferred_line_length, Some(120)); + + fs.remove_file("/settings2.json".as_ref(), Default::default()) + .await + .unwrap(); + + let settings = settings_rx.next().await.unwrap(); + assert_eq!(settings.tab_size, 4); + } +} diff --git a/crates/zed/src/test.rs b/crates/zed/src/test.rs index 5b3bb41c1523bf910a523766f6af2c9a631d264d..363c852c352e9455aa838440c62cfbefd3545efa 100644 --- a/crates/zed/src/test.rs +++ b/crates/zed/src/test.rs @@ -3,9 +3,9 @@ use client::{test::FakeHttpClient, ChannelList, Client, UserStore}; use gpui::MutableAppContext; use language::LanguageRegistry; use project::fs::FakeFs; +use settings::Settings; use std::sync::Arc; use theme::ThemeRegistry; -use workspace::Settings; #[cfg(test)] #[ctor::ctor] diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 1f84c31203223e623a30e307be70c19fd0e72c09..d15e2ce475bdcce8772fbb383581bc68d5acfdc0 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1,6 +1,7 @@ pub mod assets; pub mod languages; pub mod menus; +pub mod settings_file; #[cfg(any(test, feature = "test-support"))] pub mod test; @@ -23,9 +24,10 @@ use project::Project; pub use project::{self, fs}; use project_panel::ProjectPanel; use search::{BufferSearchBar, ProjectSearchBar}; +use settings::Settings; use std::{path::PathBuf, sync::Arc}; pub use workspace; -use workspace::{AppState, Settings, Workspace, WorkspaceParams}; +use workspace::{AppState, Workspace, WorkspaceParams}; action!(About); action!(Quit);