Detailed changes
@@ -556,18 +556,10 @@
"C": {
"format_on_save": "off"
},
- "Plain Text": {
- "soft_wrap": "preferred_line_length"
- },
- "Elixir": {
- "tab_size": 2
- },
"Gleam": {
"tab_size": 2
},
"Go": {
- "tab_size": 4,
- "hard_tabs": true,
"code_actions_on_format": {
"source.organizeImports": true
}
@@ -575,34 +567,6 @@
"Make": {
"hard_tabs": true
},
- "Markdown": {
- "tab_size": 2,
- "soft_wrap": "preferred_line_length"
- },
- "JavaScript": {
- "tab_size": 2
- },
- "Terraform": {
- "tab_size": 2
- },
- "TypeScript": {
- "tab_size": 2
- },
- "TSX": {
- "tab_size": 2
- },
- "YAML": {
- "tab_size": 2
- },
- "JSON": {
- "tab_size": 2
- },
- "OCaml": {
- "tab_size": 2
- },
- "OCaml Interface": {
- "tab_size": 2
- },
"Prisma": {
"tab_size": 2
}
@@ -10,7 +10,7 @@ use serde::{
de::{self, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
#[derive(Clone, Debug, Default, PartialEq)]
pub enum ZedDotDevModel {
@@ -332,13 +332,12 @@ impl Settings for AssistantSettings {
type FileContent = AssistantSettingsContent;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
let mut settings = AssistantSettings::default();
- for value in [default_value].iter().chain(user_values) {
+ for value in sources.defaults_and_customizations() {
let value = value.upgrade();
merge(&mut settings.enabled, value.enabled);
merge(&mut settings.button, value.button);
@@ -17,7 +17,7 @@ use serde::Deserialize;
use serde_derive::Serialize;
use smol::io::AsyncReadExt;
-use settings::{Settings, SettingsStore};
+use settings::{Settings, SettingsSources, SettingsStore};
use smol::{fs::File, process::Command};
use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
@@ -91,13 +91,12 @@ impl Settings for AutoUpdateSetting {
type FileContent = AutoUpdateSettingOverride;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
Ok(Self(
- Self::json_merge(default_value, user_values)?
+ sources
+ .release_channel
+ .or(sources.user)
+ .unwrap_or(sources.default)
.0
.ok_or_else(Self::missing_default)?,
))
@@ -2,7 +2,7 @@ use anyhow::Result;
use gpui::AppContext;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
#[derive(Deserialize, Debug)]
pub struct CallSettings {
@@ -29,14 +29,7 @@ impl Settings for CallSettings {
type FileContent = CallSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _cx: &mut AppContext,
- ) -> Result<Self>
- where
- Self: Sized,
- {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -28,7 +28,7 @@ use release_channel::{AppVersion, ReleaseChannel};
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsStore};
+use settings::{Settings, SettingsSources, SettingsStore};
use std::fmt;
use std::{
any::TypeId,
@@ -97,15 +97,11 @@ impl Settings for ClientSettings {
type FileContent = ClientSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self>
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self>
where
Self: Sized,
{
- let mut result = Self::load_via_json_merge(default_value, user_values)?;
+ let mut result = sources.json_merge::<Self>()?;
if let Some(server_url) = &*ZED_SERVER_URL {
result.server_url = server_url.clone()
}
@@ -427,21 +423,19 @@ impl settings::Settings for TelemetrySettings {
type FileContent = TelemetrySettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
Ok(Self {
- diagnostics: user_values.first().and_then(|v| v.diagnostics).unwrap_or(
- default_value
+ diagnostics: sources.user.as_ref().and_then(|v| v.diagnostics).unwrap_or(
+ sources
+ .default
.diagnostics
.ok_or_else(Self::missing_default)?,
),
- metrics: user_values
- .first()
+ metrics: sources
+ .user
+ .as_ref()
.and_then(|v| v.metrics)
- .unwrap_or(default_value.metrics.ok_or_else(Self::missing_default)?),
+ .unwrap_or(sources.default.metrics.ok_or_else(Self::missing_default)?),
})
}
}
@@ -2,7 +2,7 @@ use anyhow;
use gpui::Pixels;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use workspace::dock::DockPosition;
#[derive(Deserialize, Debug)]
@@ -53,48 +53,52 @@ pub struct MessageEditorSettings {
impl Settings for CollaborationPanelSettings {
const KEY: Option<&'static str> = Some("collaboration_panel");
+
type FileContent = PanelSettingsContent;
+
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
impl Settings for ChatPanelSettings {
const KEY: Option<&'static str> = Some("chat_panel");
+
type FileContent = PanelSettingsContent;
+
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
impl Settings for NotificationPanelSettings {
const KEY: Option<&'static str> = Some("notification_panel");
+
type FileContent = PanelSettingsContent;
+
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
impl Settings for MessageEditorSettings {
const KEY: Option<&'static str> = Some("message_editor");
+
type FileContent = MessageEditorSettings;
+
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
@@ -1,5 +1,8 @@
+use anyhow::Result;
+use gpui::AppContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
+use settings::{Settings, SettingsSources};
#[derive(Deserialize, Debug)]
pub struct ProjectDiagnosticsSettings {
@@ -15,18 +18,11 @@ pub struct ProjectDiagnosticsSettingsContent {
include_warnings: Option<bool>,
}
-impl settings::Settings for ProjectDiagnosticsSettings {
+impl Settings for ProjectDiagnosticsSettings {
const KEY: Option<&'static str> = Some("diagnostics");
type FileContent = ProjectDiagnosticsSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _cx: &mut gpui::AppContext,
- ) -> anyhow::Result<Self>
- where
- Self: Sized,
- {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1,6 +1,7 @@
+use gpui::AppContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
#[derive(Deserialize, Clone)]
pub struct EditorSettings {
@@ -224,10 +225,9 @@ impl Settings for EditorSettings {
type FileContent = EditorSettingsContent;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut gpui::AppContext,
+ sources: SettingsSources<Self::FileContent>,
+ _: &mut AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
@@ -3,7 +3,7 @@ use collections::HashMap;
use gpui::AppContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use std::sync::Arc;
#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
@@ -26,14 +26,7 @@ impl Settings for ExtensionSettings {
type FileContent = Self;
- fn load(
- _default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _cx: &mut AppContext,
- ) -> Result<Self>
- where
- Self: Sized,
- {
- Ok(user_values.get(0).copied().cloned().unwrap_or_default())
+ fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut AppContext) -> Result<Self> {
+ Ok(sources.user.cloned().unwrap_or_default())
}
}
@@ -5,7 +5,7 @@ use editor::Editor;
use gpui::{actions, AppContext, ViewContext, WindowContext};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use std::{
fs::OpenOptions,
path::{Path, PathBuf},
@@ -50,12 +50,8 @@ impl settings::Settings for JournalSettings {
type FileContent = Self;
- fn load(
- defaults: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(defaults, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -38,6 +38,7 @@ use schemars::{
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value;
use smol::future::FutureExt as _;
+use std::num::NonZeroU32;
use std::{
any::Any,
cell::RefCell,
@@ -73,6 +74,8 @@ pub use syntax_map::{OwnedSyntaxLayer, SyntaxLayer};
pub use text::LineEnding;
pub use tree_sitter::{Parser, Tree};
+use crate::language_settings::SoftWrap;
+
/// Initializes the `language` crate.
///
/// This should be called before making use of items from the create.
@@ -99,6 +102,7 @@ lazy_static! {
pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
LanguageConfig {
name: "Plain Text".into(),
+ soft_wrap: Some(SoftWrap::PreferredLineLength),
..Default::default()
},
None,
@@ -576,6 +580,17 @@ pub struct LanguageConfig {
/// The names of any Prettier plugins that should be used for this language.
#[serde(default)]
pub prettier_plugins: Vec<Arc<str>>,
+
+ /// Whether to indent lines using tab characters, as opposed to multiple
+ /// spaces.
+ #[serde(default)]
+ pub hard_tabs: Option<bool>,
+ /// How many columns a tab should occupy.
+ #[serde(default)]
+ pub tab_size: Option<NonZeroU32>,
+ /// How to soft-wrap long lines of text.
+ #[serde(default)]
+ pub soft_wrap: Option<SoftWrap>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
@@ -660,6 +675,9 @@ impl Default for LanguageConfig {
prettier_parser_name: None,
prettier_plugins: Default::default(),
collapsed_placeholder: Default::default(),
+ hard_tabs: Default::default(),
+ tab_size: Default::default(),
+ soft_wrap: Default::default(),
}
}
}
@@ -1,3 +1,4 @@
+use crate::language_settings::{AllLanguageSettingsContent, LanguageSettingsContent};
use crate::{
language_settings::all_language_settings, task_context::ContextProvider, CachedLspAdapter,
File, Language, LanguageConfig, LanguageId, LanguageMatcher, LanguageServerName, LspAdapter,
@@ -38,6 +39,7 @@ pub struct LanguageRegistry {
struct LanguageRegistryState {
next_language_server_id: usize,
languages: Vec<Arc<Language>>,
+ language_settings: AllLanguageSettingsContent,
available_languages: Vec<AvailableLanguage>,
grammars: HashMap<Arc<str>, AvailableGrammar>,
lsp_adapters: HashMap<Arc<str>, Vec<Arc<CachedLspAdapter>>>,
@@ -145,6 +147,7 @@ impl LanguageRegistry {
languages: Vec::new(),
available_languages: Vec::new(),
grammars: Default::default(),
+ language_settings: Default::default(),
loading_languages: Default::default(),
lsp_adapters: Default::default(),
subscription: watch::channel(),
@@ -338,6 +341,10 @@ impl LanguageRegistry {
*state.subscription.0.borrow_mut() = ();
}
+ pub fn language_settings(&self) -> AllLanguageSettingsContent {
+ self.state.read().language_settings.clone()
+ }
+
pub fn language_names(&self) -> Vec<String> {
let state = self.state.read();
let mut result = state
@@ -854,6 +861,16 @@ impl LanguageRegistryState {
if let Some(theme) = self.theme.as_ref() {
language.set_theme(theme.syntax());
}
+ self.language_settings.languages.insert(
+ language.name(),
+ LanguageSettingsContent {
+ tab_size: language.config.tab_size,
+ hard_tabs: language.config.hard_tabs,
+ soft_wrap: language.config.soft_wrap,
+ ..Default::default()
+ }
+ .clone(),
+ );
self.languages.push(language);
self.version += 1;
*self.subscription.0.borrow_mut() = ();
@@ -10,7 +10,7 @@ use schemars::{
JsonSchema,
};
use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsLocation};
+use settings::{Settings, SettingsLocation, SettingsSources};
use std::{num::NonZeroU32, path::Path, sync::Arc};
impl<'a> Into<SettingsLocation<'a>> for &'a dyn File {
@@ -119,7 +119,7 @@ pub struct CopilotSettings {
}
/// The settings for all languages.
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct AllLanguageSettingsContent {
/// The settings for enabling/disabling features.
#[serde(default)]
@@ -140,7 +140,7 @@ pub struct AllLanguageSettingsContent {
}
/// The settings for a particular language.
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct LanguageSettingsContent {
/// How many columns a tab should occupy.
///
@@ -249,7 +249,7 @@ pub struct LanguageSettingsContent {
}
/// The contents of the GitHub Copilot settings.
-#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
pub struct CopilotSettingsContent {
/// A list of globs representing files that Copilot should be disabled for.
#[serde(default)]
@@ -257,7 +257,7 @@ pub struct CopilotSettingsContent {
}
/// The settings for enabling/disabling features.
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct FeaturesContent {
/// Whether the GitHub Copilot feature is enabled.
@@ -473,11 +473,9 @@ impl settings::Settings for AllLanguageSettings {
type FileContent = AllLanguageSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_settings: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ let default_value = sources.default;
+
// A default is provided for all settings.
let mut defaults: LanguageSettings =
serde_json::from_value(serde_json::to_value(&default_value.defaults)?)?;
@@ -500,7 +498,8 @@ impl settings::Settings for AllLanguageSettings {
.and_then(|c| c.disabled_globs.as_ref())
.ok_or_else(Self::missing_default)?;
- for user_settings in user_settings {
+ let mut file_types: HashMap<Arc<str>, Vec<String>> = HashMap::default();
+ for user_settings in sources.customizations() {
if let Some(copilot) = user_settings.features.as_ref().and_then(|f| f.copilot) {
copilot_enabled = copilot;
}
@@ -528,11 +527,8 @@ impl settings::Settings for AllLanguageSettings {
user_language_settings,
);
}
- }
- let mut file_types: HashMap<Arc<str>, Vec<String>> = HashMap::default();
- for user_file_types in user_settings.iter().map(|s| &s.file_types) {
- for (language, suffixes) in user_file_types {
+ for (language, suffixes) in &user_settings.file_types {
file_types
.entry(language.clone())
.or_default()
@@ -2,12 +2,13 @@ use anyhow::{anyhow, bail, Context, Result};
use async_trait::async_trait;
use collections::HashMap;
use futures::StreamExt;
+use gpui::AppContext;
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::{CodeActionKind, LanguageServerBinary};
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use serde_json::json;
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use smol::{fs, fs::File};
use std::{any::Any, env::consts, ffi::OsString, path::PathBuf, sync::Arc};
use util::{
@@ -31,15 +32,8 @@ impl Settings for DenoSettings {
type FileContent = DenoSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut gpui::AppContext,
- ) -> Result<Self>
- where
- Self: Sized,
- {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1,14 +1,14 @@
use anyhow::{anyhow, bail, Context, Result};
use async_trait::async_trait;
use futures::StreamExt;
-use gpui::{AsyncAppContext, Task};
+use gpui::{AppContext, AsyncAppContext, Task};
pub use language::*;
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
use project::project_settings::ProjectSettings;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use smol::fs::{self, File};
use std::{
any::Any,
@@ -56,15 +56,8 @@ impl Settings for ElixirSettings {
type FileContent = ElixirSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut gpui::AppContext,
- ) -> Result<Self>
- where
- Self: Sized,
- {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -10,6 +10,7 @@ brackets = [
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string", "comment"] },
{ start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
]
+tab_size = 2
scope_opt_in_language_servers = ["tailwindcss-language-server"]
[overrides.string]
@@ -11,3 +11,5 @@ brackets = [
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
]
+tab_size = 4
+hard_tabs = true
@@ -15,6 +15,7 @@ brackets = [
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
]
word_characters = ["$", "#"]
+tab_size = 2
scope_opt_in_language_servers = ["tailwindcss-language-server"]
prettier_parser_name = "babel"
@@ -9,3 +9,4 @@ brackets = [
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
]
prettier_parser_name = "json"
+tab_size = 2
@@ -1,11 +1,12 @@
use anyhow::Context;
-use gpui::AppContext;
+use gpui::{AppContext, BorrowAppContext};
pub use language::*;
use node_runtime::NodeRuntime;
use rust_embed::RustEmbed;
-use settings::Settings;
+use settings::{Settings, SettingsStore};
+use smol::stream::StreamExt;
use std::{str, sync::Arc};
-use util::asset_str;
+use util::{asset_str, ResultExt};
use crate::{elixir::elixir_task_context, rust::RustContextProvider};
@@ -327,6 +328,27 @@ pub fn init(
"Svelte".into(),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
);
+
+ let mut subscription = languages.subscribe();
+ let mut prev_language_settings = languages.language_settings();
+
+ cx.spawn(|cx| async move {
+ while subscription.next().await.is_some() {
+ let language_settings = languages.language_settings();
+ if language_settings != prev_language_settings {
+ cx.update(|cx| {
+ cx.update_global(|settings: &mut SettingsStore, cx| {
+ settings
+ .set_extension_settings(language_settings.clone(), cx)
+ .log_err();
+ });
+ })?;
+ prev_language_settings = language_settings;
+ }
+ }
+ anyhow::Ok(())
+ })
+ .detach();
}
#[cfg(any(test, feature = "test-support"))]
@@ -12,3 +12,6 @@ brackets = [
{ start = "`", end = "`", close = false, newline = false },
]
prettier_parser_name = "markdown"
+
+tab_size = 2
+soft_wrap = "preferred_line_length"
@@ -10,3 +10,4 @@ brackets = [
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true }
]
+tab_size = 2
@@ -11,3 +11,4 @@ brackets = [
{ start = "(", end = ")", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] }
]
+tab_size = 2
@@ -12,3 +12,4 @@ brackets = [
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
]
+tab_size = 2
@@ -16,6 +16,7 @@ brackets = [
word_characters = ["#", "$"]
scope_opt_in_language_servers = ["tailwindcss-language-server"]
prettier_parser_name = "typescript"
+tab_size = 2
[overrides.element]
line_comments = { remove = true }
@@ -15,3 +15,4 @@ brackets = [
]
word_characters = ["#", "$"]
prettier_parser_name = "typescript"
+tab_size = 2
@@ -11,3 +11,4 @@ brackets = [
increase_indent_pattern = ":\\s*[|>]?\\s*$"
prettier_parser_name = "yaml"
+tab_size = 2
@@ -2,7 +2,7 @@ use collections::HashMap;
use gpui::AppContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use std::sync::Arc;
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
@@ -61,10 +61,9 @@ impl Settings for ProjectSettings {
type FileContent = Self;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
@@ -2,7 +2,7 @@ use anyhow;
use gpui::Pixels;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
@@ -62,10 +62,9 @@ impl Settings for ProjectPanelSettings {
type FileContent = ProjectPanelSettingsContent;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
@@ -8,7 +8,9 @@ use util::asset_str;
pub use keymap_file::KeymapFile;
pub use settings_file::*;
-pub use settings_store::{Settings, SettingsJsonSchemaParams, SettingsLocation, SettingsStore};
+pub use settings_store::{
+ Settings, SettingsJsonSchemaParams, SettingsLocation, SettingsSources, SettingsStore,
+};
#[derive(RustEmbed)]
#[folder = "../../assets"]
@@ -29,14 +29,7 @@ pub trait Settings: 'static + Send + Sync {
/// The logic for combining together values from one or more JSON files into the
/// final value for this setting.
- ///
- /// The user values are ordered from least specific (the global settings file)
- /// to most specific (the innermost local settings file).
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- cx: &mut AppContext,
- ) -> Result<Self>
+ fn load(sources: SettingsSources<Self::FileContent>, cx: &mut AppContext) -> Result<Self>
where
Self: Sized;
@@ -48,31 +41,6 @@ pub trait Settings: 'static + Send + Sync {
generator.root_schema_for::<Self::FileContent>()
}
- fn json_merge(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- ) -> Result<Self::FileContent> {
- let mut merged = serde_json::Value::Null;
- for value in [default_value].iter().chain(user_values) {
- merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
- }
- Ok(serde_json::from_value(merged)?)
- }
-
- fn load_via_json_merge(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- ) -> Result<Self>
- where
- Self: DeserializeOwned,
- {
- let mut merged = serde_json::Value::Null;
- for value in [default_value].iter().chain(user_values) {
- merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
- }
- Ok(serde_json::from_value(merged)?)
- }
-
fn missing_default() -> anyhow::Error {
anyhow::anyhow!("missing default")
}
@@ -119,6 +87,48 @@ pub trait Settings: 'static + Send + Sync {
}
}
+#[derive(Clone, Copy, Debug)]
+pub struct SettingsSources<'a, T> {
+ /// The default Zed settings.
+ pub default: &'a T,
+ /// Settings provided by extensions.
+ pub extensions: Option<&'a T>,
+ /// The user settings.
+ pub user: Option<&'a T>,
+ /// The user settings for the current release channel.
+ pub release_channel: Option<&'a T>,
+ /// The project settings, ordered from least specific to most specific.
+ pub project: &'a [&'a T],
+}
+
+impl<'a, T: Serialize> SettingsSources<'a, T> {
+ /// Returns an iterator over the default settings as well as all settings customizations.
+ pub fn defaults_and_customizations(&self) -> impl Iterator<Item = &T> {
+ [self.default].into_iter().chain(self.customizations())
+ }
+
+ /// Returns an iterator over all of the settings customizations.
+ pub fn customizations(&self) -> impl Iterator<Item = &T> {
+ self.extensions
+ .into_iter()
+ .chain(self.user)
+ .chain(self.release_channel)
+ .chain(self.project.iter().copied())
+ }
+
+ /// Returns the settings after performing a JSON merge of the customizations into the
+ /// default settings.
+ ///
+ /// More-specific customizations win out over the less-specific ones.
+ pub fn json_merge<O: DeserializeOwned>(&self) -> Result<O> {
+ let mut merged = serde_json::Value::Null;
+ for value in self.defaults_and_customizations() {
+ merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
+ }
+ Ok(serde_json::from_value(merged)?)
+ }
+}
+
#[derive(Clone, Copy)]
pub struct SettingsLocation<'a> {
pub worktree_id: usize,
@@ -136,6 +146,7 @@ pub struct SettingsStore {
setting_values: HashMap<TypeId, Box<dyn AnySettingValue>>,
raw_default_settings: serde_json::Value,
raw_user_settings: serde_json::Value,
+ raw_extension_settings: serde_json::Value,
raw_local_settings: BTreeMap<(usize, Arc<Path>), serde_json::Value>,
tab_size_callback: Option<(
TypeId,
@@ -151,6 +162,7 @@ impl Default for SettingsStore {
setting_values: Default::default(),
raw_default_settings: serde_json::json!({}),
raw_user_settings: serde_json::json!({}),
+ raw_extension_settings: serde_json::json!({}),
raw_local_settings: Default::default(),
tab_size_callback: Default::default(),
}
@@ -169,8 +181,7 @@ trait AnySettingValue: 'static + Send + Sync {
fn deserialize_setting(&self, json: &serde_json::Value) -> Result<DeserializedSetting>;
fn load_setting(
&self,
- default_value: &DeserializedSetting,
- custom: &[DeserializedSetting],
+ sources: SettingsSources<DeserializedSetting>,
cx: &mut AppContext,
) -> Result<Box<dyn Any>>;
fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any;
@@ -204,29 +215,35 @@ impl SettingsStore {
.deserialize_setting(&self.raw_default_settings)
.log_err()
{
- let mut user_values_stack = Vec::new();
-
- if let Some(user_settings) = setting_value
+ let user_value = setting_value
.deserialize_setting(&self.raw_user_settings)
- .log_err()
- {
- user_values_stack = vec![user_settings];
- }
+ .log_err();
+ let mut release_channel_value = None;
if let Some(release_settings) = &self
.raw_user_settings
.get(release_channel::RELEASE_CHANNEL.dev_name())
{
- if let Some(release_settings) = setting_value
+ release_channel_value = setting_value
.deserialize_setting(release_settings)
- .log_err()
- {
- user_values_stack.push(release_settings);
- }
+ .log_err();
}
+ let extension_value = setting_value
+ .deserialize_setting(&self.raw_extension_settings)
+ .log_err();
+
if let Some(setting) = setting_value
- .load_setting(&default_settings, &user_values_stack, cx)
+ .load_setting(
+ SettingsSources {
+ default: &default_settings,
+ release_channel: release_channel_value.as_ref(),
+ extensions: extension_value.as_ref(),
+ user: user_value.as_ref(),
+ project: &[],
+ },
+ cx,
+ )
.context("A default setting must be added to the `default.json` file")
.log_err()
{
@@ -425,6 +442,21 @@ impl SettingsStore {
Ok(())
}
+ pub fn set_extension_settings<T: Serialize>(
+ &mut self,
+ content: T,
+ cx: &mut AppContext,
+ ) -> Result<()> {
+ let settings: serde_json::Value = serde_json::to_value(content)?;
+ if settings.is_object() {
+ self.raw_extension_settings = settings;
+ self.recompute_values(None, cx)?;
+ Ok(())
+ } else {
+ Err(anyhow!("settings must be an object"))
+ }
+ }
+
/// Add or remove a set of local settings via a JSON string.
pub fn clear_local_settings(&mut self, root_id: usize, cx: &mut AppContext) -> Result<()> {
self.raw_local_settings.retain(|k, _| k.0 != root_id);
@@ -551,22 +583,20 @@ impl SettingsStore {
cx: &mut AppContext,
) -> Result<()> {
// Reload the global and local values for every setting.
- let mut user_settings_stack = Vec::<DeserializedSetting>::new();
+ let mut project_settings_stack = Vec::<DeserializedSetting>::new();
let mut paths_stack = Vec::<Option<(usize, &Path)>>::new();
for setting_value in self.setting_values.values_mut() {
let default_settings = setting_value.deserialize_setting(&self.raw_default_settings)?;
- user_settings_stack.clear();
- paths_stack.clear();
+ let extension_settings = setting_value
+ .deserialize_setting(&self.raw_extension_settings)
+ .log_err();
- if let Some(user_settings) = setting_value
+ let user_settings = setting_value
.deserialize_setting(&self.raw_user_settings)
- .log_err()
- {
- user_settings_stack.push(user_settings);
- paths_stack.push(None);
- }
+ .log_err();
+ let mut release_channel_settings = None;
if let Some(release_settings) = &self
.raw_user_settings
.get(release_channel::RELEASE_CHANNEL.dev_name())
@@ -575,15 +605,25 @@ impl SettingsStore {
.deserialize_setting(release_settings)
.log_err()
{
- user_settings_stack.push(release_settings);
- paths_stack.push(None);
+ release_channel_settings = Some(release_settings);
}
}
// If the global settings file changed, reload the global value for the field.
+ project_settings_stack.clear();
+ paths_stack.clear();
if changed_local_path.is_none() {
if let Some(value) = setting_value
- .load_setting(&default_settings, &user_settings_stack, cx)
+ .load_setting(
+ SettingsSources {
+ default: &default_settings,
+ extensions: extension_settings.as_ref(),
+ user: user_settings.as_ref(),
+ release_channel: release_channel_settings.as_ref(),
+ project: &[],
+ },
+ cx,
+ )
.log_err()
{
setting_value.set_global_value(value);
@@ -597,7 +637,7 @@ impl SettingsStore {
if let Some((prev_root_id, prev_path)) = prev_entry {
if root_id != prev_root_id || !path.starts_with(prev_path) {
paths_stack.pop();
- user_settings_stack.pop();
+ project_settings_stack.pop();
continue;
}
}
@@ -608,7 +648,7 @@ impl SettingsStore {
setting_value.deserialize_setting(local_settings).log_err()
{
paths_stack.push(Some((*root_id, path.as_ref())));
- user_settings_stack.push(local_settings);
+ project_settings_stack.push(local_settings);
// If a local settings file changed, then avoid recomputing local
// settings for any path outside of that directory.
@@ -619,7 +659,16 @@ impl SettingsStore {
}
if let Some(value) = setting_value
- .load_setting(&default_settings, &user_settings_stack, cx)
+ .load_setting(
+ SettingsSources {
+ default: &default_settings,
+ extensions: extension_settings.as_ref(),
+ user: user_settings.as_ref(),
+ release_channel: release_channel_settings.as_ref(),
+ project: &project_settings_stack.iter().collect::<Vec<_>>(),
+ },
+ cx,
+ )
.log_err()
{
setting_value.set_local_value(*root_id, path.clone(), value);
@@ -660,16 +709,30 @@ impl<T: Settings> AnySettingValue for SettingValue<T> {
fn load_setting(
&self,
- default_value: &DeserializedSetting,
- user_values: &[DeserializedSetting],
+ values: SettingsSources<DeserializedSetting>,
cx: &mut AppContext,
) -> Result<Box<dyn Any>> {
- let default_value = default_value.0.downcast_ref::<T::FileContent>().unwrap();
- let values: SmallVec<[&T::FileContent; 6]> = user_values
- .iter()
- .map(|value| value.0.downcast_ref().unwrap())
- .collect();
- Ok(Box::new(T::load(default_value, &values, cx)?))
+ Ok(Box::new(T::load(
+ SettingsSources {
+ default: values.default.0.downcast_ref::<T::FileContent>().unwrap(),
+ extensions: values
+ .extensions
+ .map(|value| value.0.downcast_ref::<T::FileContent>().unwrap()),
+ user: values
+ .user
+ .map(|value| value.0.downcast_ref::<T::FileContent>().unwrap()),
+ release_channel: values
+ .release_channel
+ .map(|value| value.0.downcast_ref::<T::FileContent>().unwrap()),
+ project: values
+ .project
+ .iter()
+ .map(|value| value.0.downcast_ref().unwrap())
+ .collect::<SmallVec<[_; 3]>>()
+ .as_slice(),
+ },
+ cx,
+ )?))
}
fn deserialize_setting(&self, mut json: &serde_json::Value) -> Result<DeserializedSetting> {
@@ -1277,12 +1340,8 @@ mod tests {
const KEY: Option<&'static str> = Some("user");
type FileContent = UserSettingsJson;
- fn load(
- default_value: &UserSettingsJson,
- user_values: &[&UserSettingsJson],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1293,12 +1352,8 @@ mod tests {
const KEY: Option<&'static str> = Some("turbo");
type FileContent = Option<bool>;
- fn load(
- default_value: &Option<bool>,
- user_values: &[&Option<bool>],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1321,12 +1376,8 @@ mod tests {
type FileContent = MultiKeySettingsJson;
- fn load(
- default_value: &MultiKeySettingsJson,
- user_values: &[&MultiKeySettingsJson],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1354,12 +1405,8 @@ mod tests {
type FileContent = JournalSettingsJson;
- fn load(
- default_value: &JournalSettingsJson,
- user_values: &[&JournalSettingsJson],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1380,8 +1427,8 @@ mod tests {
type FileContent = Self;
- fn load(default_value: &Self, user_values: &[&Self], _: &mut AppContext) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
}
@@ -1,5 +1,6 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
+use settings::{Settings, SettingsSources};
#[derive(Serialize, Deserialize, PartialEq, Default)]
pub(crate) struct TaskSettings {
@@ -13,22 +14,15 @@ pub(crate) struct TaskSettingsContent {
show_status_indicator: Option<bool>,
}
-impl settings::Settings for TaskSettings {
+impl Settings for TaskSettings {
const KEY: Option<&'static str> = Some("task");
type FileContent = TaskSettingsContent;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
- ) -> gpui::Result<Self>
- where
- Self: Sized,
- {
- let this = Self::json_merge(default_value, user_values)?;
- Ok(Self {
- show_status_indicator: this.show_status_indicator.unwrap_or(true),
- })
+ ) -> gpui::Result<Self> {
+ sources.json_merge()
}
}
@@ -7,7 +7,7 @@ use schemars::{
};
use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
-use settings::SettingsJsonSchemaParams;
+use settings::{SettingsJsonSchemaParams, SettingsSources};
use std::path::PathBuf;
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -171,12 +171,12 @@ impl settings::Settings for TerminalSettings {
type FileContent = TerminalSettingsContent;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
+
fn json_schema(
generator: &mut SchemaGenerator,
params: &SettingsJsonSchemaParams,
@@ -14,7 +14,7 @@ use schemars::{
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
-use settings::{Settings, SettingsJsonSchemaParams};
+use settings::{Settings, SettingsJsonSchemaParams, SettingsSources};
use std::sync::Arc;
use util::ResultExt as _;
@@ -316,14 +316,11 @@ impl settings::Settings for ThemeSettings {
type FileContent = ThemeSettingsContent;
- fn load(
- defaults: &Self::FileContent,
- user_values: &[&Self::FileContent],
- cx: &mut AppContext,
- ) -> Result<Self> {
+ fn load(sources: SettingsSources<Self::FileContent>, cx: &mut AppContext) -> Result<Self> {
let themes = ThemeRegistry::default_global(cx);
let system_appearance = SystemAppearance::default_global(cx);
+ let defaults = sources.default;
let mut this = Self {
ui_font_size: defaults.ui_font_size.unwrap().into(),
ui_font: Font {
@@ -348,15 +345,15 @@ impl settings::Settings for ThemeSettings {
theme_overrides: None,
};
- for value in user_values.iter().copied().cloned() {
- if let Some(value) = value.buffer_font_family {
+ for value in sources.user.into_iter().chain(sources.release_channel) {
+ if let Some(value) = value.buffer_font_family.clone() {
this.buffer_font.family = value.into();
}
if let Some(value) = value.buffer_font_features {
this.buffer_font.features = value;
}
- if let Some(value) = value.ui_font_family {
+ if let Some(value) = value.ui_font_family.clone() {
this.ui_font.family = value.into();
}
if let Some(value) = value.ui_font_features {
@@ -373,7 +370,7 @@ impl settings::Settings for ThemeSettings {
}
}
- this.theme_overrides = value.theme_overrides;
+ this.theme_overrides = value.theme_overrides.clone();
this.apply_theme_overrides();
merge(&mut this.ui_font_size, value.ui_font_size.map(Into::into));
@@ -35,7 +35,7 @@ use replace::multi_replace;
use schemars::JsonSchema;
use serde::Deserialize;
use serde_derive::Serialize;
-use settings::{update_settings_file, Settings, SettingsStore};
+use settings::{update_settings_file, Settings, SettingsSources, SettingsStore};
use state::{EditorState, Mode, Operator, RecordedSelection, WorkspaceState};
use std::{ops::Range, sync::Arc};
use surrounds::{add_surrounds, change_surrounds, delete_surrounds};
@@ -779,13 +779,9 @@ impl Settings for VimModeSetting {
type FileContent = Option<bool>;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
- Ok(Self(user_values.iter().rev().find_map(|v| **v).unwrap_or(
- default_value.ok_or_else(Self::missing_default)?,
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ Ok(Self(sources.user.copied().flatten().unwrap_or(
+ sources.default.ok_or_else(Self::missing_default)?,
)))
}
}
@@ -824,11 +820,7 @@ impl Settings for VimSettings {
type FileContent = VimSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
///
@@ -70,16 +70,12 @@ impl Settings for BaseKeymap {
type FileContent = Option<Self>;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
- ) -> anyhow::Result<Self>
- where
- Self: Sized,
- {
- Ok(user_values
- .first()
- .and_then(|v| **v)
- .unwrap_or(default_value.unwrap()))
+ ) -> anyhow::Result<Self> {
+ if let Some(Some(user_value)) = sources.user.copied() {
+ return Ok(user_value);
+ }
+ sources.default.ok_or_else(Self::missing_default)
}
}
@@ -20,7 +20,7 @@ use gpui::{
use project::{Project, ProjectEntryId, ProjectPath};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
use smallvec::SmallVec;
use std::{
any::{Any, TypeId},
@@ -76,12 +76,8 @@ impl Settings for ItemSettings {
type FileContent = ItemSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut AppContext,
- ) -> Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1,6 +1,8 @@
+use anyhow::Result;
+use gpui::AppContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
#[derive(Deserialize)]
pub struct WorkspaceSettings {
@@ -63,12 +65,8 @@ impl Settings for WorkspaceSettings {
type FileContent = WorkspaceSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut gpui::AppContext,
- ) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -77,11 +75,7 @@ impl Settings for TabBarSettings {
type FileContent = TabBarSettingsContent;
- fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
- _: &mut gpui::AppContext,
- ) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
}
}
@@ -1,7 +1,7 @@
use gpui::AppContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Settings;
+use settings::{Settings, SettingsSources};
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct WorktreeSettings {
@@ -31,10 +31,9 @@ impl Settings for WorktreeSettings {
type FileContent = Self;
fn load(
- default_value: &Self::FileContent,
- user_values: &[&Self::FileContent],
+ sources: SettingsSources<Self::FileContent>,
_: &mut AppContext,
) -> anyhow::Result<Self> {
- Self::load_via_json_merge(default_value, user_values)
+ sources.json_merge()
}
}
@@ -607,6 +607,7 @@ pub fn handle_keymap_file_changes(
cx.observe_global::<SettingsStore>(move |cx| {
let new_base_keymap = *BaseKeymap::get_global(cx);
let new_vim_enabled = VimModeSetting::get_global(cx).0;
+
if new_base_keymap != old_base_keymap || new_vim_enabled != old_vim_enabled {
old_base_keymap = new_base_keymap;
old_vim_enabled = new_vim_enabled;
@@ -3062,6 +3063,7 @@ mod tests {
let mut app_state = AppState::test(cx);
let state = Arc::get_mut(&mut app_state).unwrap();
+ env_logger::try_init().ok();
state.build_window_options = build_window_options;
theme::init(theme::LoadThemes::JustBase, cx);
@@ -9,3 +9,4 @@ brackets = [
{ start = "(", end = ")", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string", "comment"] },
]
+tab_size = 2
@@ -7,3 +7,4 @@ brackets = [
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true }
]
+tab_size = 2