merge
This commit is contained in:
commit
da653aaf6f
381 changed files with 14396 additions and 7154 deletions
|
@ -2006,7 +2006,7 @@ fn test_autoindent_language_without_indents_query(cx: &mut App) {
|
|||
#[gpui::test]
|
||||
fn test_autoindent_with_injected_languages(cx: &mut App) {
|
||||
init_settings(cx, |settings| {
|
||||
settings.languages.extend([
|
||||
settings.languages.0.extend([
|
||||
(
|
||||
"HTML".into(),
|
||||
LanguageSettingsContent {
|
||||
|
|
|
@ -39,11 +39,7 @@ use lsp::{CodeActionKind, InitializeParams, LanguageServerBinary, LanguageServer
|
|||
pub use manifest::{ManifestDelegate, ManifestName, ManifestProvider, ManifestQuery};
|
||||
use parking_lot::Mutex;
|
||||
use regex::Regex;
|
||||
use schemars::{
|
||||
JsonSchema,
|
||||
r#gen::SchemaGenerator,
|
||||
schema::{InstanceType, Schema, SchemaObject},
|
||||
};
|
||||
use schemars::{JsonSchema, SchemaGenerator, json_schema};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
||||
use serde_json::Value;
|
||||
use settings::WorktreeId;
|
||||
|
@ -694,7 +690,6 @@ pub struct LanguageConfig {
|
|||
pub matcher: LanguageMatcher,
|
||||
/// List of bracket types in a language.
|
||||
#[serde(default)]
|
||||
#[schemars(schema_with = "bracket_pair_config_json_schema")]
|
||||
pub brackets: BracketPairConfig,
|
||||
/// If set to true, auto indentation uses last non empty line to determine
|
||||
/// the indentation level for a new line.
|
||||
|
@ -735,6 +730,13 @@ pub struct LanguageConfig {
|
|||
/// Starting and closing characters of a block comment.
|
||||
#[serde(default)]
|
||||
pub block_comment: Option<(Arc<str>, Arc<str>)>,
|
||||
/// A list of additional regex patterns that should be treated as prefixes
|
||||
/// for creating boundaries during rewrapping, ensuring content from one
|
||||
/// prefixed section doesn't merge with another (e.g., markdown list items).
|
||||
/// By default, Zed treats as paragraph and comment prefixes as boundaries.
|
||||
#[serde(default, deserialize_with = "deserialize_regex_vec")]
|
||||
#[schemars(schema_with = "regex_vec_json_schema")]
|
||||
pub rewrap_prefixes: Vec<Regex>,
|
||||
/// A list of language servers that are allowed to run on subranges of a given language.
|
||||
#[serde(default)]
|
||||
pub scope_opt_in_language_servers: Vec<LanguageServerName>,
|
||||
|
@ -914,6 +916,7 @@ impl Default for LanguageConfig {
|
|||
autoclose_before: Default::default(),
|
||||
line_comments: Default::default(),
|
||||
block_comment: Default::default(),
|
||||
rewrap_prefixes: Default::default(),
|
||||
scope_opt_in_language_servers: Default::default(),
|
||||
overrides: Default::default(),
|
||||
word_characters: Default::default(),
|
||||
|
@ -944,10 +947,9 @@ fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result<Option<Regex>, D
|
|||
}
|
||||
}
|
||||
|
||||
fn regex_json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
Schema::Object(SchemaObject {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
..Default::default()
|
||||
fn regex_json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
json_schema!({
|
||||
"type": "string"
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -961,6 +963,22 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn deserialize_regex_vec<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Regex>, D::Error> {
|
||||
let sources = Vec::<String>::deserialize(d)?;
|
||||
let mut regexes = Vec::new();
|
||||
for source in sources {
|
||||
regexes.push(regex::Regex::new(&source).map_err(de::Error::custom)?);
|
||||
}
|
||||
Ok(regexes)
|
||||
}
|
||||
|
||||
fn regex_vec_json_schema(_: &mut SchemaGenerator) -> schemars::Schema {
|
||||
json_schema!({
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub struct FakeLspAdapter {
|
||||
|
@ -988,12 +1006,12 @@ pub struct FakeLspAdapter {
|
|||
/// This struct includes settings for defining which pairs of characters are considered brackets and
|
||||
/// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes.
|
||||
#[derive(Clone, Debug, Default, JsonSchema)]
|
||||
#[schemars(with = "Vec::<BracketPairContent>")]
|
||||
pub struct BracketPairConfig {
|
||||
/// A list of character pairs that should be treated as brackets in the context of a given language.
|
||||
pub pairs: Vec<BracketPair>,
|
||||
/// A list of tree-sitter scopes for which a given bracket should not be active.
|
||||
/// N-th entry in `[Self::disabled_scopes_by_bracket_ix]` contains a list of disabled scopes for an n-th entry in `[Self::pairs]`
|
||||
#[serde(skip)]
|
||||
pub disabled_scopes_by_bracket_ix: Vec<Vec<String>>,
|
||||
}
|
||||
|
||||
|
@ -1003,10 +1021,6 @@ impl BracketPairConfig {
|
|||
}
|
||||
}
|
||||
|
||||
fn bracket_pair_config_json_schema(r#gen: &mut SchemaGenerator) -> Schema {
|
||||
Option::<Vec<BracketPairContent>>::json_schema(r#gen)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BracketPairContent {
|
||||
#[serde(flatten)]
|
||||
|
@ -1841,6 +1855,14 @@ impl LanguageScope {
|
|||
.map(|e| (&e.0, &e.1))
|
||||
}
|
||||
|
||||
/// Returns additional regex patterns that act as prefix markers for creating
|
||||
/// boundaries during rewrapping.
|
||||
///
|
||||
/// By default, Zed treats as paragraph and comment prefixes as boundaries.
|
||||
pub fn rewrap_prefixes(&self) -> &[Regex] {
|
||||
&self.language.config.rewrap_prefixes
|
||||
}
|
||||
|
||||
/// Returns a list of language-specific word characters.
|
||||
///
|
||||
/// By default, Zed treats alphanumeric characters (and '_') as word characters for
|
||||
|
|
|
@ -1170,7 +1170,7 @@ impl LanguageRegistryState {
|
|||
if let Some(theme) = self.theme.as_ref() {
|
||||
language.set_theme(theme.syntax());
|
||||
}
|
||||
self.language_settings.languages.insert(
|
||||
self.language_settings.languages.0.insert(
|
||||
language.name(),
|
||||
LanguageSettingsContent {
|
||||
tab_size: language.config.tab_size,
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
use crate::{File, Language, LanguageName, LanguageServerName};
|
||||
use anyhow::Result;
|
||||
use collections::{FxHashMap, HashMap, HashSet};
|
||||
use core::slice;
|
||||
use ec4rs::{
|
||||
Properties as EditorconfigProperties,
|
||||
property::{FinalNewline, IndentSize, IndentStyle, TabWidth, TrimTrailingWs},
|
||||
|
@ -11,20 +10,18 @@ use ec4rs::{
|
|||
use globset::{Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
||||
use gpui::{App, Modifiers};
|
||||
use itertools::{Either, Itertools};
|
||||
use schemars::{
|
||||
JsonSchema,
|
||||
schema::{InstanceType, ObjectValidation, Schema, SchemaObject, SingleOrVec},
|
||||
};
|
||||
use schemars::{JsonSchema, json_schema};
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize,
|
||||
de::{self, IntoDeserializer, MapAccess, SeqAccess, Visitor},
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
use settings::{
|
||||
Settings, SettingsLocation, SettingsSources, SettingsStore, add_references_to_properties,
|
||||
ParameterizedJsonSchema, Settings, SettingsLocation, SettingsSources, SettingsStore,
|
||||
};
|
||||
use shellexpand;
|
||||
use std::{borrow::Cow, num::NonZeroU32, path::Path, sync::Arc};
|
||||
use std::{borrow::Cow, num::NonZeroU32, path::Path, slice, sync::Arc};
|
||||
use util::schemars::replace_subschema;
|
||||
use util::serde::default_true;
|
||||
|
||||
/// Initializes the language settings.
|
||||
|
@ -306,13 +303,41 @@ pub struct AllLanguageSettingsContent {
|
|||
pub defaults: LanguageSettingsContent,
|
||||
/// The settings for individual languages.
|
||||
#[serde(default)]
|
||||
pub languages: HashMap<LanguageName, LanguageSettingsContent>,
|
||||
pub languages: LanguageToSettingsMap,
|
||||
/// Settings for associating file extensions and filenames
|
||||
/// with languages.
|
||||
#[serde(default)]
|
||||
pub file_types: HashMap<Arc<str>, Vec<String>>,
|
||||
}
|
||||
|
||||
/// Map from language name to settings. Its `ParameterizedJsonSchema` allows only known language
|
||||
/// names in the keys.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct LanguageToSettingsMap(pub HashMap<LanguageName, LanguageSettingsContent>);
|
||||
|
||||
inventory::submit! {
|
||||
ParameterizedJsonSchema {
|
||||
add_and_get_ref: |generator, params, _cx| {
|
||||
let language_settings_content_ref = generator
|
||||
.subschema_for::<LanguageSettingsContent>()
|
||||
.to_value();
|
||||
replace_subschema::<LanguageToSettingsMap>(generator, || json_schema!({
|
||||
"type": "object",
|
||||
"properties": params
|
||||
.language_names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
(
|
||||
name.clone(),
|
||||
language_settings_content_ref.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<serde_json::Map<_, _>>()
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Controls how completions are processed for this language.
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -384,7 +409,6 @@ fn default_lsp_fetch_timeout_ms() -> u64 {
|
|||
|
||||
/// The settings for a particular language.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||
#[schemars(deny_unknown_fields)]
|
||||
pub struct LanguageSettingsContent {
|
||||
/// How many columns a tab should occupy.
|
||||
///
|
||||
|
@ -652,41 +676,26 @@ pub enum FormatOnSave {
|
|||
}
|
||||
|
||||
impl JsonSchema for FormatOnSave {
|
||||
fn schema_name() -> String {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
"OnSaveFormatter".into()
|
||||
}
|
||||
|
||||
fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> Schema {
|
||||
let mut schema = SchemaObject::default();
|
||||
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
let formatter_schema = Formatter::json_schema(generator);
|
||||
schema.instance_type = Some(
|
||||
vec![
|
||||
InstanceType::Object,
|
||||
InstanceType::String,
|
||||
InstanceType::Array,
|
||||
|
||||
json_schema!({
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": formatter_schema
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["on", "off", "language_server"]
|
||||
},
|
||||
formatter_schema
|
||||
]
|
||||
.into(),
|
||||
);
|
||||
|
||||
let valid_raw_values = SchemaObject {
|
||||
enum_values: Some(vec![
|
||||
Value::String("on".into()),
|
||||
Value::String("off".into()),
|
||||
Value::String("prettier".into()),
|
||||
Value::String("language_server".into()),
|
||||
]),
|
||||
..Default::default()
|
||||
};
|
||||
let mut nested_values = SchemaObject::default();
|
||||
|
||||
nested_values.array().items = Some(formatter_schema.clone().into());
|
||||
|
||||
schema.subschemas().any_of = Some(vec![
|
||||
nested_values.into(),
|
||||
valid_raw_values.into(),
|
||||
formatter_schema,
|
||||
]);
|
||||
schema.into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,8 +734,8 @@ impl<'de> Deserialize<'de> for FormatOnSave {
|
|||
} else if v == "off" {
|
||||
Ok(Self::Value::Off)
|
||||
} else if v == "language_server" {
|
||||
Ok(Self::Value::List(FormatterList(
|
||||
Formatter::LanguageServer { name: None }.into(),
|
||||
Ok(Self::Value::List(FormatterList::Single(
|
||||
Formatter::LanguageServer { name: None },
|
||||
)))
|
||||
} else {
|
||||
let ret: Result<FormatterList, _> =
|
||||
|
@ -787,41 +796,26 @@ pub enum SelectedFormatter {
|
|||
}
|
||||
|
||||
impl JsonSchema for SelectedFormatter {
|
||||
fn schema_name() -> String {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
"Formatter".into()
|
||||
}
|
||||
|
||||
fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> Schema {
|
||||
let mut schema = SchemaObject::default();
|
||||
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
let formatter_schema = Formatter::json_schema(generator);
|
||||
schema.instance_type = Some(
|
||||
vec![
|
||||
InstanceType::Object,
|
||||
InstanceType::String,
|
||||
InstanceType::Array,
|
||||
|
||||
json_schema!({
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": formatter_schema
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["auto", "language_server"]
|
||||
},
|
||||
formatter_schema
|
||||
]
|
||||
.into(),
|
||||
);
|
||||
|
||||
let valid_raw_values = SchemaObject {
|
||||
enum_values: Some(vec![
|
||||
Value::String("auto".into()),
|
||||
Value::String("prettier".into()),
|
||||
Value::String("language_server".into()),
|
||||
]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut nested_values = SchemaObject::default();
|
||||
|
||||
nested_values.array().items = Some(formatter_schema.clone().into());
|
||||
|
||||
schema.subschemas().any_of = Some(vec![
|
||||
nested_values.into(),
|
||||
valid_raw_values.into(),
|
||||
formatter_schema,
|
||||
]);
|
||||
schema.into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -836,6 +830,7 @@ impl Serialize for SelectedFormatter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SelectedFormatter {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
where
|
||||
|
@ -856,8 +851,8 @@ impl<'de> Deserialize<'de> for SelectedFormatter {
|
|||
if v == "auto" {
|
||||
Ok(Self::Value::Auto)
|
||||
} else if v == "language_server" {
|
||||
Ok(Self::Value::List(FormatterList(
|
||||
Formatter::LanguageServer { name: None }.into(),
|
||||
Ok(Self::Value::List(FormatterList::Single(
|
||||
Formatter::LanguageServer { name: None },
|
||||
)))
|
||||
} else {
|
||||
let ret: Result<FormatterList, _> =
|
||||
|
@ -885,16 +880,20 @@ impl<'de> Deserialize<'de> for SelectedFormatter {
|
|||
deserializer.deserialize_any(FormatDeserializer)
|
||||
}
|
||||
}
|
||||
/// Controls which formatter should be used when formatting code.
|
||||
|
||||
/// Controls which formatters should be used when formatting code.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case", transparent)]
|
||||
pub struct FormatterList(pub SingleOrVec<Formatter>);
|
||||
#[serde(untagged)]
|
||||
pub enum FormatterList {
|
||||
Single(Formatter),
|
||||
Vec(Vec<Formatter>),
|
||||
}
|
||||
|
||||
impl AsRef<[Formatter]> for FormatterList {
|
||||
fn as_ref(&self) -> &[Formatter] {
|
||||
match &self.0 {
|
||||
SingleOrVec::Single(single) => slice::from_ref(single),
|
||||
SingleOrVec::Vec(v) => v,
|
||||
match &self {
|
||||
Self::Single(single) => slice::from_ref(single),
|
||||
Self::Vec(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1209,7 +1208,7 @@ impl settings::Settings for AllLanguageSettings {
|
|||
serde_json::from_value(serde_json::to_value(&default_value.defaults)?)?;
|
||||
|
||||
let mut languages = HashMap::default();
|
||||
for (language_name, settings) in &default_value.languages {
|
||||
for (language_name, settings) in &default_value.languages.0 {
|
||||
let mut language_settings = defaults.clone();
|
||||
merge_settings(&mut language_settings, settings);
|
||||
languages.insert(language_name.clone(), language_settings);
|
||||
|
@ -1310,7 +1309,7 @@ impl settings::Settings for AllLanguageSettings {
|
|||
}
|
||||
|
||||
// A user's language-specific settings override default language-specific settings.
|
||||
for (language_name, user_language_settings) in &user_settings.languages {
|
||||
for (language_name, user_language_settings) in &user_settings.languages.0 {
|
||||
merge_settings(
|
||||
languages
|
||||
.entry(language_name.clone())
|
||||
|
@ -1366,51 +1365,6 @@ impl settings::Settings for AllLanguageSettings {
|
|||
})
|
||||
}
|
||||
|
||||
fn json_schema(
|
||||
generator: &mut schemars::r#gen::SchemaGenerator,
|
||||
params: &settings::SettingsJsonSchemaParams,
|
||||
_: &App,
|
||||
) -> schemars::schema::RootSchema {
|
||||
let mut root_schema = generator.root_schema_for::<Self::FileContent>();
|
||||
|
||||
// Create a schema for a 'languages overrides' object, associating editor
|
||||
// settings with specific languages.
|
||||
assert!(
|
||||
root_schema
|
||||
.definitions
|
||||
.contains_key("LanguageSettingsContent")
|
||||
);
|
||||
|
||||
let languages_object_schema = SchemaObject {
|
||||
instance_type: Some(InstanceType::Object.into()),
|
||||
object: Some(Box::new(ObjectValidation {
|
||||
properties: params
|
||||
.language_names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
(
|
||||
name.clone(),
|
||||
Schema::new_ref("#/definitions/LanguageSettingsContent".into()),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
root_schema
|
||||
.definitions
|
||||
.extend([("Languages".into(), languages_object_schema.into())]);
|
||||
|
||||
add_references_to_properties(
|
||||
&mut root_schema,
|
||||
&[("languages", "#/definitions/Languages")],
|
||||
);
|
||||
|
||||
root_schema
|
||||
}
|
||||
|
||||
fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
|
||||
let d = &mut current.defaults;
|
||||
if let Some(size) = vscode
|
||||
|
@ -1674,29 +1628,26 @@ mod tests {
|
|||
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
|
||||
assert_eq!(
|
||||
settings.formatter,
|
||||
Some(SelectedFormatter::List(FormatterList(
|
||||
Formatter::LanguageServer { name: None }.into()
|
||||
Some(SelectedFormatter::List(FormatterList::Single(
|
||||
Formatter::LanguageServer { name: None }
|
||||
)))
|
||||
);
|
||||
let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}]}";
|
||||
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
|
||||
assert_eq!(
|
||||
settings.formatter,
|
||||
Some(SelectedFormatter::List(FormatterList(
|
||||
vec![Formatter::LanguageServer { name: None }].into()
|
||||
)))
|
||||
Some(SelectedFormatter::List(FormatterList::Vec(vec![
|
||||
Formatter::LanguageServer { name: None }
|
||||
])))
|
||||
);
|
||||
let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}, \"prettier\"]}";
|
||||
let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
|
||||
assert_eq!(
|
||||
settings.formatter,
|
||||
Some(SelectedFormatter::List(FormatterList(
|
||||
vec![
|
||||
Formatter::LanguageServer { name: None },
|
||||
Formatter::Prettier
|
||||
]
|
||||
.into()
|
||||
)))
|
||||
Some(SelectedFormatter::List(FormatterList::Vec(vec![
|
||||
Formatter::LanguageServer { name: None },
|
||||
Formatter::Prettier
|
||||
])))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue