settings_content.rs

   1mod agent;
   2mod editor;
   3mod extension;
   4mod fallible_options;
   5mod language;
   6mod language_model;
   7pub mod merge_from;
   8mod project;
   9mod serde_helper;
  10mod terminal;
  11mod theme;
  12mod workspace;
  13
  14pub use agent::*;
  15pub use editor::*;
  16pub use extension::*;
  17pub use fallible_options::*;
  18pub use language::*;
  19pub use language_model::*;
  20pub use merge_from::MergeFrom as MergeFromTrait;
  21pub use project::*;
  22use serde::de::DeserializeOwned;
  23pub use serde_helper::{
  24    serialize_f32_with_two_decimal_places, serialize_optional_f32_with_two_decimal_places,
  25};
  26use settings_json::parse_json_with_comments;
  27pub use terminal::*;
  28pub use theme::*;
  29pub use workspace::*;
  30
  31use collections::{HashMap, IndexMap};
  32use schemars::JsonSchema;
  33use serde::{Deserialize, Serialize};
  34use settings_macros::{MergeFrom, with_fallible_options};
  35
  36/// Defines a settings override struct where each field is
  37/// `Option<Box<SettingsContent>>`, along with:
  38/// - `OVERRIDE_KEYS`: a `&[&str]` of the field names (the JSON keys)
  39/// - `get_by_key(&self, key) -> Option<&SettingsContent>`: accessor by key
  40///
  41/// The field list is the single source of truth for the override key strings.
  42macro_rules! settings_overrides {
  43    (
  44        $(#[$attr:meta])*
  45        pub struct $name:ident { $($field:ident),* $(,)? }
  46    ) => {
  47        $(#[$attr])*
  48        pub struct $name {
  49            $(pub $field: Option<Box<SettingsContent>>,)*
  50        }
  51
  52        impl $name {
  53            /// The JSON override keys, derived from the field names on this struct.
  54            pub const OVERRIDE_KEYS: &[&str] = &[$(stringify!($field)),*];
  55
  56            /// Look up an override by its JSON key name.
  57            pub fn get_by_key(&self, key: &str) -> Option<&SettingsContent> {
  58                match key {
  59                    $(stringify!($field) => self.$field.as_deref(),)*
  60                    _ => None,
  61                }
  62            }
  63        }
  64    }
  65}
  66use std::collections::BTreeSet;
  67use std::sync::Arc;
  68pub use util::serde::default_true;
  69
  70#[derive(Debug, Clone, PartialEq, Eq)]
  71pub enum ParseStatus {
  72    /// Settings were parsed successfully
  73    Success,
  74    /// Settings failed to parse
  75    Failed { error: String },
  76}
  77
  78#[with_fallible_options]
  79#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
  80pub struct SettingsContent {
  81    #[serde(flatten)]
  82    pub project: ProjectSettingsContent,
  83
  84    #[serde(flatten)]
  85    pub theme: Box<ThemeSettingsContent>,
  86
  87    #[serde(flatten)]
  88    pub extension: ExtensionSettingsContent,
  89
  90    #[serde(flatten)]
  91    pub workspace: WorkspaceSettingsContent,
  92
  93    #[serde(flatten)]
  94    pub editor: EditorSettingsContent,
  95
  96    #[serde(flatten)]
  97    pub remote: RemoteSettingsContent,
  98
  99    /// Settings related to the file finder.
 100    pub file_finder: Option<FileFinderSettingsContent>,
 101
 102    pub git_panel: Option<GitPanelSettingsContent>,
 103
 104    pub tabs: Option<ItemSettingsContent>,
 105    pub tab_bar: Option<TabBarSettingsContent>,
 106    pub status_bar: Option<StatusBarSettingsContent>,
 107
 108    pub preview_tabs: Option<PreviewTabsSettingsContent>,
 109
 110    pub agent: Option<AgentSettingsContent>,
 111    pub agent_servers: Option<AllAgentServersSettings>,
 112
 113    /// Configuration of audio in Zed.
 114    pub audio: Option<AudioSettingsContent>,
 115
 116    /// Whether or not to automatically check for updates.
 117    ///
 118    /// Default: true
 119    pub auto_update: Option<bool>,
 120
 121    /// This base keymap settings adjusts the default keybindings in Zed to be similar
 122    /// to other common code editors. By default, Zed's keymap closely follows VSCode's
 123    /// keymap, with minor adjustments, this corresponds to the "VSCode" setting.
 124    ///
 125    /// Default: VSCode
 126    pub base_keymap: Option<BaseKeymapContent>,
 127
 128    /// Configuration for the collab panel visual settings.
 129    pub collaboration_panel: Option<PanelSettingsContent>,
 130
 131    pub debugger: Option<DebuggerSettingsContent>,
 132
 133    /// Configuration for Diagnostics-related features.
 134    pub diagnostics: Option<DiagnosticsSettingsContent>,
 135
 136    /// Configuration for Git-related features
 137    pub git: Option<GitSettings>,
 138
 139    /// Common language server settings.
 140    pub global_lsp_settings: Option<GlobalLspSettingsContent>,
 141
 142    /// The settings for the image viewer.
 143    pub image_viewer: Option<ImageViewerSettingsContent>,
 144
 145    pub repl: Option<ReplSettingsContent>,
 146
 147    /// Whether or not to enable Helix mode.
 148    ///
 149    /// Default: false
 150    pub helix_mode: Option<bool>,
 151
 152    pub journal: Option<JournalSettingsContent>,
 153
 154    /// A map of log scopes to the desired log level.
 155    /// Useful for filtering out noisy logs or enabling more verbose logging.
 156    ///
 157    /// Example: {"log": {"client": "warn"}}
 158    pub log: Option<HashMap<String, String>>,
 159
 160    pub line_indicator_format: Option<LineIndicatorFormat>,
 161
 162    pub language_models: Option<AllLanguageModelSettingsContent>,
 163
 164    pub outline_panel: Option<OutlinePanelSettingsContent>,
 165
 166    pub project_panel: Option<ProjectPanelSettingsContent>,
 167
 168    /// Configuration for the Message Editor
 169    pub message_editor: Option<MessageEditorSettings>,
 170
 171    /// Configuration for Node-related features
 172    pub node: Option<NodeBinarySettings>,
 173
 174    /// Configuration for the Notification Panel
 175    pub notification_panel: Option<NotificationPanelSettingsContent>,
 176
 177    pub proxy: Option<String>,
 178
 179    /// The URL of the Zed server to connect to.
 180    pub server_url: Option<String>,
 181
 182    /// Configuration for session-related features
 183    pub session: Option<SessionSettingsContent>,
 184    /// Control what info is collected by Zed.
 185    pub telemetry: Option<TelemetrySettingsContent>,
 186
 187    /// Configuration of the terminal in Zed.
 188    pub terminal: Option<TerminalSettingsContent>,
 189
 190    pub title_bar: Option<TitleBarSettingsContent>,
 191
 192    /// Whether or not to enable Vim mode.
 193    ///
 194    /// Default: false
 195    pub vim_mode: Option<bool>,
 196
 197    // Settings related to calls in Zed
 198    pub calls: Option<CallSettingsContent>,
 199
 200    /// Settings for the which-key popup.
 201    pub which_key: Option<WhichKeySettingsContent>,
 202
 203    /// Settings related to Vim mode in Zed.
 204    pub vim: Option<VimSettingsContent>,
 205}
 206
 207impl SettingsContent {
 208    pub fn languages_mut(&mut self) -> &mut HashMap<String, LanguageSettingsContent> {
 209        &mut self.project.all_languages.languages.0
 210    }
 211}
 212
 213// These impls are there to optimize builds by avoiding monomorphization downstream. Yes, they're repetitive, but using default impls
 214// break the optimization, for whatever reason.
 215pub trait RootUserSettings: Sized + DeserializeOwned {
 216    fn parse_json(json: &str) -> (Option<Self>, ParseStatus);
 217    fn parse_json_with_comments(json: &str) -> anyhow::Result<Self>;
 218}
 219
 220impl RootUserSettings for SettingsContent {
 221    fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
 222        fallible_options::parse_json(json)
 223    }
 224    fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
 225        parse_json_with_comments(json)
 226    }
 227}
 228// Explicit opt-in instead of blanket impl to avoid monomorphizing downstream. Just a hunch though.
 229impl RootUserSettings for Option<SettingsContent> {
 230    fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
 231        fallible_options::parse_json(json)
 232    }
 233    fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
 234        parse_json_with_comments(json)
 235    }
 236}
 237impl RootUserSettings for UserSettingsContent {
 238    fn parse_json(json: &str) -> (Option<Self>, ParseStatus) {
 239        fallible_options::parse_json(json)
 240    }
 241    fn parse_json_with_comments(json: &str) -> anyhow::Result<Self> {
 242        parse_json_with_comments(json)
 243    }
 244}
 245
 246settings_overrides! {
 247    #[with_fallible_options]
 248    #[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
 249    pub struct ReleaseChannelOverrides { dev, nightly, preview, stable }
 250}
 251
 252settings_overrides! {
 253    #[with_fallible_options]
 254    #[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
 255    pub struct PlatformOverrides { macos, linux, windows }
 256}
 257
 258#[with_fallible_options]
 259#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize, JsonSchema, MergeFrom)]
 260pub struct UserSettingsContent {
 261    #[serde(flatten)]
 262    pub content: Box<SettingsContent>,
 263
 264    #[serde(flatten)]
 265    pub release_channel_overrides: ReleaseChannelOverrides,
 266
 267    #[serde(flatten)]
 268    pub platform_overrides: PlatformOverrides,
 269
 270    #[serde(default)]
 271    pub profiles: IndexMap<String, SettingsContent>,
 272}
 273
 274pub struct ExtensionsSettingsContent {
 275    pub all_languages: AllLanguageSettingsContent,
 276}
 277
 278/// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
 279///
 280/// Default: VSCode
 281#[derive(
 282    Copy,
 283    Clone,
 284    Debug,
 285    Serialize,
 286    Deserialize,
 287    JsonSchema,
 288    MergeFrom,
 289    PartialEq,
 290    Eq,
 291    Default,
 292    strum::VariantArray,
 293)]
 294pub enum BaseKeymapContent {
 295    #[default]
 296    VSCode,
 297    JetBrains,
 298    SublimeText,
 299    Atom,
 300    TextMate,
 301    Emacs,
 302    Cursor,
 303    None,
 304}
 305
 306impl strum::VariantNames for BaseKeymapContent {
 307    const VARIANTS: &'static [&'static str] = &[
 308        "VSCode",
 309        "JetBrains",
 310        "Sublime Text",
 311        "Atom",
 312        "TextMate",
 313        "Emacs",
 314        "Cursor",
 315        "None",
 316    ];
 317}
 318
 319#[with_fallible_options]
 320#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
 321pub struct TitleBarSettingsContent {
 322    /// Whether to show the branch icon beside branch switcher in the title bar.
 323    ///
 324    /// Default: false
 325    pub show_branch_icon: Option<bool>,
 326    /// Whether to show onboarding banners in the title bar.
 327    ///
 328    /// Default: true
 329    pub show_onboarding_banner: Option<bool>,
 330    /// Whether to show user avatar in the title bar.
 331    ///
 332    /// Default: true
 333    pub show_user_picture: Option<bool>,
 334    /// Whether to show the branch name button in the titlebar.
 335    ///
 336    /// Default: true
 337    pub show_branch_name: Option<bool>,
 338    /// Whether to show the project host and name in the titlebar.
 339    ///
 340    /// Default: true
 341    pub show_project_items: Option<bool>,
 342    /// Whether to show the sign in button in the title bar.
 343    ///
 344    /// Default: true
 345    pub show_sign_in: Option<bool>,
 346    /// Whether to show the user menu button in the title bar.
 347    ///
 348    /// Default: true
 349    pub show_user_menu: Option<bool>,
 350    /// Whether to show the menus in the title bar.
 351    ///
 352    /// Default: false
 353    pub show_menus: Option<bool>,
 354}
 355
 356/// Configuration of audio in Zed.
 357#[with_fallible_options]
 358#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
 359pub struct AudioSettingsContent {
 360    /// Opt into the new audio system.
 361    ///
 362    /// You need to rejoin a call for this setting to apply
 363    #[serde(rename = "experimental.rodio_audio")]
 364    pub rodio_audio: Option<bool>, // default is false
 365    /// Requires 'rodio_audio: true'
 366    ///
 367    /// Automatically increase or decrease you microphone's volume. This affects how
 368    /// loud you sound to others.
 369    ///
 370    /// Recommended: off (default)
 371    /// Microphones are too quite in zed, until everyone is on experimental
 372    /// audio and has auto speaker volume on this will make you very loud
 373    /// compared to other speakers.
 374    #[serde(rename = "experimental.auto_microphone_volume")]
 375    pub auto_microphone_volume: Option<bool>,
 376    /// Requires 'rodio_audio: true'
 377    ///
 378    /// Automatically increate or decrease the volume of other call members.
 379    /// This only affects how things sound for you.
 380    #[serde(rename = "experimental.auto_speaker_volume")]
 381    pub auto_speaker_volume: Option<bool>,
 382    /// Requires 'rodio_audio: true'
 383    ///
 384    /// Remove background noises. Works great for typing, cars, dogs, AC. Does
 385    /// not work well on music.
 386    #[serde(rename = "experimental.denoise")]
 387    pub denoise: Option<bool>,
 388    /// Requires 'rodio_audio: true'
 389    ///
 390    /// Use audio parameters compatible with the previous versions of
 391    /// experimental audio and non-experimental audio. When this is false you
 392    /// will sound strange to anyone not on the latest experimental audio. In
 393    /// the future we will migrate by setting this to false
 394    ///
 395    /// You need to rejoin a call for this setting to apply
 396    #[serde(rename = "experimental.legacy_audio_compatible")]
 397    pub legacy_audio_compatible: Option<bool>,
 398    /// Requires 'rodio_audio: true'
 399    ///
 400    /// Select specific output audio device.
 401    #[serde(rename = "experimental.output_audio_device")]
 402    pub output_audio_device: Option<AudioOutputDeviceName>,
 403    /// Requires 'rodio_audio: true'
 404    ///
 405    /// Select specific input audio device.
 406    #[serde(rename = "experimental.input_audio_device")]
 407    pub input_audio_device: Option<AudioInputDeviceName>,
 408}
 409
 410#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
 411#[serde(transparent)]
 412pub struct AudioOutputDeviceName(pub Option<String>);
 413
 414impl AsRef<Option<String>> for AudioInputDeviceName {
 415    fn as_ref(&self) -> &Option<String> {
 416        &self.0
 417    }
 418}
 419
 420impl From<Option<String>> for AudioInputDeviceName {
 421    fn from(value: Option<String>) -> Self {
 422        Self(value)
 423    }
 424}
 425
 426#[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)]
 427#[serde(transparent)]
 428pub struct AudioInputDeviceName(pub Option<String>);
 429
 430impl AsRef<Option<String>> for AudioOutputDeviceName {
 431    fn as_ref(&self) -> &Option<String> {
 432        &self.0
 433    }
 434}
 435
 436impl From<Option<String>> for AudioOutputDeviceName {
 437    fn from(value: Option<String>) -> Self {
 438        Self(value)
 439    }
 440}
 441
 442/// Control what info is collected by Zed.
 443#[with_fallible_options]
 444#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Debug, MergeFrom)]
 445pub struct TelemetrySettingsContent {
 446    /// Send debug info like crash reports.
 447    ///
 448    /// Default: true
 449    pub diagnostics: Option<bool>,
 450    /// Send anonymized usage data like what languages you're using Zed with.
 451    ///
 452    /// Default: true
 453    pub metrics: Option<bool>,
 454}
 455
 456impl Default for TelemetrySettingsContent {
 457    fn default() -> Self {
 458        Self {
 459            diagnostics: Some(true),
 460            metrics: Some(true),
 461        }
 462    }
 463}
 464
 465#[with_fallible_options]
 466#[derive(Default, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Clone, MergeFrom)]
 467pub struct DebuggerSettingsContent {
 468    /// Determines the stepping granularity.
 469    ///
 470    /// Default: line
 471    pub stepping_granularity: Option<SteppingGranularity>,
 472    /// Whether the breakpoints should be reused across Zed sessions.
 473    ///
 474    /// Default: true
 475    pub save_breakpoints: Option<bool>,
 476    /// Whether to show the debug button in the status bar.
 477    ///
 478    /// Default: true
 479    pub button: Option<bool>,
 480    /// Time in milliseconds until timeout error when connecting to a TCP debug adapter
 481    ///
 482    /// Default: 2000ms
 483    pub timeout: Option<u64>,
 484    /// Whether to log messages between active debug adapters and Zed
 485    ///
 486    /// Default: true
 487    pub log_dap_communications: Option<bool>,
 488    /// Whether to format dap messages in when adding them to debug adapter logger
 489    ///
 490    /// Default: true
 491    pub format_dap_log_messages: Option<bool>,
 492    /// The dock position of the debug panel
 493    ///
 494    /// Default: Bottom
 495    pub dock: Option<DockPosition>,
 496}
 497
 498/// The granularity of one 'step' in the stepping requests `next`, `stepIn`, `stepOut`, and `stepBack`.
 499#[derive(
 500    PartialEq,
 501    Eq,
 502    Debug,
 503    Hash,
 504    Clone,
 505    Copy,
 506    Deserialize,
 507    Serialize,
 508    JsonSchema,
 509    MergeFrom,
 510    strum::VariantArray,
 511    strum::VariantNames,
 512)]
 513#[serde(rename_all = "snake_case")]
 514pub enum SteppingGranularity {
 515    /// The step should allow the program to run until the current statement has finished executing.
 516    /// The meaning of a statement is determined by the adapter and it may be considered equivalent to a line.
 517    /// For example 'for(int i = 0; i < 10; i++)' could be considered to have 3 statements 'int i = 0', 'i < 10', and 'i++'.
 518    Statement,
 519    /// The step should allow the program to run until the current source line has executed.
 520    Line,
 521    /// The step should allow one instruction to execute (e.g. one x86 instruction).
 522    Instruction,
 523}
 524
 525#[derive(
 526    Copy,
 527    Clone,
 528    Debug,
 529    Serialize,
 530    Deserialize,
 531    JsonSchema,
 532    MergeFrom,
 533    PartialEq,
 534    Eq,
 535    strum::VariantArray,
 536    strum::VariantNames,
 537)]
 538#[serde(rename_all = "snake_case")]
 539pub enum DockPosition {
 540    Left,
 541    Bottom,
 542    Right,
 543}
 544
 545/// Settings for slash commands.
 546#[with_fallible_options]
 547#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, MergeFrom, PartialEq, Eq)]
 548pub struct SlashCommandSettings {
 549    /// Settings for the `/cargo-workspace` slash command.
 550    pub cargo_workspace: Option<CargoWorkspaceCommandSettings>,
 551}
 552
 553/// Settings for the `/cargo-workspace` slash command.
 554#[with_fallible_options]
 555#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, MergeFrom, PartialEq, Eq)]
 556pub struct CargoWorkspaceCommandSettings {
 557    /// Whether `/cargo-workspace` is enabled.
 558    pub enabled: Option<bool>,
 559}
 560
 561/// Configuration of voice calls in Zed.
 562#[with_fallible_options]
 563#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
 564pub struct CallSettingsContent {
 565    /// Whether the microphone should be muted when joining a channel or a call.
 566    ///
 567    /// Default: false
 568    pub mute_on_join: Option<bool>,
 569
 570    /// Whether your current project should be shared when joining an empty channel.
 571    ///
 572    /// Default: false
 573    pub share_on_join: Option<bool>,
 574}
 575
 576#[with_fallible_options]
 577#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
 578pub struct GitPanelSettingsContent {
 579    /// Whether to show the panel button in the status bar.
 580    ///
 581    /// Default: true
 582    pub button: Option<bool>,
 583    /// Where to dock the panel.
 584    ///
 585    /// Default: left
 586    pub dock: Option<DockPosition>,
 587    /// Default width of the panel in pixels.
 588    ///
 589    /// Default: 360
 590    #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
 591    pub default_width: Option<f32>,
 592    /// How entry statuses are displayed.
 593    ///
 594    /// Default: icon
 595    pub status_style: Option<StatusStyle>,
 596
 597    /// Whether to show file icons in the git panel.
 598    ///
 599    /// Default: false
 600    pub file_icons: Option<bool>,
 601
 602    /// Whether to show folder icons or chevrons for directories in the git panel.
 603    ///
 604    /// Default: true
 605    pub folder_icons: Option<bool>,
 606
 607    /// How and when the scrollbar should be displayed.
 608    ///
 609    /// Default: inherits editor scrollbar settings
 610    pub scrollbar: Option<ScrollbarSettings>,
 611
 612    /// What the default branch name should be when
 613    /// `init.defaultBranch` is not set in git
 614    ///
 615    /// Default: main
 616    pub fallback_branch_name: Option<String>,
 617
 618    /// Whether to sort entries in the panel by path
 619    /// or by status (the default).
 620    ///
 621    /// Default: false
 622    pub sort_by_path: Option<bool>,
 623
 624    /// Whether to collapse untracked files in the diff panel.
 625    ///
 626    /// Default: false
 627    pub collapse_untracked_diff: Option<bool>,
 628
 629    /// Whether to show entries with tree or flat view in the panel
 630    ///
 631    /// Default: false
 632    pub tree_view: Option<bool>,
 633
 634    /// Whether to show the addition/deletion change count next to each file in the Git panel.
 635    ///
 636    /// Default: true
 637    pub diff_stats: Option<bool>,
 638
 639    /// Whether to show a badge on the git panel icon with the count of uncommitted changes.
 640    ///
 641    /// Default: false
 642    pub show_count_badge: Option<bool>,
 643
 644    /// Whether the git panel should open on startup.
 645    ///
 646    /// Default: false
 647    pub starts_open: Option<bool>,
 648}
 649
 650#[derive(
 651    Default,
 652    Copy,
 653    Clone,
 654    Debug,
 655    Serialize,
 656    Deserialize,
 657    JsonSchema,
 658    MergeFrom,
 659    PartialEq,
 660    Eq,
 661    strum::VariantArray,
 662    strum::VariantNames,
 663)]
 664#[serde(rename_all = "snake_case")]
 665pub enum StatusStyle {
 666    #[default]
 667    Icon,
 668    LabelColor,
 669}
 670
 671#[with_fallible_options]
 672#[derive(
 673    Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq,
 674)]
 675pub struct ScrollbarSettings {
 676    pub show: Option<ShowScrollbar>,
 677}
 678
 679#[with_fallible_options]
 680#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
 681pub struct NotificationPanelSettingsContent {
 682    /// Whether to show the panel button in the status bar.
 683    ///
 684    /// Default: true
 685    pub button: Option<bool>,
 686    /// Where to dock the panel.
 687    ///
 688    /// Default: right
 689    pub dock: Option<DockPosition>,
 690    /// Default width of the panel in pixels.
 691    ///
 692    /// Default: 300
 693    #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
 694    pub default_width: Option<f32>,
 695    /// Whether to show a badge on the notification panel icon with the count of unread notifications.
 696    ///
 697    /// Default: false
 698    pub show_count_badge: Option<bool>,
 699}
 700
 701#[with_fallible_options]
 702#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
 703pub struct PanelSettingsContent {
 704    /// Whether to show the panel button in the status bar.
 705    ///
 706    /// Default: true
 707    pub button: Option<bool>,
 708    /// Where to dock the panel.
 709    ///
 710    /// Default: left
 711    pub dock: Option<DockPosition>,
 712    /// Default width of the panel in pixels.
 713    ///
 714    /// Default: 240
 715    #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
 716    pub default_width: Option<f32>,
 717}
 718
 719#[with_fallible_options]
 720#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
 721pub struct MessageEditorSettings {
 722    /// Whether to automatically replace emoji shortcodes with emoji characters.
 723    /// For example: typing `:wave:` gets replaced with `👋`.
 724    ///
 725    /// Default: false
 726    pub auto_replace_emoji_shortcode: Option<bool>,
 727}
 728
 729#[with_fallible_options]
 730#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
 731pub struct FileFinderSettingsContent {
 732    /// Whether to show file icons in the file finder.
 733    ///
 734    /// Default: true
 735    pub file_icons: Option<bool>,
 736    /// Determines how much space the file finder can take up in relation to the available window width.
 737    ///
 738    /// Default: small
 739    pub modal_max_width: Option<FileFinderWidthContent>,
 740    /// Determines whether the file finder should skip focus for the active file in search results.
 741    ///
 742    /// Default: true
 743    pub skip_focus_for_active_in_search: Option<bool>,
 744    /// Whether to use gitignored files when searching.
 745    /// Only the file Zed had indexed will be used, not necessary all the gitignored files.
 746    ///
 747    /// Default: Smart
 748    pub include_ignored: Option<IncludeIgnoredContent>,
 749    /// Whether to include text channels in file finder results.
 750    ///
 751    /// Default: false
 752    pub include_channels: Option<bool>,
 753}
 754
 755#[derive(
 756    Debug,
 757    PartialEq,
 758    Eq,
 759    Clone,
 760    Copy,
 761    Default,
 762    Serialize,
 763    Deserialize,
 764    JsonSchema,
 765    MergeFrom,
 766    strum::VariantArray,
 767    strum::VariantNames,
 768)]
 769#[serde(rename_all = "snake_case")]
 770pub enum IncludeIgnoredContent {
 771    /// Use all gitignored files
 772    All,
 773    /// Use only the files Zed had indexed
 774    Indexed,
 775    /// Be smart and search for ignored when called from a gitignored worktree
 776    #[default]
 777    Smart,
 778}
 779
 780#[derive(
 781    Debug,
 782    PartialEq,
 783    Eq,
 784    Clone,
 785    Copy,
 786    Default,
 787    Serialize,
 788    Deserialize,
 789    JsonSchema,
 790    MergeFrom,
 791    strum::VariantArray,
 792    strum::VariantNames,
 793)]
 794#[serde(rename_all = "lowercase")]
 795pub enum FileFinderWidthContent {
 796    #[default]
 797    Small,
 798    Medium,
 799    Large,
 800    XLarge,
 801    Full,
 802}
 803
 804#[with_fallible_options]
 805#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Debug, JsonSchema, MergeFrom)]
 806pub struct VimSettingsContent {
 807    pub default_mode: Option<ModeContent>,
 808    pub toggle_relative_line_numbers: Option<bool>,
 809    pub use_system_clipboard: Option<UseSystemClipboard>,
 810    pub use_smartcase_find: Option<bool>,
 811    /// When enabled, the `:substitute` command replaces all matches in a line
 812    /// by default. The 'g' flag then toggles this behavior.,
 813    pub gdefault: Option<bool>,
 814    pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
 815    pub highlight_on_yank_duration: Option<u64>,
 816    pub cursor_shape: Option<CursorShapeSettings>,
 817}
 818
 819#[derive(
 820    Copy,
 821    Clone,
 822    Default,
 823    Serialize,
 824    Deserialize,
 825    JsonSchema,
 826    MergeFrom,
 827    PartialEq,
 828    Debug,
 829    strum::VariantArray,
 830    strum::VariantNames,
 831)]
 832#[serde(rename_all = "snake_case")]
 833pub enum ModeContent {
 834    #[default]
 835    Normal,
 836    Insert,
 837}
 838
 839/// Controls when to use system clipboard.
 840#[derive(
 841    Copy,
 842    Clone,
 843    Debug,
 844    Serialize,
 845    Deserialize,
 846    PartialEq,
 847    Eq,
 848    JsonSchema,
 849    MergeFrom,
 850    strum::VariantArray,
 851    strum::VariantNames,
 852)]
 853#[serde(rename_all = "snake_case")]
 854pub enum UseSystemClipboard {
 855    /// Don't use system clipboard.
 856    Never,
 857    /// Use system clipboard.
 858    Always,
 859    /// Use system clipboard for yank operations.
 860    OnYank,
 861}
 862
 863/// Cursor shape configuration for insert mode in Vim.
 864#[derive(
 865    Copy,
 866    Clone,
 867    Debug,
 868    Serialize,
 869    Deserialize,
 870    PartialEq,
 871    Eq,
 872    JsonSchema,
 873    MergeFrom,
 874    strum::VariantArray,
 875    strum::VariantNames,
 876)]
 877#[serde(rename_all = "snake_case")]
 878pub enum VimInsertModeCursorShape {
 879    /// Inherit cursor shape from the editor's base cursor_shape setting.
 880    Inherit,
 881    /// Vertical bar cursor.
 882    Bar,
 883    /// Block cursor that surrounds the character.
 884    Block,
 885    /// Underline cursor.
 886    Underline,
 887    /// Hollow box cursor.
 888    Hollow,
 889}
 890
 891/// The settings for cursor shape.
 892#[with_fallible_options]
 893#[derive(
 894    Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom,
 895)]
 896pub struct CursorShapeSettings {
 897    /// Cursor shape for the normal mode.
 898    ///
 899    /// Default: block
 900    pub normal: Option<CursorShape>,
 901    /// Cursor shape for the replace mode.
 902    ///
 903    /// Default: underline
 904    pub replace: Option<CursorShape>,
 905    /// Cursor shape for the visual mode.
 906    ///
 907    /// Default: block
 908    pub visual: Option<CursorShape>,
 909    /// Cursor shape for the insert mode.
 910    ///
 911    /// The default value follows the primary cursor_shape.
 912    pub insert: Option<VimInsertModeCursorShape>,
 913}
 914
 915/// Settings specific to journaling
 916#[with_fallible_options]
 917#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
 918pub struct JournalSettingsContent {
 919    /// The path of the directory where journal entries are stored.
 920    ///
 921    /// Default: `~`
 922    pub path: Option<String>,
 923    /// What format to display the hours in.
 924    ///
 925    /// Default: hour12
 926    pub hour_format: Option<HourFormat>,
 927}
 928
 929#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
 930#[serde(rename_all = "snake_case")]
 931pub enum HourFormat {
 932    #[default]
 933    Hour12,
 934    Hour24,
 935}
 936
 937#[with_fallible_options]
 938#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug, PartialEq)]
 939pub struct OutlinePanelSettingsContent {
 940    /// Whether to show the outline panel button in the status bar.
 941    ///
 942    /// Default: true
 943    pub button: Option<bool>,
 944    /// Customize default width (in pixels) taken by outline panel
 945    ///
 946    /// Default: 240
 947    #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
 948    pub default_width: Option<f32>,
 949    /// The position of outline panel
 950    ///
 951    /// Default: left
 952    pub dock: Option<DockSide>,
 953    /// Whether to show file icons in the outline panel.
 954    ///
 955    /// Default: true
 956    pub file_icons: Option<bool>,
 957    /// Whether to show folder icons or chevrons for directories in the outline panel.
 958    ///
 959    /// Default: true
 960    pub folder_icons: Option<bool>,
 961    /// Whether to show the git status in the outline panel.
 962    ///
 963    /// Default: true
 964    pub git_status: Option<bool>,
 965    /// Amount of indentation (in pixels) for nested items.
 966    ///
 967    /// Default: 20
 968    #[serde(serialize_with = "crate::serialize_optional_f32_with_two_decimal_places")]
 969    pub indent_size: Option<f32>,
 970    /// Whether to reveal it in the outline panel automatically,
 971    /// when a corresponding project entry becomes active.
 972    /// Gitignored entries are never auto revealed.
 973    ///
 974    /// Default: true
 975    pub auto_reveal_entries: Option<bool>,
 976    /// Whether to fold directories automatically
 977    /// when directory has only one directory inside.
 978    ///
 979    /// Default: true
 980    pub auto_fold_dirs: Option<bool>,
 981    /// Settings related to indent guides in the outline panel.
 982    pub indent_guides: Option<IndentGuidesSettingsContent>,
 983    /// Scrollbar-related settings
 984    pub scrollbar: Option<ScrollbarSettingsContent>,
 985    /// Default depth to expand outline items in the current file.
 986    /// The default depth to which outline entries are expanded on reveal.
 987    /// - Set to 0 to collapse all items that have children
 988    /// - Set to 1 or higher to collapse items at that depth or deeper
 989    ///
 990    /// Default: 100
 991    pub expand_outlines_with_depth: Option<usize>,
 992}
 993
 994#[derive(
 995    Clone,
 996    Copy,
 997    Debug,
 998    PartialEq,
 999    Eq,
1000    Serialize,
1001    Deserialize,
1002    JsonSchema,
1003    MergeFrom,
1004    strum::VariantArray,
1005    strum::VariantNames,
1006)]
1007#[serde(rename_all = "snake_case")]
1008pub enum DockSide {
1009    Left,
1010    Right,
1011}
1012
1013#[derive(
1014    Copy,
1015    Clone,
1016    Debug,
1017    PartialEq,
1018    Eq,
1019    Deserialize,
1020    Serialize,
1021    JsonSchema,
1022    MergeFrom,
1023    strum::VariantArray,
1024    strum::VariantNames,
1025)]
1026#[serde(rename_all = "snake_case")]
1027pub enum ShowIndentGuides {
1028    Always,
1029    Never,
1030}
1031
1032#[with_fallible_options]
1033#[derive(
1034    Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq, Default,
1035)]
1036pub struct IndentGuidesSettingsContent {
1037    /// When to show the scrollbar in the outline panel.
1038    pub show: Option<ShowIndentGuides>,
1039}
1040
1041#[derive(Clone, Copy, Default, PartialEq, Debug, JsonSchema, MergeFrom, Deserialize, Serialize)]
1042#[serde(rename_all = "snake_case")]
1043pub enum LineIndicatorFormat {
1044    Short,
1045    #[default]
1046    Long,
1047}
1048
1049/// The settings for the image viewer.
1050#[with_fallible_options]
1051#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, Default, PartialEq)]
1052pub struct ImageViewerSettingsContent {
1053    /// The unit to use for displaying image file sizes.
1054    ///
1055    /// Default: "binary"
1056    pub unit: Option<ImageFileSizeUnit>,
1057}
1058
1059#[with_fallible_options]
1060#[derive(
1061    Clone,
1062    Copy,
1063    Debug,
1064    Serialize,
1065    Deserialize,
1066    JsonSchema,
1067    MergeFrom,
1068    Default,
1069    PartialEq,
1070    strum::VariantArray,
1071    strum::VariantNames,
1072)]
1073#[serde(rename_all = "snake_case")]
1074pub enum ImageFileSizeUnit {
1075    /// Displays file size in binary units (e.g., KiB, MiB).
1076    #[default]
1077    Binary,
1078    /// Displays file size in decimal units (e.g., KB, MB).
1079    Decimal,
1080}
1081
1082#[with_fallible_options]
1083#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq)]
1084pub struct RemoteSettingsContent {
1085    pub ssh_connections: Option<Vec<SshConnection>>,
1086    pub wsl_connections: Option<Vec<WslConnection>>,
1087    pub dev_container_connections: Option<Vec<DevContainerConnection>>,
1088    pub read_ssh_config: Option<bool>,
1089    pub use_podman: Option<bool>,
1090}
1091
1092#[with_fallible_options]
1093#[derive(
1094    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, Hash,
1095)]
1096pub struct DevContainerConnection {
1097    pub name: String,
1098    pub remote_user: String,
1099    pub container_id: String,
1100    pub use_podman: bool,
1101}
1102
1103#[with_fallible_options]
1104#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom)]
1105pub struct SshConnection {
1106    pub host: String,
1107    pub username: Option<String>,
1108    pub port: Option<u16>,
1109    #[serde(default)]
1110    pub args: Vec<String>,
1111    #[serde(default)]
1112    pub projects: collections::BTreeSet<RemoteProject>,
1113    /// Name to use for this server in UI.
1114    pub nickname: Option<String>,
1115    // By default Zed will download the binary to the host directly.
1116    // If this is set to true, Zed will download the binary to your local machine,
1117    // and then upload it over the SSH connection. Useful if your SSH server has
1118    // limited outbound internet access.
1119    pub upload_binary_over_ssh: Option<bool>,
1120
1121    pub port_forwards: Option<Vec<SshPortForwardOption>>,
1122    /// Timeout in seconds for SSH connection and downloading the remote server binary.
1123    /// Defaults to 10 seconds if not specified.
1124    pub connection_timeout: Option<u16>,
1125}
1126
1127#[derive(Clone, Default, Serialize, Deserialize, PartialEq, JsonSchema, MergeFrom, Debug)]
1128pub struct WslConnection {
1129    pub distro_name: String,
1130    pub user: Option<String>,
1131    #[serde(default)]
1132    pub projects: BTreeSet<RemoteProject>,
1133}
1134
1135#[with_fallible_options]
1136#[derive(
1137    Clone, Debug, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize, JsonSchema,
1138)]
1139pub struct RemoteProject {
1140    pub paths: Vec<String>,
1141}
1142
1143#[with_fallible_options]
1144#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, JsonSchema, MergeFrom)]
1145pub struct SshPortForwardOption {
1146    pub local_host: Option<String>,
1147    pub local_port: u16,
1148    pub remote_host: Option<String>,
1149    pub remote_port: u16,
1150}
1151
1152/// Settings for configuring REPL display and behavior.
1153#[with_fallible_options]
1154#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
1155pub struct ReplSettingsContent {
1156    /// Maximum number of lines to keep in REPL's scrollback buffer.
1157    /// Clamped with [4, 256] range.
1158    ///
1159    /// Default: 32
1160    pub max_lines: Option<usize>,
1161    /// Maximum number of columns to keep in REPL's scrollback buffer.
1162    /// Clamped with [20, 512] range.
1163    ///
1164    /// Default: 128
1165    pub max_columns: Option<usize>,
1166    /// Whether to show small single-line outputs inline instead of in a block.
1167    ///
1168    /// Default: true
1169    pub inline_output: Option<bool>,
1170    /// Maximum number of characters for an output to be shown inline.
1171    /// Only applies when `inline_output` is true.
1172    ///
1173    /// Default: 50
1174    pub inline_output_max_length: Option<usize>,
1175    /// Maximum number of lines of output to display before scrolling.
1176    /// Set to 0 to disable output height limits.
1177    ///
1178    /// Default: 0
1179    pub output_max_height_lines: Option<usize>,
1180}
1181
1182/// Settings for configuring the which-key popup behaviour.
1183#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)]
1184pub struct WhichKeySettingsContent {
1185    /// Whether to show the which-key popup when holding down key combinations
1186    ///
1187    /// Default: false
1188    pub enabled: Option<bool>,
1189    /// Delay in milliseconds before showing the which-key popup.
1190    ///
1191    /// Default: 700
1192    pub delay_ms: Option<u64>,
1193}
1194
1195#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1196/// An ExtendingVec in the settings can only accumulate new values.
1197///
1198/// This is useful for things like private files where you only want
1199/// to allow new values to be added.
1200///
1201/// Consider using a HashMap<String, bool> instead of this type
1202/// (like auto_install_extensions) so that user settings files can both add
1203/// and remove values from the set.
1204pub struct ExtendingVec<T>(pub Vec<T>);
1205
1206impl<T> Into<Vec<T>> for ExtendingVec<T> {
1207    fn into(self) -> Vec<T> {
1208        self.0
1209    }
1210}
1211impl<T> From<Vec<T>> for ExtendingVec<T> {
1212    fn from(vec: Vec<T>) -> Self {
1213        ExtendingVec(vec)
1214    }
1215}
1216
1217impl<T: Clone> merge_from::MergeFrom for ExtendingVec<T> {
1218    fn merge_from(&mut self, other: &Self) {
1219        self.0.extend_from_slice(other.0.as_slice());
1220    }
1221}
1222
1223/// A SaturatingBool in the settings can only ever be set to true,
1224/// later attempts to set it to false will be ignored.
1225///
1226/// Used by `disable_ai`.
1227#[derive(Debug, Default, Copy, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
1228pub struct SaturatingBool(pub bool);
1229
1230impl From<bool> for SaturatingBool {
1231    fn from(value: bool) -> Self {
1232        SaturatingBool(value)
1233    }
1234}
1235
1236impl From<SaturatingBool> for bool {
1237    fn from(value: SaturatingBool) -> bool {
1238        value.0
1239    }
1240}
1241
1242impl merge_from::MergeFrom for SaturatingBool {
1243    fn merge_from(&mut self, other: &Self) {
1244        self.0 |= other.0
1245    }
1246}
1247
1248#[derive(
1249    Copy,
1250    Clone,
1251    Default,
1252    Debug,
1253    PartialEq,
1254    Eq,
1255    PartialOrd,
1256    Ord,
1257    Serialize,
1258    Deserialize,
1259    MergeFrom,
1260    JsonSchema,
1261    derive_more::FromStr,
1262)]
1263#[serde(transparent)]
1264pub struct DelayMs(pub u64);
1265
1266impl From<u64> for DelayMs {
1267    fn from(n: u64) -> Self {
1268        Self(n)
1269    }
1270}
1271
1272impl std::fmt::Display for DelayMs {
1273    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1274        write!(f, "{}ms", self.0)
1275    }
1276}