Add the ability for extensions to provide language settings (#10296)

This PR adds the ability for extensions to provide certain language
settings via the language `config.toml`.

These settings are then merged in with the rest of the settings when the
language is loaded from the extension.

The language settings that are available are:

- `tab_size`
- `hard_tabs`
- `soft_wrap`

Additionally, for bundled languages we moved these settings out of the
`settings/default.json` and into their respective `config.toml`s .

For languages currently provided by extensions, we are leaving the
values in the `settings/default.json` temporarily until all released
versions of Zed are able to load these settings from the extension.

---

Along the way we ended up refactoring the `Settings::load` method
slightly, introducing a new `SettingsSources` struct to better convey
where the settings are being loaded from.

This makes it easier to load settings from specific locations/sets of
locations in an explicit way.

Release Notes:

- N/A

---------

Co-authored-by: Max <max@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Marshall Bowers 2024-04-08 19:17:12 -04:00 committed by GitHub
parent 4a3032c5e5
commit 7c5bc3c26f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 349 additions and 338 deletions

View file

@ -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()
}
}

View file

@ -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()
}
}

View file

@ -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]

View file

@ -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

View file

@ -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"

View file

@ -9,3 +9,4 @@ brackets = [
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
]
prettier_parser_name = "json"
tab_size = 2

View file

@ -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"))]

View file

@ -12,3 +12,6 @@ brackets = [
{ start = "`", end = "`", close = false, newline = false },
]
prettier_parser_name = "markdown"
tab_size = 2
soft_wrap = "preferred_line_length"

View file

@ -10,3 +10,4 @@ brackets = [
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true }
]
tab_size = 2

View file

@ -11,3 +11,4 @@ brackets = [
{ start = "(", end = ")", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] }
]
tab_size = 2

View file

@ -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

View file

@ -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 }

View file

@ -15,3 +15,4 @@ brackets = [
]
word_characters = ["#", "$"]
prettier_parser_name = "typescript"
tab_size = 2

View file

@ -11,3 +11,4 @@ brackets = [
increase_indent_pattern = ":\\s*[|>]?\\s*$"
prettier_parser_name = "yaml"
tab_size = 2