diff --git a/Cargo.lock b/Cargo.lock index b76445011c..d380fa4306 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 7dbafdb3be..88fd614a89 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 59c8b08b68..b2bba37e38 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 a64ecc8b7b..95426517d7 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 a7c9123894..9d575768a6 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 43bd2548a8..6a4dbf653d 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 06c6b8f1bb..deb6f8e4a3 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 4cf45041e9..4f59ffc68c 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 da50e99f1e..1d317278a6 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 690c5100ec..41826017cd 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 77e169b91b..4664d9c52e 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 2bea851ec2..27db9a8de5 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 0a019e1701..46d71ebeae 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 18f780dacc..0ffe3feb6d 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 67d5aee773..9a102dd5ce 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 b946ea48fb..47dd9b15bc 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 471e43a0ed..7dfe9a54de 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 eaad41e080..76744274c7 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 109d33097d..19b43d5721 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 e5ed300dc7..fc9444a14c 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 c33cb60b3e..14b57f2d13 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 2e50178036..81e975cc73 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 0dd6b08bac..6ae81fcb5e 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 cdaedf109c..de22c0eda0 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 74e7d90d68..f707aa30f7 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 5553e3b9a2..77961de01f 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 b5f8eedf80..5dc93245b9 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 745f23154f..9009dfee79 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 c39fb2f10b..6e27fa16c5 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 eb12de9b72..51c7807660 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 0000000000..baaf787bee --- /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 0000000000..467456b2fc --- /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 ff3d50454f..585d10d563 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 d61cac1c44..5bcbd62e09 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 28ee7de872..4ffa6a4363 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 609843d969..16ee1612d5 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 7ef0bd8543..75d1b1b8f2 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 a12f81857f..cf920b108d 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 fb13ef2fd0..d3fa9dbfbf 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 5ccf8056e6..0000000000 --- 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 a91dd645a0..c9a2c819e2 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 8212b25082..e9b20bf3a0 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 cd3e0e7b30..7ee7d5cf44 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 86011fdb46..25f45b9cc0 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 49efc9ade2..a13cbe86f9 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 0000000000..46a3d41eb1 --- /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 5b3bb41c15..363c852c35 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 1f84c31203..d15e2ce475 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);