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::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 tab_size = cfg.get::<IndentSize>().ok().and_then(|v| match v {
 880        IndentSize::Value(u) => NonZeroU32::new(u as u32),
 881        IndentSize::UseTabWidth => cfg.get::<TabWidth>().ok().and_then(|w| match w {
 882            TabWidth::Value(u) => NonZeroU32::new(u as u32),
 883        }),
 884    });
 885    let hard_tabs = cfg
 886        .get::<IndentStyle>()
 887        .map(|v| v.eq(&IndentStyle::Tabs))
 888        .ok();
 889    let ensure_final_newline_on_save = cfg
 890        .get::<FinalNewline>()
 891        .map(|v| match v {
 892            FinalNewline::Value(b) => b,
 893        })
 894        .ok();
 895    let remove_trailing_whitespace_on_save = cfg
 896        .get::<TrimTrailingWs>()
 897        .map(|v| match v {
 898            TrimTrailingWs::Value(b) => b,
 899        })
 900        .ok();
 901    fn merge<T>(target: &mut T, value: Option<T>) {
 902        if let Some(value) = value {
 903            *target = value;
 904        }
 905    }
 906    merge(&mut settings.tab_size, tab_size);
 907    merge(&mut settings.hard_tabs, hard_tabs);
 908    merge(
 909        &mut settings.remove_trailing_whitespace_on_save,
 910        remove_trailing_whitespace_on_save,
 911    );
 912    merge(
 913        &mut settings.ensure_final_newline_on_save,
 914        ensure_final_newline_on_save,
 915    );
 916}
 917
 918/// The kind of an inlay hint.
 919#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 920pub enum InlayHintKind {
 921    /// An inlay hint for a type.
 922    Type,
 923    /// An inlay hint for a parameter.
 924    Parameter,
 925}
 926
 927impl InlayHintKind {
 928    /// Returns the [`InlayHintKind`] from the given name.
 929    ///
 930    /// Returns `None` if `name` does not match any of the expected
 931    /// string representations.
 932    pub fn from_name(name: &str) -> Option<Self> {
 933        match name {
 934            "type" => Some(InlayHintKind::Type),
 935            "parameter" => Some(InlayHintKind::Parameter),
 936            _ => None,
 937        }
 938    }
 939
 940    /// Returns the name of this [`InlayHintKind`].
 941    pub fn name(&self) -> &'static str {
 942        match self {
 943            InlayHintKind::Type => "type",
 944            InlayHintKind::Parameter => "parameter",
 945        }
 946    }
 947}
 948
 949impl settings::Settings for AllLanguageSettings {
 950    const KEY: Option<&'static str> = None;
 951
 952    type FileContent = AllLanguageSettingsContent;
 953
 954    fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
 955        let default_value = sources.default;
 956
 957        // A default is provided for all settings.
 958        let mut defaults: LanguageSettings =
 959            serde_json::from_value(serde_json::to_value(&default_value.defaults)?)?;
 960
 961        let mut languages = HashMap::default();
 962        for (language_name, settings) in &default_value.languages {
 963            let mut language_settings = defaults.clone();
 964            merge_settings(&mut language_settings, settings);
 965            languages.insert(language_name.clone(), language_settings);
 966        }
 967
 968        let mut copilot_enabled = default_value.features.as_ref().and_then(|f| f.copilot);
 969        let mut inline_completion_provider = default_value
 970            .features
 971            .as_ref()
 972            .and_then(|f| f.inline_completion_provider);
 973        let mut completion_globs = default_value
 974            .inline_completions
 975            .as_ref()
 976            .and_then(|c| c.disabled_globs.as_ref())
 977            .ok_or_else(Self::missing_default)?;
 978
 979        let mut file_types: HashMap<Arc<str>, GlobSet> = HashMap::default();
 980
 981        for (language, suffixes) in &default_value.file_types {
 982            let mut builder = GlobSetBuilder::new();
 983
 984            for suffix in suffixes {
 985                builder.add(Glob::new(suffix)?);
 986            }
 987
 988            file_types.insert(language.clone(), builder.build()?);
 989        }
 990
 991        for user_settings in sources.customizations() {
 992            if let Some(copilot) = user_settings.features.as_ref().and_then(|f| f.copilot) {
 993                copilot_enabled = Some(copilot);
 994            }
 995            if let Some(provider) = user_settings
 996                .features
 997                .as_ref()
 998                .and_then(|f| f.inline_completion_provider)
 999            {
1000                inline_completion_provider = Some(provider);
1001            }
1002            if let Some(globs) = user_settings
1003                .inline_completions
1004                .as_ref()
1005                .and_then(|f| f.disabled_globs.as_ref())
1006            {
1007                completion_globs = globs;
1008            }
1009
1010            // A user's global settings override the default global settings and
1011            // all default language-specific settings.
1012            merge_settings(&mut defaults, &user_settings.defaults);
1013            for language_settings in languages.values_mut() {
1014                merge_settings(language_settings, &user_settings.defaults);
1015            }
1016
1017            // A user's language-specific settings override default language-specific settings.
1018            for (language_name, user_language_settings) in &user_settings.languages {
1019                merge_settings(
1020                    languages
1021                        .entry(language_name.clone())
1022                        .or_insert_with(|| defaults.clone()),
1023                    user_language_settings,
1024                );
1025            }
1026
1027            for (language, suffixes) in &user_settings.file_types {
1028                let mut builder = GlobSetBuilder::new();
1029
1030                let default_value = default_value.file_types.get(&language.clone());
1031
1032                // Merge the default value with the user's value.
1033                if let Some(suffixes) = default_value {
1034                    for suffix in suffixes {
1035                        builder.add(Glob::new(suffix)?);
1036                    }
1037                }
1038
1039                for suffix in suffixes {
1040                    builder.add(Glob::new(suffix)?);
1041                }
1042
1043                file_types.insert(language.clone(), builder.build()?);
1044            }
1045        }
1046
1047        Ok(Self {
1048            inline_completions: InlineCompletionSettings {
1049                provider: if let Some(provider) = inline_completion_provider {
1050                    provider
1051                } else if copilot_enabled.unwrap_or(true) {
1052                    InlineCompletionProvider::Copilot
1053                } else {
1054                    InlineCompletionProvider::None
1055                },
1056                disabled_globs: completion_globs
1057                    .iter()
1058                    .filter_map(|g| Some(globset::Glob::new(g).ok()?.compile_matcher()))
1059                    .collect(),
1060            },
1061            defaults,
1062            languages,
1063            file_types,
1064        })
1065    }
1066
1067    fn json_schema(
1068        generator: &mut schemars::gen::SchemaGenerator,
1069        params: &settings::SettingsJsonSchemaParams,
1070        _: &AppContext,
1071    ) -> schemars::schema::RootSchema {
1072        let mut root_schema = generator.root_schema_for::<Self::FileContent>();
1073
1074        // Create a schema for a 'languages overrides' object, associating editor
1075        // settings with specific languages.
1076        assert!(root_schema
1077            .definitions
1078            .contains_key("LanguageSettingsContent"));
1079
1080        let languages_object_schema = SchemaObject {
1081            instance_type: Some(InstanceType::Object.into()),
1082            object: Some(Box::new(ObjectValidation {
1083                properties: params
1084                    .language_names
1085                    .iter()
1086                    .map(|name| {
1087                        (
1088                            name.clone(),
1089                            Schema::new_ref("#/definitions/LanguageSettingsContent".into()),
1090                        )
1091                    })
1092                    .collect(),
1093                ..Default::default()
1094            })),
1095            ..Default::default()
1096        };
1097
1098        root_schema
1099            .definitions
1100            .extend([("Languages".into(), languages_object_schema.into())]);
1101
1102        add_references_to_properties(
1103            &mut root_schema,
1104            &[("languages", "#/definitions/Languages")],
1105        );
1106
1107        root_schema
1108    }
1109}
1110
1111fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent) {
1112    fn merge<T>(target: &mut T, value: Option<T>) {
1113        if let Some(value) = value {
1114            *target = value;
1115        }
1116    }
1117
1118    merge(&mut settings.tab_size, src.tab_size);
1119    settings.tab_size = settings
1120        .tab_size
1121        .clamp(NonZeroU32::new(1).unwrap(), NonZeroU32::new(16).unwrap());
1122
1123    merge(&mut settings.hard_tabs, src.hard_tabs);
1124    merge(&mut settings.soft_wrap, src.soft_wrap);
1125    merge(&mut settings.use_autoclose, src.use_autoclose);
1126    merge(&mut settings.use_auto_surround, src.use_auto_surround);
1127    merge(&mut settings.use_on_type_format, src.use_on_type_format);
1128    merge(&mut settings.auto_indent_on_paste, src.auto_indent_on_paste);
1129    merge(
1130        &mut settings.always_treat_brackets_as_autoclosed,
1131        src.always_treat_brackets_as_autoclosed,
1132    );
1133    merge(&mut settings.show_wrap_guides, src.show_wrap_guides);
1134    merge(&mut settings.wrap_guides, src.wrap_guides.clone());
1135    merge(&mut settings.indent_guides, src.indent_guides);
1136    merge(
1137        &mut settings.code_actions_on_format,
1138        src.code_actions_on_format.clone(),
1139    );
1140    merge(&mut settings.linked_edits, src.linked_edits);
1141    merge(&mut settings.tasks, src.tasks.clone());
1142
1143    merge(
1144        &mut settings.preferred_line_length,
1145        src.preferred_line_length,
1146    );
1147    merge(&mut settings.formatter, src.formatter.clone());
1148    merge(&mut settings.prettier, src.prettier.clone());
1149    merge(&mut settings.format_on_save, src.format_on_save.clone());
1150    merge(
1151        &mut settings.remove_trailing_whitespace_on_save,
1152        src.remove_trailing_whitespace_on_save,
1153    );
1154    merge(
1155        &mut settings.ensure_final_newline_on_save,
1156        src.ensure_final_newline_on_save,
1157    );
1158    merge(
1159        &mut settings.enable_language_server,
1160        src.enable_language_server,
1161    );
1162    merge(&mut settings.language_servers, src.language_servers.clone());
1163    merge(
1164        &mut settings.show_inline_completions,
1165        src.show_inline_completions,
1166    );
1167    merge(&mut settings.show_whitespaces, src.show_whitespaces);
1168    merge(
1169        &mut settings.extend_comment_on_newline,
1170        src.extend_comment_on_newline,
1171    );
1172    merge(&mut settings.inlay_hints, src.inlay_hints);
1173}
1174
1175/// Allows to enable/disable formatting with Prettier
1176/// and configure default Prettier, used when no project-level Prettier installation is found.
1177/// Prettier formatting is disabled by default.
1178#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1179pub struct PrettierSettings {
1180    /// Enables or disables formatting with Prettier for a given language.
1181    #[serde(default)]
1182    pub allowed: bool,
1183
1184    /// Forces Prettier integration to use a specific parser name when formatting files with the language.
1185    #[serde(default)]
1186    pub parser: Option<String>,
1187
1188    /// Forces Prettier integration to use specific plugins when formatting files with the language.
1189    /// The default Prettier will be installed with these plugins.
1190    #[serde(default)]
1191    pub plugins: HashSet<String>,
1192
1193    /// Default Prettier options, in the format as in package.json section for Prettier.
1194    /// If project installs Prettier via its package.json, these options will be ignored.
1195    #[serde(flatten)]
1196    pub options: HashMap<String, serde_json::Value>,
1197}
1198
1199#[cfg(test)]
1200mod tests {
1201    use super::*;
1202
1203    #[test]
1204    fn test_formatter_deserialization() {
1205        let raw_auto = "{\"formatter\": \"auto\"}";
1206        let settings: LanguageSettingsContent = serde_json::from_str(raw_auto).unwrap();
1207        assert_eq!(settings.formatter, Some(SelectedFormatter::Auto));
1208        let raw = "{\"formatter\": \"language_server\"}";
1209        let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
1210        assert_eq!(
1211            settings.formatter,
1212            Some(SelectedFormatter::List(FormatterList(
1213                Formatter::LanguageServer { name: None }.into()
1214            )))
1215        );
1216        let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}]}";
1217        let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
1218        assert_eq!(
1219            settings.formatter,
1220            Some(SelectedFormatter::List(FormatterList(
1221                vec![Formatter::LanguageServer { name: None }].into()
1222            )))
1223        );
1224        let raw = "{\"formatter\": [{\"language_server\": {\"name\": null}}, \"prettier\"]}";
1225        let settings: LanguageSettingsContent = serde_json::from_str(raw).unwrap();
1226        assert_eq!(
1227            settings.formatter,
1228            Some(SelectedFormatter::List(FormatterList(
1229                vec![
1230                    Formatter::LanguageServer { name: None },
1231                    Formatter::Prettier
1232                ]
1233                .into()
1234            )))
1235        );
1236    }
1237
1238    #[test]
1239    fn test_formatter_deserialization_invalid() {
1240        let raw_auto = "{\"formatter\": {}}";
1241        let result: Result<LanguageSettingsContent, _> = serde_json::from_str(raw_auto);
1242        assert!(result.is_err());
1243    }
1244
1245    #[test]
1246    pub fn test_resolve_language_servers() {
1247        fn language_server_names(names: &[&str]) -> Vec<LanguageServerName> {
1248            names
1249                .iter()
1250                .copied()
1251                .map(|name| LanguageServerName(name.to_string().into()))
1252                .collect::<Vec<_>>()
1253        }
1254
1255        let available_language_servers = language_server_names(&[
1256            "typescript-language-server",
1257            "biome",
1258            "deno",
1259            "eslint",
1260            "tailwind",
1261        ]);
1262
1263        // A value of just `["..."]` is the same as taking all of the available language servers.
1264        assert_eq!(
1265            LanguageSettings::resolve_language_servers(
1266                &[LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()],
1267                &available_language_servers,
1268            ),
1269            available_language_servers
1270        );
1271
1272        // Referencing one of the available language servers will change its order.
1273        assert_eq!(
1274            LanguageSettings::resolve_language_servers(
1275                &[
1276                    "biome".into(),
1277                    LanguageSettings::REST_OF_LANGUAGE_SERVERS.into(),
1278                    "deno".into()
1279                ],
1280                &available_language_servers
1281            ),
1282            language_server_names(&[
1283                "biome",
1284                "typescript-language-server",
1285                "eslint",
1286                "tailwind",
1287                "deno",
1288            ])
1289        );
1290
1291        // Negating an available language server removes it from the list.
1292        assert_eq!(
1293            LanguageSettings::resolve_language_servers(
1294                &[
1295                    "deno".into(),
1296                    "!typescript-language-server".into(),
1297                    "!biome".into(),
1298                    LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()
1299                ],
1300                &available_language_servers
1301            ),
1302            language_server_names(&["deno", "eslint", "tailwind"])
1303        );
1304
1305        // Adding a language server not in the list of available language servers adds it to the list.
1306        assert_eq!(
1307            LanguageSettings::resolve_language_servers(
1308                &[
1309                    "my-cool-language-server".into(),
1310                    LanguageSettings::REST_OF_LANGUAGE_SERVERS.into()
1311                ],
1312                &available_language_servers
1313            ),
1314            language_server_names(&[
1315                "my-cool-language-server",
1316                "typescript-language-server",
1317                "biome",
1318                "deno",
1319                "eslint",
1320                "tailwind",
1321            ])
1322        );
1323    }
1324}