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