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