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