language_settings.rs

   1//! Provides `language`-related settings.
   2
   3use crate::{File, Language, LanguageName, LanguageServerName};
   4use anyhow::Result;
   5use collections::{HashMap, HashSet};
   6use core::slice;
   7use ec4rs::{
   8    property::{FinalNewline, IndentSize, IndentStyle, TabWidth, TrimTrailingWs},
   9    Properties as EditorconfigProperties,
  10};
  11use globset::{Glob, GlobMatcher, GlobSet, GlobSetBuilder};
  12use gpui::App;
  13use itertools::{Either, Itertools};
  14use schemars::{
  15    schema::{InstanceType, ObjectValidation, Schema, SchemaObject, SingleOrVec},
  16    JsonSchema,
  17};
  18use serde::{
  19    de::{self, IntoDeserializer, MapAccess, SeqAccess, Visitor},
  20    Deserialize, Deserializer, Serialize,
  21};
  22use serde_json::Value;
  23use settings::{
  24    add_references_to_properties, Settings, SettingsLocation, SettingsSources, SettingsStore,
  25};
  26use std::{borrow::Cow, num::NonZeroU32, path::Path, sync::Arc};
  27use util::serde::default_true;
  28
  29/// Initializes the language settings.
  30pub fn init(cx: &mut App) {
  31    AllLanguageSettings::register(cx);
  32}
  33
  34/// Returns the settings for the specified language from the provided file.
  35pub fn language_settings<'a>(
  36    language: Option<LanguageName>,
  37    file: Option<&'a Arc<dyn File>>,
  38    cx: &'a App,
  39) -> Cow<'a, LanguageSettings> {
  40    let location = file.map(|f| SettingsLocation {
  41        worktree_id: f.worktree_id(cx),
  42        path: f.path().as_ref(),
  43    });
  44    AllLanguageSettings::get(location, cx).language(location, language.as_ref(), cx)
  45}
  46
  47/// Returns the settings for all languages from the provided file.
  48pub fn all_language_settings<'a>(
  49    file: Option<&'a Arc<dyn File>>,
  50    cx: &'a App,
  51) -> &'a AllLanguageSettings {
  52    let location = file.map(|f| SettingsLocation {
  53        worktree_id: f.worktree_id(cx),
  54        path: f.path().as_ref(),
  55    });
  56    AllLanguageSettings::get(location, cx)
  57}
  58
  59/// The settings for all languages.
  60#[derive(Debug, Clone)]
  61pub struct AllLanguageSettings {
  62    /// The edit prediction settings.
  63    pub edit_predictions: EditPredictionSettings,
  64    defaults: LanguageSettings,
  65    languages: HashMap<LanguageName, LanguageSettings>,
  66    pub(crate) file_types: HashMap<Arc<str>, GlobSet>,
  67}
  68
  69/// The settings for a particular language.
  70#[derive(Debug, Clone, Deserialize)]
  71pub struct LanguageSettings {
  72    /// How many columns a tab should occupy.
  73    pub tab_size: NonZeroU32,
  74    /// Whether to indent lines using tab characters, as opposed to multiple
  75    /// spaces.
  76    pub hard_tabs: bool,
  77    /// How to soft-wrap long lines of text.
  78    pub soft_wrap: SoftWrap,
  79    /// The column at which to soft-wrap lines, for buffers where soft-wrap
  80    /// is enabled.
  81    pub preferred_line_length: u32,
  82    // Whether to show wrap guides (vertical rulers) in the editor.
  83    // Setting this to true will show a guide at the 'preferred_line_length' value
  84    // if softwrap is set to 'preferred_line_length', and will show any
  85    // additional guides as specified by the 'wrap_guides' setting.
  86    pub show_wrap_guides: bool,
  87    /// Character counts at which to show wrap guides (vertical rulers) in the editor.
  88    pub wrap_guides: Vec<usize>,
  89    /// Indent guide related settings.
  90    pub indent_guides: IndentGuideSettings,
  91    /// Whether or not to perform a buffer format before saving.
  92    pub format_on_save: FormatOnSave,
  93    /// Whether or not to remove any trailing whitespace from lines of a buffer
  94    /// before saving it.
  95    pub remove_trailing_whitespace_on_save: bool,
  96    /// Whether or not to ensure there's a single newline at the end of a buffer
  97    /// when saving it.
  98    pub ensure_final_newline_on_save: bool,
  99    /// How to perform a buffer format.
 100    pub formatter: SelectedFormatter,
 101    /// Zed's Prettier integration settings.
 102    pub prettier: PrettierSettings,
 103    /// Whether to use language servers to provide code intelligence.
 104    pub enable_language_server: bool,
 105    /// The list of language servers to use (or disable) for this language.
 106    ///
 107    /// This array should consist of language server IDs, as well as the following
 108    /// special tokens:
 109    /// - `"!<language_server_id>"` - A language server ID prefixed with a `!` will be disabled.
 110    /// - `"..."` - A placeholder to refer to the **rest** of the registered language servers for this language.
 111    pub language_servers: Vec<String>,
 112    /// Controls where the `editor::Rewrap` action is allowed for this language.
 113    ///
 114    /// Note: This setting has no effect in Vim mode, as rewrap is already
 115    /// allowed everywhere.
 116    pub allow_rewrap: RewrapBehavior,
 117    /// Controls whether edit predictions are shown immediately (true)
 118    /// or manually by triggering `editor::ShowEditPrediction` (false).
 119    pub show_edit_predictions: bool,
 120    /// Controls whether edit predictions are shown in the given language
 121    /// scopes.
 122    pub edit_predictions_disabled_in: Vec<String>,
 123    /// Whether to show tabs and spaces in the editor.
 124    pub show_whitespaces: ShowWhitespaceSetting,
 125    /// Whether to start a new line with a comment when a previous line is a comment as well.
 126    pub extend_comment_on_newline: bool,
 127    /// Inlay hint related settings.
 128    pub inlay_hints: InlayHintSettings,
 129    /// Whether to automatically close brackets.
 130    pub use_autoclose: bool,
 131    /// Whether to automatically surround text with brackets.
 132    pub use_auto_surround: bool,
 133    /// Whether to use additional LSP queries to format (and amend) the code after
 134    /// every "trigger" symbol input, defined by LSP server capabilities.
 135    pub use_on_type_format: bool,
 136    /// Whether indentation of pasted content should be adjusted based on the context.
 137    pub auto_indent_on_paste: bool,
 138    // Controls how the editor handles the autoclosed characters.
 139    pub always_treat_brackets_as_autoclosed: bool,
 140    /// Which code actions to run on save
 141    pub code_actions_on_format: HashMap<String, bool>,
 142    /// Whether to perform linked edits
 143    pub linked_edits: bool,
 144    /// Task configuration for this language.
 145    pub tasks: LanguageTaskConfig,
 146    /// Whether to pop the completions menu while typing in an editor without
 147    /// explicitly requesting it.
 148    pub show_completions_on_input: bool,
 149    /// Whether to display inline and alongside documentation for items in the
 150    /// completions menu.
 151    pub show_completion_documentation: bool,
 152}
 153
 154impl LanguageSettings {
 155    /// A token representing the rest of the available language servers.
 156    const REST_OF_LANGUAGE_SERVERS: &'static str = "...";
 157
 158    /// Returns the customized list of language servers from the list of
 159    /// available language servers.
 160    pub fn customized_language_servers(
 161        &self,
 162        available_language_servers: &[LanguageServerName],
 163    ) -> Vec<LanguageServerName> {
 164        Self::resolve_language_servers(&self.language_servers, available_language_servers)
 165    }
 166
 167    pub(crate) fn resolve_language_servers(
 168        configured_language_servers: &[String],
 169        available_language_servers: &[LanguageServerName],
 170    ) -> Vec<LanguageServerName> {
 171        let (disabled_language_servers, enabled_language_servers): (
 172            Vec<LanguageServerName>,
 173            Vec<LanguageServerName>,
 174        ) = configured_language_servers.iter().partition_map(
 175            |language_server| match language_server.strip_prefix('!') {
 176                Some(disabled) => Either::Left(LanguageServerName(disabled.to_string().into())),
 177                None => Either::Right(LanguageServerName(language_server.clone().into())),
 178            },
 179        );
 180
 181        let rest = available_language_servers
 182            .iter()
 183            .filter(|&available_language_server| {
 184                !disabled_language_servers.contains(&available_language_server)
 185                    && !enabled_language_servers.contains(&available_language_server)
 186            })
 187            .cloned()
 188            .collect::<Vec<_>>();
 189
 190        enabled_language_servers
 191            .into_iter()
 192            .flat_map(|language_server| {
 193                if language_server.0.as_ref() == Self::REST_OF_LANGUAGE_SERVERS {
 194                    rest.clone()
 195                } else {
 196                    vec![language_server.clone()]
 197                }
 198            })
 199            .collect::<Vec<_>>()
 200    }
 201}
 202
 203/// The provider that supplies edit predictions.
 204#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
 205#[serde(rename_all = "snake_case")]
 206pub enum EditPredictionProvider {
 207    None,
 208    #[default]
 209    Copilot,
 210    Supermaven,
 211    Zed,
 212}
 213
 214impl EditPredictionProvider {
 215    pub fn is_zed(&self) -> bool {
 216        match self {
 217            EditPredictionProvider::Zed => true,
 218            EditPredictionProvider::None
 219            | EditPredictionProvider::Copilot
 220            | EditPredictionProvider::Supermaven => false,
 221        }
 222    }
 223}
 224
 225/// The settings for edit predictions, such as [GitHub Copilot](https://github.com/features/copilot)
 226/// or [Supermaven](https://supermaven.com).
 227#[derive(Clone, Debug, Default)]
 228pub struct EditPredictionSettings {
 229    /// The provider that supplies edit predictions.
 230    pub provider: EditPredictionProvider,
 231    /// A list of globs representing files that edit predictions should be disabled for.
 232    /// This list adds to a pre-existing, sensible default set of globs.
 233    /// Any additional ones you add are combined with them.
 234    pub disabled_globs: Vec<GlobMatcher>,
 235    /// Configures how edit predictions are displayed in the buffer.
 236    pub mode: EditPredictionsMode,
 237    /// Settings specific to GitHub Copilot.
 238    pub copilot: CopilotSettings,
 239}
 240
 241/// The mode in which edit predictions should be displayed.
 242#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
 243#[serde(rename_all = "snake_case")]
 244pub enum EditPredictionsMode {
 245    /// If provider supports it, display inline when holding modifier key (e.g., alt).
 246    /// Otherwise, eager preview is used.
 247    Auto,
 248    /// Display inline when there are no language server completions available.
 249    #[default]
 250    EagerPreview,
 251}
 252
 253#[derive(Clone, Debug, Default)]
 254pub struct CopilotSettings {
 255    /// HTTP/HTTPS proxy to use for Copilot.
 256    pub proxy: Option<String>,
 257    /// Disable certificate verification for proxy (not recommended).
 258    pub proxy_no_verify: Option<bool>,
 259}
 260
 261/// The settings for all languages.
 262#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
 263pub struct AllLanguageSettingsContent {
 264    /// The settings for enabling/disabling features.
 265    #[serde(default)]
 266    pub features: Option<FeaturesContent>,
 267    /// The edit prediction settings.
 268    #[serde(default)]
 269    pub edit_predictions: Option<EditPredictionSettingsContent>,
 270    /// The default language settings.
 271    #[serde(flatten)]
 272    pub defaults: LanguageSettingsContent,
 273    /// The settings for individual languages.
 274    #[serde(default)]
 275    pub languages: HashMap<LanguageName, LanguageSettingsContent>,
 276    /// Settings for associating file extensions and filenames
 277    /// with languages.
 278    #[serde(default)]
 279    pub file_types: HashMap<Arc<str>, Vec<String>>,
 280}
 281
 282/// The settings for a particular language.
 283#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
 284pub struct LanguageSettingsContent {
 285    /// How many columns a tab should occupy.
 286    ///
 287    /// Default: 4
 288    #[serde(default)]
 289    pub tab_size: Option<NonZeroU32>,
 290    /// Whether to indent lines using tab characters, as opposed to multiple
 291    /// spaces.
 292    ///
 293    /// Default: false
 294    #[serde(default)]
 295    pub hard_tabs: Option<bool>,
 296    /// How to soft-wrap long lines of text.
 297    ///
 298    /// Default: none
 299    #[serde(default)]
 300    pub soft_wrap: Option<SoftWrap>,
 301    /// The column at which to soft-wrap lines, for buffers where soft-wrap
 302    /// is enabled.
 303    ///
 304    /// Default: 80
 305    #[serde(default)]
 306    pub preferred_line_length: Option<u32>,
 307    /// Whether to show wrap guides in the editor. Setting this to true will
 308    /// show a guide at the 'preferred_line_length' value if softwrap is set to
 309    /// 'preferred_line_length', and will show any additional guides as specified
 310    /// by the 'wrap_guides' setting.
 311    ///
 312    /// Default: true
 313    #[serde(default)]
 314    pub show_wrap_guides: Option<bool>,
 315    /// Character counts at which to show wrap guides in the editor.
 316    ///
 317    /// Default: []
 318    #[serde(default)]
 319    pub wrap_guides: Option<Vec<usize>>,
 320    /// Indent guide related settings.
 321    #[serde(default)]
 322    pub indent_guides: Option<IndentGuideSettings>,
 323    /// Whether or not to perform a buffer format before saving.
 324    ///
 325    /// Default: on
 326    #[serde(default)]
 327    pub format_on_save: Option<FormatOnSave>,
 328    /// Whether or not to remove any trailing whitespace from lines of a buffer
 329    /// before saving it.
 330    ///
 331    /// Default: true
 332    #[serde(default)]
 333    pub remove_trailing_whitespace_on_save: Option<bool>,
 334    /// Whether or not to ensure there's a single newline at the end of a buffer
 335    /// when saving it.
 336    ///
 337    /// Default: true
 338    #[serde(default)]
 339    pub ensure_final_newline_on_save: Option<bool>,
 340    /// How to perform a buffer format.
 341    ///
 342    /// Default: auto
 343    #[serde(default)]
 344    pub formatter: Option<SelectedFormatter>,
 345    /// Zed's Prettier integration settings.
 346    /// Allows to enable/disable formatting with Prettier
 347    /// and configure default Prettier, used when no project-level Prettier installation is found.
 348    ///
 349    /// Default: off
 350    #[serde(default)]
 351    pub prettier: Option<PrettierSettings>,
 352    /// Whether to use language servers to provide code intelligence.
 353    ///
 354    /// Default: true
 355    #[serde(default)]
 356    pub enable_language_server: Option<bool>,
 357    /// The list of language servers to use (or disable) for this language.
 358    ///
 359    /// This array should consist of language server IDs, as well as the following
 360    /// special tokens:
 361    /// - `"!<language_server_id>"` - A language server ID prefixed with a `!` will be disabled.
 362    /// - `"..."` - A placeholder to refer to the **rest** of the registered language servers for this language.
 363    ///
 364    /// Default: ["..."]
 365    #[serde(default)]
 366    pub language_servers: Option<Vec<String>>,
 367    /// Controls where the `editor::Rewrap` action is allowed for this language.
 368    ///
 369    /// Note: This setting has no effect in Vim mode, as rewrap is already
 370    /// allowed everywhere.
 371    ///
 372    /// Default: "in_comments"
 373    #[serde(default)]
 374    pub allow_rewrap: Option<RewrapBehavior>,
 375    /// Controls whether edit predictions are shown immediately (true)
 376    /// or manually by triggering `editor::ShowEditPrediction` (false).
 377    ///
 378    /// Default: true
 379    #[serde(default)]
 380    pub show_edit_predictions: Option<bool>,
 381    /// Controls whether edit predictions are shown in the given language
 382    /// scopes.
 383    ///
 384    /// Example: ["string", "comment"]
 385    ///
 386    /// Default: []
 387    #[serde(default)]
 388    pub edit_predictions_disabled_in: Option<Vec<String>>,
 389    /// Whether to show tabs and spaces in the editor.
 390    #[serde(default)]
 391    pub show_whitespaces: Option<ShowWhitespaceSetting>,
 392    /// Whether to start a new line with a comment when a previous line is a comment as well.
 393    ///
 394    /// Default: true
 395    #[serde(default)]
 396    pub extend_comment_on_newline: Option<bool>,
 397    /// Inlay hint related settings.
 398    #[serde(default)]
 399    pub inlay_hints: Option<InlayHintSettings>,
 400    /// Whether to automatically type closing characters for you. For example,
 401    /// when you type (, Zed will automatically add a closing ) at the correct position.
 402    ///
 403    /// Default: true
 404    pub use_autoclose: Option<bool>,
 405    /// Whether to automatically surround text with characters for you. For example,
 406    /// when you select text and type (, Zed will automatically surround text with ().
 407    ///
 408    /// Default: true
 409    pub use_auto_surround: Option<bool>,
 410    /// Controls how the editor handles the autoclosed characters.
 411    /// When set to `false`(default), skipping over and auto-removing of the closing characters
 412    /// happen only for auto-inserted characters.
 413    /// Otherwise(when `true`), the closing characters are always skipped over and auto-removed
 414    /// no matter how they were inserted.
 415    ///
 416    /// Default: false
 417    pub always_treat_brackets_as_autoclosed: Option<bool>,
 418    /// Whether to use additional LSP queries to format (and amend) the code after
 419    /// every "trigger" symbol input, defined by LSP server capabilities.
 420    ///
 421    /// Default: true
 422    pub use_on_type_format: Option<bool>,
 423    /// Which code actions to run on save after the formatter.
 424    /// These are not run if formatting is off.
 425    ///
 426    /// Default: {} (or {"source.organizeImports": true} for Go).
 427    pub code_actions_on_format: Option<HashMap<String, bool>>,
 428    /// Whether to perform linked edits of associated ranges, if the language server supports it.
 429    /// For example, when editing opening <html> tag, the contents of the closing </html> tag will be edited as well.
 430    ///
 431    /// Default: true
 432    pub linked_edits: Option<bool>,
 433    /// Whether indentation of pasted content should be adjusted based on the context.
 434    ///
 435    /// Default: true
 436    pub auto_indent_on_paste: Option<bool>,
 437    /// Task configuration for this language.
 438    ///
 439    /// Default: {}
 440    pub tasks: Option<LanguageTaskConfig>,
 441    /// Whether to pop the completions menu while typing in an editor without
 442    /// explicitly requesting it.
 443    ///
 444    /// Default: true
 445    pub show_completions_on_input: Option<bool>,
 446    /// Whether to display inline and alongside documentation for items in the
 447    /// completions menu.
 448    ///
 449    /// Default: true
 450    pub show_completion_documentation: Option<bool>,
 451}
 452
 453/// The behavior of `editor::Rewrap`.
 454#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)]
 455#[serde(rename_all = "snake_case")]
 456pub enum RewrapBehavior {
 457    /// Only rewrap within comments.
 458    #[default]
 459    InComments,
 460    /// Only rewrap within the current selection(s).
 461    InSelections,
 462    /// Allow rewrapping anywhere.
 463    Anywhere,
 464}
 465
 466/// The contents of the edit prediction settings.
 467#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
 468pub struct EditPredictionSettingsContent {
 469    /// A list of globs representing files that edit predictions should be disabled for.
 470    /// This list adds to a pre-existing, sensible default set of globs.
 471    /// Any additional ones you add are combined with them.
 472    #[serde(default)]
 473    pub disabled_globs: Option<Vec<String>>,
 474    /// The mode used to display edit predictions in the buffer.
 475    /// Provider support required.
 476    #[serde(default)]
 477    pub mode: EditPredictionsMode,
 478    /// Settings specific to GitHub Copilot.
 479    #[serde(default)]
 480    pub copilot: CopilotSettingsContent,
 481}
 482
 483#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)]
 484pub struct CopilotSettingsContent {
 485    /// HTTP/HTTPS proxy to use for Copilot.
 486    ///
 487    /// Default: none
 488    #[serde(default)]
 489    pub proxy: Option<String>,
 490    /// Disable certificate verification for the proxy (not recommended).
 491    ///
 492    /// Default: false
 493    #[serde(default)]
 494    pub proxy_no_verify: Option<bool>,
 495}
 496
 497/// The settings for enabling/disabling features.
 498#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
 499#[serde(rename_all = "snake_case")]
 500pub struct FeaturesContent {
 501    /// Whether the GitHub Copilot feature is enabled.
 502    pub copilot: Option<bool>,
 503    /// Determines which edit prediction provider to use.
 504    pub edit_prediction_provider: Option<EditPredictionProvider>,
 505}
 506
 507/// Controls the soft-wrapping behavior in the editor.
 508#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 509#[serde(rename_all = "snake_case")]
 510pub enum SoftWrap {
 511    /// Prefer a single line generally, unless an overly long line is encountered.
 512    None,
 513    /// Deprecated: use None instead. Left to avoid breaking existing users' configs.
 514    /// Prefer a single line generally, unless an overly long line is encountered.
 515    PreferLine,
 516    /// Soft wrap lines that exceed the editor width.
 517    EditorWidth,
 518    /// Soft wrap lines at the preferred line length.
 519    PreferredLineLength,
 520    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
 521    Bounded,
 522}
 523
 524/// Controls the behavior of formatting files when they are saved.
 525#[derive(Debug, Clone, PartialEq, Eq)]
 526pub enum FormatOnSave {
 527    /// Files should be formatted on save.
 528    On,
 529    /// Files should not be formatted on save.
 530    Off,
 531    List(FormatterList),
 532}
 533
 534impl JsonSchema for FormatOnSave {
 535    fn schema_name() -> String {
 536        "OnSaveFormatter".into()
 537    }
 538
 539    fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> Schema {
 540        let mut schema = SchemaObject::default();
 541        let formatter_schema = Formatter::json_schema(generator);
 542        schema.instance_type = Some(
 543            vec![
 544                InstanceType::Object,
 545                InstanceType::String,
 546                InstanceType::Array,
 547            ]
 548            .into(),
 549        );
 550
 551        let valid_raw_values = SchemaObject {
 552            enum_values: Some(vec![
 553                Value::String("on".into()),
 554                Value::String("off".into()),
 555                Value::String("prettier".into()),
 556                Value::String("language_server".into()),
 557            ]),
 558            ..Default::default()
 559        };
 560        let mut nested_values = SchemaObject::default();
 561
 562        nested_values.array().items = Some(formatter_schema.clone().into());
 563
 564        schema.subschemas().any_of = Some(vec![
 565            nested_values.into(),
 566            valid_raw_values.into(),
 567            formatter_schema,
 568        ]);
 569        schema.into()
 570    }
 571}
 572
 573impl Serialize for FormatOnSave {
 574    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
 575    where
 576        S: serde::Serializer,
 577    {
 578        match self {
 579            Self::On => serializer.serialize_str("on"),
 580            Self::Off => serializer.serialize_str("off"),
 581            Self::List(list) => list.serialize(serializer),
 582        }
 583    }
 584}
 585
 586impl<'de> Deserialize<'de> for FormatOnSave {
 587    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
 588    where
 589        D: Deserializer<'de>,
 590    {
 591        struct FormatDeserializer;
 592
 593        impl<'d> Visitor<'d> for FormatDeserializer {
 594            type Value = FormatOnSave;
 595
 596            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
 597                formatter.write_str("a valid on-save formatter kind")
 598            }
 599            fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
 600            where
 601                E: serde::de::Error,
 602            {
 603                if v == "on" {
 604                    Ok(Self::Value::On)
 605                } else if v == "off" {
 606                    Ok(Self::Value::Off)
 607                } else if v == "language_server" {
 608                    Ok(Self::Value::List(FormatterList(
 609                        Formatter::LanguageServer { name: None }.into(),
 610                    )))
 611                } else {
 612                    let ret: Result<FormatterList, _> =
 613                        Deserialize::deserialize(v.into_deserializer());
 614                    ret.map(Self::Value::List)
 615                }
 616            }
 617            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
 618            where
 619                A: MapAccess<'d>,
 620            {
 621                let ret: Result<FormatterList, _> =
 622                    Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
 623                ret.map(Self::Value::List)
 624            }
 625            fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
 626            where
 627                A: SeqAccess<'d>,
 628            {
 629                let ret: Result<FormatterList, _> =
 630                    Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
 631                ret.map(Self::Value::List)
 632            }
 633        }
 634        deserializer.deserialize_any(FormatDeserializer)
 635    }
 636}
 637
 638/// Controls how whitespace should be displayedin the editor.
 639#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 640#[serde(rename_all = "snake_case")]
 641pub enum ShowWhitespaceSetting {
 642    /// Draw whitespace only for the selected text.
 643    Selection,
 644    /// Do not draw any tabs or spaces.
 645    None,
 646    /// Draw all invisible symbols.
 647    All,
 648    /// Draw whitespaces at boundaries only.
 649    ///
 650    /// For a whitespace to be on a boundary, any of the following conditions need to be met:
 651    /// - It is a tab
 652    /// - It is adjacent to an edge (start or end)
 653    /// - It is adjacent to a whitespace (left or right)
 654    Boundary,
 655}
 656
 657/// Controls which formatter should be used when formatting code.
 658#[derive(Clone, Debug, Default, PartialEq, Eq)]
 659pub enum SelectedFormatter {
 660    /// Format files using Zed's Prettier integration (if applicable),
 661    /// or falling back to formatting via language server.
 662    #[default]
 663    Auto,
 664    List(FormatterList),
 665}
 666
 667impl JsonSchema for SelectedFormatter {
 668    fn schema_name() -> String {
 669        "Formatter".into()
 670    }
 671
 672    fn json_schema(generator: &mut schemars::r#gen::SchemaGenerator) -> Schema {
 673        let mut schema = SchemaObject::default();
 674        let formatter_schema = Formatter::json_schema(generator);
 675        schema.instance_type = Some(
 676            vec![
 677                InstanceType::Object,
 678                InstanceType::String,
 679                InstanceType::Array,
 680            ]
 681            .into(),
 682        );
 683
 684        let valid_raw_values = SchemaObject {
 685            enum_values: Some(vec![
 686                Value::String("auto".into()),
 687                Value::String("prettier".into()),
 688                Value::String("language_server".into()),
 689            ]),
 690            ..Default::default()
 691        };
 692
 693        let mut nested_values = SchemaObject::default();
 694
 695        nested_values.array().items = Some(formatter_schema.clone().into());
 696
 697        schema.subschemas().any_of = Some(vec![
 698            nested_values.into(),
 699            valid_raw_values.into(),
 700            formatter_schema,
 701        ]);
 702        schema.into()
 703    }
 704}
 705
 706impl Serialize for SelectedFormatter {
 707    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
 708    where
 709        S: serde::Serializer,
 710    {
 711        match self {
 712            SelectedFormatter::Auto => serializer.serialize_str("auto"),
 713            SelectedFormatter::List(list) => list.serialize(serializer),
 714        }
 715    }
 716}
 717impl<'de> Deserialize<'de> for SelectedFormatter {
 718    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
 719    where
 720        D: Deserializer<'de>,
 721    {
 722        struct FormatDeserializer;
 723
 724        impl<'d> Visitor<'d> for FormatDeserializer {
 725            type Value = SelectedFormatter;
 726
 727            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
 728                formatter.write_str("a valid formatter kind")
 729            }
 730            fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
 731            where
 732                E: serde::de::Error,
 733            {
 734                if v == "auto" {
 735                    Ok(Self::Value::Auto)
 736                } else if v == "language_server" {
 737                    Ok(Self::Value::List(FormatterList(
 738                        Formatter::LanguageServer { name: None }.into(),
 739                    )))
 740                } else {
 741                    let ret: Result<FormatterList, _> =
 742                        Deserialize::deserialize(v.into_deserializer());
 743                    ret.map(SelectedFormatter::List)
 744                }
 745            }
 746            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
 747            where
 748                A: MapAccess<'d>,
 749            {
 750                let ret: Result<FormatterList, _> =
 751                    Deserialize::deserialize(de::value::MapAccessDeserializer::new(map));
 752                ret.map(SelectedFormatter::List)
 753            }
 754            fn visit_seq<A>(self, map: A) -> Result<Self::Value, A::Error>
 755            where
 756                A: SeqAccess<'d>,
 757            {
 758                let ret: Result<FormatterList, _> =
 759                    Deserialize::deserialize(de::value::SeqAccessDeserializer::new(map));
 760                ret.map(SelectedFormatter::List)
 761            }
 762        }
 763        deserializer.deserialize_any(FormatDeserializer)
 764    }
 765}
 766/// Controls which formatter should be used when formatting code.
 767#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 768#[serde(rename_all = "snake_case", transparent)]
 769pub struct FormatterList(pub SingleOrVec<Formatter>);
 770
 771impl AsRef<[Formatter]> for FormatterList {
 772    fn as_ref(&self) -> &[Formatter] {
 773        match &self.0 {
 774            SingleOrVec::Single(single) => slice::from_ref(single),
 775            SingleOrVec::Vec(v) => v,
 776        }
 777    }
 778}
 779
 780/// Controls which formatter should be used when formatting code. If there are multiple formatters, they are executed in the order of declaration.
 781#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
 782#[serde(rename_all = "snake_case")]
 783pub enum Formatter {
 784    /// Format code using the current language server.
 785    LanguageServer { name: Option<String> },
 786    /// Format code using Zed's Prettier integration.
 787    Prettier,
 788    /// Format code using an external command.
 789    External {
 790        /// The external program to run.
 791        command: Arc<str>,
 792        /// The arguments to pass to the program.
 793        arguments: Option<Arc<[String]>>,
 794    },
 795    /// Files should be formatted using code actions executed by language servers.
 796    CodeActions(HashMap<String, bool>),
 797}
 798
 799/// The settings for indent guides.
 800#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
 801pub struct IndentGuideSettings {
 802    /// Whether to display indent guides in the editor.
 803    ///
 804    /// Default: true
 805    #[serde(default = "default_true")]
 806    pub enabled: bool,
 807    /// The width of the indent guides in pixels, between 1 and 10.
 808    ///
 809    /// Default: 1
 810    #[serde(default = "line_width")]
 811    pub line_width: u32,
 812    /// The width of the active indent guide in pixels, between 1 and 10.
 813    ///
 814    /// Default: 1
 815    #[serde(default = "active_line_width")]
 816    pub active_line_width: u32,
 817    /// Determines how indent guides are colored.
 818    ///
 819    /// Default: Fixed
 820    #[serde(default)]
 821    pub coloring: IndentGuideColoring,
 822    /// Determines how indent guide backgrounds are colored.
 823    ///
 824    /// Default: Disabled
 825    #[serde(default)]
 826    pub background_coloring: IndentGuideBackgroundColoring,
 827}
 828
 829fn line_width() -> u32 {
 830    1
 831}
 832
 833fn active_line_width() -> u32 {
 834    line_width()
 835}
 836
 837/// Determines how indent guides are colored.
 838#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
 839#[serde(rename_all = "snake_case")]
 840pub enum IndentGuideColoring {
 841    /// Do not render any lines for indent guides.
 842    Disabled,
 843    /// Use the same color for all indentation levels.
 844    #[default]
 845    Fixed,
 846    /// Use a different color for each indentation level.
 847    IndentAware,
 848}
 849
 850/// Determines how indent guide backgrounds are colored.
 851#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
 852#[serde(rename_all = "snake_case")]
 853pub enum IndentGuideBackgroundColoring {
 854    /// Do not render any background for indent guides.
 855    #[default]
 856    Disabled,
 857    /// Use a different color for each indentation level.
 858    IndentAware,
 859}
 860
 861/// The settings for inlay hints.
 862#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
 863pub struct InlayHintSettings {
 864    /// Global switch to toggle hints on and off.
 865    ///
 866    /// Default: false
 867    #[serde(default)]
 868    pub enabled: bool,
 869    /// Whether type hints should be shown.
 870    ///
 871    /// Default: true
 872    #[serde(default = "default_true")]
 873    pub show_type_hints: bool,
 874    /// Whether parameter hints should be shown.
 875    ///
 876    /// Default: true
 877    #[serde(default = "default_true")]
 878    pub show_parameter_hints: bool,
 879    /// Whether other hints should be shown.
 880    ///
 881    /// Default: true
 882    #[serde(default = "default_true")]
 883    pub show_other_hints: bool,
 884    /// Whether to show a background for inlay hints.
 885    ///
 886    /// If set to `true`, the background will use the `hint.background` color
 887    /// from the current theme.
 888    ///
 889    /// Default: false
 890    #[serde(default)]
 891    pub show_background: bool,
 892    /// Whether or not to debounce inlay hints updates after buffer edits.
 893    ///
 894    /// Set to 0 to disable debouncing.
 895    ///
 896    /// Default: 700
 897    #[serde(default = "edit_debounce_ms")]
 898    pub edit_debounce_ms: u64,
 899    /// Whether or not to debounce inlay hints updates after buffer scrolls.
 900    ///
 901    /// Set to 0 to disable debouncing.
 902    ///
 903    /// Default: 50
 904    #[serde(default = "scroll_debounce_ms")]
 905    pub scroll_debounce_ms: u64,
 906}
 907
 908fn edit_debounce_ms() -> u64 {
 909    700
 910}
 911
 912fn scroll_debounce_ms() -> u64 {
 913    50
 914}
 915
 916/// The task settings for a particular language.
 917#[derive(Debug, Clone, Deserialize, PartialEq, Serialize, JsonSchema)]
 918pub struct LanguageTaskConfig {
 919    /// Extra task variables to set for a particular language.
 920    pub variables: HashMap<String, String>,
 921}
 922
 923impl InlayHintSettings {
 924    /// Returns the kinds of inlay hints that are enabled based on the settings.
 925    pub fn enabled_inlay_hint_kinds(&self) -> HashSet<Option<InlayHintKind>> {
 926        let mut kinds = HashSet::default();
 927        if self.show_type_hints {
 928            kinds.insert(Some(InlayHintKind::Type));
 929        }
 930        if self.show_parameter_hints {
 931            kinds.insert(Some(InlayHintKind::Parameter));
 932        }
 933        if self.show_other_hints {
 934            kinds.insert(None);
 935        }
 936        kinds
 937    }
 938}
 939
 940impl AllLanguageSettings {
 941    /// Returns the [`LanguageSettings`] for the language with the specified name.
 942    pub fn language<'a>(
 943        &'a self,
 944        location: Option<SettingsLocation<'a>>,
 945        language_name: Option<&LanguageName>,
 946        cx: &'a App,
 947    ) -> Cow<'a, LanguageSettings> {
 948        let settings = language_name
 949            .and_then(|name| self.languages.get(name))
 950            .unwrap_or(&self.defaults);
 951
 952        let editorconfig_properties = location.and_then(|location| {
 953            cx.global::<SettingsStore>()
 954                .editorconfig_properties(location.worktree_id, location.path)
 955        });
 956        if let Some(editorconfig_properties) = editorconfig_properties {
 957            let mut settings = settings.clone();
 958            merge_with_editorconfig(&mut settings, &editorconfig_properties);
 959            Cow::Owned(settings)
 960        } else {
 961            Cow::Borrowed(settings)
 962        }
 963    }
 964
 965    /// Returns whether edit predictions are enabled for the given path.
 966    pub fn inline_completions_enabled_for_path(&self, path: &Path) -> bool {
 967        !self
 968            .edit_predictions
 969            .disabled_globs
 970            .iter()
 971            .any(|glob| glob.is_match(path))
 972    }
 973
 974    /// Returns whether edit predictions are enabled for the given language and path.
 975    pub fn show_inline_completions(&self, language: Option<&Arc<Language>>, cx: &App) -> bool {
 976        self.language(None, language.map(|l| l.name()).as_ref(), cx)
 977            .show_edit_predictions
 978    }
 979
 980    /// Returns the edit predictions preview mode for the given language and path.
 981    pub fn edit_predictions_mode(&self) -> EditPredictionsMode {
 982        self.edit_predictions.mode
 983    }
 984}
 985
 986fn merge_with_editorconfig(settings: &mut LanguageSettings, cfg: &EditorconfigProperties) {
 987    let tab_size = cfg.get::<IndentSize>().ok().and_then(|v| match v {
 988        IndentSize::Value(u) => NonZeroU32::new(u as u32),
 989        IndentSize::UseTabWidth => cfg.get::<TabWidth>().ok().and_then(|w| match w {
 990            TabWidth::Value(u) => NonZeroU32::new(u as u32),
 991        }),
 992    });
 993    let hard_tabs = cfg
 994        .get::<IndentStyle>()
 995        .map(|v| v.eq(&IndentStyle::Tabs))
 996        .ok();
 997    let ensure_final_newline_on_save = cfg
 998        .get::<FinalNewline>()
 999        .map(|v| match v {
1000            FinalNewline::Value(b) => b,
1001        })
1002        .ok();
1003    let remove_trailing_whitespace_on_save = cfg
1004        .get::<TrimTrailingWs>()
1005        .map(|v| match v {
1006            TrimTrailingWs::Value(b) => b,
1007        })
1008        .ok();
1009    fn merge<T>(target: &mut T, value: Option<T>) {
1010        if let Some(value) = value {
1011            *target = value;
1012        }
1013    }
1014    merge(&mut settings.tab_size, tab_size);
1015    merge(&mut settings.hard_tabs, hard_tabs);
1016    merge(
1017        &mut settings.remove_trailing_whitespace_on_save,
1018        remove_trailing_whitespace_on_save,
1019    );
1020    merge(
1021        &mut settings.ensure_final_newline_on_save,
1022        ensure_final_newline_on_save,
1023    );
1024}
1025
1026/// The kind of an inlay hint.
1027#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1028pub enum InlayHintKind {
1029    /// An inlay hint for a type.
1030    Type,
1031    /// An inlay hint for a parameter.
1032    Parameter,
1033}
1034
1035impl InlayHintKind {
1036    /// Returns the [`InlayHintKind`] from the given name.
1037    ///
1038    /// Returns `None` if `name` does not match any of the expected
1039    /// string representations.
1040    pub fn from_name(name: &str) -> Option<Self> {
1041        match name {
1042            "type" => Some(InlayHintKind::Type),
1043            "parameter" => Some(InlayHintKind::Parameter),
1044            _ => None,
1045        }
1046    }
1047
1048    /// Returns the name of this [`InlayHintKind`].
1049    pub fn name(&self) -> &'static str {
1050        match self {
1051            InlayHintKind::Type => "type",
1052            InlayHintKind::Parameter => "parameter",
1053        }
1054    }
1055}
1056
1057impl settings::Settings for AllLanguageSettings {
1058    const KEY: Option<&'static str> = None;
1059
1060    type FileContent = AllLanguageSettingsContent;
1061
1062    fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1063        let default_value = sources.default;
1064
1065        // A default is provided for all settings.
1066        let mut defaults: LanguageSettings =
1067            serde_json::from_value(serde_json::to_value(&default_value.defaults)?)?;
1068
1069        let mut languages = HashMap::default();
1070        for (language_name, settings) in &default_value.languages {
1071            let mut language_settings = defaults.clone();
1072            merge_settings(&mut language_settings, settings);
1073            languages.insert(language_name.clone(), language_settings);
1074        }
1075
1076        let mut copilot_enabled = default_value.features.as_ref().and_then(|f| f.copilot);
1077        let mut edit_prediction_provider = default_value
1078            .features
1079            .as_ref()
1080            .and_then(|f| f.edit_prediction_provider);
1081        let mut edit_predictions_mode = default_value
1082            .edit_predictions
1083            .as_ref()
1084            .map(|edit_predictions| edit_predictions.mode)
1085            .ok_or_else(Self::missing_default)?;
1086
1087        let mut completion_globs: HashSet<&String> = default_value
1088            .edit_predictions
1089            .as_ref()
1090            .and_then(|c| c.disabled_globs.as_ref())
1091            .map(|globs| globs.iter().collect())
1092            .ok_or_else(Self::missing_default)?;
1093
1094        let mut copilot_settings = default_value
1095            .edit_predictions
1096            .as_ref()
1097            .map(|settings| settings.copilot.clone())
1098            .map(|copilot| CopilotSettings {
1099                proxy: copilot.proxy,
1100                proxy_no_verify: copilot.proxy_no_verify,
1101            })
1102            .unwrap_or_default();
1103
1104        let mut file_types: HashMap<Arc<str>, GlobSet> = HashMap::default();
1105
1106        for (language, suffixes) in &default_value.file_types {
1107            let mut builder = GlobSetBuilder::new();
1108
1109            for suffix in suffixes {
1110                builder.add(Glob::new(suffix)?);
1111            }
1112
1113            file_types.insert(language.clone(), builder.build()?);
1114        }
1115
1116        for user_settings in sources.customizations() {
1117            if let Some(copilot) = user_settings.features.as_ref().and_then(|f| f.copilot) {
1118                copilot_enabled = Some(copilot);
1119            }
1120            if let Some(provider) = user_settings
1121                .features
1122                .as_ref()
1123                .and_then(|f| f.edit_prediction_provider)
1124            {
1125                edit_prediction_provider = Some(provider);
1126            }
1127
1128            if let Some(edit_predictions) = user_settings.edit_predictions.as_ref() {
1129                edit_predictions_mode = edit_predictions.mode;
1130
1131                if let Some(disabled_globs) = edit_predictions.disabled_globs.as_ref() {
1132                    completion_globs.extend(disabled_globs.iter());
1133                }
1134            }
1135
1136            if let Some(proxy) = user_settings
1137                .edit_predictions
1138                .as_ref()
1139                .and_then(|settings| settings.copilot.proxy.clone())
1140            {
1141                copilot_settings.proxy = Some(proxy);
1142            }
1143
1144            if let Some(proxy_no_verify) = user_settings
1145                .edit_predictions
1146                .as_ref()
1147                .and_then(|settings| settings.copilot.proxy_no_verify)
1148            {
1149                copilot_settings.proxy_no_verify = Some(proxy_no_verify);
1150            }
1151
1152            // A user's global settings override the default global settings and
1153            // all default language-specific settings.
1154            merge_settings(&mut defaults, &user_settings.defaults);
1155            for language_settings in languages.values_mut() {
1156                merge_settings(language_settings, &user_settings.defaults);
1157            }
1158
1159            // A user's language-specific settings override default language-specific settings.
1160            for (language_name, user_language_settings) in &user_settings.languages {
1161                merge_settings(
1162                    languages
1163                        .entry(language_name.clone())
1164                        .or_insert_with(|| defaults.clone()),
1165                    user_language_settings,
1166                );
1167            }
1168
1169            for (language, suffixes) in &user_settings.file_types {
1170                let mut builder = GlobSetBuilder::new();
1171
1172                let default_value = default_value.file_types.get(&language.clone());
1173
1174                // Merge the default value with the user's value.
1175                if let Some(suffixes) = default_value {
1176                    for suffix in suffixes {
1177                        builder.add(Glob::new(suffix)?);
1178                    }
1179                }
1180
1181                for suffix in suffixes {
1182                    builder.add(Glob::new(suffix)?);
1183                }
1184
1185                file_types.insert(language.clone(), builder.build()?);
1186            }
1187        }
1188
1189        Ok(Self {
1190            edit_predictions: EditPredictionSettings {
1191                provider: if let Some(provider) = edit_prediction_provider {
1192                    provider
1193                } else if copilot_enabled.unwrap_or(true) {
1194                    EditPredictionProvider::Copilot
1195                } else {
1196                    EditPredictionProvider::None
1197                },
1198                disabled_globs: completion_globs
1199                    .iter()
1200                    .filter_map(|g| Some(globset::Glob::new(g).ok()?.compile_matcher()))
1201                    .collect(),
1202                mode: edit_predictions_mode,
1203                copilot: copilot_settings,
1204            },
1205            defaults,
1206            languages,
1207            file_types,
1208        })
1209    }
1210
1211    fn json_schema(
1212        generator: &mut schemars::gen::SchemaGenerator,
1213        params: &settings::SettingsJsonSchemaParams,
1214        _: &App,
1215    ) -> schemars::schema::RootSchema {
1216        let mut root_schema = generator.root_schema_for::<Self::FileContent>();
1217
1218        // Create a schema for a 'languages overrides' object, associating editor
1219        // settings with specific languages.
1220        assert!(root_schema
1221            .definitions
1222            .contains_key("LanguageSettingsContent"));
1223
1224        let languages_object_schema = SchemaObject {
1225            instance_type: Some(InstanceType::Object.into()),
1226            object: Some(Box::new(ObjectValidation {
1227                properties: params
1228                    .language_names
1229                    .iter()
1230                    .map(|name| {
1231                        (
1232                            name.clone(),
1233                            Schema::new_ref("#/definitions/LanguageSettingsContent".into()),
1234                        )
1235                    })
1236                    .collect(),
1237                ..Default::default()
1238            })),
1239            ..Default::default()
1240        };
1241
1242        root_schema
1243            .definitions
1244            .extend([("Languages".into(), languages_object_schema.into())]);
1245
1246        add_references_to_properties(
1247            &mut root_schema,
1248            &[("languages", "#/definitions/Languages")],
1249        );
1250
1251        root_schema
1252    }
1253}
1254
1255fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent) {
1256    fn merge<T>(target: &mut T, value: Option<T>) {
1257        if let Some(value) = value {
1258            *target = value;
1259        }
1260    }
1261
1262    merge(&mut settings.tab_size, src.tab_size);
1263    settings.tab_size = settings
1264        .tab_size
1265        .clamp(NonZeroU32::new(1).unwrap(), NonZeroU32::new(16).unwrap());
1266
1267    merge(&mut settings.hard_tabs, src.hard_tabs);
1268    merge(&mut settings.soft_wrap, src.soft_wrap);
1269    merge(&mut settings.use_autoclose, src.use_autoclose);
1270    merge(&mut settings.use_auto_surround, src.use_auto_surround);
1271    merge(&mut settings.use_on_type_format, src.use_on_type_format);
1272    merge(&mut settings.auto_indent_on_paste, src.auto_indent_on_paste);
1273    merge(
1274        &mut settings.always_treat_brackets_as_autoclosed,
1275        src.always_treat_brackets_as_autoclosed,
1276    );
1277    merge(&mut settings.show_wrap_guides, src.show_wrap_guides);
1278    merge(&mut settings.wrap_guides, src.wrap_guides.clone());
1279    merge(&mut settings.indent_guides, src.indent_guides);
1280    merge(
1281        &mut settings.code_actions_on_format,
1282        src.code_actions_on_format.clone(),
1283    );
1284    merge(&mut settings.linked_edits, src.linked_edits);
1285    merge(&mut settings.tasks, src.tasks.clone());
1286
1287    merge(
1288        &mut settings.preferred_line_length,
1289        src.preferred_line_length,
1290    );
1291    merge(&mut settings.formatter, src.formatter.clone());
1292    merge(&mut settings.prettier, src.prettier.clone());
1293    merge(&mut settings.format_on_save, src.format_on_save.clone());
1294    merge(
1295        &mut settings.remove_trailing_whitespace_on_save,
1296        src.remove_trailing_whitespace_on_save,
1297    );
1298    merge(
1299        &mut settings.ensure_final_newline_on_save,
1300        src.ensure_final_newline_on_save,
1301    );
1302    merge(
1303        &mut settings.enable_language_server,
1304        src.enable_language_server,
1305    );
1306    merge(&mut settings.language_servers, src.language_servers.clone());
1307    merge(&mut settings.allow_rewrap, src.allow_rewrap);
1308    merge(
1309        &mut settings.show_edit_predictions,
1310        src.show_edit_predictions,
1311    );
1312    merge(
1313        &mut settings.edit_predictions_disabled_in,
1314        src.edit_predictions_disabled_in.clone(),
1315    );
1316    merge(&mut settings.show_whitespaces, src.show_whitespaces);
1317    merge(
1318        &mut settings.extend_comment_on_newline,
1319        src.extend_comment_on_newline,
1320    );
1321    merge(&mut settings.inlay_hints, src.inlay_hints);
1322    merge(
1323        &mut settings.show_completions_on_input,
1324        src.show_completions_on_input,
1325    );
1326    merge(
1327        &mut settings.show_completion_documentation,
1328        src.show_completion_documentation,
1329    );
1330}
1331
1332/// Allows to enable/disable formatting with Prettier
1333/// and configure default Prettier, used when no project-level Prettier installation is found.
1334/// Prettier formatting is disabled by default.
1335#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1336pub struct PrettierSettings {
1337    /// Enables or disables formatting with Prettier for a given language.
1338    #[serde(default)]
1339    pub allowed: bool,
1340
1341    /// Forces Prettier integration to use a specific parser name when formatting files with the language.
1342    #[serde(default)]
1343    pub parser: Option<String>,
1344
1345    /// Forces Prettier integration to use specific plugins when formatting files with the language.
1346    /// The default Prettier will be installed with these plugins.
1347    #[serde(default)]
1348    pub plugins: HashSet<String>,
1349
1350    /// Default Prettier options, in the format as in package.json section for Prettier.
1351    /// If project installs Prettier via its package.json, these options will be ignored.
1352    #[serde(flatten)]
1353    pub options: HashMap<String, serde_json::Value>,
1354}
1355
1356#[cfg(test)]
1357mod tests {
1358    use super::*;
1359
1360    #[test]
1361    fn test_formatter_deserialization() {
1362        let raw_auto = "{\"formatter\": \"auto\"}";
1363        let settings: LanguageSettingsContent = serde_json::from_str(raw_auto).unwrap();
1364        assert_eq!(settings.formatter, Some(SelectedFormatter::Auto));
1365        let raw = "{\"formatter\": \"language_server\"}";
1366        let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
1367        assert_eq!(
1368            settings.formatter,
1369            Some(SelectedFormatter::List(FormatterList(
1370                Formatter::LanguageServer { name: None }.into()
1371            )))
1372        );
1373        let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}]}";
1374        let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
1375        assert_eq!(
1376            settings.formatter,
1377            Some(SelectedFormatter::List(FormatterList(
1378                vec![Formatter::LanguageServer { name: None }].into()
1379            )))
1380        );
1381        let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}, \"prettier\"]}";
1382        let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
1383        assert_eq!(
1384            settings.formatter,
1385            Some(SelectedFormatter::List(FormatterList(
1386                vec![
1387                    Formatter::LanguageServer { name: None },
1388                    Formatter::Prettier
1389                ]
1390                .into()
1391            )))
1392        );
1393    }
1394
1395    #[test]
1396    fn test_formatter_deserialization_invalid() {
1397        let raw_auto = "{\"formatter\": {}}";
1398        let result: Result<LanguageSettingsContent, _> = serde_json::from_str(raw_auto);
1399        assert!(result.is_err());
1400    }
1401
1402    #[test]
1403    pub fn test_resolve_language_servers() {
1404        fn language_server_names(names: &[&str]) -> Vec<LanguageServerName> {
1405            names
1406                .iter()
1407                .copied()
1408                .map(|name| LanguageServerName(name.to_string().into()))
1409                .collect::<Vec<_>>()
1410        }
1411
1412        let available_language_servers = language_server_names(&[
1413            "typescript-language-server",
1414            "biome",
1415            "deno",
1416            "eslint",
1417            "tailwind",
1418        ]);
1419
1420        // A value of just `["..."]` is the same as taking all of the available language servers.
1421        assert_eq!(
1422            LanguageSettings::resolve_language_servers(
1423                &[LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()],
1424                &available_language_servers,
1425            ),
1426            available_language_servers
1427        );
1428
1429        // Referencing one of the available language servers will change its order.
1430        assert_eq!(
1431            LanguageSettings::resolve_language_servers(
1432                &[
1433                    "biome".into(),
1434                    LanguageSettings::REST_OF_LANGUAGE_SERVERS.into(),
1435                    "deno".into()
1436                ],
1437                &available_language_servers
1438            ),
1439            language_server_names(&[
1440                "biome",
1441                "typescript-language-server",
1442                "eslint",
1443                "tailwind",
1444                "deno",
1445            ])
1446        );
1447
1448        // Negating an available language server removes it from the list.
1449        assert_eq!(
1450            LanguageSettings::resolve_language_servers(
1451                &[
1452                    "deno".into(),
1453                    "!typescript-language-server".into(),
1454                    "!biome".into(),
1455                    LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()
1456                ],
1457                &available_language_servers
1458            ),
1459            language_server_names(&["deno", "eslint", "tailwind"])
1460        );
1461
1462        // Adding a language server not in the list of available language servers adds it to the list.
1463        assert_eq!(
1464            LanguageSettings::resolve_language_servers(
1465                &[
1466                    "my-cool-language-server".into(),
1467                    LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()
1468                ],
1469                &available_language_servers
1470            ),
1471            language_server_names(&[
1472                "my-cool-language-server",
1473                "typescript-language-server",
1474                "biome",
1475                "deno",
1476                "eslint",
1477                "tailwind",
1478            ])
1479        );
1480    }
1481}