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