page_data.rs

   1use gpui::App;
   2use settings::{LanguageSettingsContent, SettingsContent};
   3use std::sync::Arc;
   4use strum::IntoDiscriminant as _;
   5use ui::{IntoElement, SharedString};
   6
   7use crate::{
   8    DynamicItem, PROJECT, SettingField, SettingItem, SettingsFieldMetadata, SettingsPage,
   9    SettingsPageItem, SubPageLink, USER, all_language_names, sub_page_stack,
  10};
  11
  12const DEFAULT_STRING: String = String::new();
  13/// A default empty string reference. Useful in `pick` functions for cases either in dynamic item fields, or when dealing with `settings::Maybe`
  14/// to avoid the "NO DEFAULT" case.
  15const DEFAULT_EMPTY_STRING: Option<&String> = Some(&DEFAULT_STRING);
  16
  17const DEFAULT_SHARED_STRING: SharedString = SharedString::new_static("");
  18/// A default empty string reference. Useful in `pick` functions for cases either in dynamic item fields, or when dealing with `settings::Maybe`
  19/// to avoid the "NO DEFAULT" case.
  20const DEFAULT_EMPTY_SHARED_STRING: Option<&SharedString> = Some(&DEFAULT_SHARED_STRING);
  21
  22pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
  23    vec![
  24        SettingsPage {
  25            title: "General",
  26            items: vec![
  27                SettingsPageItem::SectionHeader("General Settings"),
  28                SettingsPageItem::SettingItem(SettingItem {
  29                    files: PROJECT,
  30                    title: "Project Name",
  31                    description: "The displayed name of this project. If left empty, the root directory name will be displayed.",
  32                    field: Box::new(
  33                        SettingField {
  34                            json_path: Some("project_name"),
  35                            pick: |settings_content| {
  36                                settings_content.project.worktree.project_name.as_ref().or(DEFAULT_EMPTY_STRING)
  37                            },
  38                            write: |settings_content, value| {
  39                                settings_content.project.worktree.project_name = value.filter(|name| !name.is_empty());
  40                            },
  41                        }
  42                    ),
  43                    metadata: Some(Box::new(SettingsFieldMetadata { placeholder: Some("Project Name"), ..Default::default() })),
  44                }),
  45                SettingsPageItem::SettingItem(SettingItem {
  46                    title: "When Closing With No Tabs",
  47                    description: "What to do when using the 'close active item' action with no tabs.",
  48                    field: Box::new(SettingField {
  49                        json_path: Some("when_closing_with_no_tabs"),
  50                        pick: |settings_content| {
  51                            settings_content
  52                                .workspace
  53                                .when_closing_with_no_tabs
  54                                .as_ref()
  55                        },
  56                        write: |settings_content, value| {
  57                            settings_content.workspace.when_closing_with_no_tabs = value;
  58                        },
  59                    }),
  60                    metadata: None,
  61                    files: USER,
  62                }),
  63                SettingsPageItem::SettingItem(SettingItem {
  64                    title: "On Last Window Closed",
  65                    description: "What to do when the last window is closed.",
  66                    field: Box::new(SettingField {
  67                        json_path: Some("on_last_window_closed"),
  68                        pick: |settings_content| {
  69                            settings_content.workspace.on_last_window_closed.as_ref()
  70                        },
  71                        write: |settings_content, value| {
  72                            settings_content.workspace.on_last_window_closed = value;
  73                        },
  74                    }),
  75                    metadata: None,
  76                    files: USER,
  77                }),
  78                SettingsPageItem::SettingItem(SettingItem {
  79                    title: "Use System Path Prompts",
  80                    description: "Use native OS dialogs for 'Open' and 'Save As'.",
  81                    field: Box::new(SettingField {
  82                        json_path: Some("use_system_path_prompts"),
  83                        pick: |settings_content| {
  84                            settings_content.workspace.use_system_path_prompts.as_ref()
  85                        },
  86                        write: |settings_content, value| {
  87                            settings_content.workspace.use_system_path_prompts = value;
  88                        },
  89                    }),
  90                    metadata: None,
  91                    files: USER,
  92                }),
  93                SettingsPageItem::SettingItem(SettingItem {
  94                    title: "Use System Prompts",
  95                    description: "Use native OS dialogs for confirmations.",
  96                    field: Box::new(SettingField {
  97                        json_path: Some("use_system_prompts"),
  98                        pick: |settings_content| {
  99                            settings_content.workspace.use_system_prompts.as_ref()
 100                        },
 101                        write: |settings_content, value| {
 102                            settings_content.workspace.use_system_prompts = value;
 103                        },
 104                    }),
 105                    metadata: None,
 106                    files: USER,
 107                }),
 108                SettingsPageItem::SettingItem(SettingItem {
 109                    title: "Redact Private Values",
 110                    description: "Hide the values of variables in private files.",
 111                    field: Box::new(SettingField {
 112                        json_path: Some("redact_private_values"),
 113                        pick: |settings_content| {
 114                            settings_content.editor.redact_private_values.as_ref()
 115                        },
 116                        write: |settings_content, value| {
 117                            settings_content.editor.redact_private_values = value;
 118                        },
 119                    }),
 120                    metadata: None,
 121                    files: USER,
 122                }),
 123                SettingsPageItem::SettingItem(SettingItem {
 124                    title: "Private Files",
 125                    description: "Globs to match against file paths to determine if a file is private.",
 126                    field: Box::new(
 127                        SettingField {
 128                            json_path: Some("worktree.private_files"),
 129                            pick: |settings_content| {
 130                                settings_content.project.worktree.private_files.as_ref()
 131                            },
 132                            write: |settings_content, value| {
 133                                settings_content.project.worktree.private_files = value;
 134                            },
 135                        }
 136                        .unimplemented(),
 137                    ),
 138                    metadata: None,
 139                    files: USER,
 140                }),
 141                SettingsPageItem::SectionHeader("Workspace Restoration"),
 142                SettingsPageItem::SettingItem(SettingItem {
 143                    title: "Restore Unsaved Buffers",
 144                    description: "Whether or not to restore unsaved buffers on restart.",
 145                    field: Box::new(SettingField {
 146                        json_path: Some("session.restore_unsaved_buffers"),
 147                        pick: |settings_content| {
 148                            settings_content
 149                                .session
 150                                .as_ref()
 151                                .and_then(|session| session.restore_unsaved_buffers.as_ref())
 152                        },
 153                        write: |settings_content, value| {
 154                            settings_content
 155                                .session
 156                                .get_or_insert_default()
 157                                .restore_unsaved_buffers = value;
 158                        },
 159                    }),
 160                    metadata: None,
 161                    files: USER,
 162                }),
 163                SettingsPageItem::SettingItem(SettingItem {
 164                    title: "Restore On Startup",
 165                    description: "What to restore from the previous session when opening Zed.",
 166                    field: Box::new(SettingField {
 167                        json_path: Some("restore_on_startup"),
 168                        pick: |settings_content| {
 169                            settings_content.workspace.restore_on_startup.as_ref()
 170                        },
 171                        write: |settings_content, value| {
 172                            settings_content.workspace.restore_on_startup = value;
 173                        },
 174                    }),
 175                    metadata: None,
 176                    files: USER,
 177                }),
 178                SettingsPageItem::SectionHeader("Scoped Settings"),
 179                SettingsPageItem::SettingItem(SettingItem {
 180                    files: USER,
 181                    title: "Preview Channel",
 182                    description: "Which settings should be activated only in Preview build of Zed.",
 183                    field: Box::new(
 184                        SettingField {
 185                            json_path: Some("preview_channel_settings"),
 186                            pick: |settings_content| {
 187                                Some(settings_content)
 188                            },
 189                            write: |_settings_content, _value| {
 190
 191                            },
 192                        }
 193                        .unimplemented(),
 194                    ),
 195                    metadata: None,
 196                }),
 197                SettingsPageItem::SettingItem(SettingItem {
 198                    files: USER,
 199                    title: "Settings Profiles",
 200                    description: "Any number of settings profiles that are temporarily applied on top of your existing user settings.",
 201                    field: Box::new(
 202                        SettingField {
 203                            json_path: Some("settings_profiles"),
 204                            pick: |settings_content| {
 205                                Some(settings_content)
 206                            },
 207                            write: |_settings_content, _value| {
 208                            },
 209                        }
 210                        .unimplemented(),
 211                    ),
 212                    metadata: None,
 213                }),
 214                SettingsPageItem::SectionHeader("Privacy"),
 215                SettingsPageItem::SettingItem(SettingItem {
 216                    title: "Telemetry Diagnostics",
 217                    description: "Send debug information like crash reports.",
 218                    field: Box::new(SettingField {
 219                        json_path: Some("telemetry.diagnostics"),
 220                        pick: |settings_content| {
 221                            settings_content
 222                                .telemetry
 223                                .as_ref()
 224                                .and_then(|telemetry| telemetry.diagnostics.as_ref())
 225                        },
 226                        write: |settings_content, value| {
 227                            settings_content
 228                                .telemetry
 229                                .get_or_insert_default()
 230                                .diagnostics = value;
 231                        },
 232                    }),
 233                    metadata: None,
 234                    files: USER,
 235                }),
 236                SettingsPageItem::SettingItem(SettingItem {
 237                    title: "Telemetry Metrics",
 238                    description: "Send anonymized usage data like what languages you're using Zed with.",
 239                    field: Box::new(SettingField {
 240                        json_path: Some("telemetry.metrics"),
 241                        pick: |settings_content| {
 242                            settings_content
 243                                .telemetry
 244                                .as_ref()
 245                                .and_then(|telemetry| telemetry.metrics.as_ref())
 246                        },
 247                        write: |settings_content, value| {
 248                            settings_content.telemetry.get_or_insert_default().metrics = value;
 249                        },
 250                    }),
 251                    metadata: None,
 252                    files: USER,
 253                }),
 254                SettingsPageItem::SectionHeader("Auto Update"),
 255                SettingsPageItem::SettingItem(SettingItem {
 256                    title: "Auto Update",
 257                    description: "Whether or not to automatically check for updates.",
 258                    field: Box::new(SettingField {
 259                        json_path: Some("auto_update"),
 260                        pick: |settings_content| settings_content.auto_update.as_ref(),
 261                        write: |settings_content, value| {
 262                            settings_content.auto_update = value;
 263                        },
 264                    }),
 265                    metadata: None,
 266                    files: USER,
 267                }),
 268            ],
 269        },
 270        SettingsPage {
 271            title: "Appearance",
 272            items: vec![
 273                SettingsPageItem::SectionHeader("Theme"),
 274                SettingsPageItem::DynamicItem(DynamicItem {
 275                    discriminant: SettingItem {
 276                        files: USER,
 277                        title: "Theme Mode",
 278                        description: "Choose a static, fixed theme or dynamically select themes based on appearance and light/dark modes.",
 279                        field: Box::new(SettingField {
 280                            json_path: Some("theme$"),
 281                            pick: |settings_content| {
 282                                Some(&dynamic_variants::<settings::ThemeSelection>()[
 283                                    settings_content
 284                                        .theme
 285                                        .theme
 286                                        .as_ref()?
 287                                        .discriminant() as usize])
 288                            },
 289                            write: |settings_content, value| {
 290                                let Some(value) = value else {
 291                                    settings_content.theme.theme = None;
 292                                    return;
 293                                };
 294                                let settings_value = settings_content.theme.theme.get_or_insert_with(|| {
 295                                    settings::ThemeSelection::Static(theme::ThemeName(theme::default_theme(theme::SystemAppearance::default().0).into()))
 296                                });
 297                                *settings_value = match value {
 298                                    settings::ThemeSelectionDiscriminants::Static => {
 299                                        let name = match settings_value {
 300                                            settings::ThemeSelection::Static(_) => return,
 301                                            settings::ThemeSelection::Dynamic { mode, light, dark } => {
 302                                                match mode {
 303                                                    theme::ThemeAppearanceMode::Light => light.clone(),
 304                                                    theme::ThemeAppearanceMode::Dark => dark.clone(),
 305                                                    theme::ThemeAppearanceMode::System => dark.clone(), // no cx, can't determine correct choice
 306                                                }
 307                                            },
 308                                        };
 309                                        settings::ThemeSelection::Static(name)
 310                                    },
 311                                    settings::ThemeSelectionDiscriminants::Dynamic => {
 312                                        let static_name = match settings_value {
 313                                            settings::ThemeSelection::Static(theme_name) => theme_name.clone(),
 314                                            settings::ThemeSelection::Dynamic {..} => return,
 315                                        };
 316
 317                                        settings::ThemeSelection::Dynamic {
 318                                            mode: settings::ThemeAppearanceMode::System,
 319                                            light: static_name.clone(),
 320                                            dark: static_name,
 321                                        }
 322                                    },
 323                                };
 324                            },
 325                        }),
 326                        metadata: None,
 327                    },
 328                    pick_discriminant: |settings_content| {
 329                        Some(settings_content.theme.theme.as_ref()?.discriminant() as usize)
 330                    },
 331                    fields: dynamic_variants::<settings::ThemeSelection>().into_iter().map(|variant| {
 332                        match variant {
 333                            settings::ThemeSelectionDiscriminants::Static => vec![
 334                                SettingItem {
 335                                    files: USER,
 336                                    title: "Theme Name",
 337                                    description: "The name of your selected theme.",
 338                                    field: Box::new(SettingField {
 339                                        json_path: Some("theme"),
 340                                        pick: |settings_content| {
 341                                            match settings_content.theme.theme.as_ref() {
 342                                                Some(settings::ThemeSelection::Static(name)) => Some(name),
 343                                                _ => None
 344                                            }
 345                                        },
 346                                        write: |settings_content, value| {
 347                                            let Some(value) = value else {
 348                                                return;
 349                                            };
 350                                            match settings_content
 351                                                .theme
 352                                                .theme.as_mut() {
 353                                                    Some(settings::ThemeSelection::Static(theme_name)) => *theme_name = value,
 354                                                    _ => return
 355                                                }
 356                                        },
 357                                    }),
 358                                    metadata: None,
 359                                }
 360                            ],
 361                            settings::ThemeSelectionDiscriminants::Dynamic => vec![
 362                                SettingItem {
 363                                    files: USER,
 364                                    title: "Mode",
 365                                    description: "Choose whether to use the selected light or dark theme or to follow your OS appearance configuration.",
 366                                    field: Box::new(SettingField {
 367                                        json_path: Some("theme.mode"),
 368                                        pick: |settings_content| {
 369                                            match settings_content.theme.theme.as_ref() {
 370                                                Some(settings::ThemeSelection::Dynamic { mode, ..}) => Some(mode),
 371                                                _ => None
 372                                            }
 373                                        },
 374                                        write: |settings_content, value| {
 375                                            let Some(value) = value else {
 376                                                return;
 377                                            };
 378                                            match settings_content
 379                                                .theme
 380                                                .theme.as_mut() {
 381                                                    Some(settings::ThemeSelection::Dynamic{ mode, ..}) => *mode = value,
 382                                                    _ => return
 383                                                }
 384                                        },
 385                                    }),
 386                                    metadata: None,
 387                                },
 388                                SettingItem {
 389                                    files: USER,
 390                                    title: "Light Theme",
 391                                    description: "The theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
 392                                    field: Box::new(SettingField {
 393                                        json_path: Some("theme.light"),
 394                                        pick: |settings_content| {
 395                                            match settings_content.theme.theme.as_ref() {
 396                                                Some(settings::ThemeSelection::Dynamic { light, ..}) => Some(light),
 397                                                _ => None
 398                                            }
 399                                        },
 400                                        write: |settings_content, value| {
 401                                            let Some(value) = value else {
 402                                                return;
 403                                            };
 404                                            match settings_content
 405                                                .theme
 406                                                .theme.as_mut() {
 407                                                    Some(settings::ThemeSelection::Dynamic{ light, ..}) => *light = value,
 408                                                    _ => return
 409                                                }
 410                                        },
 411                                    }),
 412                                    metadata: None,
 413                                },
 414                                SettingItem {
 415                                    files: USER,
 416                                    title: "Dark Theme",
 417                                    description: "The theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
 418                                    field: Box::new(SettingField {
 419                                        json_path: Some("theme.dark"),
 420                                        pick: |settings_content| {
 421                                            match settings_content.theme.theme.as_ref() {
 422                                                Some(settings::ThemeSelection::Dynamic { dark, ..}) => Some(dark),
 423                                                _ => None
 424                                            }
 425                                        },
 426                                        write: |settings_content, value| {
 427                                            let Some(value) = value else {
 428                                                return;
 429                                            };
 430                                            match settings_content
 431                                                .theme
 432                                                .theme.as_mut() {
 433                                                    Some(settings::ThemeSelection::Dynamic{ dark, ..}) => *dark = value,
 434                                                    _ => return
 435                                                }
 436                                        },
 437                                    }),
 438                                    metadata: None,
 439                                }
 440                            ],
 441                        }
 442                    }).collect(),
 443                }),
 444                SettingsPageItem::DynamicItem(DynamicItem {
 445                    discriminant: SettingItem {
 446                        files: USER,
 447                        title: "Icon Theme",
 448                        description: "The custom set of icons Zed will associate with files and directories.",
 449                        field: Box::new(SettingField {
 450                            json_path: Some("icon_theme$"),
 451                            pick: |settings_content| {
 452                                Some(&dynamic_variants::<settings::IconThemeSelection>()[
 453                                    settings_content
 454                                        .theme
 455                                        .icon_theme
 456                                        .as_ref()?
 457                                        .discriminant() as usize])
 458                            },
 459                            write: |settings_content, value| {
 460                                let Some(value) = value else {
 461                                    settings_content.theme.icon_theme = None;
 462                                    return;
 463                                };
 464                                let settings_value = settings_content.theme.icon_theme.get_or_insert_with(|| {
 465                                    settings::IconThemeSelection::Static(settings::IconThemeName(theme::default_icon_theme().name.clone().into()))
 466                                });
 467                                *settings_value = match value {
 468                                    settings::IconThemeSelectionDiscriminants::Static => {
 469                                        let name = match settings_value {
 470                                            settings::IconThemeSelection::Static(_) => return,
 471                                            settings::IconThemeSelection::Dynamic { mode, light, dark } => {
 472                                                match mode {
 473                                                    theme::ThemeAppearanceMode::Light => light.clone(),
 474                                                    theme::ThemeAppearanceMode::Dark => dark.clone(),
 475                                                    theme::ThemeAppearanceMode::System => dark.clone(), // no cx, can't determine correct choice
 476                                                }
 477                                            },
 478                                        };
 479                                        settings::IconThemeSelection::Static(name)
 480                                    },
 481                                    settings::IconThemeSelectionDiscriminants::Dynamic => {
 482                                        let static_name = match settings_value {
 483                                            settings::IconThemeSelection::Static(theme_name) => theme_name.clone(),
 484                                            settings::IconThemeSelection::Dynamic {..} => return,
 485                                        };
 486
 487                                        settings::IconThemeSelection::Dynamic {
 488                                            mode: settings::ThemeAppearanceMode::System,
 489                                            light: static_name.clone(),
 490                                            dark: static_name,
 491                                        }
 492                                    },
 493                                };
 494                            },
 495                        }),
 496                        metadata: None,
 497                    },
 498                    pick_discriminant: |settings_content| {
 499                        Some(settings_content.theme.icon_theme.as_ref()?.discriminant() as usize)
 500                    },
 501                    fields: dynamic_variants::<settings::IconThemeSelection>().into_iter().map(|variant| {
 502                        match variant {
 503                            settings::IconThemeSelectionDiscriminants::Static => vec![
 504                                SettingItem {
 505                                    files: USER,
 506                                    title: "Icon Theme Name",
 507                                    description: "The name of your selected icon theme.",
 508                                    field: Box::new(SettingField {
 509                                        json_path: Some("icon_theme$string"),
 510                                        pick: |settings_content| {
 511                                            match settings_content.theme.icon_theme.as_ref() {
 512                                                Some(settings::IconThemeSelection::Static(name)) => Some(name),
 513                                                _ => None
 514                                            }
 515                                        },
 516                                        write: |settings_content, value| {
 517                                            let Some(value) = value else {
 518                                                return;
 519                                            };
 520                                            match settings_content
 521                                                .theme
 522                                                .icon_theme.as_mut() {
 523                                                    Some(settings::IconThemeSelection::Static(theme_name)) => *theme_name = value,
 524                                                    _ => return
 525                                                }
 526                                        },
 527                                    }),
 528                                    metadata: None,
 529                                }
 530                            ],
 531                            settings::IconThemeSelectionDiscriminants::Dynamic => vec![
 532                                SettingItem {
 533                                    files: USER,
 534                                    title: "Mode",
 535                                    description: "Choose whether to use the selected light or dark icon theme or to follow your OS appearance configuration.",
 536                                    field: Box::new(SettingField {
 537                                        json_path: Some("icon_theme"),
 538                                        pick: |settings_content| {
 539                                            match settings_content.theme.icon_theme.as_ref() {
 540                                                Some(settings::IconThemeSelection::Dynamic { mode, ..}) => Some(mode),
 541                                                _ => None
 542                                            }
 543                                        },
 544                                        write: |settings_content, value| {
 545                                            let Some(value) = value else {
 546                                                return;
 547                                            };
 548                                            match settings_content
 549                                                .theme
 550                                                .icon_theme.as_mut() {
 551                                                    Some(settings::IconThemeSelection::Dynamic{ mode, ..}) => *mode = value,
 552                                                    _ => return
 553                                                }
 554                                        },
 555                                    }),
 556                                    metadata: None,
 557                                },
 558                                SettingItem {
 559                                    files: USER,
 560                                    title: "Light Icon Theme",
 561                                    description: "The icon theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
 562                                    field: Box::new(SettingField {
 563                                        json_path: Some("icon_theme.light"),
 564                                        pick: |settings_content| {
 565                                            match settings_content.theme.icon_theme.as_ref() {
 566                                                Some(settings::IconThemeSelection::Dynamic { light, ..}) => Some(light),
 567                                                _ => None
 568                                            }
 569                                        },
 570                                        write: |settings_content, value| {
 571                                            let Some(value) = value else {
 572                                                return;
 573                                            };
 574                                            match settings_content
 575                                                .theme
 576                                                .icon_theme.as_mut() {
 577                                                    Some(settings::IconThemeSelection::Dynamic{ light, ..}) => *light = value,
 578                                                    _ => return
 579                                                }
 580                                        },
 581                                    }),
 582                                    metadata: None,
 583                                },
 584                                SettingItem {
 585                                    files: USER,
 586                                    title: "Dark Icon Theme",
 587                                    description: "The icon theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
 588                                    field: Box::new(SettingField {
 589                                        json_path: Some("icon_theme.dark"),
 590                                        pick: |settings_content| {
 591                                            match settings_content.theme.icon_theme.as_ref() {
 592                                                Some(settings::IconThemeSelection::Dynamic { dark, ..}) => Some(dark),
 593                                                _ => None
 594                                            }
 595                                        },
 596                                        write: |settings_content, value| {
 597                                            let Some(value) = value else {
 598                                                return;
 599                                            };
 600                                            match settings_content
 601                                                .theme
 602                                                .icon_theme.as_mut() {
 603                                                    Some(settings::IconThemeSelection::Dynamic{ dark, ..}) => *dark = value,
 604                                                    _ => return
 605                                                }
 606                                        },
 607                                    }),
 608                                    metadata: None,
 609                                }
 610                            ],
 611                        }
 612                    }).collect(),
 613                }),
 614                SettingsPageItem::SectionHeader("Buffer Font"),
 615                SettingsPageItem::SettingItem(SettingItem {
 616                    title: "Font Family",
 617                    description: "Font family for editor text.",
 618                    field: Box::new(SettingField {
 619                        json_path: Some("buffer_font_family"),
 620                        pick: |settings_content| settings_content.theme.buffer_font_family.as_ref(),
 621                        write: |settings_content, value|{  settings_content.theme.buffer_font_family = value;},
 622                    }),
 623                    metadata: None,
 624                    files: USER,
 625                }),
 626                SettingsPageItem::SettingItem(SettingItem {
 627                    title: "Font Size",
 628                    description: "Font size for editor text.",
 629                    field: Box::new(SettingField {
 630                        json_path: Some("buffer_font_size"),
 631                        pick: |settings_content| settings_content.theme.buffer_font_size.as_ref(),
 632                        write: |settings_content, value|{  settings_content.theme.buffer_font_size = value;},
 633                    }),
 634                    metadata: None,
 635                    files: USER,
 636                }),
 637                SettingsPageItem::SettingItem(SettingItem {
 638                    title: "Font Weight",
 639                    description: "Font weight for editor text (100-900).",
 640                    field: Box::new(SettingField {
 641                        json_path: Some("buffer_font_weight"),
 642                        pick: |settings_content| settings_content.theme.buffer_font_weight.as_ref(),
 643                        write: |settings_content, value|{  settings_content.theme.buffer_font_weight = value;},
 644                    }),
 645                    metadata: None,
 646                    files: USER,
 647                }),
 648                SettingsPageItem::DynamicItem(DynamicItem {
 649                    discriminant: SettingItem {
 650                        files: USER,
 651                        title: "Line Height",
 652                        description: "Line height for editor text.",
 653                        field: Box::new(SettingField {
 654                            json_path: Some("buffer_line_height$"),
 655                            pick: |settings_content| {
 656                                Some(&dynamic_variants::<settings::BufferLineHeight>()[
 657                                    settings_content
 658                                        .theme
 659                                        .buffer_line_height
 660                                        .as_ref()?
 661                                        .discriminant() as usize])
 662                            },
 663                            write: |settings_content, value| {
 664                                let Some(value) = value else {
 665                                    settings_content.theme.buffer_line_height = None;
 666                                    return;
 667                                };
 668                                let settings_value = settings_content.theme.buffer_line_height.get_or_insert_with(|| {
 669                                    settings::BufferLineHeight::default()
 670                                });
 671                                *settings_value = match value {
 672                                    settings::BufferLineHeightDiscriminants::Comfortable => {
 673                                        settings::BufferLineHeight::Comfortable
 674                                    },
 675                                    settings::BufferLineHeightDiscriminants::Standard => {
 676                                        settings::BufferLineHeight::Standard
 677                                    },
 678                                    settings::BufferLineHeightDiscriminants::Custom => {
 679                                        let custom_value = theme::BufferLineHeight::from(*settings_value).value();
 680                                        settings::BufferLineHeight::Custom(custom_value)
 681                                    },
 682                                };
 683                            },
 684                        }),
 685                        metadata: None,
 686                    },
 687                    pick_discriminant: |settings_content| {
 688                        Some(settings_content.theme.buffer_line_height.as_ref()?.discriminant() as usize)
 689                    },
 690                    fields: dynamic_variants::<settings::BufferLineHeight>().into_iter().map(|variant| {
 691                        match variant {
 692                            settings::BufferLineHeightDiscriminants::Comfortable => vec![],
 693                            settings::BufferLineHeightDiscriminants::Standard => vec![],
 694                            settings::BufferLineHeightDiscriminants::Custom => vec![
 695                                SettingItem {
 696                                    files: USER,
 697                                    title: "Custom Line Height",
 698                                    description: "Custom line height value (must be at least 1.0).",
 699                                    field: Box::new(SettingField {
 700                                        json_path: Some("buffer_line_height"),
 701                                        pick: |settings_content| {
 702                                            match settings_content.theme.buffer_line_height.as_ref() {
 703                                                Some(settings::BufferLineHeight::Custom(value)) => Some(value),
 704                                                _ => None
 705                                            }
 706                                        },
 707                                        write: |settings_content, value| {
 708                                            let Some(value) = value else {
 709                                                return;
 710                                            };
 711                                            match settings_content
 712                                                .theme
 713                                                .buffer_line_height.as_mut() {
 714                                                    Some(settings::BufferLineHeight::Custom(line_height)) => *line_height = f32::max(value, 1.0),
 715                                                    _ => return
 716                                                }
 717                                        },
 718                                    }),
 719                                    metadata: None,
 720                                }
 721                            ],
 722                        }
 723                    }).collect(),
 724                }),
 725                SettingsPageItem::SettingItem(SettingItem {
 726                    files: USER,
 727                    title: "Font Features",
 728                    description: "The OpenType features to enable for rendering in text buffers.",
 729                    field: Box::new(
 730                        SettingField {
 731                            json_path: Some("buffer_font_features"),
 732                            pick: |settings_content| {
 733                                settings_content.theme.buffer_font_features.as_ref()
 734                            },
 735                            write: |settings_content, value| {
 736                                settings_content.theme.buffer_font_features = value;
 737
 738                            },
 739                        }
 740                        .unimplemented(),
 741                    ),
 742                    metadata: None,
 743                }),
 744                SettingsPageItem::SettingItem(SettingItem {
 745                    files: USER,
 746                    title: "Font Fallbacks",
 747                    description: "The font fallbacks to use for rendering in text buffers.",
 748                    field: Box::new(
 749                        SettingField {
 750                            json_path: Some("buffer_font_fallbacks"),
 751                            pick: |settings_content| {
 752                                settings_content.theme.buffer_font_fallbacks.as_ref()
 753                            },
 754                            write: |settings_content, value| {
 755                                settings_content.theme.buffer_font_fallbacks = value;
 756
 757                            },
 758                        }
 759                        .unimplemented(),
 760                    ),
 761                    metadata: None,
 762                }),
 763                SettingsPageItem::SectionHeader("UI Font"),
 764                SettingsPageItem::SettingItem(SettingItem {
 765                    title: "Font Family",
 766                    description: "Font family for UI elements.",
 767                    field: Box::new(SettingField {
 768                        json_path: Some("ui_font_family"),
 769                        pick: |settings_content| settings_content.theme.ui_font_family.as_ref(),
 770                        write: |settings_content, value|{  settings_content.theme.ui_font_family = value;},
 771                    }),
 772                    metadata: None,
 773                    files: USER,
 774                }),
 775                SettingsPageItem::SettingItem(SettingItem {
 776                    title: "Font Size",
 777                    description: "Font size for UI elements.",
 778                    field: Box::new(SettingField {
 779                        json_path: Some("ui_font_size"),
 780                        pick: |settings_content| settings_content.theme.ui_font_size.as_ref(),
 781                        write: |settings_content, value|{  settings_content.theme.ui_font_size = value;},
 782                    }),
 783                    metadata: None,
 784                    files: USER,
 785                }),
 786                SettingsPageItem::SettingItem(SettingItem {
 787                    title: "Font Weight",
 788                    description: "Font weight for UI elements (100-900).",
 789                    field: Box::new(SettingField {
 790                        json_path: Some("ui_font_weight"),
 791                        pick: |settings_content| settings_content.theme.ui_font_weight.as_ref(),
 792                        write: |settings_content, value|{  settings_content.theme.ui_font_weight = value;},
 793                    }),
 794                    metadata: None,
 795                    files: USER,
 796                }),
 797                SettingsPageItem::SettingItem(SettingItem {
 798                    files: USER,
 799                    title: "Font Features",
 800                    description: "The OpenType features to enable for rendering in UI elements.",
 801                    field: Box::new(
 802                        SettingField {
 803                            json_path: Some("ui_font_features"),
 804                            pick: |settings_content| {
 805                                settings_content.theme.ui_font_features.as_ref()
 806                            },
 807                            write: |settings_content, value| {
 808                                settings_content.theme.ui_font_features = value;
 809
 810                            },
 811                        }
 812                        .unimplemented(),
 813                    ),
 814                    metadata: None,
 815                }),
 816                SettingsPageItem::SettingItem(SettingItem {
 817                    files: USER,
 818                    title: "Font Fallbacks",
 819                    description: "The font fallbacks to use for rendering in the UI.",
 820                    field: Box::new(
 821                        SettingField {
 822                            json_path: Some("ui_font_fallbacks"),
 823                            pick: |settings_content| {
 824                                settings_content.theme.ui_font_fallbacks.as_ref()
 825                            },
 826                            write: |settings_content, value| {
 827                                settings_content.theme.ui_font_fallbacks = value;
 828
 829                            },
 830                        }
 831                        .unimplemented(),
 832                    ),
 833                    metadata: None,
 834                }),
 835                SettingsPageItem::SectionHeader("Agent Panel Font"),
 836                SettingsPageItem::SettingItem(SettingItem {
 837                    title: "UI Font Size",
 838                    description: "Font size for agent response text in the agent panel. Falls back to the regular UI font size.",
 839                    field: Box::new(SettingField {
 840                        json_path: Some("agent_ui_font_size"),
 841                        pick: |settings_content| {
 842                            settings_content
 843                                .theme
 844                                .agent_ui_font_size
 845                                .as_ref()
 846                                .or(settings_content.theme.ui_font_size.as_ref())
 847                        },
 848                        write: |settings_content, value|{  settings_content.theme.agent_ui_font_size = value;},
 849                    }),
 850                    metadata: None,
 851                    files: USER,
 852                }),
 853                SettingsPageItem::SettingItem(SettingItem {
 854                    title: "Buffer Font Size",
 855                    description: "Font size for user messages text in the agent panel.",
 856                    field: Box::new(SettingField {
 857                        json_path: Some("agent_buffer_font_size"),
 858                        pick: |settings_content| {
 859                            settings_content
 860                                .theme
 861                                .agent_buffer_font_size
 862                                .as_ref()
 863                                .or(settings_content.theme.buffer_font_size.as_ref())
 864                        },
 865                        write: |settings_content, value| {
 866                            settings_content.theme.agent_buffer_font_size = value;
 867
 868                        },
 869                    }),
 870                    metadata: None,
 871                    files: USER,
 872                }),
 873                SettingsPageItem::SectionHeader("Cursor"),
 874                SettingsPageItem::SettingItem(SettingItem {
 875                    title: "Multi Cursor Modifier",
 876                    description: "Modifier key for adding multiple cursors.",
 877                    field: Box::new(SettingField {
 878                        json_path: Some("multi_cursor_modifier"),
 879                        pick: |settings_content| {
 880                            settings_content.editor.multi_cursor_modifier.as_ref()
 881                        },
 882                        write: |settings_content, value| {
 883                            settings_content.editor.multi_cursor_modifier = value;
 884
 885                        },
 886                    }),
 887                    metadata: None,
 888                    files: USER,
 889                }),
 890                SettingsPageItem::SettingItem(SettingItem {
 891                    title: "Cursor Blink",
 892                    description: "Whether the cursor blinks in the editor.",
 893                    field: Box::new(SettingField {
 894                        json_path: Some("cursor_blink"),
 895                        pick: |settings_content| settings_content.editor.cursor_blink.as_ref(),
 896                        write: |settings_content, value|{  settings_content.editor.cursor_blink = value;},
 897                    }),
 898                    metadata: None,
 899                    files: USER,
 900                }),
 901                SettingsPageItem::SettingItem(SettingItem {
 902                    title: "Cursor Shape",
 903                    description: "Cursor shape for the editor.",
 904                    field: Box::new(SettingField {
 905                        json_path: Some("cursor_shape"),
 906                        pick: |settings_content| settings_content.editor.cursor_shape.as_ref(),
 907                        write: |settings_content, value|{  settings_content.editor.cursor_shape = value;},
 908                    }),
 909                    metadata: None,
 910                    files: USER,
 911                }),
 912                SettingsPageItem::SettingItem(SettingItem {
 913                    title: "Hide Mouse",
 914                    description: "When to hide the mouse cursor.",
 915                    field: Box::new(SettingField {
 916                        json_path: Some("hide_mouse"),
 917                        pick: |settings_content| settings_content.editor.hide_mouse.as_ref(),
 918                        write: |settings_content, value|{  settings_content.editor.hide_mouse = value;},
 919                    }),
 920                    metadata: None,
 921                    files: USER,
 922                }),
 923                SettingsPageItem::SectionHeader("Highlighting"),
 924                SettingsPageItem::SettingItem(SettingItem {
 925                    title: "Unnecessary Code Fade",
 926                    description: "How much to fade out unused code (0.0 - 0.9).",
 927                    field: Box::new(SettingField {
 928                        json_path: Some("unnecessary_code_fade"),
 929                        pick: |settings_content| {
 930                            settings_content.theme.unnecessary_code_fade.as_ref()
 931                        },
 932                        write: |settings_content, value| {
 933                            settings_content.theme.unnecessary_code_fade = value;
 934
 935                        },
 936                    }),
 937                    metadata: None,
 938                    files: USER,
 939                }),
 940                SettingsPageItem::SettingItem(SettingItem {
 941                    title: "Current Line Highlight",
 942                    description: "How to highlight the current line.",
 943                    field: Box::new(SettingField {
 944                        json_path: Some("current_line_highlight"),
 945                        pick: |settings_content| {
 946                            settings_content.editor.current_line_highlight.as_ref()
 947                        },
 948                        write: |settings_content, value| {
 949                            settings_content.editor.current_line_highlight = value;
 950
 951                        },
 952                    }),
 953                    metadata: None,
 954                    files: USER,
 955                }),
 956                SettingsPageItem::SettingItem(SettingItem {
 957                    title: "Selection Highlight",
 958                    description: "Highlight all occurrences of selected text.",
 959                    field: Box::new(SettingField {
 960                        json_path: Some("selection_highlight"),
 961                        pick: |settings_content| {
 962                            settings_content.editor.selection_highlight.as_ref()
 963                        },
 964                        write: |settings_content, value| {
 965                            settings_content.editor.selection_highlight = value;
 966
 967                        },
 968                    }),
 969                    metadata: None,
 970                    files: USER,
 971                }),
 972                SettingsPageItem::SettingItem(SettingItem {
 973                    title: "Rounded Selection",
 974                    description: "Whether the text selection should have rounded corners.",
 975                    field: Box::new(SettingField {
 976                        json_path: Some("rounded_selection"),
 977                        pick: |settings_content| settings_content.editor.rounded_selection.as_ref(),
 978                        write: |settings_content, value|{  settings_content.editor.rounded_selection = value;},
 979                    }),
 980                    metadata: None,
 981                    files: USER,
 982                }),
 983                SettingsPageItem::SettingItem(SettingItem {
 984                    title: "Minimum Contrast For Highlights",
 985                    description: "The minimum APCA perceptual contrast to maintain when rendering text over highlight backgrounds.",
 986                    field: Box::new(SettingField {
 987                        json_path: Some("minimum_contrast_for_highlights"),
 988                        pick: |settings_content| {
 989                            settings_content
 990                                .editor
 991                                .minimum_contrast_for_highlights
 992                                .as_ref()
 993                        },
 994                        write: |settings_content, value| {
 995                            settings_content.editor.minimum_contrast_for_highlights = value;
 996
 997                        },
 998                    }),
 999                    metadata: None,
1000                    files: USER,
1001                }),
1002                SettingsPageItem::SectionHeader("Guides"),
1003                SettingsPageItem::SettingItem(SettingItem {
1004                    title: "Show Wrap Guides",
1005                    description: "Show wrap guides (vertical rulers).",
1006                    field: Box::new(SettingField {
1007                        json_path: Some("show_wrap_guides"),
1008                        pick: |settings_content| {
1009                            settings_content
1010                                .project
1011                                .all_languages
1012                                .defaults
1013                                .show_wrap_guides
1014                                .as_ref()
1015                        },
1016                        write: |settings_content, value| {
1017                            settings_content
1018
1019                                .project
1020                                .all_languages
1021                                .defaults
1022                                .show_wrap_guides = value;
1023                        },
1024                    }),
1025                    metadata: None,
1026                    files: USER | PROJECT,
1027                }),
1028                // todo(settings_ui): This needs a custom component
1029                SettingsPageItem::SettingItem(SettingItem {
1030                    title: "Wrap Guides",
1031                    description: "Character counts at which to show wrap guides.",
1032                    field: Box::new(
1033                        SettingField {
1034                            json_path: Some("wrap_guides"),
1035                            pick: |settings_content| {
1036                                settings_content
1037                                    .project
1038                                    .all_languages
1039                                    .defaults
1040                                    .wrap_guides
1041                                    .as_ref()
1042                            },
1043                            write: |settings_content, value| {
1044                                settings_content.project.all_languages.defaults.wrap_guides = value;
1045                            },
1046                        }
1047                        .unimplemented(),
1048                    ),
1049                    metadata: None,
1050                    files: USER | PROJECT,
1051                }),
1052            ],
1053        },
1054        SettingsPage {
1055            title: "Keymap",
1056            items: vec![
1057                SettingsPageItem::SectionHeader("Base Keymap"),
1058                SettingsPageItem::SettingItem(SettingItem {
1059                    title: "Base Keymap",
1060                    description: "The name of a base set of key bindings to use.",
1061                    field: Box::new(SettingField {
1062                        json_path: Some("base_keymap"),
1063                        pick: |settings_content| settings_content.base_keymap.as_ref(),
1064                        write: |settings_content, value| {
1065                            settings_content.base_keymap = value;
1066                        },
1067                    }),
1068                    metadata: Some(Box::new(SettingsFieldMetadata {
1069                        should_do_titlecase: Some(false),
1070                        ..Default::default()
1071                    })),
1072                    files: USER,
1073                }),
1074                SettingsPageItem::SectionHeader("Modal Editing"),
1075                // todo(settings_ui): Vim/Helix Mode should be apart of one type because it's undefined
1076                // behavior to have them both enabled at the same time
1077                SettingsPageItem::SettingItem(SettingItem {
1078                    title: "Vim Mode",
1079                    description: "Enable Vim mode and key bindings.",
1080                    field: Box::new(SettingField {
1081                        json_path: Some("vim_mode"),
1082                        pick: |settings_content| settings_content.vim_mode.as_ref(),
1083                        write: |settings_content, value| {
1084                            settings_content.vim_mode = value;
1085                        },
1086                    }),
1087                    metadata: None,
1088                    files: USER,
1089                }),
1090                SettingsPageItem::SettingItem(SettingItem {
1091                    title: "Helix Mode",
1092                    description: "Enable Helix mode and key bindings.",
1093                    field: Box::new(SettingField {
1094                        json_path: Some("helix_mode"),
1095                        pick: |settings_content| settings_content.helix_mode.as_ref(),
1096                        write: |settings_content, value| {
1097                            settings_content.helix_mode = value;
1098                        },
1099                    }),
1100                    metadata: None,
1101                    files: USER,
1102                }),
1103            ],
1104        },
1105        SettingsPage {
1106            title: "Editor",
1107            items: {
1108                let mut items = vec![
1109                    SettingsPageItem::SectionHeader("Auto Save"),
1110                    SettingsPageItem::DynamicItem(DynamicItem {
1111                        discriminant: SettingItem {
1112                            files: USER,
1113                            title: "Auto Save Mode",
1114                            description: "When to auto save buffer changes.",
1115                            field: Box::new(SettingField {
1116                                json_path: Some("autosave$"),
1117                                pick: |settings_content| {
1118                                    Some(&dynamic_variants::<settings::AutosaveSetting>()[
1119                                        settings_content
1120                                            .workspace
1121                                            .autosave
1122                                            .as_ref()?
1123                                            .discriminant() as usize])
1124                                },
1125                                write: |settings_content, value| {
1126                                    let Some(value) = value else {
1127                                        settings_content.workspace.autosave = None;
1128                                        return;
1129                                    };
1130                                    let settings_value = settings_content.workspace.autosave.get_or_insert_with(|| {
1131                                        settings::AutosaveSetting::Off
1132                                    });
1133                                    *settings_value = match value {
1134                                        settings::AutosaveSettingDiscriminants::Off => {
1135                                            settings::AutosaveSetting::Off
1136                                        },
1137                                        settings::AutosaveSettingDiscriminants::AfterDelay => {
1138                                            let milliseconds = match settings_value {
1139                                                settings::AutosaveSetting::AfterDelay { milliseconds } => *milliseconds,
1140                                                _ => settings::DelayMs(1000),
1141                                            };
1142                                            settings::AutosaveSetting::AfterDelay { milliseconds }
1143                                        },
1144                                        settings::AutosaveSettingDiscriminants::OnFocusChange => {
1145                                            settings::AutosaveSetting::OnFocusChange
1146                                        },
1147                                        settings::AutosaveSettingDiscriminants::OnWindowChange => {
1148                                            settings::AutosaveSetting::OnWindowChange
1149                                        },
1150                                    };
1151                                },
1152                            }),
1153                            metadata: None,
1154                        },
1155                        pick_discriminant: |settings_content| {
1156                            Some(settings_content.workspace.autosave.as_ref()?.discriminant() as usize)
1157                        },
1158                        fields: dynamic_variants::<settings::AutosaveSetting>().into_iter().map(|variant| {
1159                            match variant {
1160                                settings::AutosaveSettingDiscriminants::Off => vec![],
1161                                settings::AutosaveSettingDiscriminants::AfterDelay => vec![
1162                                    SettingItem {
1163                                        files: USER,
1164                                        title: "Delay (milliseconds)",
1165                                        description: "Save after inactivity period (in milliseconds).",
1166                                        field: Box::new(SettingField {
1167                                            json_path: Some("autosave.after_delay.milliseconds"),
1168                                            pick: |settings_content| {
1169                                                match settings_content.workspace.autosave.as_ref() {
1170                                                    Some(settings::AutosaveSetting::AfterDelay { milliseconds }) => Some(milliseconds),
1171                                                    _ => None
1172                                                }
1173                                            },
1174                                            write: |settings_content, value| {
1175                                                let Some(value) = value else {
1176                                                    settings_content.workspace.autosave = None;
1177                                                    return;
1178                                                };
1179                                                match settings_content
1180                                                    .workspace
1181                                                    .autosave.as_mut() {
1182                                                        Some(settings::AutosaveSetting::AfterDelay { milliseconds }) => *milliseconds = value,
1183                                                        _ => return
1184                                                    }
1185                                            },
1186                                        }),
1187                                        metadata: None,
1188                                    }
1189                                ],
1190                                settings::AutosaveSettingDiscriminants::OnFocusChange => vec![],
1191                                settings::AutosaveSettingDiscriminants::OnWindowChange => vec![],
1192                            }
1193                        }).collect(),
1194                    }),
1195                    SettingsPageItem::SectionHeader("Multibuffer"),
1196                    SettingsPageItem::SettingItem(SettingItem {
1197                        title: "Double Click In Multibuffer",
1198                        description: "What to do when multibuffer is double-clicked in some of its excerpts.",
1199                        field: Box::new(SettingField {
1200                            json_path: Some("double_click_in_multibuffer"),
1201                            pick: |settings_content| {
1202                                settings_content.editor.double_click_in_multibuffer.as_ref()
1203                            },
1204                            write: |settings_content, value| {
1205                                settings_content.editor.double_click_in_multibuffer = value;
1206                            },
1207                        }),
1208                        metadata: None,
1209                        files: USER,
1210                    }),
1211                    SettingsPageItem::SettingItem(SettingItem {
1212                        title: "Expand Excerpt Lines",
1213                        description: "How many lines to expand the multibuffer excerpts by default.",
1214                        field: Box::new(SettingField {
1215                            json_path: Some("expand_excerpt_lines"),
1216                            pick: |settings_content| {
1217                                settings_content.editor.expand_excerpt_lines.as_ref()
1218                            },
1219                            write: |settings_content, value| {
1220                                settings_content.editor.expand_excerpt_lines = value;
1221                            },
1222                        }),
1223                        metadata: None,
1224                        files: USER,
1225                    }),
1226                    SettingsPageItem::SettingItem(SettingItem {
1227                        title: "Excerpt Context Lines",
1228                        description: "How many lines of context to provide in multibuffer excerpts by default.",
1229                        field: Box::new(SettingField {
1230                            json_path: Some("excerpt_context_lines"),
1231                            pick: |settings_content| {
1232                                settings_content.editor.excerpt_context_lines.as_ref()
1233                            },
1234                            write: |settings_content, value| {
1235                                settings_content.editor.excerpt_context_lines = value;
1236                            },
1237                        }),
1238                        metadata: None,
1239                        files: USER,
1240                    }),
1241                    SettingsPageItem::SettingItem(SettingItem {
1242                        title: "Expand Outlines With Depth",
1243                        description: "Default depth to expand outline items in the current file.",
1244                        field: Box::new(SettingField {
1245                            json_path: Some("outline_panel.expand_outlines_with_depth"),
1246                            pick: |settings_content| {
1247                                settings_content
1248                                    .outline_panel
1249                                    .as_ref()
1250                                    .and_then(|outline_panel| {
1251                                        outline_panel.expand_outlines_with_depth.as_ref()
1252                                    })
1253                            },
1254                            write: |settings_content, value| {
1255                                settings_content
1256                                    .outline_panel
1257                                    .get_or_insert_default()
1258                                    .expand_outlines_with_depth = value;
1259                            },
1260                        }),
1261                        metadata: None,
1262                        files: USER,
1263                    }),
1264                    SettingsPageItem::SectionHeader("Scrolling"),
1265                    SettingsPageItem::SettingItem(SettingItem {
1266                        title: "Scroll Beyond Last Line",
1267                        description: "Whether the editor will scroll beyond the last line.",
1268                        field: Box::new(SettingField {
1269                            json_path: Some("scroll_beyond_last_line"),
1270                            pick: |settings_content| {
1271                                settings_content.editor.scroll_beyond_last_line.as_ref()
1272                            },
1273                            write: |settings_content, value| {
1274                                settings_content.editor.scroll_beyond_last_line = value;
1275                            },
1276                        }),
1277                        metadata: None,
1278                        files: USER,
1279                    }),
1280                    SettingsPageItem::SettingItem(SettingItem {
1281                        title: "Vertical Scroll Margin",
1282                        description: "The number of lines to keep above/below the cursor when auto-scrolling.",
1283                        field: Box::new(SettingField {
1284                            json_path: Some("vertical_scroll_margin"),
1285                            pick: |settings_content| {
1286                                settings_content.editor.vertical_scroll_margin.as_ref()
1287                            },
1288                            write: |settings_content, value| {
1289                                settings_content.editor.vertical_scroll_margin = value;
1290                            },
1291                        }),
1292                        metadata: None,
1293                        files: USER,
1294                    }),
1295                    SettingsPageItem::SettingItem(SettingItem {
1296                        title: "Horizontal Scroll Margin",
1297                        description: "The number of characters to keep on either side when scrolling with the mouse.",
1298                        field: Box::new(SettingField {
1299                            json_path: Some("horizontal_scroll_margin"),
1300                            pick: |settings_content| {
1301                                settings_content.editor.horizontal_scroll_margin.as_ref()
1302                            },
1303                            write: |settings_content, value| {
1304                                settings_content.editor.horizontal_scroll_margin = value;
1305                            },
1306                        }),
1307                        metadata: None,
1308                        files: USER,
1309                    }),
1310                    SettingsPageItem::SettingItem(SettingItem {
1311                        title: "Scroll Sensitivity",
1312                        description: "Scroll sensitivity multiplier for both horizontal and vertical scrolling.",
1313                        field: Box::new(SettingField {
1314                            json_path: Some("scroll_sensitivity"),
1315                            pick: |settings_content| {
1316                                settings_content.editor.scroll_sensitivity.as_ref()
1317                            },
1318                            write: |settings_content, value| {
1319                                settings_content.editor.scroll_sensitivity = value;
1320                            },
1321                        }),
1322                        metadata: None,
1323                        files: USER,
1324                    }),
1325                    SettingsPageItem::SettingItem(SettingItem {
1326                        title: "Fast Scroll Sensitivity",
1327                        description: "Fast scroll sensitivity multiplier for both horizontal and vertical scrolling.",
1328                        field: Box::new(SettingField {
1329                            json_path: Some("fast_scroll_sensitivity"),
1330                            pick: |settings_content| {
1331                                settings_content.editor.fast_scroll_sensitivity.as_ref()
1332                            },
1333                            write: |settings_content, value| {
1334                                settings_content.editor.fast_scroll_sensitivity = value;
1335                            },
1336                        }),
1337                        metadata: None,
1338                        files: USER,
1339                    }),
1340                    SettingsPageItem::SettingItem(SettingItem {
1341                        title: "Autoscroll On Clicks",
1342                        description: "Whether to scroll when clicking near the edge of the visible text area.",
1343                        field: Box::new(SettingField {
1344                            json_path: Some("autoscroll_on_clicks"),
1345                            pick: |settings_content| {
1346                                settings_content.editor.autoscroll_on_clicks.as_ref()
1347                            },
1348                            write: |settings_content, value| {
1349                                settings_content.editor.autoscroll_on_clicks = value;
1350                            },
1351                        }),
1352                        metadata: None,
1353                        files: USER,
1354                    }),
1355                    SettingsPageItem::SettingItem(SettingItem {
1356                        title: "Sticky Scroll",
1357                        description: "Whether to stick scopes to the top of the editor",
1358                        field: Box::new(SettingField {
1359                            json_path: Some("sticky_scroll.enabled"),
1360                            pick: |settings_content| {
1361                                settings_content.editor.sticky_scroll.as_ref().and_then(|sticky_scroll| sticky_scroll.enabled.as_ref())
1362                            },
1363                            write: |settings_content, value| {
1364                                settings_content.editor.sticky_scroll.get_or_insert_default().enabled = value;
1365                            },
1366                        }),
1367                        metadata: None,
1368                        files: USER,
1369                    }),
1370                    SettingsPageItem::SectionHeader("Signature Help"),
1371                    SettingsPageItem::SettingItem(SettingItem {
1372                        title: "Auto Signature Help",
1373                        description: "Automatically show a signature help pop-up.",
1374                        field: Box::new(SettingField {
1375                            json_path: Some("auto_signature_help"),
1376                            pick: |settings_content| {
1377                                settings_content.editor.auto_signature_help.as_ref()
1378                            },
1379                            write: |settings_content, value| {
1380                                settings_content.editor.auto_signature_help = value;
1381                            },
1382                        }),
1383                        metadata: None,
1384                        files: USER,
1385                    }),
1386                    SettingsPageItem::SettingItem(SettingItem {
1387                        title: "Show Signature Help After Edits",
1388                        description: "Show the signature help pop-up after completions or bracket pairs are inserted.",
1389                        field: Box::new(SettingField {
1390                            json_path: Some("show_signature_help_after_edits"),
1391                            pick: |settings_content| {
1392                                settings_content
1393                                    .editor
1394                                    .show_signature_help_after_edits
1395                                    .as_ref()
1396                            },
1397                            write: |settings_content, value| {
1398                                settings_content.editor.show_signature_help_after_edits = value;
1399                            },
1400                        }),
1401                        metadata: None,
1402                        files: USER,
1403                    }),
1404                    SettingsPageItem::SettingItem(SettingItem {
1405                        title: "Snippet Sort Order",
1406                        description: "Determines how snippets are sorted relative to other completion items.",
1407                        field: Box::new(SettingField {
1408                            json_path: Some("snippet_sort_order"),
1409                            pick: |settings_content| {
1410                                settings_content.editor.snippet_sort_order.as_ref()
1411                            },
1412                            write: |settings_content, value| {
1413                                settings_content.editor.snippet_sort_order = value;
1414                            },
1415                        }),
1416                        metadata: None,
1417                        files: USER,
1418                    }),
1419                    SettingsPageItem::SectionHeader("Hover Popover"),
1420                    SettingsPageItem::SettingItem(SettingItem {
1421                        title: "Enabled",
1422                        description: "Show the informational hover box when moving the mouse over symbols in the editor.",
1423                        field: Box::new(SettingField {
1424                            json_path: Some("hover_popover_enabled"),
1425                            pick: |settings_content| {
1426                                settings_content.editor.hover_popover_enabled.as_ref()
1427                            },
1428                            write: |settings_content, value| {
1429                                settings_content.editor.hover_popover_enabled = value;
1430                            },
1431                        }),
1432                        metadata: None,
1433                        files: USER,
1434                    }),
1435                    // todo(settings ui): add units to this number input
1436                    SettingsPageItem::SettingItem(SettingItem {
1437                        title: "Delay",
1438                        description: "Time to wait in milliseconds before showing the informational hover box.",
1439                        field: Box::new(SettingField {
1440                            json_path: Some("hover_popover_enabled"),
1441                            pick: |settings_content| {
1442                                settings_content.editor.hover_popover_delay.as_ref()
1443                            },
1444                            write: |settings_content, value| {
1445                                settings_content.editor.hover_popover_delay = value;
1446                            },
1447                        }),
1448                        metadata: None,
1449                        files: USER,
1450                    }),
1451                    SettingsPageItem::SectionHeader("Drag And Drop Selection"),
1452                    SettingsPageItem::SettingItem(SettingItem {
1453                        title: "Enabled",
1454                        description: "Enable drag and drop selection.",
1455                        field: Box::new(SettingField {
1456                            json_path: Some("drag_and_drop_selection.enabled"),
1457                            pick: |settings_content| {
1458                                settings_content
1459                                    .editor
1460                                    .drag_and_drop_selection
1461                                    .as_ref()
1462                                    .and_then(|drag_and_drop| drag_and_drop.enabled.as_ref())
1463                            },
1464                            write: |settings_content, value| {
1465                                settings_content
1466                                    .editor
1467                                    .drag_and_drop_selection
1468                                    .get_or_insert_default()
1469                                    .enabled = value;
1470                            },
1471                        }),
1472                        metadata: None,
1473                        files: USER,
1474                    }),
1475                    SettingsPageItem::SettingItem(SettingItem {
1476                        title: "Delay",
1477                        description: "Delay in milliseconds before drag and drop selection starts.",
1478                        field: Box::new(SettingField {
1479                            json_path: Some("drag_and_drop_selection.delay"),
1480                            pick: |settings_content| {
1481                                settings_content
1482                                    .editor
1483                                    .drag_and_drop_selection
1484                                    .as_ref()
1485                                    .and_then(|drag_and_drop| drag_and_drop.delay.as_ref())
1486                            },
1487                            write: |settings_content, value| {
1488                                settings_content
1489                                    .editor
1490                                    .drag_and_drop_selection
1491                                    .get_or_insert_default()
1492                                    .delay = value;
1493                            },
1494                        }),
1495                        metadata: None,
1496                        files: USER,
1497                    }),
1498                    SettingsPageItem::SectionHeader("Gutter"),
1499                    SettingsPageItem::SettingItem(SettingItem {
1500                        title: "Show Line Numbers",
1501                        description: "Show line numbers in the gutter.",
1502                        field: Box::new(SettingField {
1503                            json_path: Some("gutter.line_numbers"),
1504                            pick: |settings_content| {
1505                                settings_content
1506                                    .editor
1507                                    .gutter
1508                                    .as_ref()
1509                                    .and_then(|gutter| gutter.line_numbers.as_ref())
1510                            },
1511                            write: |settings_content, value| {
1512                                settings_content
1513                                    .editor
1514                                    .gutter
1515                                    .get_or_insert_default()
1516                                    .line_numbers = value;
1517                            },
1518                        }),
1519                        metadata: None,
1520                        files: USER,
1521                    }),
1522                    SettingsPageItem::SettingItem(SettingItem {
1523                        title: "Relative Line Numbers",
1524                        description: "Controls line number display in the editor's gutter. \"disabled\" shows absolute line numbers, \"enabled\" shows relative line numbers for each absolute line, and \"wrapped\" shows relative line numbers for every line, absolute or wrapped.",
1525                        field: Box::new(SettingField {
1526                            json_path: Some("relative_line_numbers"),
1527                            pick: |settings_content| {
1528                                settings_content.editor.relative_line_numbers.as_ref()
1529                            },
1530                            write: |settings_content, value| {
1531                                settings_content.editor.relative_line_numbers = value;
1532                            },
1533                        }),
1534                        metadata: None,
1535                        files: USER,
1536                    }),
1537                    SettingsPageItem::SettingItem(SettingItem {
1538                        title: "Show Runnables",
1539                        description: "Show runnable buttons in the gutter.",
1540                        field: Box::new(SettingField {
1541                            json_path: Some("gutter.runnables"),
1542                            pick: |settings_content| {
1543                                settings_content
1544                                    .editor
1545                                    .gutter
1546                                    .as_ref()
1547                                    .and_then(|gutter| gutter.runnables.as_ref())
1548                            },
1549                            write: |settings_content, value| {
1550                                settings_content
1551                                    .editor
1552                                    .gutter
1553                                    .get_or_insert_default()
1554                                    .runnables = value;
1555                            },
1556                        }),
1557                        metadata: None,
1558                        files: USER,
1559                    }),
1560                    SettingsPageItem::SettingItem(SettingItem {
1561                        title: "Show Breakpoints",
1562                        description: "Show breakpoints in the gutter.",
1563                        field: Box::new(SettingField {
1564                            json_path: Some("gutter.breakpoints"),
1565                            pick: |settings_content| {
1566                                settings_content
1567                                    .editor
1568                                    .gutter
1569                                    .as_ref()
1570                                    .and_then(|gutter| gutter.breakpoints.as_ref())
1571                            },
1572                            write: |settings_content, value| {
1573                                settings_content
1574                                    .editor
1575                                    .gutter
1576                                    .get_or_insert_default()
1577                                    .breakpoints = value;
1578                            },
1579                        }),
1580                        metadata: None,
1581                        files: USER,
1582                    }),
1583                    SettingsPageItem::SettingItem(SettingItem {
1584                        title: "Show Folds",
1585                        description: "Show code folding controls in the gutter.",
1586                        field: Box::new(SettingField {
1587                            json_path: Some("gutter.folds"),
1588                            pick: |settings_content| {
1589                                settings_content
1590                                    .editor
1591                                    .gutter
1592                                    .as_ref()
1593                                    .and_then(|gutter| gutter.folds.as_ref())
1594                            },
1595                            write: |settings_content, value| {
1596                                settings_content.editor.gutter.get_or_insert_default().folds =
1597                                    value;
1598                            },
1599                        }),
1600                        metadata: None,
1601                        files: USER,
1602                    }),
1603                    SettingsPageItem::SettingItem(SettingItem {
1604                        title: "Min Line Number Digits",
1605                        description: "Minimum number of characters to reserve space for in the gutter.",
1606                        field: Box::new(SettingField {
1607                            json_path: Some("gutter.min_line_number_digits"),
1608                            pick: |settings_content| {
1609                                settings_content
1610                                    .editor
1611                                    .gutter
1612                                    .as_ref()
1613                                    .and_then(|gutter| gutter.min_line_number_digits.as_ref())
1614                            },
1615                            write: |settings_content, value| {
1616                                settings_content
1617                                    .editor
1618                                    .gutter
1619                                    .get_or_insert_default()
1620                                    .min_line_number_digits = value;
1621                            },
1622                        }),
1623                        metadata: None,
1624                        files: USER,
1625                    }),
1626                    SettingsPageItem::SettingItem(SettingItem {
1627                        title: "Inline Code Actions",
1628                        description: "Show code action button at start of buffer line.",
1629                        field: Box::new(SettingField {
1630                            json_path: Some("inline_code_actions"),
1631                            pick: |settings_content| {
1632                                settings_content.editor.inline_code_actions.as_ref()
1633                            },
1634                            write: |settings_content, value| {
1635                                settings_content.editor.inline_code_actions = value;
1636                            },
1637                        }),
1638                        metadata: None,
1639                        files: USER,
1640                    }),
1641                    SettingsPageItem::SectionHeader("Scrollbar"),
1642                    SettingsPageItem::SettingItem(SettingItem {
1643                        title: "Show",
1644                        description: "When to show the scrollbar in the editor.",
1645                        field: Box::new(SettingField {
1646                            json_path: Some("scrollbar"),
1647                            pick: |settings_content| {
1648                                settings_content.editor.scrollbar.as_ref()?.show.as_ref()
1649                            },
1650                            write: |settings_content, value| {
1651                                settings_content
1652                                    .editor
1653                                    .scrollbar
1654                                    .get_or_insert_default()
1655                                    .show = value;
1656                            },
1657                        }),
1658                        metadata: None,
1659                        files: USER,
1660                    }),
1661                    SettingsPageItem::SettingItem(SettingItem {
1662                        title: "Cursors",
1663                        description: "Show cursor positions in the scrollbar.",
1664                        field: Box::new(SettingField {
1665                            json_path: Some("scrollbar.cursors"),
1666                            pick: |settings_content| {
1667                                settings_content.editor.scrollbar.as_ref()?.cursors.as_ref()
1668                            },
1669                            write: |settings_content, value| {
1670                                settings_content
1671                                    .editor
1672                                    .scrollbar
1673                                    .get_or_insert_default()
1674                                    .cursors = value;
1675                            },
1676                        }),
1677                        metadata: None,
1678                        files: USER,
1679                    }),
1680                    SettingsPageItem::SettingItem(SettingItem {
1681                        title: "Git Diff",
1682                        description: "Show Git diff indicators in the scrollbar.",
1683                        field: Box::new(SettingField {
1684                            json_path: Some("scrollbar.git_diff"),
1685                            pick: |settings_content| {
1686                                settings_content
1687                                    .editor
1688                                    .scrollbar
1689                                    .as_ref()?
1690                                    .git_diff
1691                                    .as_ref()
1692                            },
1693                            write: |settings_content, value| {
1694                                settings_content
1695                                    .editor
1696                                    .scrollbar
1697                                    .get_or_insert_default()
1698                                    .git_diff = value;
1699                            },
1700                        }),
1701                        metadata: None,
1702                        files: USER,
1703                    }),
1704                    SettingsPageItem::SettingItem(SettingItem {
1705                        title: "Search Results",
1706                        description: "Show buffer search result indicators in the scrollbar.",
1707                        field: Box::new(SettingField {
1708                            json_path: Some("scrollbar.search_results"),
1709                            pick: |settings_content| {
1710                                settings_content
1711                                    .editor
1712                                    .scrollbar
1713                                    .as_ref()?
1714                                    .search_results
1715                                    .as_ref()
1716                            },
1717                            write: |settings_content, value| {
1718                                settings_content
1719                                    .editor
1720                                    .scrollbar
1721                                    .get_or_insert_default()
1722                                    .search_results = value;
1723                            },
1724                        }),
1725                        metadata: None,
1726                        files: USER,
1727                    }),
1728                    SettingsPageItem::SettingItem(SettingItem {
1729                        title: "Selected Text",
1730                        description: "Show selected text occurrences in the scrollbar.",
1731                        field: Box::new(SettingField {
1732                            json_path: Some("scrollbar.selected_text"),
1733                            pick: |settings_content| {
1734                                settings_content
1735                                    .editor
1736                                    .scrollbar
1737                                    .as_ref()?
1738                                    .selected_text
1739                                    .as_ref()
1740                            },
1741                            write: |settings_content, value| {
1742                                settings_content
1743                                    .editor
1744                                    .scrollbar
1745                                    .get_or_insert_default()
1746                                    .selected_text = value;
1747                            },
1748                        }),
1749                        metadata: None,
1750                        files: USER,
1751                    }),
1752                    SettingsPageItem::SettingItem(SettingItem {
1753                        title: "Selected Symbol",
1754                        description: "Show selected symbol occurrences in the scrollbar.",
1755                        field: Box::new(SettingField {
1756                            json_path: Some("scrollbar.selected_symbol"),
1757                            pick: |settings_content| {
1758                                settings_content
1759                                    .editor
1760                                    .scrollbar
1761                                    .as_ref()?
1762                                    .selected_symbol
1763                                    .as_ref()
1764                            },
1765                            write: |settings_content, value| {
1766                                settings_content
1767                                    .editor
1768                                    .scrollbar
1769                                    .get_or_insert_default()
1770                                    .selected_symbol = value;
1771                            },
1772                        }),
1773                        metadata: None,
1774                        files: USER,
1775                    }),
1776                    SettingsPageItem::SettingItem(SettingItem {
1777                        title: "Diagnostics",
1778                        description: "Which diagnostic indicators to show in the scrollbar.",
1779                        field: Box::new(SettingField {
1780                            json_path: Some("scrollbar.diagnostics"),
1781                            pick: |settings_content| {
1782                                settings_content
1783                                    .editor
1784                                    .scrollbar
1785                                    .as_ref()?
1786                                    .diagnostics
1787                                    .as_ref()
1788                            },
1789                            write: |settings_content, value| {
1790                                settings_content
1791                                    .editor
1792                                    .scrollbar
1793                                    .get_or_insert_default()
1794                                    .diagnostics = value;
1795                            },
1796                        }),
1797                        metadata: None,
1798                        files: USER,
1799                    }),
1800                    SettingsPageItem::SettingItem(SettingItem {
1801                        title: "Horizontal Scrollbar",
1802                        description: "When false, forcefully disables the horizontal scrollbar.",
1803                        field: Box::new(SettingField {
1804                            json_path: Some("scrollbar.axes.horizontal"),
1805                            pick: |settings_content| {
1806                                settings_content
1807                                    .editor
1808                                    .scrollbar
1809                                    .as_ref()?
1810                                    .axes
1811                                    .as_ref()?
1812                                    .horizontal
1813                                    .as_ref()
1814                            },
1815                            write: |settings_content, value| {
1816                                settings_content
1817                                    .editor
1818                                    .scrollbar
1819                                    .get_or_insert_default()
1820                                    .axes
1821                                    .get_or_insert_default()
1822                                    .horizontal = value;
1823                            },
1824                        }),
1825                        metadata: None,
1826                        files: USER,
1827                    }),
1828                    SettingsPageItem::SettingItem(SettingItem {
1829                        title: "Vertical Scrollbar",
1830                        description: "When false, forcefully disables the vertical scrollbar.",
1831                        field: Box::new(SettingField {
1832                            json_path: Some("scrollbar.axes.vertical"),
1833                            pick: |settings_content| {
1834                                settings_content
1835                                    .editor
1836                                    .scrollbar
1837                                    .as_ref()?
1838                                    .axes
1839                                    .as_ref()?
1840                                    .vertical
1841                                    .as_ref()
1842                            },
1843                            write: |settings_content, value| {
1844                                settings_content
1845                                    .editor
1846                                    .scrollbar
1847                                    .get_or_insert_default()
1848                                    .axes
1849                                    .get_or_insert_default()
1850                                    .vertical = value;
1851                            },
1852                        }),
1853                        metadata: None,
1854                        files: USER,
1855                    }),
1856                    SettingsPageItem::SectionHeader("Minimap"),
1857                    SettingsPageItem::SettingItem(SettingItem {
1858                        title: "Show",
1859                        description: "When to show the minimap in the editor.",
1860                        field: Box::new(SettingField {
1861                            json_path: Some("minimap.show"),
1862                            pick: |settings_content| {
1863                                settings_content.editor.minimap.as_ref()?.show.as_ref()
1864                            },
1865                            write: |settings_content, value| {
1866                                settings_content.editor.minimap.get_or_insert_default().show =
1867                                    value;
1868                            },
1869                        }),
1870                        metadata: None,
1871                        files: USER,
1872                    }),
1873                    SettingsPageItem::SettingItem(SettingItem {
1874                        title: "Display In",
1875                        description: "Where to show the minimap in the editor.",
1876                        field: Box::new(SettingField {
1877                            json_path: Some("minimap.display_in"),
1878                            pick: |settings_content| {
1879                                settings_content
1880                                    .editor
1881                                    .minimap
1882                                    .as_ref()?
1883                                    .display_in
1884                                    .as_ref()
1885                            },
1886                            write: |settings_content, value| {
1887                                settings_content
1888                                    .editor
1889                                    .minimap
1890                                    .get_or_insert_default()
1891                                    .display_in = value;
1892                            },
1893                        }),
1894                        metadata: None,
1895                        files: USER,
1896                    }),
1897                    SettingsPageItem::SettingItem(SettingItem {
1898                        title: "Thumb",
1899                        description: "When to show the minimap thumb.",
1900                        field: Box::new(SettingField {
1901                            json_path: Some("minimap.thumb"),
1902                            pick: |settings_content| {
1903                                settings_content.editor.minimap.as_ref()?.thumb.as_ref()
1904                            },
1905                            write: |settings_content, value| {
1906                                settings_content
1907                                    .editor
1908                                    .minimap
1909                                    .get_or_insert_default()
1910                                    .thumb = value;
1911                            },
1912                        }),
1913                        metadata: None,
1914                        files: USER,
1915                    }),
1916                    SettingsPageItem::SettingItem(SettingItem {
1917                        title: "Thumb Border",
1918                        description: "Border style for the minimap's scrollbar thumb.",
1919                        field: Box::new(SettingField {
1920                            json_path: Some("minimap.thumb_border"),
1921                            pick: |settings_content| {
1922                                settings_content
1923                                    .editor
1924                                    .minimap
1925                                    .as_ref()?
1926                                    .thumb_border
1927                                    .as_ref()
1928                            },
1929                            write: |settings_content, value| {
1930                                settings_content
1931                                    .editor
1932                                    .minimap
1933                                    .get_or_insert_default()
1934                                    .thumb_border = value;
1935                            },
1936                        }),
1937                        metadata: None,
1938                        files: USER,
1939                    }),
1940                    SettingsPageItem::SettingItem(SettingItem {
1941                        title: "Current Line Highlight",
1942                        description: "How to highlight the current line in the minimap.",
1943                        field: Box::new(SettingField {
1944                            json_path: Some("minimap.current_line_highlight"),
1945                            pick: |settings_content| {
1946                                settings_content
1947                                    .editor
1948                                    .minimap
1949                                    .as_ref()
1950                                    .and_then(|minimap| minimap.current_line_highlight.as_ref())
1951                                    .or(settings_content.editor.current_line_highlight.as_ref())
1952                            },
1953                            write: |settings_content, value| {
1954                                settings_content
1955                                    .editor
1956                                    .minimap
1957                                    .get_or_insert_default()
1958                                    .current_line_highlight = value;
1959                            },
1960                        }),
1961                        metadata: None,
1962                        files: USER,
1963                    }),
1964                    SettingsPageItem::SettingItem(SettingItem {
1965                        title: "Max Width Columns",
1966                        description: "Maximum number of columns to display in the minimap.",
1967                        field: Box::new(SettingField {
1968                            json_path: Some("minimap.max_width_columns"),
1969                            pick: |settings_content| {
1970                                settings_content
1971                                    .editor
1972                                    .minimap
1973                                    .as_ref()?
1974                                    .max_width_columns
1975                                    .as_ref()
1976                            },
1977                            write: |settings_content, value| {
1978                                settings_content
1979                                    .editor
1980                                    .minimap
1981                                    .get_or_insert_default()
1982                                    .max_width_columns = value;
1983                            },
1984                        }),
1985                        metadata: None,
1986                        files: USER,
1987                    }),
1988                    SettingsPageItem::SectionHeader("Toolbar"),
1989                    SettingsPageItem::SettingItem(SettingItem {
1990                        title: "Breadcrumbs",
1991                        description: "Show breadcrumbs.",
1992                        field: Box::new(SettingField {
1993                            json_path: Some("toolbar.breadcrumbs"),
1994                            pick: |settings_content| {
1995                                settings_content
1996                                    .editor
1997                                    .toolbar
1998                                    .as_ref()?
1999                                    .breadcrumbs
2000                                    .as_ref()
2001                            },
2002                            write: |settings_content, value| {
2003                                settings_content
2004                                    .editor
2005                                    .toolbar
2006                                    .get_or_insert_default()
2007                                    .breadcrumbs = value;
2008                            },
2009                        }),
2010                        metadata: None,
2011                        files: USER,
2012                    }),
2013                    SettingsPageItem::SettingItem(SettingItem {
2014                        title: "Quick Actions",
2015                        description: "Show quick action buttons (e.g., search, selection, editor controls, etc.).",
2016                        field: Box::new(SettingField {
2017                            json_path: Some("toolbar.quick_actions"),
2018                            pick: |settings_content| {
2019                                settings_content
2020                                    .editor
2021                                    .toolbar
2022                                    .as_ref()?
2023                                    .quick_actions
2024                                    .as_ref()
2025                            },
2026                            write: |settings_content, value| {
2027                                settings_content
2028                                    .editor
2029                                    .toolbar
2030                                    .get_or_insert_default()
2031                                    .quick_actions = value;
2032                            },
2033                        }),
2034                        metadata: None,
2035                        files: USER,
2036                    }),
2037                    SettingsPageItem::SettingItem(SettingItem {
2038                        title: "Selections Menu",
2039                        description: "Show the selections menu in the editor toolbar.",
2040                        field: Box::new(SettingField {
2041                            json_path: Some("toolbar.selections_menu"),
2042                            pick: |settings_content| {
2043                                settings_content
2044                                    .editor
2045                                    .toolbar
2046                                    .as_ref()?
2047                                    .selections_menu
2048                                    .as_ref()
2049                            },
2050                            write: |settings_content, value| {
2051                                settings_content
2052                                    .editor
2053                                    .toolbar
2054                                    .get_or_insert_default()
2055                                    .selections_menu = value;
2056                            },
2057                        }),
2058                        metadata: None,
2059                        files: USER,
2060                    }),
2061                    SettingsPageItem::SettingItem(SettingItem {
2062                        title: "Agent Review",
2063                        description: "Show agent review buttons in the editor toolbar.",
2064                        field: Box::new(SettingField {
2065                            json_path: Some("toolbar.agent_review"),
2066                            pick: |settings_content| {
2067                                settings_content
2068                                    .editor
2069                                    .toolbar
2070                                    .as_ref()?
2071                                    .agent_review
2072                                    .as_ref()
2073                            },
2074                            write: |settings_content, value| {
2075                                settings_content
2076                                    .editor
2077                                    .toolbar
2078                                    .get_or_insert_default()
2079                                    .agent_review = value;
2080                            },
2081                        }),
2082                        metadata: None,
2083                        files: USER,
2084                    }),
2085                    SettingsPageItem::SettingItem(SettingItem {
2086                        title: "Code Actions",
2087                        description: "Show code action buttons in the editor toolbar.",
2088                        field: Box::new(SettingField {
2089                            json_path: Some("toolbar.code_actions"),
2090                            pick: |settings_content| {
2091                                settings_content
2092                                    .editor
2093                                    .toolbar
2094                                    .as_ref()?
2095                                    .code_actions
2096                                    .as_ref()
2097                            },
2098                            write: |settings_content, value| {
2099                                settings_content
2100                                    .editor
2101                                    .toolbar
2102                                    .get_or_insert_default()
2103                                    .code_actions = value;
2104                            },
2105                        }),
2106                        metadata: None,
2107                        files: USER,
2108                    }),
2109                ];
2110                items.extend(language_settings_data());
2111                items
2112            },
2113        },
2114        SettingsPage {
2115            title: "Languages & Tools",
2116            items: {
2117                let mut items = vec![];
2118                items.extend(non_editor_language_settings_data());
2119                items.extend([
2120                    SettingsPageItem::SectionHeader("File Types"),
2121                    SettingsPageItem::SettingItem(SettingItem {
2122                        title: "File Type Associations",
2123                        description: "A mapping from languages to files and file extensions that should be treated as that language.",
2124                        field: Box::new(
2125                            SettingField {
2126                                json_path: Some("file_type_associations"),
2127                                pick: |settings_content| {
2128                                    settings_content.project.all_languages.file_types.as_ref()
2129                                },
2130                                write: |settings_content, value| {
2131                                    settings_content.project.all_languages.file_types = value;
2132
2133                                },
2134                            }
2135                            .unimplemented(),
2136                        ),
2137                        metadata: None,
2138                        files: USER | PROJECT,
2139                    }),
2140                ]);
2141
2142                items.extend([
2143                    SettingsPageItem::SectionHeader("Diagnostics"),
2144                    SettingsPageItem::SettingItem(SettingItem {
2145                        title: "Max Severity",
2146                        description: "Which level to use to filter out diagnostics displayed in the editor.",
2147                        field: Box::new(SettingField {
2148                            json_path: Some("diagnostics_max_severity"),
2149                            pick: |settings_content| settings_content.editor.diagnostics_max_severity.as_ref(),
2150                            write: |settings_content, value| {
2151                                settings_content.editor.diagnostics_max_severity = value;
2152
2153                            },
2154                        }),
2155                        metadata: None,
2156                        files: USER,
2157                    }),
2158                    SettingsPageItem::SettingItem(SettingItem {
2159                        title: "Include Warnings",
2160                        description: "Whether to show warnings or not by default.",
2161                        field: Box::new(SettingField {
2162                            json_path: Some("diagnostics.include_warnings"),
2163                            pick: |settings_content| {
2164                                settings_content.diagnostics.as_ref()?.include_warnings.as_ref()
2165                            },
2166                            write: |settings_content, value| {
2167                                settings_content
2168
2169                                    .diagnostics
2170                                    .get_or_insert_default()
2171                                    .include_warnings
2172                                    = value;
2173                            },
2174                        }),
2175                        metadata: None,
2176                        files: USER,
2177                    }),
2178                    SettingsPageItem::SectionHeader("Inline Diagnostics"),
2179                    SettingsPageItem::SettingItem(SettingItem {
2180                        title: "Enabled",
2181                        description: "Whether to show diagnostics inline or not.",
2182                        field: Box::new(SettingField {
2183                            json_path: Some("diagnostics.inline.enabled"),
2184                            pick: |settings_content| {
2185                                settings_content.diagnostics.as_ref()?.inline.as_ref()?.enabled.as_ref()
2186                            },
2187                            write: |settings_content, value| {
2188                                settings_content
2189
2190                                    .diagnostics
2191                                    .get_or_insert_default()
2192                                    .inline
2193                                    .get_or_insert_default()
2194                                    .enabled
2195                                    = value;
2196                            },
2197                        }),
2198                        metadata: None,
2199                        files: USER,
2200                    }),
2201                    SettingsPageItem::SettingItem(SettingItem {
2202                        title: "Update Debounce",
2203                        description: "The delay in milliseconds to show inline diagnostics after the last diagnostic update.",
2204                        field: Box::new(SettingField {
2205                            json_path: Some("diagnostics.inline.update_debounce_ms"),
2206                            pick: |settings_content| {
2207                                settings_content.diagnostics.as_ref()?.inline.as_ref()?.update_debounce_ms.as_ref()
2208                            },
2209                            write: |settings_content, value| {
2210                                settings_content
2211
2212                                    .diagnostics
2213                                    .get_or_insert_default()
2214                                    .inline
2215                                    .get_or_insert_default()
2216                                    .update_debounce_ms
2217                                    = value;
2218                            },
2219                        }),
2220                        metadata: None,
2221                        files: USER,
2222                    }),
2223                    SettingsPageItem::SettingItem(SettingItem {
2224                        title: "Padding",
2225                        description: "The amount of padding between the end of the source line and the start of the inline diagnostic.",
2226                        field: Box::new(SettingField {
2227                            json_path: Some("diagnostics.inline.padding"),
2228                            pick: |settings_content| {
2229                                settings_content.diagnostics.as_ref()?.inline.as_ref()?.padding.as_ref()
2230                            },
2231                            write: |settings_content, value| {
2232                                settings_content
2233
2234                                    .diagnostics
2235                                    .get_or_insert_default()
2236                                    .inline
2237                                    .get_or_insert_default()
2238                                    .padding
2239                                    = value;
2240                            },
2241                        }),
2242                        metadata: None,
2243                        files: USER,
2244                    }),
2245                    SettingsPageItem::SettingItem(SettingItem {
2246                        title: "Minimum Column",
2247                        description: "The minimum column at which to display inline diagnostics.",
2248                        field: Box::new(SettingField {
2249                            json_path: Some("diagnostics.inline.min_column"),
2250                            pick: |settings_content| {
2251                                settings_content.diagnostics.as_ref()?.inline.as_ref()?.min_column.as_ref()
2252                            },
2253                            write: |settings_content, value| {
2254                                settings_content
2255
2256                                    .diagnostics
2257                                    .get_or_insert_default()
2258                                    .inline
2259                                    .get_or_insert_default()
2260                                    .min_column
2261                                    = value;
2262                            },
2263                        }),
2264                        metadata: None,
2265                        files: USER,
2266                    }),
2267                    SettingsPageItem::SectionHeader("LSP Pull Diagnostics"),
2268                    SettingsPageItem::SettingItem(SettingItem {
2269                        title: "Enabled",
2270                        description: "Whether to pull for language server-powered diagnostics or not.",
2271                        field: Box::new(SettingField {
2272                            json_path: Some("diagnostics.lsp_pull_diagnostics.enabled"),
2273                            pick: |settings_content| {
2274                                settings_content.diagnostics.as_ref()?.lsp_pull_diagnostics.as_ref()?.enabled.as_ref()
2275                            },
2276                            write: |settings_content, value| {
2277                                settings_content
2278
2279                                    .diagnostics
2280                                    .get_or_insert_default()
2281                                    .lsp_pull_diagnostics
2282                                    .get_or_insert_default()
2283                                    .enabled
2284                                    = value;
2285                            },
2286                        }),
2287                        metadata: None,
2288                        files: USER,
2289                    }),
2290                    // todo(settings_ui): Needs unit
2291                    SettingsPageItem::SettingItem(SettingItem {
2292                        title: "Debounce",
2293                        description: "Minimum time to wait before pulling diagnostics from the language server(s).",
2294                        field: Box::new(SettingField {
2295                            json_path: Some("diagnostics.lsp_pull_diagnostics.debounce_ms"),
2296                            pick: |settings_content| {
2297                                settings_content.diagnostics.as_ref()?.lsp_pull_diagnostics.as_ref()?.debounce_ms.as_ref()
2298                            },
2299                            write: |settings_content, value| {
2300                                settings_content
2301
2302                                    .diagnostics
2303                                    .get_or_insert_default()
2304                                    .lsp_pull_diagnostics
2305                                    .get_or_insert_default()
2306                                    .debounce_ms
2307                                    = value;
2308                            },
2309                        }),
2310                        metadata: None,
2311                        files: USER,
2312                    }),
2313                    SettingsPageItem::SectionHeader("LSP Highlights"),
2314                    SettingsPageItem::SettingItem(SettingItem {
2315                        title: "Debounce",
2316                        description: "The debounce delay before querying highlights from the language.",
2317                        field: Box::new(SettingField {
2318                            json_path: Some("lsp_highlight_debounce"),
2319                            pick: |settings_content| settings_content.editor.lsp_highlight_debounce.as_ref(),
2320                            write: |settings_content, value| {
2321                                settings_content.editor.lsp_highlight_debounce = value;
2322                            },
2323                        }),
2324                        metadata: None,
2325                        files: USER,
2326                    }),
2327                ]);
2328
2329                // todo(settings_ui): Refresh on extension (un)/installed
2330                // Note that `crates/json_schema_store` solves the same problem, there is probably a way to unify the two
2331                items.push(SettingsPageItem::SectionHeader(LANGUAGES_SECTION_HEADER));
2332                items.extend(all_language_names(cx).into_iter().map(|language_name| {
2333                    SettingsPageItem::SubPageLink(SubPageLink {
2334                        title: language_name,
2335                        files: USER | PROJECT,
2336                        render: Arc::new(|this, window, cx| {
2337                            this.render_sub_page_items(
2338                                language_settings_data()
2339                                    .iter()
2340                                    .chain(non_editor_language_settings_data().iter())
2341                                    .chain(edit_prediction_language_settings_section().iter())
2342                                    .enumerate(),
2343                                None,
2344                                window,
2345                                cx,
2346                            )
2347                            .into_any_element()
2348                        }),
2349                    })
2350                }));
2351                items
2352            },
2353        },
2354        SettingsPage {
2355            title: "Search & Files",
2356            items: vec![
2357                SettingsPageItem::SectionHeader("Search"),
2358                SettingsPageItem::SettingItem(SettingItem {
2359                    title: "Whole Word",
2360                    description: "Search for whole words by default.",
2361                    field: Box::new(SettingField {
2362                        json_path: Some("search.whole_word"),
2363                        pick: |settings_content| {
2364                            settings_content.editor.search.as_ref()?.whole_word.as_ref()
2365                        },
2366                        write: |settings_content, value| {
2367                            settings_content
2368                                .editor
2369                                .search
2370                                .get_or_insert_default()
2371                                .whole_word = value;
2372                        },
2373                    }),
2374                    metadata: None,
2375                    files: USER,
2376                }),
2377                SettingsPageItem::SettingItem(SettingItem {
2378                    title: "Case Sensitive",
2379                    description: "Search case-sensitively by default.",
2380                    field: Box::new(SettingField {
2381                        json_path: Some("search.case_sensitive"),
2382                        pick: |settings_content| {
2383                            settings_content
2384                                .editor
2385                                .search
2386                                .as_ref()?
2387                                .case_sensitive
2388                                .as_ref()
2389                        },
2390                        write: |settings_content, value| {
2391                            settings_content
2392                                .editor
2393                                .search
2394                                .get_or_insert_default()
2395                                .case_sensitive = value;
2396                        },
2397                    }),
2398                    metadata: None,
2399                    files: USER,
2400                }),
2401                SettingsPageItem::SettingItem(SettingItem {
2402                    title: "Use Smartcase Search",
2403                    description: "Whether to automatically enable case-sensitive search based on the search query.",
2404                    field: Box::new(SettingField {
2405                        json_path: Some("use_smartcase_search"),
2406                        pick: |settings_content| {
2407                            settings_content.editor.use_smartcase_search.as_ref()
2408                        },
2409                        write: |settings_content, value| {
2410                            settings_content.editor.use_smartcase_search = value;
2411                        },
2412                    }),
2413                    metadata: None,
2414                    files: USER,
2415                }),
2416                SettingsPageItem::SettingItem(SettingItem {
2417                    title: "Include Ignored",
2418                    description: "Include ignored files in search results by default.",
2419                    field: Box::new(SettingField {
2420                        json_path: Some("search.include_ignored"),
2421                        pick: |settings_content| {
2422                            settings_content
2423                                .editor
2424                                .search
2425                                .as_ref()?
2426                                .include_ignored
2427                                .as_ref()
2428                        },
2429                        write: |settings_content, value| {
2430                            settings_content
2431                                .editor
2432                                .search
2433                                .get_or_insert_default()
2434                                .include_ignored = value;
2435                        },
2436                    }),
2437                    metadata: None,
2438                    files: USER,
2439                }),
2440                SettingsPageItem::SettingItem(SettingItem {
2441                    title: "Regex",
2442                    description: "Use regex search by default.",
2443                    field: Box::new(SettingField {
2444                        json_path: Some("search.regex"),
2445                        pick: |settings_content| {
2446                            settings_content.editor.search.as_ref()?.regex.as_ref()
2447                        },
2448                        write: |settings_content, value| {
2449                            settings_content.editor.search.get_or_insert_default().regex = value;
2450                        },
2451                    }),
2452                    metadata: None,
2453                    files: USER,
2454                }),
2455                SettingsPageItem::SettingItem(SettingItem {
2456                    title: "Search Wrap",
2457                    description: "Whether the editor search results will loop.",
2458                    field: Box::new(SettingField {
2459                        json_path: Some("search_wrap"),
2460                        pick: |settings_content| settings_content.editor.search_wrap.as_ref(),
2461                        write: |settings_content, value| {
2462                            settings_content.editor.search_wrap = value;
2463                        },
2464                    }),
2465                    metadata: None,
2466                    files: USER,
2467                }),
2468                SettingsPageItem::SettingItem(SettingItem {
2469                    title: "Center on Match",
2470                    description: "Whether to center the current match in the editor",
2471                    field: Box::new(SettingField {
2472                        json_path: Some("editor.search.center_on_match"),
2473                        pick: |settings_content| {
2474                            settings_content
2475                                .editor
2476                                .search
2477                                .as_ref()
2478                                .and_then(|search| search.center_on_match.as_ref())
2479                        },
2480                        write: |settings_content, value| {
2481                            settings_content
2482                                .editor
2483                                .search
2484                                .get_or_insert_default()
2485                                .center_on_match = value;
2486                        },
2487                    }),
2488                    metadata: None,
2489                    files: USER,
2490                }),
2491                SettingsPageItem::SettingItem(SettingItem {
2492                    title: "Seed Search Query From Cursor",
2493                    description: "When to populate a new search's query based on the text under the cursor.",
2494                    field: Box::new(SettingField {
2495                        json_path: Some("seed_search_query_from_cursor"),
2496                        pick: |settings_content| {
2497                            settings_content
2498                                .editor
2499                                .seed_search_query_from_cursor
2500                                .as_ref()
2501                        },
2502                        write: |settings_content, value| {
2503                            settings_content.editor.seed_search_query_from_cursor = value;
2504                        },
2505                    }),
2506                    metadata: None,
2507                    files: USER,
2508                }),
2509                SettingsPageItem::SectionHeader("File Finder"),
2510                // todo: null by default
2511                SettingsPageItem::SettingItem(SettingItem {
2512                    title: "Include Ignored in Search",
2513                    description: "Use gitignored files when searching.",
2514                    field: Box::new(
2515                        SettingField {
2516                            json_path: Some("file_finder.include_ignored"),
2517                            pick: |settings_content| {
2518                                settings_content
2519                                    .file_finder
2520                                    .as_ref()?
2521                                    .include_ignored
2522                                    .as_ref()
2523                            },
2524                            write: |settings_content, value| {
2525                                settings_content
2526                                    .file_finder
2527                                    .get_or_insert_default()
2528                                    .include_ignored = value;
2529                            },
2530                        }
2531                    ),
2532                    metadata: None,
2533                    files: USER,
2534                }),
2535                SettingsPageItem::SettingItem(SettingItem {
2536                    title: "File Icons",
2537                    description: "Show file icons in the file finder.",
2538                    field: Box::new(SettingField {
2539                        json_path: Some("file_finder.file_icons"),
2540                        pick: |settings_content| {
2541                            settings_content.file_finder.as_ref()?.file_icons.as_ref()
2542                        },
2543                        write: |settings_content, value| {
2544                            settings_content
2545                                .file_finder
2546                                .get_or_insert_default()
2547                                .file_icons = value;
2548                        },
2549                    }),
2550                    metadata: None,
2551                    files: USER,
2552                }),
2553                SettingsPageItem::SettingItem(SettingItem {
2554                    title: "Modal Max Width",
2555                    description: "Determines how much space the file finder can take up in relation to the available window width.",
2556                    field: Box::new(SettingField {
2557                        json_path: Some("file_finder.modal_max_width"),
2558                        pick: |settings_content| {
2559                            settings_content
2560                                .file_finder
2561                                .as_ref()?
2562                                .modal_max_width
2563                                .as_ref()
2564                        },
2565                        write: |settings_content, value| {
2566                            settings_content
2567                                .file_finder
2568                                .get_or_insert_default()
2569                                .modal_max_width = value;
2570                        },
2571                    }),
2572                    metadata: None,
2573                    files: USER,
2574                }),
2575                SettingsPageItem::SettingItem(SettingItem {
2576                    title: "Skip Focus For Active In Search",
2577                    description: "Whether the file finder should skip focus for the active file in search results.",
2578                    field: Box::new(SettingField {
2579                        json_path: Some("file_finder.skip_focus_for_active_in_search"),
2580                        pick: |settings_content| {
2581                            settings_content
2582                                .file_finder
2583                                .as_ref()?
2584                                .skip_focus_for_active_in_search
2585                                .as_ref()
2586                        },
2587                        write: |settings_content, value| {
2588                            settings_content
2589                                .file_finder
2590                                .get_or_insert_default()
2591                                .skip_focus_for_active_in_search = value;
2592                        },
2593                    }),
2594                    metadata: None,
2595                    files: USER,
2596                }),
2597                SettingsPageItem::SettingItem(SettingItem {
2598                    title: "Git Status",
2599                    description: "Show the Git status in the file finder.",
2600                    field: Box::new(SettingField {
2601                        json_path: Some("file_finder.git_status"),
2602                        pick: |settings_content| {
2603                            settings_content.file_finder.as_ref()?.git_status.as_ref()
2604                        },
2605                        write: |settings_content, value| {
2606                            settings_content
2607                                .file_finder
2608                                .get_or_insert_default()
2609                                .git_status = value;
2610                        },
2611                    }),
2612                    metadata: None,
2613                    files: USER,
2614                }),
2615                SettingsPageItem::SectionHeader("File Scan"),
2616                SettingsPageItem::SettingItem(SettingItem {
2617                    title: "File Scan Exclusions",
2618                    description: "Files or globs of files that will be excluded by Zed entirely. They will be skipped during file scans, file searches, and not be displayed in the project file tree. Takes precedence over \"File Scan Inclusions\"",
2619                    field: Box::new(
2620                        SettingField {
2621                            json_path: Some("file_scan_exclusions"),
2622                            pick: |settings_content| {
2623                                settings_content
2624                                    .project
2625                                    .worktree
2626                                    .file_scan_exclusions
2627                                    .as_ref()
2628                            },
2629                            write: |settings_content, value| {
2630                                settings_content.project.worktree.file_scan_exclusions = value;
2631                            },
2632                        }
2633                        .unimplemented(),
2634                    ),
2635                    metadata: None,
2636                    files: USER,
2637                }),
2638                SettingsPageItem::SettingItem(SettingItem {
2639                    title: "File Scan Inclusions",
2640                    description: "Files or globs of files that will be included by Zed, even when ignored by git. This is useful for files that are not tracked by git, but are still important to your project. Note that globs that are overly broad can slow down Zed's file scanning. \"File Scan Exclusions\" takes precedence over these inclusions",
2641                    field: Box::new(
2642                        SettingField {
2643                            json_path: Some("file_scan_inclusions"),
2644                            pick: |settings_content| {
2645                                settings_content
2646                                    .project
2647                                    .worktree
2648                                    .file_scan_inclusions
2649                                    .as_ref()
2650                            },
2651                            write: |settings_content, value| {
2652                                settings_content.project.worktree.file_scan_inclusions = value;
2653                            },
2654                        }
2655                        .unimplemented(),
2656                    ),
2657                    metadata: None,
2658                    files: USER,
2659                }),
2660                SettingsPageItem::SettingItem(SettingItem {
2661                    title: "Restore File State",
2662                    description: "Restore previous file state when reopening.",
2663                    field: Box::new(SettingField {
2664                        json_path: Some("restore_on_file_reopen"),
2665                        pick: |settings_content| {
2666                            settings_content.workspace.restore_on_file_reopen.as_ref()
2667                        },
2668                        write: |settings_content, value| {
2669                            settings_content.workspace.restore_on_file_reopen = value;
2670                        },
2671                    }),
2672                    metadata: None,
2673                    files: USER,
2674                }),
2675                SettingsPageItem::SettingItem(SettingItem {
2676                    title: "Close on File Delete",
2677                    description: "Automatically close files that have been deleted.",
2678                    field: Box::new(SettingField {
2679                        json_path: Some("close_on_file_delete"),
2680                        pick: |settings_content| {
2681                            settings_content.workspace.close_on_file_delete.as_ref()
2682                        },
2683                        write: |settings_content, value| {
2684                            settings_content.workspace.close_on_file_delete = value;
2685                        },
2686                    }),
2687                    metadata: None,
2688                    files: USER,
2689                }),
2690            ],
2691        },
2692        SettingsPage {
2693            title: "Window & Layout",
2694            items: vec![
2695                SettingsPageItem::SectionHeader("Status Bar"),
2696                SettingsPageItem::SettingItem(SettingItem {
2697                    title: "Project Panel Button",
2698                    description: "Show the project panel button in the status bar.",
2699                    field: Box::new(SettingField {
2700                        json_path: Some("project_panel.button"),
2701                        pick: |settings_content| {
2702                            settings_content.project_panel.as_ref()?.button.as_ref()
2703                        },
2704                        write: |settings_content, value| {
2705                            settings_content
2706                                .project_panel
2707                                .get_or_insert_default()
2708                                .button = value;
2709                        },
2710                    }),
2711                    metadata: None,
2712                    files: USER,
2713                }),
2714                SettingsPageItem::SettingItem(SettingItem {
2715                    title: "Active Language Button",
2716                    description: "Show the active language button in the status bar.",
2717                    field: Box::new(SettingField {
2718                        json_path: Some("status_bar.active_language_button"),
2719                        pick: |settings_content| {
2720                            settings_content
2721                                .status_bar
2722                                .as_ref()?
2723                                .active_language_button
2724                                .as_ref()
2725                        },
2726                        write: |settings_content, value| {
2727                            settings_content
2728                                .status_bar
2729                                .get_or_insert_default()
2730                                .active_language_button = value;
2731                        },
2732                    }),
2733                    metadata: None,
2734                    files: USER,
2735                }),
2736                SettingsPageItem::SettingItem(SettingItem {
2737                    title: "Cursor Position Button",
2738                    description: "Show the cursor position button in the status bar.",
2739                    field: Box::new(SettingField {
2740                        json_path: Some("status_bar.cursor_position_button"),
2741                        pick: |settings_content| {
2742                            settings_content
2743                                .status_bar
2744                                .as_ref()?
2745                                .cursor_position_button
2746                                .as_ref()
2747                        },
2748                        write: |settings_content, value| {
2749                            settings_content
2750                                .status_bar
2751                                .get_or_insert_default()
2752                                .cursor_position_button = value;
2753                        },
2754                    }),
2755                    metadata: None,
2756                    files: USER,
2757                }),
2758                SettingsPageItem::SettingItem(SettingItem {
2759                    title: "Terminal Button",
2760                    description: "Show the terminal button in the status bar.",
2761                    field: Box::new(SettingField {
2762                        json_path: Some("terminal.button"),
2763                        pick: |settings_content| {
2764                            settings_content.terminal.as_ref()?.button.as_ref()
2765                        },
2766                        write: |settings_content, value| {
2767                            settings_content.terminal.get_or_insert_default().button = value;
2768                        },
2769                    }),
2770                    metadata: None,
2771                    files: USER,
2772                }),
2773                SettingsPageItem::SettingItem(SettingItem {
2774                    title: "Diagnostics Button",
2775                    description: "Show the project diagnostics button in the status bar.",
2776                    field: Box::new(SettingField {
2777                        json_path: Some("diagnostics.button"),
2778                        pick: |settings_content| {
2779                            settings_content.diagnostics.as_ref()?.button.as_ref()
2780                        },
2781                        write: |settings_content, value| {
2782                            settings_content.diagnostics.get_or_insert_default().button = value;
2783                        },
2784                    }),
2785                    metadata: None,
2786                    files: USER,
2787                }),
2788                SettingsPageItem::SettingItem(SettingItem {
2789                    title: "Project Search Button",
2790                    description: "Show the project search button in the status bar.",
2791                    field: Box::new(SettingField {
2792                        json_path: Some("search.button"),
2793                        pick: |settings_content| {
2794                            settings_content.editor.search.as_ref()?.button.as_ref()
2795                        },
2796                        write: |settings_content, value| {
2797                            settings_content
2798                                .editor
2799                                .search
2800                                .get_or_insert_default()
2801                                .button = value;
2802                        },
2803                    }),
2804                    metadata: None,
2805                    files: USER,
2806                }),
2807                SettingsPageItem::SettingItem(SettingItem {
2808                    title: "Debugger Button",
2809                    description: "Show the debugger button in the status bar.",
2810                    field: Box::new(SettingField {
2811                        json_path: Some("debugger.button"),
2812                        pick: |settings_content| {
2813                            settings_content.debugger.as_ref()?.button.as_ref()
2814                        },
2815                        write: |settings_content, value| {
2816                            settings_content.debugger.get_or_insert_default().button = value;
2817                        },
2818                    }),
2819                    metadata: None,
2820                    files: USER,
2821                }),
2822                SettingsPageItem::SectionHeader("Title Bar"),
2823                SettingsPageItem::SettingItem(SettingItem {
2824                    title: "Show Branch Icon",
2825                    description: "Show the branch icon beside branch switcher in the titlebar.",
2826                    field: Box::new(SettingField {
2827                        json_path: Some("title_bar.show_branch_icon"),
2828                        pick: |settings_content| {
2829                            settings_content
2830                                .title_bar
2831                                .as_ref()?
2832                                .show_branch_icon
2833                                .as_ref()
2834                        },
2835                        write: |settings_content, value| {
2836                            settings_content
2837                                .title_bar
2838                                .get_or_insert_default()
2839                                .show_branch_icon = value;
2840                        },
2841                    }),
2842                    metadata: None,
2843                    files: USER,
2844                }),
2845                SettingsPageItem::SettingItem(SettingItem {
2846                    title: "Show Branch Name",
2847                    description: "Show the branch name button in the titlebar.",
2848                    field: Box::new(SettingField {
2849                        json_path: Some("title_bar.show_branch_name"),
2850                        pick: |settings_content| {
2851                            settings_content
2852                                .title_bar
2853                                .as_ref()?
2854                                .show_branch_name
2855                                .as_ref()
2856                        },
2857                        write: |settings_content, value| {
2858                            settings_content
2859                                .title_bar
2860                                .get_or_insert_default()
2861                                .show_branch_name = value;
2862                        },
2863                    }),
2864                    metadata: None,
2865                    files: USER,
2866                }),
2867                SettingsPageItem::SettingItem(SettingItem {
2868                    title: "Show Project Items",
2869                    description: "Show the project host and name in the titlebar.",
2870                    field: Box::new(SettingField {
2871                        json_path: Some("title_bar.show_project_items"),
2872                        pick: |settings_content| {
2873                            settings_content
2874                                .title_bar
2875                                .as_ref()?
2876                                .show_project_items
2877                                .as_ref()
2878                        },
2879                        write: |settings_content, value| {
2880                            settings_content
2881                                .title_bar
2882                                .get_or_insert_default()
2883                                .show_project_items = value;
2884                        },
2885                    }),
2886                    metadata: None,
2887                    files: USER,
2888                }),
2889                SettingsPageItem::SettingItem(SettingItem {
2890                    title: "Show Onboarding Banner",
2891                    description: "Show banners announcing new features in the titlebar.",
2892                    field: Box::new(SettingField {
2893                        json_path: Some("title_bar.show_onboarding_banner"),
2894                        pick: |settings_content| {
2895                            settings_content
2896                                .title_bar
2897                                .as_ref()?
2898                                .show_onboarding_banner
2899                                .as_ref()
2900                        },
2901                        write: |settings_content, value| {
2902                            settings_content
2903                                .title_bar
2904                                .get_or_insert_default()
2905                                .show_onboarding_banner = value;
2906                        },
2907                    }),
2908                    metadata: None,
2909                    files: USER,
2910                }),
2911                SettingsPageItem::SettingItem(SettingItem {
2912                    title: "Show User Picture",
2913                    description: "Show user picture in the titlebar.",
2914                    field: Box::new(SettingField {
2915                        json_path: Some("title_bar.show_user_picture"),
2916                        pick: |settings_content| {
2917                            settings_content
2918                                .title_bar
2919                                .as_ref()?
2920                                .show_user_picture
2921                                .as_ref()
2922                        },
2923                        write: |settings_content, value| {
2924                            settings_content
2925                                .title_bar
2926                                .get_or_insert_default()
2927                                .show_user_picture = value;
2928                        },
2929                    }),
2930                    metadata: None,
2931                    files: USER,
2932                }),
2933                SettingsPageItem::SettingItem(SettingItem {
2934                    title: "Show Sign In",
2935                    description: "Show the sign in button in the titlebar.",
2936                    field: Box::new(SettingField {
2937                        json_path: Some("title_bar.show_sign_in"),
2938                        pick: |settings_content| {
2939                            settings_content.title_bar.as_ref()?.show_sign_in.as_ref()
2940                        },
2941                        write: |settings_content, value| {
2942                            settings_content
2943                                .title_bar
2944                                .get_or_insert_default()
2945                                .show_sign_in = value;
2946                        },
2947                    }),
2948                    metadata: None,
2949                    files: USER,
2950                }),
2951                SettingsPageItem::SettingItem(SettingItem {
2952                    title: "Show Menus",
2953                    description: "Show the menus in the titlebar.",
2954                    field: Box::new(SettingField {
2955                        json_path: Some("title_bar.show_menus"),
2956                        pick: |settings_content| {
2957                            settings_content.title_bar.as_ref()?.show_menus.as_ref()
2958                        },
2959                        write: |settings_content, value| {
2960                            settings_content
2961                                .title_bar
2962                                .get_or_insert_default()
2963                                .show_menus = value;
2964                        },
2965                    }),
2966                    metadata: None,
2967                    files: USER,
2968                }),
2969                SettingsPageItem::SectionHeader("Tab Bar"),
2970                SettingsPageItem::SettingItem(SettingItem {
2971                    title: "Show Tab Bar",
2972                    description: "Show the tab bar in the editor.",
2973                    field: Box::new(SettingField {
2974                        json_path: Some("tab_bar.show"),
2975                        pick: |settings_content| settings_content.tab_bar.as_ref()?.show.as_ref(),
2976                        write: |settings_content, value| {
2977                            settings_content.tab_bar.get_or_insert_default().show = value;
2978                        },
2979                    }),
2980                    metadata: None,
2981                    files: USER,
2982                }),
2983                SettingsPageItem::SettingItem(SettingItem {
2984                    title: "Show Git Status In Tabs",
2985                    description: "Show the Git file status on a tab item.",
2986                    field: Box::new(SettingField {
2987                        json_path: Some("tabs.git_status"),
2988                        pick: |settings_content| {
2989                            settings_content.tabs.as_ref()?.git_status.as_ref()
2990                        },
2991                        write: |settings_content, value| {
2992                            settings_content.tabs.get_or_insert_default().git_status = value;
2993                        },
2994                    }),
2995                    metadata: None,
2996                    files: USER,
2997                }),
2998                SettingsPageItem::SettingItem(SettingItem {
2999                    title: "Show File Icons In Tabs",
3000                    description: "Show the file icon for a tab.",
3001                    field: Box::new(SettingField {
3002                        json_path: Some("tabs.file_icons"),
3003                        pick: |settings_content| {
3004                            settings_content.tabs.as_ref()?.file_icons.as_ref()
3005                        },
3006                        write: |settings_content, value| {
3007                            settings_content.tabs.get_or_insert_default().file_icons = value;
3008                        },
3009                    }),
3010                    metadata: None,
3011                    files: USER,
3012                }),
3013                SettingsPageItem::SettingItem(SettingItem {
3014                    title: "Tab Close Position",
3015                    description: "Position of the close button in a tab.",
3016                    field: Box::new(SettingField {
3017                        json_path: Some("tabs.close_position"),
3018                        pick: |settings_content| {
3019                            settings_content.tabs.as_ref()?.close_position.as_ref()
3020                        },
3021                        write: |settings_content, value| {
3022                            settings_content.tabs.get_or_insert_default().close_position = value;
3023                        },
3024                    }),
3025                    metadata: None,
3026                    files: USER,
3027                }),
3028                SettingsPageItem::SettingItem(SettingItem {
3029                    files: USER,
3030                    title: "Maximum Tabs",
3031                    description: "Maximum open tabs in a pane. Will not close an unsaved tab.",
3032                    // todo(settings_ui): The default for this value is null and it's use in code
3033                    // is complex, so I'm going to come back to this later
3034                    field: Box::new(
3035                        SettingField {
3036                            json_path: Some("max_tabs"),
3037                            pick: |settings_content| settings_content.workspace.max_tabs.as_ref(),
3038                            write: |settings_content, value| {
3039                                settings_content.workspace.max_tabs = value;
3040                            },
3041                        }
3042                        .unimplemented(),
3043                    ),
3044                    metadata: None,
3045                }),
3046                SettingsPageItem::SettingItem(SettingItem {
3047                    title: "Show Navigation History Buttons",
3048                    description: "Show the navigation history buttons in the tab bar.",
3049                    field: Box::new(SettingField {
3050                        json_path: Some("tab_bar.show_nav_history_buttons"),
3051                        pick: |settings_content| {
3052                            settings_content
3053                                .tab_bar
3054                                .as_ref()?
3055                                .show_nav_history_buttons
3056                                .as_ref()
3057                        },
3058                        write: |settings_content, value| {
3059                            settings_content
3060                                .tab_bar
3061                                .get_or_insert_default()
3062                                .show_nav_history_buttons = value;
3063                        },
3064                    }),
3065                    metadata: None,
3066                    files: USER,
3067                }),
3068                SettingsPageItem::SettingItem(SettingItem {
3069                    title: "Show Tab Bar Buttons",
3070                    description: "Show the tab bar buttons (New, Split Pane, Zoom).",
3071                    field: Box::new(SettingField {
3072                        json_path: Some("tab_bar.show_tab_bar_buttons"),
3073                        pick: |settings_content| {
3074                            settings_content
3075                                .tab_bar
3076                                .as_ref()?
3077                                .show_tab_bar_buttons
3078                                .as_ref()
3079                        },
3080                        write: |settings_content, value| {
3081                            settings_content
3082                                .tab_bar
3083                                .get_or_insert_default()
3084                                .show_tab_bar_buttons = value;
3085                        },
3086                    }),
3087                    metadata: None,
3088                    files: USER,
3089                }),
3090                SettingsPageItem::SectionHeader("Tab Settings"),
3091                SettingsPageItem::SettingItem(SettingItem {
3092                    title: "Activate On Close",
3093                    description: "What to do after closing the current tab.",
3094                    field: Box::new(SettingField {
3095                        json_path: Some("tabs.activate_on_close"),
3096                        pick: |settings_content| {
3097                            settings_content.tabs.as_ref()?.activate_on_close.as_ref()
3098                        },
3099                        write: |settings_content, value| {
3100                            settings_content
3101                                .tabs
3102                                .get_or_insert_default()
3103                                .activate_on_close = value;
3104                        },
3105                    }),
3106                    metadata: None,
3107                    files: USER,
3108                }),
3109                SettingsPageItem::SettingItem(SettingItem {
3110                    title: "Tab Show Diagnostics",
3111                    description: "Which files containing diagnostic errors/warnings to mark in the tabs.",
3112                    field: Box::new(SettingField {
3113                        json_path: Some("tabs.show_diagnostics"),
3114                        pick: |settings_content| {
3115                            settings_content.tabs.as_ref()?.show_diagnostics.as_ref()
3116                        },
3117                        write: |settings_content, value| {
3118                            settings_content
3119                                .tabs
3120                                .get_or_insert_default()
3121                                .show_diagnostics = value;
3122                        },
3123                    }),
3124                    metadata: None,
3125                    files: USER,
3126                }),
3127                SettingsPageItem::SettingItem(SettingItem {
3128                    title: "Show Close Button",
3129                    description: "Controls the appearance behavior of the tab's close button.",
3130                    field: Box::new(SettingField {
3131                        json_path: Some("tabs.show_close_button"),
3132                        pick: |settings_content| {
3133                            settings_content.tabs.as_ref()?.show_close_button.as_ref()
3134                        },
3135                        write: |settings_content, value| {
3136                            settings_content
3137                                .tabs
3138                                .get_or_insert_default()
3139                                .show_close_button = value;
3140                        },
3141                    }),
3142                    metadata: None,
3143                    files: USER,
3144                }),
3145                SettingsPageItem::SectionHeader("Preview Tabs"),
3146                SettingsPageItem::SettingItem(SettingItem {
3147                    title: "Preview Tabs Enabled",
3148                    description: "Show opened editors as preview tabs.",
3149                    field: Box::new(SettingField {
3150                        json_path: Some("preview_tabs.enabled"),
3151                        pick: |settings_content| {
3152                            settings_content.preview_tabs.as_ref()?.enabled.as_ref()
3153                        },
3154                        write: |settings_content, value| {
3155                            settings_content
3156                                .preview_tabs
3157                                .get_or_insert_default()
3158                                .enabled = value;
3159                        },
3160                    }),
3161                    metadata: None,
3162                    files: USER,
3163                }),
3164                SettingsPageItem::SettingItem(SettingItem {
3165                    title: "Enable Preview From Project Panel",
3166                    description: "Whether to open tabs in preview mode when opened from the project panel with a single click.",
3167                    field: Box::new(SettingField {
3168                        json_path: Some("preview_tabs.enable_preview_from_project_panel"),
3169                        pick: |settings_content| {
3170                            settings_content
3171                                .preview_tabs
3172                                .as_ref()?
3173                                .enable_preview_from_project_panel
3174                                .as_ref()
3175                        },
3176                        write: |settings_content, value| {
3177                            settings_content
3178                                .preview_tabs
3179                                .get_or_insert_default()
3180                                .enable_preview_from_project_panel = value;
3181                        },
3182                    }),
3183                    metadata: None,
3184                    files: USER,
3185                }),
3186                SettingsPageItem::SettingItem(SettingItem {
3187                    title: "Enable Preview From File Finder",
3188                    description: "Whether to open tabs in preview mode when selected from the file finder.",
3189                    field: Box::new(SettingField {
3190                        json_path: Some("preview_tabs.enable_preview_from_file_finder"),
3191                        pick: |settings_content| {
3192                            settings_content
3193                                .preview_tabs
3194                                .as_ref()?
3195                                .enable_preview_from_file_finder
3196                                .as_ref()
3197                        },
3198                        write: |settings_content, value| {
3199                            settings_content
3200                                .preview_tabs
3201                                .get_or_insert_default()
3202                                .enable_preview_from_file_finder = value;
3203                        },
3204                    }),
3205                    metadata: None,
3206                    files: USER,
3207                }),
3208                SettingsPageItem::SettingItem(SettingItem {
3209                    title: "Enable Preview From Multibuffer",
3210                    description: "Whether to open tabs in preview mode when opened from a multibuffer.",
3211                    field: Box::new(SettingField {
3212                        json_path: Some("preview_tabs.enable_preview_from_multibuffer"),
3213                        pick: |settings_content| {
3214                            settings_content
3215                                .preview_tabs
3216                                .as_ref()?
3217                                .enable_preview_from_multibuffer
3218                                .as_ref()
3219                        },
3220                        write: |settings_content, value| {
3221                            settings_content
3222                                .preview_tabs
3223                                .get_or_insert_default()
3224                                .enable_preview_from_multibuffer = value;
3225                        },
3226                    }),
3227                    metadata: None,
3228                    files: USER,
3229                }),
3230                SettingsPageItem::SettingItem(SettingItem {
3231                    title: "Enable Preview Multibuffer From Code Navigation",
3232                    description: "Whether to open tabs in preview mode when code navigation is used to open a multibuffer.",
3233                    field: Box::new(SettingField {
3234                        json_path: Some("preview_tabs.enable_preview_multibuffer_from_code_navigation"),
3235                        pick: |settings_content| {
3236                            settings_content
3237                                .preview_tabs
3238                                .as_ref()?
3239                                .enable_preview_multibuffer_from_code_navigation
3240                                .as_ref()
3241                        },
3242                        write: |settings_content, value| {
3243                            settings_content
3244                                .preview_tabs
3245                                .get_or_insert_default()
3246                                .enable_preview_multibuffer_from_code_navigation = value;
3247                        },
3248                    }),
3249                    metadata: None,
3250                    files: USER,
3251                }),
3252                SettingsPageItem::SettingItem(SettingItem {
3253                    title: "Enable Preview File From Code Navigation",
3254                    description: "Whether to open tabs in preview mode when code navigation is used to open a single file.",
3255                    field: Box::new(SettingField {
3256                        json_path: Some("preview_tabs.enable_preview_file_from_code_navigation"),
3257                        pick: |settings_content| {
3258                            settings_content
3259                                .preview_tabs
3260                                .as_ref()?
3261                                .enable_preview_file_from_code_navigation
3262                                .as_ref()
3263                        },
3264                        write: |settings_content, value| {
3265                            settings_content
3266                                .preview_tabs
3267                                .get_or_insert_default()
3268                                .enable_preview_file_from_code_navigation = value;
3269                        },
3270                    }),
3271                    metadata: None,
3272                    files: USER,
3273                }),
3274                SettingsPageItem::SettingItem(SettingItem {
3275                    title: "Enable Keep Preview On Code Navigation",
3276                    description: "Whether to keep tabs in preview mode when code navigation is used to navigate away from them. If `enable_preview_file_from_code_navigation` or `enable_preview_multibuffer_from_code_navigation` is also true, the new tab may replace the existing one.",
3277                    field: Box::new(SettingField {
3278                        json_path: Some("preview_tabs.enable_keep_preview_on_code_navigation"),
3279                        pick: |settings_content| {
3280                            settings_content
3281                                .preview_tabs
3282                                .as_ref()?
3283                                .enable_keep_preview_on_code_navigation
3284                                .as_ref()
3285                        },
3286                        write: |settings_content, value| {
3287                            settings_content
3288                                .preview_tabs
3289                                .get_or_insert_default()
3290                                .enable_keep_preview_on_code_navigation = value;
3291                        },
3292                    }),
3293                    metadata: None,
3294                    files: USER,
3295                }),
3296                SettingsPageItem::SectionHeader("Layout"),
3297                SettingsPageItem::SettingItem(SettingItem {
3298                    title: "Bottom Dock Layout",
3299                    description: "Layout mode for the bottom dock.",
3300                    field: Box::new(SettingField {
3301                        json_path: Some("bottom_dock_layout"),
3302                        pick: |settings_content| {
3303                            settings_content.workspace.bottom_dock_layout.as_ref()
3304                        },
3305                        write: |settings_content, value| {
3306                            settings_content.workspace.bottom_dock_layout = value;
3307                        },
3308                    }),
3309                    metadata: None,
3310                    files: USER,
3311                }),
3312                SettingsPageItem::SettingItem(SettingItem {
3313                    files: USER,
3314                    title: "Centered Layout Left Padding",
3315                    description: "Left padding for centered layout.",
3316                    field: Box::new(SettingField {
3317                        json_path: Some("centered_layout.left_padding"),
3318                        pick: |settings_content| {
3319                            settings_content
3320                                .workspace
3321                                .centered_layout
3322                                .as_ref()?
3323                                .left_padding
3324                                .as_ref()
3325                        },
3326                        write: |settings_content, value| {
3327                            settings_content
3328                                .workspace
3329                                .centered_layout
3330                                .get_or_insert_default()
3331                                .left_padding = value;
3332                        },
3333                    }),
3334                    metadata: None,
3335                }),
3336                SettingsPageItem::SettingItem(SettingItem {
3337                    files: USER,
3338                    title: "Centered Layout Right Padding",
3339                    description: "Right padding for centered layout.",
3340                    field: Box::new(SettingField {
3341                        json_path: Some("centered_layout.right_padding"),
3342                        pick: |settings_content| {
3343                            settings_content
3344                                .workspace
3345                                .centered_layout
3346                                .as_ref()?
3347                                .right_padding
3348                                .as_ref()
3349                        },
3350                        write: |settings_content, value| {
3351                            settings_content
3352                                .workspace
3353                                .centered_layout
3354                                .get_or_insert_default()
3355                                .right_padding = value;
3356                        },
3357                    }),
3358                    metadata: None,
3359                }),
3360                SettingsPageItem::SectionHeader("Window"),
3361                // todo(settings_ui): Should we filter by platform.as_ref()?
3362                SettingsPageItem::SettingItem(SettingItem {
3363                    title: "Use System Window Tabs",
3364                    description: "(macOS only) whether to allow Windows to tab together.",
3365                    field: Box::new(SettingField {
3366                        json_path: Some("use_system_window_tabs"),
3367                        pick: |settings_content| {
3368                            settings_content.workspace.use_system_window_tabs.as_ref()
3369                        },
3370                        write: |settings_content, value| {
3371                            settings_content.workspace.use_system_window_tabs = value;
3372                        },
3373                    }),
3374                    metadata: None,
3375                    files: USER,
3376                }),
3377                SettingsPageItem::SettingItem(SettingItem {
3378                    title: "Window Decorations",
3379                    description: "(Linux only) whether Zed or your compositor should draw window decorations.",
3380                    field: Box::new(SettingField {
3381                        json_path: Some("window_decorations"),
3382                        pick: |settings_content| {
3383                            settings_content.workspace.window_decorations.as_ref()
3384                        },
3385                        write: |settings_content, value| {
3386                            settings_content.workspace.window_decorations = value;
3387                        },
3388                    }),
3389                    metadata: None,
3390                    files: USER,
3391                }),
3392                SettingsPageItem::SectionHeader("Pane Modifiers"),
3393                SettingsPageItem::SettingItem(SettingItem {
3394                    title: "Inactive Opacity",
3395                    description: "Opacity of inactive panels (0.0 - 1.0).",
3396                    field: Box::new(SettingField {
3397                        json_path: Some("active_pane_modifiers.inactive_opacity"),
3398                        pick: |settings_content| {
3399                            settings_content
3400                                .workspace
3401                                .active_pane_modifiers
3402                                .as_ref()?
3403                                .inactive_opacity
3404                                .as_ref()
3405                        },
3406                        write: |settings_content, value| {
3407                            settings_content
3408                                .workspace
3409                                .active_pane_modifiers
3410                                .get_or_insert_default()
3411                                .inactive_opacity = value;
3412                        },
3413                    }),
3414                    metadata: None,
3415                    files: USER,
3416                }),
3417                SettingsPageItem::SettingItem(SettingItem {
3418                    title: "Border Size",
3419                    description: "Size of the border surrounding the active pane.",
3420                    field: Box::new(SettingField {
3421                        json_path: Some("active_pane_modifiers.border_size"),
3422                        pick: |settings_content| {
3423                            settings_content
3424                                .workspace
3425                                .active_pane_modifiers
3426                                .as_ref()?
3427                                .border_size
3428                                .as_ref()
3429                        },
3430                        write: |settings_content, value| {
3431                            settings_content
3432                                .workspace
3433                                .active_pane_modifiers
3434                                .get_or_insert_default()
3435                                .border_size = value;
3436                        },
3437                    }),
3438                    metadata: None,
3439                    files: USER,
3440                }),
3441                SettingsPageItem::SettingItem(SettingItem {
3442                    title: "Zoomed Padding",
3443                    description: "Show padding for zoomed panes.",
3444                    field: Box::new(SettingField {
3445                        json_path: Some("zoomed_padding"),
3446                        pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
3447                        write: |settings_content, value| {
3448                            settings_content.workspace.zoomed_padding = value;
3449                        },
3450                    }),
3451                    metadata: None,
3452                    files: USER,
3453                }),
3454                SettingsPageItem::SectionHeader("Pane Split Direction"),
3455                SettingsPageItem::SettingItem(SettingItem {
3456                    title: "Vertical Split Direction",
3457                    description: "Direction to split vertically.",
3458                    field: Box::new(SettingField {
3459                        json_path: Some("pane_split_direction_vertical"),
3460                        pick: |settings_content| {
3461                            settings_content
3462                                .workspace
3463                                .pane_split_direction_vertical
3464                                .as_ref()
3465                        },
3466                        write: |settings_content, value| {
3467                            settings_content.workspace.pane_split_direction_vertical = value;
3468                        },
3469                    }),
3470                    metadata: None,
3471                    files: USER,
3472                }),
3473                SettingsPageItem::SettingItem(SettingItem {
3474                    title: "Horizontal Split Direction",
3475                    description: "Direction to split horizontally.",
3476                    field: Box::new(SettingField {
3477                        json_path: Some("pane_split_direction_horizontal"),
3478                        pick: |settings_content| {
3479                            settings_content
3480                                .workspace
3481                                .pane_split_direction_horizontal
3482                                .as_ref()
3483                        },
3484                        write: |settings_content, value| {
3485                            settings_content.workspace.pane_split_direction_horizontal = value;
3486                        },
3487                    }),
3488                    metadata: None,
3489                    files: USER,
3490                }),
3491            ],
3492        },
3493        SettingsPage {
3494            title: "Panels",
3495            items: vec![
3496                SettingsPageItem::SectionHeader("Project Panel"),
3497                SettingsPageItem::SettingItem(SettingItem {
3498                    title: "Project Panel Dock",
3499                    description: "Where to dock the project panel.",
3500                    field: Box::new(SettingField {
3501                        json_path: Some("project_panel.dock"),
3502                        pick: |settings_content| {
3503                            settings_content.project_panel.as_ref()?.dock.as_ref()
3504                        },
3505                        write: |settings_content, value| {
3506                            settings_content.project_panel.get_or_insert_default().dock = value;
3507                        },
3508                    }),
3509                    metadata: None,
3510                    files: USER,
3511                }),
3512                SettingsPageItem::SettingItem(SettingItem {
3513                    title: "Project Panel Default Width",
3514                    description: "Default width of the project panel in pixels.",
3515                    field: Box::new(SettingField {
3516                        json_path: Some("project_panel.default_width"),
3517                        pick: |settings_content| {
3518                            settings_content
3519                                .project_panel
3520                                .as_ref()?
3521                                .default_width
3522                                .as_ref()
3523                        },
3524                        write: |settings_content, value| {
3525                            settings_content
3526                                .project_panel
3527                                .get_or_insert_default()
3528                                .default_width = value;
3529                        },
3530                    }),
3531                    metadata: None,
3532                    files: USER,
3533                }),
3534                SettingsPageItem::SettingItem(SettingItem {
3535                    title: "Hide .gitignore",
3536                    description: "Whether to hide the gitignore entries in the project panel.",
3537                    field: Box::new(SettingField {
3538                        json_path: Some("project_panel.hide_gitignore"),
3539                        pick: |settings_content| {
3540                            settings_content
3541                                .project_panel
3542                                .as_ref()?
3543                                .hide_gitignore
3544                                .as_ref()
3545                        },
3546                        write: |settings_content, value| {
3547                            settings_content
3548                                .project_panel
3549                                .get_or_insert_default()
3550                                .hide_gitignore = value;
3551                        },
3552                    }),
3553                    metadata: None,
3554                    files: USER,
3555                }),
3556                SettingsPageItem::SettingItem(SettingItem {
3557                    title: "Entry Spacing",
3558                    description: "Spacing between worktree entries in the project panel.",
3559                    field: Box::new(SettingField {
3560                        json_path: Some("project_panel.entry_spacing"),
3561                        pick: |settings_content| {
3562                            settings_content
3563                                .project_panel
3564                                .as_ref()?
3565                                .entry_spacing
3566                                .as_ref()
3567                        },
3568                        write: |settings_content, value| {
3569                            settings_content
3570                                .project_panel
3571                                .get_or_insert_default()
3572                                .entry_spacing = value;
3573                        },
3574                    }),
3575                    metadata: None,
3576                    files: USER,
3577                }),
3578                SettingsPageItem::SettingItem(SettingItem {
3579                    title: "File Icons",
3580                    description: "Show file icons in the project panel.",
3581                    field: Box::new(SettingField {
3582                        json_path: Some("project_panel.file_icons"),
3583                        pick: |settings_content| {
3584                            settings_content.project_panel.as_ref()?.file_icons.as_ref()
3585                        },
3586                        write: |settings_content, value| {
3587                            settings_content
3588                                .project_panel
3589                                .get_or_insert_default()
3590                                .file_icons = value;
3591                        },
3592                    }),
3593                    metadata: None,
3594                    files: USER,
3595                }),
3596                SettingsPageItem::SettingItem(SettingItem {
3597                    title: "Folder Icons",
3598                    description: "Whether to show folder icons or chevrons for directories in the project panel.",
3599                    field: Box::new(SettingField {
3600                        json_path: Some("project_panel.folder_icons"),
3601                        pick: |settings_content| {
3602                            settings_content
3603                                .project_panel
3604                                .as_ref()?
3605                                .folder_icons
3606                                .as_ref()
3607                        },
3608                        write: |settings_content, value| {
3609                            settings_content
3610                                .project_panel
3611                                .get_or_insert_default()
3612                                .folder_icons = value;
3613                        },
3614                    }),
3615                    metadata: None,
3616                    files: USER,
3617                }),
3618                SettingsPageItem::SettingItem(SettingItem {
3619                    title: "Git Status",
3620                    description: "Show the Git status in the project panel.",
3621                    field: Box::new(SettingField {
3622                        json_path: Some("project_panel.git_status"),
3623                        pick: |settings_content| {
3624                            settings_content.project_panel.as_ref()?.git_status.as_ref()
3625                        },
3626                        write: |settings_content, value| {
3627                            settings_content
3628                                .project_panel
3629                                .get_or_insert_default()
3630                                .git_status = value;
3631                        },
3632                    }),
3633                    metadata: None,
3634                    files: USER,
3635                }),
3636                SettingsPageItem::SettingItem(SettingItem {
3637                    title: "Indent Size",
3638                    description: "Amount of indentation for nested items.",
3639                    field: Box::new(SettingField {
3640                        json_path: Some("project_panel.indent_size"),
3641                        pick: |settings_content| {
3642                            settings_content
3643                                .project_panel
3644                                .as_ref()?
3645                                .indent_size
3646                                .as_ref()
3647                        },
3648                        write: |settings_content, value| {
3649                            settings_content
3650                                .project_panel
3651                                .get_or_insert_default()
3652                                .indent_size = value;
3653                        },
3654                    }),
3655                    metadata: None,
3656                    files: USER,
3657                }),
3658                SettingsPageItem::SettingItem(SettingItem {
3659                    title: "Auto Reveal Entries",
3660                    description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
3661                    field: Box::new(SettingField {
3662                        json_path: Some("project_panel.auto_reveal_entries"),
3663                        pick: |settings_content| {
3664                            settings_content
3665                                .project_panel
3666                                .as_ref()?
3667                                .auto_reveal_entries
3668                                .as_ref()
3669                        },
3670                        write: |settings_content, value| {
3671                            settings_content
3672                                .project_panel
3673                                .get_or_insert_default()
3674                                .auto_reveal_entries = value;
3675                        },
3676                    }),
3677                    metadata: None,
3678                    files: USER,
3679                }),
3680                SettingsPageItem::SettingItem(SettingItem {
3681                    title: "Starts Open",
3682                    description: "Whether the project panel should open on startup.",
3683                    field: Box::new(SettingField {
3684                        json_path: Some("project_panel.starts_open"),
3685                        pick: |settings_content| {
3686                            settings_content
3687                                .project_panel
3688                                .as_ref()?
3689                                .starts_open
3690                                .as_ref()
3691                        },
3692                        write: |settings_content, value| {
3693                            settings_content
3694                                .project_panel
3695                                .get_or_insert_default()
3696                                .starts_open = value;
3697                        },
3698                    }),
3699                    metadata: None,
3700                    files: USER,
3701                }),
3702                SettingsPageItem::SettingItem(SettingItem {
3703                    title: "Auto Fold Directories",
3704                    description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
3705                    field: Box::new(SettingField {
3706                        json_path: Some("project_panel.auto_fold_dirs"),
3707                        pick: |settings_content| {
3708                            settings_content
3709                                .project_panel
3710                                .as_ref()?
3711                                .auto_fold_dirs
3712                                .as_ref()
3713                        },
3714                        write: |settings_content, value| {
3715                            settings_content
3716                                .project_panel
3717                                .get_or_insert_default()
3718                                .auto_fold_dirs = value;
3719                        },
3720                    }),
3721                    metadata: None,
3722                    files: USER,
3723                }),
3724                SettingsPageItem::SettingItem(SettingItem {
3725                    title: "Show Scrollbar",
3726                    description: "Show the scrollbar in the project panel.",
3727                    field: Box::new(SettingField {
3728                        json_path: Some("project_panel.scrollbar.show"),
3729                        pick: |settings_content| {
3730                            show_scrollbar_or_editor(settings_content, |settings_content| {
3731                                settings_content
3732                                    .project_panel
3733                                    .as_ref()?
3734                                    .scrollbar
3735                                    .as_ref()?
3736                                    .show
3737                                    .as_ref()
3738                            })
3739                        },
3740                        write: |settings_content, value| {
3741                            settings_content
3742                                .project_panel
3743                                .get_or_insert_default()
3744                                .scrollbar
3745                                .get_or_insert_default()
3746                                .show = value;
3747                        },
3748                    }),
3749                    metadata: None,
3750                    files: USER,
3751                }),
3752                SettingsPageItem::SettingItem(SettingItem {
3753                    title: "Show Diagnostics",
3754                    description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
3755                    field: Box::new(SettingField {
3756                        json_path: Some("project_panel.show_diagnostics"),
3757                        pick: |settings_content| {
3758                            settings_content
3759                                .project_panel
3760                                .as_ref()?
3761                                .show_diagnostics
3762                                .as_ref()
3763                        },
3764                        write: |settings_content, value| {
3765                            settings_content
3766                                .project_panel
3767                                .get_or_insert_default()
3768                                .show_diagnostics = value;
3769                        },
3770                    }),
3771                    metadata: None,
3772                    files: USER,
3773                }),
3774                SettingsPageItem::SettingItem(SettingItem {
3775                    title: "Sticky Scroll",
3776                    description: "Whether to stick parent directories at top of the project panel.",
3777                    field: Box::new(SettingField {
3778                        json_path: Some("project_panel.sticky_scroll"),
3779                        pick: |settings_content| {
3780                            settings_content
3781                                .project_panel
3782                                .as_ref()?
3783                                .sticky_scroll
3784                                .as_ref()
3785                        },
3786                        write: |settings_content, value| {
3787                            settings_content
3788                                .project_panel
3789                                .get_or_insert_default()
3790                                .sticky_scroll = value;
3791                        },
3792                    }),
3793                    metadata: None,
3794                    files: USER,
3795                }),
3796                SettingsPageItem::SettingItem(SettingItem {
3797                    files: USER,
3798                    title: "Show Indent Guides",
3799                    description: "Show indent guides in the project panel.",
3800                    field: Box::new(
3801                        SettingField {
3802                            json_path: Some("project_panel.indent_guides.show"),
3803                            pick: |settings_content| {
3804                                settings_content
3805                                    .project_panel
3806                                    .as_ref()?
3807                                    .indent_guides
3808                                    .as_ref()?
3809                                    .show
3810                                    .as_ref()
3811                            },
3812                            write: |settings_content, value| {
3813                                settings_content
3814                                    .project_panel
3815                                    .get_or_insert_default()
3816                                    .indent_guides
3817                                    .get_or_insert_default()
3818                                    .show = value;
3819                            },
3820                        }
3821                    ),
3822                    metadata: None,
3823                }),
3824                SettingsPageItem::SettingItem(SettingItem {
3825                    title: "Drag and Drop",
3826                    description: "Whether to enable drag-and-drop operations in the project panel.",
3827                    field: Box::new(SettingField {
3828                        json_path: Some("project_panel.drag_and_drop"),
3829                        pick: |settings_content| {
3830                            settings_content
3831                                .project_panel
3832                                .as_ref()?
3833                                .drag_and_drop
3834                                .as_ref()
3835                        },
3836                        write: |settings_content, value| {
3837                            settings_content
3838                                .project_panel
3839                                .get_or_insert_default()
3840                                .drag_and_drop = value;
3841                        },
3842                    }),
3843                    metadata: None,
3844                    files: USER,
3845                }),
3846                SettingsPageItem::SettingItem(SettingItem {
3847                    title: "Hide Root",
3848                    description: "Whether to hide the root entry when only one folder is open in the window.",
3849                    field: Box::new(SettingField {
3850                        json_path: Some("project_panel.drag_and_drop"),
3851                        pick: |settings_content| {
3852                            settings_content.project_panel.as_ref()?.hide_root.as_ref()
3853                        },
3854                        write: |settings_content, value| {
3855                            settings_content
3856                                .project_panel
3857                                .get_or_insert_default()
3858                                .hide_root = value;
3859                        },
3860                    }),
3861                    metadata: None,
3862                    files: USER,
3863                }),
3864                SettingsPageItem::SettingItem(SettingItem {
3865                    title: "Hide Hidden",
3866                    description: "Whether to hide the hidden entries in the project panel.",
3867                    field: Box::new(SettingField {
3868                        json_path: Some("project_panel.hide_hidden"),
3869                        pick: |settings_content| {
3870                            settings_content
3871                                .project_panel
3872                                .as_ref()?
3873                                .hide_hidden
3874                                .as_ref()
3875                        },
3876                        write: |settings_content, value| {
3877                            settings_content
3878                                .project_panel
3879                                .get_or_insert_default()
3880                                .hide_hidden = value;
3881                        },
3882                    }),
3883                    metadata: None,
3884                    files: USER,
3885                }),
3886                SettingsPageItem::SettingItem(SettingItem {
3887                    title: "Hidden Files",
3888                    description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
3889                    field: Box::new(
3890                        SettingField {
3891                            json_path: Some("worktree.hidden_files"),
3892                            pick: |settings_content| {
3893                                settings_content.project.worktree.hidden_files.as_ref()
3894                            },
3895                            write: |settings_content, value| {
3896                                settings_content.project.worktree.hidden_files = value;
3897                            },
3898                        }
3899                        .unimplemented(),
3900                    ),
3901                    metadata: None,
3902                    files: USER,
3903                }),
3904                SettingsPageItem::SectionHeader("Auto Open Files"),
3905                SettingsPageItem::SettingItem(SettingItem {
3906                    title: "On Create",
3907                    description: "Whether to automatically open newly created files in the editor.",
3908                    field: Box::new(SettingField {
3909                        json_path: Some("project_panel.auto_open.on_create"),
3910                        pick: |settings_content| {
3911                            settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_create.as_ref()
3912                        },
3913                        write: |settings_content, value| {
3914                            settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_create = value;
3915                        },
3916                    }),
3917                    metadata: None,
3918                    files: USER,
3919                }),
3920                SettingsPageItem::SettingItem(SettingItem {
3921                    title: "On Paste",
3922                    description: "Whether to automatically open files after pasting or duplicating them.",
3923                    field: Box::new(SettingField {
3924                        json_path: Some("project_panel.auto_open.on_paste"),
3925                        pick: |settings_content| {
3926                            settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_paste.as_ref()
3927                        },
3928                        write: |settings_content, value| {
3929                            settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_paste = value;
3930                        },
3931                    }),
3932                    metadata: None,
3933                    files: USER,
3934                }),
3935                SettingsPageItem::SettingItem(SettingItem {
3936                    title: "On Drop",
3937                    description: "Whether to automatically open files dropped from external sources.",
3938                    field: Box::new(SettingField {
3939                        json_path: Some("project_panel.auto_open.on_drop"),
3940                        pick: |settings_content| {
3941                            settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_drop.as_ref()
3942                        },
3943                        write: |settings_content, value| {
3944                            settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_drop = value;
3945                        },
3946                    }),
3947                    metadata: None,
3948                    files: USER,
3949                }),
3950                SettingsPageItem::SettingItem(SettingItem {
3951                    title: "Sort Mode",
3952                    description: "Sort order for entries in the project panel.",
3953                    field: Box::new(SettingField {
3954                        pick: |settings_content| {
3955                            settings_content.project_panel.as_ref()?.sort_mode.as_ref()
3956                        },
3957                        write: |settings_content, value| {
3958                            settings_content
3959                                .project_panel
3960                                .get_or_insert_default()
3961                                .sort_mode = value;
3962                        },
3963                        json_path: Some("project_panel.sort_mode"),
3964                    }),
3965                    metadata: None,
3966                    files: USER,
3967                }),
3968                SettingsPageItem::SectionHeader("Terminal Panel"),
3969                SettingsPageItem::SettingItem(SettingItem {
3970                    title: "Terminal Dock",
3971                    description: "Where to dock the terminal panel.",
3972                    field: Box::new(SettingField {
3973                        json_path: Some("terminal.dock"),
3974                        pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
3975                        write: |settings_content, value| {
3976                            settings_content.terminal.get_or_insert_default().dock = value;
3977                        },
3978                    }),
3979                    metadata: None,
3980                    files: USER,
3981                }),
3982                SettingsPageItem::SectionHeader("Outline Panel"),
3983                SettingsPageItem::SettingItem(SettingItem {
3984                    title: "Outline Panel Button",
3985                    description: "Show the outline panel button in the status bar.",
3986                    field: Box::new(SettingField {
3987                        json_path: Some("outline_panel.button"),
3988                        pick: |settings_content| {
3989                            settings_content.outline_panel.as_ref()?.button.as_ref()
3990                        },
3991                        write: |settings_content, value| {
3992                            settings_content
3993                                .outline_panel
3994                                .get_or_insert_default()
3995                                .button = value;
3996                        },
3997                    }),
3998                    metadata: None,
3999                    files: USER,
4000                }),
4001                SettingsPageItem::SettingItem(SettingItem {
4002                    title: "Outline Panel Dock",
4003                    description: "Where to dock the outline panel.",
4004                    field: Box::new(SettingField {
4005                        json_path: Some("outline_panel.dock"),
4006                        pick: |settings_content| {
4007                            settings_content.outline_panel.as_ref()?.dock.as_ref()
4008                        },
4009                        write: |settings_content, value| {
4010                            settings_content.outline_panel.get_or_insert_default().dock = value;
4011                        },
4012                    }),
4013                    metadata: None,
4014                    files: USER,
4015                }),
4016                SettingsPageItem::SettingItem(SettingItem {
4017                    title: "Outline Panel Default Width",
4018                    description: "Default width of the outline panel in pixels.",
4019                    field: Box::new(SettingField {
4020                        json_path: Some("outline_panel.default_width"),
4021                        pick: |settings_content| {
4022                            settings_content
4023                                .outline_panel
4024                                .as_ref()?
4025                                .default_width
4026                                .as_ref()
4027                        },
4028                        write: |settings_content, value| {
4029                            settings_content
4030                                .outline_panel
4031                                .get_or_insert_default()
4032                                .default_width = value;
4033                        },
4034                    }),
4035                    metadata: None,
4036                    files: USER,
4037                }),
4038                SettingsPageItem::SettingItem(SettingItem {
4039                    title: "File Icons",
4040                    description: "Show file icons in the outline panel.",
4041                    field: Box::new(SettingField {
4042                        json_path: Some("outline_panel.file_icons"),
4043                        pick: |settings_content| {
4044                            settings_content.outline_panel.as_ref()?.file_icons.as_ref()
4045                        },
4046                        write: |settings_content, value| {
4047                            settings_content
4048                                .outline_panel
4049                                .get_or_insert_default()
4050                                .file_icons = value;
4051                        },
4052                    }),
4053                    metadata: None,
4054                    files: USER,
4055                }),
4056                SettingsPageItem::SettingItem(SettingItem {
4057                    title: "Folder Icons",
4058                    description: "Whether to show folder icons or chevrons for directories in the outline panel.",
4059                    field: Box::new(SettingField {
4060                        json_path: Some("outline_panel.folder_icons"),
4061                        pick: |settings_content| {
4062                            settings_content
4063                                .outline_panel
4064                                .as_ref()?
4065                                .folder_icons
4066                                .as_ref()
4067                        },
4068                        write: |settings_content, value| {
4069                            settings_content
4070                                .outline_panel
4071                                .get_or_insert_default()
4072                                .folder_icons = value;
4073                        },
4074                    }),
4075                    metadata: None,
4076                    files: USER,
4077                }),
4078                SettingsPageItem::SettingItem(SettingItem {
4079                    title: "Git Status",
4080                    description: "Show the Git status in the outline panel.",
4081                    field: Box::new(SettingField {
4082                        json_path: Some("outline_panel.git_status"),
4083                        pick: |settings_content| {
4084                            settings_content.outline_panel.as_ref()?.git_status.as_ref()
4085                        },
4086                        write: |settings_content, value| {
4087                            settings_content
4088                                .outline_panel
4089                                .get_or_insert_default()
4090                                .git_status = value;
4091                        },
4092                    }),
4093                    metadata: None,
4094                    files: USER,
4095                }),
4096                SettingsPageItem::SettingItem(SettingItem {
4097                    title: "Indent Size",
4098                    description: "Amount of indentation for nested items.",
4099                    field: Box::new(SettingField {
4100                        json_path: Some("outline_panel.indent_size"),
4101                        pick: |settings_content| {
4102                            settings_content
4103                                .outline_panel
4104                                .as_ref()?
4105                                .indent_size
4106                                .as_ref()
4107                        },
4108                        write: |settings_content, value| {
4109                            settings_content
4110                                .outline_panel
4111                                .get_or_insert_default()
4112                                .indent_size = value;
4113                        },
4114                    }),
4115                    metadata: None,
4116                    files: USER,
4117                }),
4118                SettingsPageItem::SettingItem(SettingItem {
4119                    title: "Auto Reveal Entries",
4120                    description: "Whether to reveal when a corresponding outline entry becomes active.",
4121                    field: Box::new(SettingField {
4122                        json_path: Some("outline_panel.auto_reveal_entries"),
4123                        pick: |settings_content| {
4124                            settings_content
4125                                .outline_panel
4126                                .as_ref()?
4127                                .auto_reveal_entries
4128                                .as_ref()
4129                        },
4130                        write: |settings_content, value| {
4131                            settings_content
4132                                .outline_panel
4133                                .get_or_insert_default()
4134                                .auto_reveal_entries = value;
4135                        },
4136                    }),
4137                    metadata: None,
4138                    files: USER,
4139                }),
4140                SettingsPageItem::SettingItem(SettingItem {
4141                    title: "Auto Fold Directories",
4142                    description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
4143                    field: Box::new(SettingField {
4144                        json_path: Some("outline_panel.auto_fold_dirs"),
4145                        pick: |settings_content| {
4146                            settings_content
4147                                .outline_panel
4148                                .as_ref()?
4149                                .auto_fold_dirs
4150                                .as_ref()
4151                        },
4152                        write: |settings_content, value| {
4153                            settings_content
4154                                .outline_panel
4155                                .get_or_insert_default()
4156                                .auto_fold_dirs = value;
4157                        },
4158                    }),
4159                    metadata: None,
4160                    files: USER,
4161                }),
4162                SettingsPageItem::SettingItem(SettingItem {
4163                    files: USER,
4164                    title: "Show Indent Guides",
4165                    description: "When to show indent guides in the outline panel.",
4166                    field: Box::new(
4167                        SettingField {
4168                            json_path: Some("outline_panel.indent_guides.show"),
4169                            pick: |settings_content| {
4170                                settings_content
4171                                    .outline_panel
4172                                    .as_ref()?
4173                                    .indent_guides
4174                                    .as_ref()?
4175                                    .show
4176                                    .as_ref()
4177                            },
4178                            write: |settings_content, value| {
4179                                settings_content
4180                                    .outline_panel
4181                                    .get_or_insert_default()
4182                                    .indent_guides
4183                                    .get_or_insert_default()
4184                                    .show = value;
4185                            },
4186                        }
4187                    ),
4188                    metadata: None,
4189                }),
4190                SettingsPageItem::SectionHeader("Git Panel"),
4191                SettingsPageItem::SettingItem(SettingItem {
4192                    title: "Git Panel Button",
4193                    description: "Show the Git panel button in the status bar.",
4194                    field: Box::new(SettingField {
4195                        json_path: Some("git_panel.button"),
4196                        pick: |settings_content| {
4197                            settings_content.git_panel.as_ref()?.button.as_ref()
4198                        },
4199                        write: |settings_content, value| {
4200                            settings_content.git_panel.get_or_insert_default().button = value;
4201                        },
4202                    }),
4203                    metadata: None,
4204                    files: USER,
4205                }),
4206                SettingsPageItem::SettingItem(SettingItem {
4207                    title: "Git Panel Dock",
4208                    description: "Where to dock the Git panel.",
4209                    field: Box::new(SettingField {
4210                        json_path: Some("git_panel.dock"),
4211                        pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
4212                        write: |settings_content, value| {
4213                            settings_content.git_panel.get_or_insert_default().dock = value;
4214                        },
4215                    }),
4216                    metadata: None,
4217                    files: USER,
4218                }),
4219                SettingsPageItem::SettingItem(SettingItem {
4220                    title: "Git Panel Default Width",
4221                    description: "Default width of the Git panel in pixels.",
4222                    field: Box::new(SettingField {
4223                        json_path: Some("git_panel.default_width"),
4224                        pick: |settings_content| {
4225                            settings_content.git_panel.as_ref()?.default_width.as_ref()
4226                        },
4227                        write: |settings_content, value| {
4228                            settings_content
4229                                .git_panel
4230                                .get_or_insert_default()
4231                                .default_width = value;
4232                        },
4233                    }),
4234                    metadata: None,
4235                    files: USER,
4236                }),
4237                SettingsPageItem::SettingItem(SettingItem {
4238                    title: "Git Panel Status Style",
4239                    description: "How entry statuses are displayed.",
4240                    field: Box::new(SettingField {
4241                        json_path: Some("git_panel.status_style"),
4242                        pick: |settings_content| {
4243                            settings_content.git_panel.as_ref()?.status_style.as_ref()
4244                        },
4245                        write: |settings_content, value| {
4246                            settings_content
4247                                .git_panel
4248                                .get_or_insert_default()
4249                                .status_style = value;
4250                        },
4251                    }),
4252                    metadata: None,
4253                    files: USER,
4254                }),
4255                SettingsPageItem::SettingItem(SettingItem {
4256                    title: "Fallback Branch Name",
4257                    description: "Default branch name will be when init.defaultbranch is not set in Git.",
4258                    field: Box::new(SettingField {
4259                        json_path: Some("git_panel.fallback_branch_name"),
4260                        pick: |settings_content| {
4261                            settings_content
4262                                .git_panel
4263                                .as_ref()?
4264                                .fallback_branch_name
4265                                .as_ref()
4266                        },
4267                        write: |settings_content, value| {
4268                            settings_content
4269                                .git_panel
4270                                .get_or_insert_default()
4271                                .fallback_branch_name = value;
4272                        },
4273                    }),
4274                    metadata: None,
4275                    files: USER,
4276                }),
4277                SettingsPageItem::SettingItem(SettingItem {
4278                    title: "Sort By Path",
4279                    description: "Enable to sort entries in the panel by path, disable to sort by status.",
4280                    field: Box::new(SettingField {
4281                        json_path: Some("git_panel.sort_by_path"),
4282                        pick: |settings_content| {
4283                            settings_content.git_panel.as_ref()?.sort_by_path.as_ref()
4284                        },
4285                        write: |settings_content, value| {
4286                            settings_content
4287                                .git_panel
4288                                .get_or_insert_default()
4289                                .sort_by_path = value;
4290                        },
4291                    }),
4292                    metadata: None,
4293                    files: USER,
4294                }),
4295                SettingsPageItem::SettingItem(SettingItem {
4296                    title: "Collapse Untracked Diff",
4297                    description: "Whether to collapse untracked files in the diff panel.",
4298                    field: Box::new(SettingField {
4299                        json_path: Some("git_panel.collapse_untracked_diff"),
4300                        pick: |settings_content| {
4301                            settings_content
4302                                .git_panel
4303                                .as_ref()?
4304                                .collapse_untracked_diff
4305                                .as_ref()
4306                        },
4307                        write: |settings_content, value| {
4308                            settings_content
4309                                .git_panel
4310                                .get_or_insert_default()
4311                                .collapse_untracked_diff = value;
4312                        },
4313                    }),
4314                    metadata: None,
4315                    files: USER,
4316                }),
4317                SettingsPageItem::SettingItem(SettingItem {
4318                    title: "Scroll Bar",
4319                    description: "How and when the scrollbar should be displayed.",
4320                    field: Box::new(SettingField {
4321                        json_path: Some("git_panel.scrollbar.show"),
4322                        pick: |settings_content| {
4323                            show_scrollbar_or_editor(settings_content, |settings_content| {
4324                                settings_content
4325                                    .git_panel
4326                                    .as_ref()?
4327                                    .scrollbar
4328                                    .as_ref()?
4329                                    .show
4330                                    .as_ref()
4331                            })
4332                        },
4333                        write: |settings_content, value| {
4334                            settings_content
4335                                .git_panel
4336                                .get_or_insert_default()
4337                                .scrollbar
4338                                .get_or_insert_default()
4339                                .show = value;
4340                        },
4341                    }),
4342                    metadata: None,
4343                    files: USER,
4344                }),
4345                SettingsPageItem::SectionHeader("Debugger Panel"),
4346                SettingsPageItem::SettingItem(SettingItem {
4347                    title: "Debugger Panel Dock",
4348                    description: "The dock position of the debug panel.",
4349                    field: Box::new(SettingField {
4350                        json_path: Some("debugger.dock"),
4351                        pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
4352                        write: |settings_content, value| {
4353                            settings_content.debugger.get_or_insert_default().dock = value;
4354                        },
4355                    }),
4356                    metadata: None,
4357                    files: USER,
4358                }),
4359                SettingsPageItem::SectionHeader("Notification Panel"),
4360                SettingsPageItem::SettingItem(SettingItem {
4361                    title: "Notification Panel Button",
4362                    description: "Show the notification panel button in the status bar.",
4363                    field: Box::new(SettingField {
4364                        json_path: Some("notification_panel.button"),
4365                        pick: |settings_content| {
4366                            settings_content
4367                                .notification_panel
4368                                .as_ref()?
4369                                .button
4370                                .as_ref()
4371                        },
4372                        write: |settings_content, value| {
4373                            settings_content
4374                                .notification_panel
4375                                .get_or_insert_default()
4376                                .button = value;
4377                        },
4378                    }),
4379                    metadata: None,
4380                    files: USER,
4381                }),
4382                SettingsPageItem::SettingItem(SettingItem {
4383                    title: "Notification Panel Dock",
4384                    description: "Where to dock the notification panel.",
4385                    field: Box::new(SettingField {
4386                        json_path: Some("notification_panel.dock"),
4387                        pick: |settings_content| {
4388                            settings_content.notification_panel.as_ref()?.dock.as_ref()
4389                        },
4390                        write: |settings_content, value| {
4391                            settings_content
4392                                .notification_panel
4393                                .get_or_insert_default()
4394                                .dock = value;
4395                        },
4396                    }),
4397                    metadata: None,
4398                    files: USER,
4399                }),
4400                SettingsPageItem::SettingItem(SettingItem {
4401                    title: "Notification Panel Default Width",
4402                    description: "Default width of the notification panel in pixels.",
4403                    field: Box::new(SettingField {
4404                        json_path: Some("notification_panel.default_width"),
4405                        pick: |settings_content| {
4406                            settings_content
4407                                .notification_panel
4408                                .as_ref()?
4409                                .default_width
4410                                .as_ref()
4411                        },
4412                        write: |settings_content, value| {
4413                            settings_content
4414                                .notification_panel
4415                                .get_or_insert_default()
4416                                .default_width = value;
4417                        },
4418                    }),
4419                    metadata: None,
4420                    files: USER,
4421                }),
4422                SettingsPageItem::SectionHeader("Collaboration Panel"),
4423                SettingsPageItem::SettingItem(SettingItem {
4424                    title: "Collaboration Panel Button",
4425                    description: "Show the collaboration panel button in the status bar.",
4426                    field: Box::new(SettingField {
4427                        json_path: Some("collaboration_panel.button"),
4428                        pick: |settings_content| {
4429                            settings_content
4430                                .collaboration_panel
4431                                .as_ref()?
4432                                .button
4433                                .as_ref()
4434                        },
4435                        write: |settings_content, value| {
4436                            settings_content
4437                                .collaboration_panel
4438                                .get_or_insert_default()
4439                                .button = value;
4440                        },
4441                    }),
4442                    metadata: None,
4443                    files: USER,
4444                }),
4445                SettingsPageItem::SettingItem(SettingItem {
4446                    title: "Collaboration Panel Dock",
4447                    description: "Where to dock the collaboration panel.",
4448                    field: Box::new(SettingField {
4449                        json_path: Some("collaboration_panel.dock"),
4450                        pick: |settings_content| {
4451                            settings_content.collaboration_panel.as_ref()?.dock.as_ref()
4452                        },
4453                        write: |settings_content, value| {
4454                            settings_content
4455                                .collaboration_panel
4456                                .get_or_insert_default()
4457                                .dock = value;
4458                        },
4459                    }),
4460                    metadata: None,
4461                    files: USER,
4462                }),
4463                SettingsPageItem::SettingItem(SettingItem {
4464                    title: "Collaboration Panel Default Width",
4465                    description: "Default width of the collaboration panel in pixels.",
4466                    field: Box::new(SettingField {
4467                        json_path: Some("collaboration_panel.dock"),
4468                        pick: |settings_content| {
4469                            settings_content
4470                                .collaboration_panel
4471                                .as_ref()?
4472                                .default_width
4473                                .as_ref()
4474                        },
4475                        write: |settings_content, value| {
4476                            settings_content
4477                                .collaboration_panel
4478                                .get_or_insert_default()
4479                                .default_width = value;
4480                        },
4481                    }),
4482                    metadata: None,
4483                    files: USER,
4484                }),
4485                SettingsPageItem::SectionHeader("Agent Panel"),
4486                SettingsPageItem::SettingItem(SettingItem {
4487                    title: "Agent Panel Button",
4488                    description: "Whether to show the agent panel button in the status bar.",
4489                    field: Box::new(SettingField {
4490                        json_path: Some("agent.button"),
4491                        pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
4492                        write: |settings_content, value| {
4493                            settings_content.agent.get_or_insert_default().button = value;
4494                        },
4495                    }),
4496                    metadata: None,
4497                    files: USER,
4498                }),
4499                SettingsPageItem::SettingItem(SettingItem {
4500                    title: "Agent Panel Dock",
4501                    description: "Where to dock the agent panel.",
4502                    field: Box::new(SettingField {
4503                        json_path: Some("agent.dock"),
4504                        pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
4505                        write: |settings_content, value| {
4506                            settings_content.agent.get_or_insert_default().dock = value;
4507                        },
4508                    }),
4509                    metadata: None,
4510                    files: USER,
4511                }),
4512                SettingsPageItem::SettingItem(SettingItem {
4513                    title: "Agent Panel Default Width",
4514                    description: "Default width when the agent panel is docked to the left or right.",
4515                    field: Box::new(SettingField {
4516                        json_path: Some("agent.default_width"),
4517                        pick: |settings_content| {
4518                            settings_content.agent.as_ref()?.default_width.as_ref()
4519                        },
4520                        write: |settings_content, value| {
4521                            settings_content.agent.get_or_insert_default().default_width = value;
4522                        },
4523                    }),
4524                    metadata: None,
4525                    files: USER,
4526                }),
4527                SettingsPageItem::SettingItem(SettingItem {
4528                    title: "Agent Panel Default Height",
4529                    description: "Default height when the agent panel is docked to the bottom.",
4530                    field: Box::new(SettingField {
4531                        json_path: Some("agent.default_height"),
4532                        pick: |settings_content| {
4533                            settings_content.agent.as_ref()?.default_height.as_ref()
4534                        },
4535                        write: |settings_content, value| {
4536                            settings_content
4537                                .agent
4538                                .get_or_insert_default()
4539                                .default_height = value;
4540                        },
4541                    }),
4542                    metadata: None,
4543                    files: USER,
4544                }),
4545            ],
4546        },
4547        SettingsPage {
4548            title: "Debugger",
4549            items: vec![
4550                SettingsPageItem::SectionHeader("General"),
4551                SettingsPageItem::SettingItem(SettingItem {
4552                    title: "Stepping Granularity",
4553                    description: "Determines the stepping granularity for debug operations.",
4554                    field: Box::new(SettingField {
4555                        json_path: Some("debugger.stepping_granularity"),
4556                        pick: |settings_content| {
4557                            settings_content
4558                                .debugger
4559                                .as_ref()?
4560                                .stepping_granularity
4561                                .as_ref()
4562                        },
4563                        write: |settings_content, value| {
4564                            settings_content
4565                                .debugger
4566                                .get_or_insert_default()
4567                                .stepping_granularity = value;
4568                        },
4569                    }),
4570                    metadata: None,
4571                    files: USER,
4572                }),
4573                SettingsPageItem::SettingItem(SettingItem {
4574                    title: "Save Breakpoints",
4575                    description: "Whether breakpoints should be reused across Zed sessions.",
4576                    field: Box::new(SettingField {
4577                        json_path: Some("debugger.save_breakpoints"),
4578                        pick: |settings_content| {
4579                            settings_content
4580                                .debugger
4581                                .as_ref()?
4582                                .save_breakpoints
4583                                .as_ref()
4584                        },
4585                        write: |settings_content, value| {
4586                            settings_content
4587                                .debugger
4588                                .get_or_insert_default()
4589                                .save_breakpoints = value;
4590                        },
4591                    }),
4592                    metadata: None,
4593                    files: USER,
4594                }),
4595                SettingsPageItem::SettingItem(SettingItem {
4596                    title: "Timeout",
4597                    description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
4598                    field: Box::new(SettingField {
4599                        json_path: Some("debugger.timeout"),
4600                        pick: |settings_content| {
4601                            settings_content.debugger.as_ref()?.timeout.as_ref()
4602                        },
4603                        write: |settings_content, value| {
4604                            settings_content.debugger.get_or_insert_default().timeout = value;
4605                        },
4606                    }),
4607                    metadata: None,
4608                    files: USER,
4609                }),
4610                SettingsPageItem::SettingItem(SettingItem {
4611                    title: "Log DAP Communications",
4612                    description: "Whether to log messages between active debug adapters and Zed.",
4613                    field: Box::new(SettingField {
4614                        json_path: Some("debugger.log_dap_communications"),
4615                        pick: |settings_content| {
4616                            settings_content
4617                                .debugger
4618                                .as_ref()?
4619                                .log_dap_communications
4620                                .as_ref()
4621                        },
4622                        write: |settings_content, value| {
4623                            settings_content
4624                                .debugger
4625                                .get_or_insert_default()
4626                                .log_dap_communications = value;
4627                        },
4628                    }),
4629                    metadata: None,
4630                    files: USER,
4631                }),
4632                SettingsPageItem::SettingItem(SettingItem {
4633                    title: "Format DAP Log Messages",
4634                    description: "Whether to format DAP messages when adding them to debug adapter logger.",
4635                    field: Box::new(SettingField {
4636                        json_path: Some("debugger.format_dap_log_messages"),
4637                        pick: |settings_content| {
4638                            settings_content
4639                                .debugger
4640                                .as_ref()?
4641                                .format_dap_log_messages
4642                                .as_ref()
4643                        },
4644                        write: |settings_content, value| {
4645                            settings_content
4646                                .debugger
4647                                .get_or_insert_default()
4648                                .format_dap_log_messages = value;
4649                        },
4650                    }),
4651                    metadata: None,
4652                    files: USER,
4653                }),
4654            ],
4655        },
4656        SettingsPage {
4657            title: "Terminal",
4658            items: vec![
4659                SettingsPageItem::SectionHeader("Environment"),
4660                SettingsPageItem::DynamicItem(DynamicItem {
4661                    discriminant: SettingItem {
4662                        files: USER | PROJECT,
4663                        title: "Shell",
4664                        description: "What shell to use when opening a terminal.",
4665                        field: Box::new(SettingField {
4666                            json_path: Some("terminal.shell$"),
4667                            pick: |settings_content| {
4668                                Some(&dynamic_variants::<settings::Shell>()[
4669                                    settings_content
4670                                        .terminal
4671                                        .as_ref()?
4672                                        .project
4673                                        .shell
4674                                        .as_ref()?
4675                                        .discriminant() as usize])
4676                            },
4677                            write: |settings_content, value| {
4678                                let Some(value) = value else {
4679                                    if let Some(terminal) = settings_content.terminal.as_mut() {
4680                                        terminal.project.shell = None;
4681                                    }
4682                                    return;
4683                                };
4684                                let settings_value = settings_content
4685                                    .terminal
4686                                    .get_or_insert_default()
4687                                    .project
4688                                    .shell
4689                                    .get_or_insert_with(|| settings::Shell::default());
4690                                let default_shell = if cfg!(target_os = "windows") {
4691                                    "powershell.exe"
4692                                } else {
4693                                    "sh"
4694                                };
4695                                *settings_value = match value {
4696                                    settings::ShellDiscriminants::System => {
4697                                        settings::Shell::System
4698                                    },
4699                                    settings::ShellDiscriminants::Program => {
4700                                        let program = match settings_value {
4701                                            settings::Shell::Program(p) => p.clone(),
4702                                            settings::Shell::WithArguments { program, .. } => program.clone(),
4703                                            _ => String::from(default_shell),
4704                                        };
4705                                        settings::Shell::Program(program)
4706                                    },
4707                                    settings::ShellDiscriminants::WithArguments => {
4708                                        let (program, args, title_override) = match settings_value {
4709                                            settings::Shell::Program(p) => (p.clone(), vec![], None),
4710                                            settings::Shell::WithArguments { program, args, title_override } => {
4711                                                (program.clone(), args.clone(), title_override.clone())
4712                                            },
4713                                            _ => (String::from(default_shell), vec![], None),
4714                                        };
4715                                        settings::Shell::WithArguments {
4716                                            program,
4717                                            args,
4718                                            title_override,
4719                                        }
4720                                    },
4721                                };
4722                            },
4723                        }),
4724                        metadata: None,
4725                    },
4726                    pick_discriminant: |settings_content| {
4727                        Some(settings_content.terminal.as_ref()?.project.shell.as_ref()?.discriminant() as usize)
4728                    },
4729                    fields: dynamic_variants::<settings::Shell>().into_iter().map(|variant| {
4730                        match variant {
4731                            settings::ShellDiscriminants::System => vec![],
4732                            settings::ShellDiscriminants::Program => vec![
4733                                SettingItem {
4734                                    files: USER | PROJECT,
4735                                    title: "Program",
4736                                    description: "The shell program to use.",
4737                                    field: Box::new(SettingField {
4738                                        json_path: Some("terminal.shell"),
4739                                        pick: |settings_content| {
4740                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4741                                                Some(settings::Shell::Program(program)) => Some(program),
4742                                                _ => None
4743                                            }
4744                                        },
4745                                        write: |settings_content, value| {
4746                                            let Some(value) = value else {
4747                                                return;
4748                                            };
4749                                            match settings_content
4750                                                .terminal
4751                                                .get_or_insert_default()
4752                                                .project
4753                                                .shell.as_mut() {
4754                                                    Some(settings::Shell::Program(program)) => *program = value,
4755                                                    _ => return
4756                                                }
4757                                        },
4758                                    }),
4759                                    metadata: None,
4760                                }
4761                            ],
4762                            settings::ShellDiscriminants::WithArguments => vec![
4763                                SettingItem {
4764                                    files: USER | PROJECT,
4765                                    title: "Program",
4766                                    description: "The shell program to run.",
4767                                    field: Box::new(SettingField {
4768                                        json_path: Some("terminal.shell.program"),
4769                                        pick: |settings_content| {
4770                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4771                                                Some(settings::Shell::WithArguments { program, .. }) => Some(program),
4772                                                _ => None
4773                                            }
4774                                        },
4775                                        write: |settings_content, value| {
4776                                            let Some(value) = value else {
4777                                                return;
4778                                            };
4779                                            match settings_content
4780                                                .terminal
4781                                                .get_or_insert_default()
4782                                                .project
4783                                                .shell.as_mut() {
4784                                                    Some(settings::Shell::WithArguments { program, .. }) => *program = value,
4785                                                    _ => return
4786                                                }
4787                                        },
4788                                    }),
4789                                    metadata: None,
4790                                },
4791                                SettingItem {
4792                                    files: USER | PROJECT,
4793                                    title: "Arguments",
4794                                    description: "The arguments to pass to the shell program.",
4795                                    field: Box::new(
4796                                        SettingField {
4797                                            json_path: Some("terminal.shell.args"),
4798                                            pick: |settings_content| {
4799                                                match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4800                                                    Some(settings::Shell::WithArguments { args, .. }) => Some(args),
4801                                                    _ => None
4802                                                }
4803                                            },
4804                                            write: |settings_content, value| {
4805                                                let Some(value) = value else {
4806                                                    return;
4807                                                };
4808                                                match settings_content
4809                                                    .terminal
4810                                                    .get_or_insert_default()
4811                                                    .project
4812                                                    .shell.as_mut() {
4813                                                        Some(settings::Shell::WithArguments { args, .. }) => *args = value,
4814                                                        _ => return
4815                                                    }
4816                                            },
4817                                        }
4818                                        .unimplemented(),
4819                                    ),
4820                                    metadata: None,
4821                                },
4822                                SettingItem {
4823                                    files: USER | PROJECT,
4824                                    title: "Title Override",
4825                                    description: "An optional string to override the title of the terminal tab.",
4826                                    field: Box::new(SettingField {
4827                                        json_path: Some("terminal.shell.title_override"),
4828                                        pick: |settings_content| {
4829                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4830                                                Some(settings::Shell::WithArguments { title_override, .. }) => title_override.as_ref().or(DEFAULT_EMPTY_SHARED_STRING),
4831                                                _ => None
4832                                            }
4833                                        },
4834                                        write: |settings_content, value| {
4835                                            match settings_content
4836                                                .terminal
4837                                                .get_or_insert_default()
4838                                                .project
4839                                                .shell.as_mut() {
4840                                                    Some(settings::Shell::WithArguments { title_override, .. }) => *title_override = value.filter(|s| !s.is_empty()),
4841                                                    _ => return
4842                                                }
4843                                        },
4844                                    }),
4845                                    metadata: None,
4846                                }
4847                            ],
4848                        }
4849                    }).collect(),
4850                }),
4851                SettingsPageItem::DynamicItem(DynamicItem {
4852                    discriminant: SettingItem {
4853                        files: USER | PROJECT,
4854                        title: "Working Directory",
4855                        description: "What working directory to use when launching the terminal.",
4856                        field: Box::new(SettingField {
4857                            json_path: Some("terminal.working_directory$"),
4858                            pick: |settings_content| {
4859                                Some(&dynamic_variants::<settings::WorkingDirectory>()[
4860                                    settings_content
4861                                        .terminal
4862                                        .as_ref()?
4863                                        .project
4864                                        .working_directory
4865                                        .as_ref()?
4866                                        .discriminant() as usize])
4867                            },
4868                            write: |settings_content, value| {
4869                                let Some(value) = value else {
4870                                    if let Some(terminal) = settings_content.terminal.as_mut() {
4871                                        terminal.project.working_directory = None;
4872                                    }
4873                                    return;
4874                                };
4875                                let settings_value = settings_content
4876                                    .terminal
4877                                    .get_or_insert_default()
4878                                    .project
4879                                    .working_directory
4880                                    .get_or_insert_with(|| settings::WorkingDirectory::CurrentProjectDirectory);
4881                                *settings_value = match value {
4882                                    settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => {
4883                                        settings::WorkingDirectory::CurrentProjectDirectory
4884                                    },
4885                                    settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => {
4886                                        settings::WorkingDirectory::FirstProjectDirectory
4887                                    },
4888                                    settings::WorkingDirectoryDiscriminants::AlwaysHome => {
4889                                        settings::WorkingDirectory::AlwaysHome
4890                                    },
4891                                    settings::WorkingDirectoryDiscriminants::Always => {
4892                                        let directory = match settings_value {
4893                                            settings::WorkingDirectory::Always { .. } => return,
4894                                            _ => String::new(),
4895                                        };
4896                                        settings::WorkingDirectory::Always { directory }
4897                                    },
4898                                };
4899                            },
4900                        }),
4901                        metadata: None,
4902                    },
4903                    pick_discriminant: |settings_content| {
4904                        Some(settings_content.terminal.as_ref()?.project.working_directory.as_ref()?.discriminant() as usize)
4905                    },
4906                    fields: dynamic_variants::<settings::WorkingDirectory>().into_iter().map(|variant| {
4907                        match variant {
4908                            settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => vec![],
4909                            settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => vec![],
4910                            settings::WorkingDirectoryDiscriminants::AlwaysHome => vec![],
4911                            settings::WorkingDirectoryDiscriminants::Always => vec![
4912                                SettingItem {
4913                                    files: USER | PROJECT,
4914                                    title: "Directory",
4915                                    description: "The directory path to use (will be shell expanded).",
4916                                    field: Box::new(SettingField {
4917                                        json_path: Some("terminal.working_directory.always"),
4918                                        pick: |settings_content| {
4919                                            match settings_content.terminal.as_ref()?.project.working_directory.as_ref() {
4920                                                Some(settings::WorkingDirectory::Always { directory }) => Some(directory),
4921                                                _ => None
4922                                            }
4923                                        },
4924                                        write: |settings_content, value| {
4925                                            let value = value.unwrap_or_default();
4926                                            match settings_content
4927                                                .terminal
4928                                                .get_or_insert_default()
4929                                                .project
4930                                                .working_directory.as_mut() {
4931                                                    Some(settings::WorkingDirectory::Always { directory }) => *directory = value,
4932                                                    _ => return
4933                                                }
4934                                        },
4935                                    }),
4936                                    metadata: None,
4937                                }
4938                            ],
4939                        }
4940                    }).collect(),
4941                }),
4942                SettingsPageItem::SettingItem(SettingItem {
4943                    title: "Environment Variables",
4944                    description: "Key-value pairs to add to the terminal's environment.",
4945                    field: Box::new(
4946                        SettingField {
4947                            json_path: Some("terminal.env"),
4948                            pick: |settings_content| {
4949                                settings_content.terminal.as_ref()?.project.env.as_ref()
4950                            },
4951                            write: |settings_content, value| {
4952                                settings_content
4953                                    .terminal
4954                                    .get_or_insert_default()
4955                                    .project
4956                                    .env = value;
4957                            },
4958                        }
4959                        .unimplemented(),
4960                    ),
4961                    metadata: None,
4962                    files: USER | PROJECT,
4963                }),
4964                SettingsPageItem::SettingItem(SettingItem {
4965                    title: "Detect Virtual Environment",
4966                    description: "Activates the Python virtual environment, if one is found, in the terminal's working directory.",
4967                    field: Box::new(
4968                        SettingField {
4969                            json_path: Some("terminal.detect_venv"),
4970                            pick: |settings_content| {
4971                                settings_content
4972                                    .terminal
4973                                    .as_ref()?
4974                                    .project
4975                                    .detect_venv
4976                                    .as_ref()
4977                            },
4978                            write: |settings_content, value| {
4979                                settings_content
4980                                    .terminal
4981                                    .get_or_insert_default()
4982                                    .project
4983                                    .detect_venv = value;
4984                            },
4985                        }
4986                        .unimplemented(),
4987                    ),
4988                    metadata: None,
4989                    files: USER | PROJECT,
4990                }),
4991                SettingsPageItem::SectionHeader("Font"),
4992                SettingsPageItem::SettingItem(SettingItem {
4993                    title: "Font Size",
4994                    description: "Font size for terminal text. If not set, defaults to buffer font size.",
4995                    field: Box::new(SettingField {
4996                        json_path: Some("terminal.font_size"),
4997                        pick: |settings_content| {
4998                            settings_content
4999                                .terminal
5000                                .as_ref()
5001                                .and_then(|terminal| terminal.font_size.as_ref())
5002                                .or(settings_content.theme.buffer_font_size.as_ref())
5003                        },
5004                        write: |settings_content, value| {
5005                            settings_content.terminal.get_or_insert_default().font_size = value;
5006                        },
5007                    }),
5008                    metadata: None,
5009                    files: USER,
5010                }),
5011                SettingsPageItem::SettingItem(SettingItem {
5012                    title: "Font Family",
5013                    description: "Font family for terminal text. If not set, defaults to buffer font family.",
5014                    field: Box::new(SettingField {
5015                        json_path: Some("terminal.font_family"),
5016                        pick: |settings_content| {
5017                            settings_content
5018                                .terminal
5019                                .as_ref()
5020                                .and_then(|terminal| terminal.font_family.as_ref())
5021                                .or(settings_content.theme.buffer_font_family.as_ref())
5022                        },
5023                        write: |settings_content, value| {
5024                            settings_content
5025                                .terminal
5026                                .get_or_insert_default()
5027                                .font_family = value;
5028                        },
5029                    }),
5030                    metadata: None,
5031                    files: USER,
5032                }),
5033                SettingsPageItem::SettingItem(SettingItem {
5034                    title: "Font Fallbacks",
5035                    description: "Font fallbacks for terminal text. If not set, defaults to buffer font fallbacks.",
5036                    field: Box::new(
5037                        SettingField {
5038                            json_path: Some("terminal.font_fallbacks"),
5039                            pick: |settings_content| {
5040                                settings_content
5041                                    .terminal
5042                                    .as_ref()
5043                                    .and_then(|terminal| terminal.font_fallbacks.as_ref())
5044                                    .or(settings_content.theme.buffer_font_fallbacks.as_ref())
5045                            },
5046                            write: |settings_content, value| {
5047                                settings_content
5048                                    .terminal
5049                                    .get_or_insert_default()
5050                                    .font_fallbacks = value;
5051                            },
5052                        }
5053                        .unimplemented(),
5054                    ),
5055                    metadata: None,
5056                    files: USER,
5057                }),
5058                SettingsPageItem::SettingItem(SettingItem {
5059                    title: "Font Weight",
5060                    description: "Font weight for terminal text in CSS weight units (100-900).",
5061                    field: Box::new(SettingField {
5062                        json_path: Some("terminal.font_weight"),
5063                        pick: |settings_content| {
5064                            settings_content.terminal.as_ref()?.font_weight.as_ref()
5065                        },
5066                        write: |settings_content, value| {
5067                            settings_content
5068                                .terminal
5069                                .get_or_insert_default()
5070                                .font_weight = value;
5071                        },
5072                    }),
5073                    metadata: None,
5074                    files: USER,
5075                }),
5076                SettingsPageItem::SettingItem(SettingItem {
5077                    title: "Font Features",
5078                    description: "Font features for terminal text.",
5079                    field: Box::new(
5080                        SettingField {
5081                            json_path: Some("terminal.font_features"),
5082                            pick: |settings_content| {
5083                                settings_content
5084                                    .terminal
5085                                    .as_ref()
5086                                    .and_then(|terminal| terminal.font_features.as_ref())
5087                                    .or(settings_content.theme.buffer_font_features.as_ref())
5088                            },
5089                            write: |settings_content, value| {
5090                                settings_content
5091                                    .terminal
5092                                    .get_or_insert_default()
5093                                    .font_features = value;
5094                            },
5095                        }
5096                        .unimplemented(),
5097                    ),
5098                    metadata: None,
5099                    files: USER,
5100                }),
5101                SettingsPageItem::SectionHeader("Display Settings"),
5102                SettingsPageItem::SettingItem(SettingItem {
5103                    title: "Line Height",
5104                    description: "Line height for terminal text.",
5105                    field: Box::new(
5106                        SettingField {
5107                            json_path: Some("terminal.line_height"),
5108                            pick: |settings_content| {
5109                                settings_content.terminal.as_ref()?.line_height.as_ref()
5110                            },
5111                            write: |settings_content, value| {
5112                                settings_content
5113                                    .terminal
5114                                    .get_or_insert_default()
5115                                    .line_height = value;
5116                            },
5117                        }
5118                        .unimplemented(),
5119                    ),
5120                    metadata: None,
5121                    files: USER,
5122                }),
5123                SettingsPageItem::SettingItem(SettingItem {
5124                    title: "Cursor Shape",
5125                    description: "Default cursor shape for the terminal (bar, block, underline, or hollow).",
5126                    field: Box::new(SettingField {
5127                        json_path: Some("terminal.cursor_shape"),
5128                        pick: |settings_content| {
5129                            settings_content.terminal.as_ref()?.cursor_shape.as_ref()
5130                        },
5131                        write: |settings_content, value| {
5132                            settings_content
5133                                .terminal
5134                                .get_or_insert_default()
5135                                .cursor_shape = value;
5136                        },
5137                    }),
5138                    metadata: None,
5139                    files: USER,
5140                }),
5141                SettingsPageItem::SettingItem(SettingItem {
5142                    title: "Cursor Blinking",
5143                    description: "Sets the cursor blinking behavior in the terminal.",
5144                    field: Box::new(SettingField {
5145                        json_path: Some("terminal.blinking"),
5146                        pick: |settings_content| {
5147                            settings_content.terminal.as_ref()?.blinking.as_ref()
5148                        },
5149                        write: |settings_content, value| {
5150                            settings_content.terminal.get_or_insert_default().blinking = value;
5151                        },
5152                    }),
5153                    metadata: None,
5154                    files: USER,
5155                }),
5156                SettingsPageItem::SettingItem(SettingItem {
5157                    title: "Alternate Scroll",
5158                    description: "Whether alternate scroll mode is active by default (converts mouse scroll to arrow keys in apps like Vim).",
5159                    field: Box::new(SettingField {
5160                        json_path: Some("terminal.alternate_scroll"),
5161                        pick: |settings_content| {
5162                            settings_content
5163                                .terminal
5164                                .as_ref()?
5165                                .alternate_scroll
5166                                .as_ref()
5167                        },
5168                        write: |settings_content, value| {
5169                            settings_content
5170                                .terminal
5171                                .get_or_insert_default()
5172                                .alternate_scroll = value;
5173                        },
5174                    }),
5175                    metadata: None,
5176                    files: USER,
5177                }),
5178                SettingsPageItem::SettingItem(SettingItem {
5179                    title: "Minimum Contrast",
5180                    description: "The minimum APCA perceptual contrast between foreground and background colors (0-106).",
5181                    field: Box::new(SettingField {
5182                        json_path: Some("terminal.minimum_contrast"),
5183                        pick: |settings_content| {
5184                            settings_content
5185                                .terminal
5186                                .as_ref()?
5187                                .minimum_contrast
5188                                .as_ref()
5189                        },
5190                        write: |settings_content, value| {
5191                            settings_content
5192                                .terminal
5193                                .get_or_insert_default()
5194                                .minimum_contrast = value;
5195                        },
5196                    }),
5197                    metadata: None,
5198                    files: USER,
5199                }),
5200                SettingsPageItem::SectionHeader("Behavior Settings"),
5201                SettingsPageItem::SettingItem(SettingItem {
5202                    title: "Option As Meta",
5203                    description: "Whether the option key behaves as the meta key.",
5204                    field: Box::new(SettingField {
5205                        json_path: Some("terminal.option_as_meta"),
5206                        pick: |settings_content| {
5207                            settings_content.terminal.as_ref()?.option_as_meta.as_ref()
5208                        },
5209                        write: |settings_content, value| {
5210                            settings_content
5211                                .terminal
5212                                .get_or_insert_default()
5213                                .option_as_meta = value;
5214                        },
5215                    }),
5216                    metadata: None,
5217                    files: USER,
5218                }),
5219                SettingsPageItem::SettingItem(SettingItem {
5220                    title: "Copy On Select",
5221                    description: "Whether selecting text in the terminal automatically copies to the system clipboard.",
5222                    field: Box::new(SettingField {
5223                        json_path: Some("terminal.copy_on_select"),
5224                        pick: |settings_content| {
5225                            settings_content.terminal.as_ref()?.copy_on_select.as_ref()
5226                        },
5227                        write: |settings_content, value| {
5228                            settings_content
5229                                .terminal
5230                                .get_or_insert_default()
5231                                .copy_on_select = value;
5232                        },
5233                    }),
5234                    metadata: None,
5235                    files: USER,
5236                }),
5237                SettingsPageItem::SettingItem(SettingItem {
5238                    title: "Keep Selection On Copy",
5239                    description: "Whether to keep the text selection after copying it to the clipboard.",
5240                    field: Box::new(SettingField {
5241                        json_path: Some("terminal.keep_selection_on_copy"),
5242                        pick: |settings_content| {
5243                            settings_content
5244                                .terminal
5245                                .as_ref()?
5246                                .keep_selection_on_copy
5247                                .as_ref()
5248                        },
5249                        write: |settings_content, value| {
5250                            settings_content
5251                                .terminal
5252                                .get_or_insert_default()
5253                                .keep_selection_on_copy = value;
5254                        },
5255                    }),
5256                    metadata: None,
5257                    files: USER,
5258                }),
5259                SettingsPageItem::SectionHeader("Layout Settings"),
5260                SettingsPageItem::SettingItem(SettingItem {
5261                    title: "Default Width",
5262                    description: "Default width when the terminal is docked to the left or right (in pixels).",
5263                    field: Box::new(SettingField {
5264                        json_path: Some("terminal.default_width"),
5265                        pick: |settings_content| {
5266                            settings_content.terminal.as_ref()?.default_width.as_ref()
5267                        },
5268                        write: |settings_content, value| {
5269                            settings_content
5270                                .terminal
5271                                .get_or_insert_default()
5272                                .default_width = value;
5273                        },
5274                    }),
5275                    metadata: None,
5276                    files: USER,
5277                }),
5278                SettingsPageItem::SettingItem(SettingItem {
5279                    title: "Default Height",
5280                    description: "Default height when the terminal is docked to the bottom (in pixels).",
5281                    field: Box::new(SettingField {
5282                        json_path: Some("terminal.default_height"),
5283                        pick: |settings_content| {
5284                            settings_content.terminal.as_ref()?.default_height.as_ref()
5285                        },
5286                        write: |settings_content, value| {
5287                            settings_content
5288                                .terminal
5289                                .get_or_insert_default()
5290                                .default_height = value;
5291                        },
5292                    }),
5293                    metadata: None,
5294                    files: USER,
5295                }),
5296                SettingsPageItem::SectionHeader("Advanced Settings"),
5297                SettingsPageItem::SettingItem(SettingItem {
5298                    title: "Max Scroll History Lines",
5299                    description: "Maximum number of lines to keep in scrollback history (max: 100,000; 0 disables scrolling).",
5300                    field: Box::new(SettingField {
5301                        json_path: Some("terminal.max_scroll_history_lines"),
5302                        pick: |settings_content| {
5303                            settings_content
5304                                .terminal
5305                                .as_ref()?
5306                                .max_scroll_history_lines
5307                                .as_ref()
5308                        },
5309                        write: |settings_content, value| {
5310                            settings_content
5311                                .terminal
5312                                .get_or_insert_default()
5313                                .max_scroll_history_lines = value;
5314                        },
5315                    }),
5316                    metadata: None,
5317                    files: USER,
5318                }),
5319                SettingsPageItem::SettingItem(SettingItem {
5320                    title: "Scroll Multiplier",
5321                    description: "The multiplier for scrolling in the terminal with the mouse wheel",
5322                    field: Box::new(SettingField {
5323                        json_path: Some("terminal.scroll_multiplier"),
5324                        pick: |settings_content| {
5325                            settings_content.terminal.as_ref()?.scroll_multiplier.as_ref()
5326                        },
5327                        write: |settings_content, value| {
5328                            settings_content
5329                                .terminal
5330                                .get_or_insert_default()
5331                                .scroll_multiplier = value;
5332                        },
5333                    }),
5334                    metadata: None,
5335                    files: USER,
5336                }),
5337                SettingsPageItem::SectionHeader("Toolbar"),
5338                SettingsPageItem::SettingItem(SettingItem {
5339                    title: "Breadcrumbs",
5340                    description: "Display the terminal title in breadcrumbs inside the terminal pane.",
5341                    field: Box::new(SettingField {
5342                        json_path: Some("terminal.toolbar.breadcrumbs"),
5343                        pick: |settings_content| {
5344                            settings_content
5345                                .terminal
5346                                .as_ref()?
5347                                .toolbar
5348                                .as_ref()?
5349                                .breadcrumbs
5350                                .as_ref()
5351                        },
5352                        write: |settings_content, value| {
5353                            settings_content
5354                                .terminal
5355                                .get_or_insert_default()
5356                                .toolbar
5357                                .get_or_insert_default()
5358                                .breadcrumbs = value;
5359                        },
5360                    }),
5361                    metadata: None,
5362                    files: USER,
5363                }),
5364                SettingsPageItem::SectionHeader("Scrollbar"),
5365                SettingsPageItem::SettingItem(SettingItem {
5366                    title: "Show Scrollbar",
5367                    description: "When to show the scrollbar in the terminal.",
5368                    field: Box::new(SettingField {
5369                        json_path: Some("terminal.scrollbar.show"),
5370                        pick: |settings_content| {
5371                            show_scrollbar_or_editor(settings_content, |settings_content| {
5372                                settings_content
5373                                    .terminal
5374                                    .as_ref()?
5375                                    .scrollbar
5376                                    .as_ref()?
5377                                    .show
5378                                    .as_ref()
5379                            })
5380                        },
5381                        write: |settings_content, value| {
5382                            settings_content
5383                                .terminal
5384                                .get_or_insert_default()
5385                                .scrollbar
5386                                .get_or_insert_default()
5387                                .show = value;
5388                        },
5389                    }),
5390                    metadata: None,
5391                    files: USER,
5392                }),
5393            ],
5394        },
5395        SettingsPage {
5396            title: "Version Control",
5397            items: vec![
5398                SettingsPageItem::SectionHeader("Git Gutter"),
5399                SettingsPageItem::SettingItem(SettingItem {
5400                    title: "Visibility",
5401                    description: "Control whether Git status is shown in the editor's gutter.",
5402                    field: Box::new(SettingField {
5403                        json_path: Some("git.git_gutter"),
5404                        pick: |settings_content| settings_content.git.as_ref()?.git_gutter.as_ref(),
5405                        write: |settings_content, value| {
5406                            settings_content.git.get_or_insert_default().git_gutter = value;
5407                        },
5408                    }),
5409                    metadata: None,
5410                    files: USER,
5411                }),
5412                // todo(settings_ui): Figure out the right default for this value in default.json
5413                SettingsPageItem::SettingItem(SettingItem {
5414                    title: "Debounce",
5415                    description: "Debounce threshold in milliseconds after which changes are reflected in the Git gutter.",
5416                    field: Box::new(SettingField {
5417                        json_path: Some("git.gutter_debounce"),
5418                        pick: |settings_content| {
5419                            settings_content.git.as_ref()?.gutter_debounce.as_ref()
5420                        },
5421                        write: |settings_content, value| {
5422                            settings_content.git.get_or_insert_default().gutter_debounce = value;
5423                        },
5424                    }),
5425                    metadata: None,
5426                    files: USER,
5427                }),
5428                SettingsPageItem::SectionHeader("Inline Git Blame"),
5429                SettingsPageItem::SettingItem(SettingItem {
5430                    title: "Enabled",
5431                    description: "Whether or not to show Git blame data inline in the currently focused line.",
5432                    field: Box::new(SettingField {
5433                        json_path: Some("git.inline_blame.enabled"),
5434                        pick: |settings_content| {
5435                            settings_content
5436                                .git
5437                                .as_ref()?
5438                                .inline_blame
5439                                .as_ref()?
5440                                .enabled
5441                                .as_ref()
5442                        },
5443                        write: |settings_content, value| {
5444                            settings_content
5445                                .git
5446                                .get_or_insert_default()
5447                                .inline_blame
5448                                .get_or_insert_default()
5449                                .enabled = value;
5450                        },
5451                    }),
5452                    metadata: None,
5453                    files: USER,
5454                }),
5455                SettingsPageItem::SettingItem(SettingItem {
5456                    title: "Delay",
5457                    description: "The delay after which the inline blame information is shown.",
5458                    field: Box::new(SettingField {
5459                        json_path: Some("git.inline_blame.delay_ms"),
5460                        pick: |settings_content| {
5461                            settings_content
5462                                .git
5463                                .as_ref()?
5464                                .inline_blame
5465                                .as_ref()?
5466                                .delay_ms
5467                                .as_ref()
5468                        },
5469                        write: |settings_content, value| {
5470                            settings_content
5471                                .git
5472                                .get_or_insert_default()
5473                                .inline_blame
5474                                .get_or_insert_default()
5475                                .delay_ms = value;
5476                        },
5477                    }),
5478                    metadata: None,
5479                    files: USER,
5480                }),
5481                SettingsPageItem::SettingItem(SettingItem {
5482                    title: "Padding",
5483                    description: "Padding between the end of the source line and the start of the inline blame in columns.",
5484                    field: Box::new(SettingField {
5485                        json_path: Some("git.inline_blame.padding"),
5486                        pick: |settings_content| {
5487                            settings_content
5488                                .git
5489                                .as_ref()?
5490                                .inline_blame
5491                                .as_ref()?
5492                                .padding
5493                                .as_ref()
5494                        },
5495                        write: |settings_content, value| {
5496                            settings_content
5497                                .git
5498                                .get_or_insert_default()
5499                                .inline_blame
5500                                .get_or_insert_default()
5501                                .padding = value;
5502                        },
5503                    }),
5504                    metadata: None,
5505                    files: USER,
5506                }),
5507                SettingsPageItem::SettingItem(SettingItem {
5508                    title: "Minimum Column",
5509                    description: "The minimum column number at which to show the inline blame information.",
5510                    field: Box::new(SettingField {
5511                        json_path: Some("git.inline_blame.min_column"),
5512                        pick: |settings_content| {
5513                            settings_content
5514                                .git
5515                                .as_ref()?
5516                                .inline_blame
5517                                .as_ref()?
5518                                .min_column
5519                                .as_ref()
5520                        },
5521                        write: |settings_content, value| {
5522                            settings_content
5523                                .git
5524                                .get_or_insert_default()
5525                                .inline_blame
5526                                .get_or_insert_default()
5527                                .min_column = value;
5528                        },
5529                    }),
5530                    metadata: None,
5531                    files: USER,
5532                }),
5533                SettingsPageItem::SettingItem(SettingItem {
5534                    title: "Show Commit Summary",
5535                    description: "Show commit summary as part of the inline blame.",
5536                    field: Box::new(SettingField {
5537                        json_path: Some("git.inline_blame.show_commit_summary"),
5538                        pick: |settings_content| {
5539                            settings_content
5540                                .git
5541                                .as_ref()?
5542                                .inline_blame
5543                                .as_ref()?
5544                                .show_commit_summary
5545                                .as_ref()
5546                        },
5547                        write: |settings_content, value| {
5548                            settings_content
5549                                .git
5550                                .get_or_insert_default()
5551                                .inline_blame
5552                                .get_or_insert_default()
5553                                .show_commit_summary = value;
5554                        },
5555                    }),
5556                    metadata: None,
5557                    files: USER,
5558                }),
5559                SettingsPageItem::SectionHeader("Git Blame View"),
5560                SettingsPageItem::SettingItem(SettingItem {
5561                    title: "Show Avatar",
5562                    description: "Show the avatar of the author of the commit.",
5563                    field: Box::new(SettingField {
5564                        json_path: Some("git.blame.show_avatar"),
5565                        pick: |settings_content| {
5566                            settings_content
5567                                .git
5568                                .as_ref()?
5569                                .blame
5570                                .as_ref()?
5571                                .show_avatar
5572                                .as_ref()
5573                        },
5574                        write: |settings_content, value| {
5575                            settings_content
5576                                .git
5577                                .get_or_insert_default()
5578                                .blame
5579                                .get_or_insert_default()
5580                                .show_avatar = value;
5581                        },
5582                    }),
5583                    metadata: None,
5584                    files: USER,
5585                }),
5586                SettingsPageItem::SectionHeader("Branch Picker"),
5587                SettingsPageItem::SettingItem(SettingItem {
5588                    title: "Show Author Name",
5589                    description: "Show author name as part of the commit information in branch picker.",
5590                    field: Box::new(SettingField {
5591                        json_path: Some("git.branch_picker.show_author_name"),
5592                        pick: |settings_content| {
5593                            settings_content
5594                                .git
5595                                .as_ref()?
5596                                .branch_picker
5597                                .as_ref()?
5598                                .show_author_name
5599                                .as_ref()
5600                        },
5601                        write: |settings_content, value| {
5602                            settings_content
5603                                .git
5604                                .get_or_insert_default()
5605                                .branch_picker
5606                                .get_or_insert_default()
5607                                .show_author_name = value;
5608                        },
5609                    }),
5610                    metadata: None,
5611                    files: USER,
5612                }),
5613                SettingsPageItem::SectionHeader("Git Hunks"),
5614                SettingsPageItem::SettingItem(SettingItem {
5615                    title: "Hunk Style",
5616                    description: "How Git hunks are displayed visually in the editor.",
5617                    field: Box::new(SettingField {
5618                        json_path: Some("git.hunk_style"),
5619                        pick: |settings_content| settings_content.git.as_ref()?.hunk_style.as_ref(),
5620                        write: |settings_content, value| {
5621                            settings_content.git.get_or_insert_default().hunk_style = value;
5622                        },
5623                    }),
5624                    metadata: None,
5625                    files: USER,
5626                }),
5627                SettingsPageItem::SettingItem(SettingItem {
5628                    title: "Path Style",
5629                    description: "Should the name or path be displayed first in the git view.",
5630                    field: Box::new(SettingField {
5631                        json_path: Some("git.path_style"),
5632                        pick: |settings_content| settings_content.git.as_ref()?.path_style.as_ref(),
5633                        write: |settings_content, value| {
5634                            settings_content.git.get_or_insert_default().path_style = value;
5635                        },
5636                    }),
5637                    metadata: None,
5638                    files: USER,
5639                }),
5640            ],
5641        },
5642        SettingsPage {
5643            title: "Collaboration",
5644            items: vec![
5645                SettingsPageItem::SectionHeader("Calls"),
5646                SettingsPageItem::SettingItem(SettingItem {
5647                    title: "Mute On Join",
5648                    description: "Whether the microphone should be muted when joining a channel or a call.",
5649                    field: Box::new(SettingField {
5650                        json_path: Some("calls.mute_on_join"),
5651                        pick: |settings_content| {
5652                            settings_content.calls.as_ref()?.mute_on_join.as_ref()
5653                        },
5654                        write: |settings_content, value| {
5655                            settings_content.calls.get_or_insert_default().mute_on_join = value;
5656                        },
5657                    }),
5658                    metadata: None,
5659                    files: USER,
5660                }),
5661                SettingsPageItem::SettingItem(SettingItem {
5662                    title: "Share On Join",
5663                    description: "Whether your current project should be shared when joining an empty channel.",
5664                    field: Box::new(SettingField {
5665                        json_path: Some("calls.share_on_join"),
5666                        pick: |settings_content| {
5667                            settings_content.calls.as_ref()?.share_on_join.as_ref()
5668                        },
5669                        write: |settings_content, value| {
5670                            settings_content.calls.get_or_insert_default().share_on_join = value;
5671                        },
5672                    }),
5673                    metadata: None,
5674                    files: USER,
5675                }),
5676                SettingsPageItem::SectionHeader("Experimental"),
5677                SettingsPageItem::SettingItem(SettingItem {
5678                    title: "Rodio Audio",
5679                    description: "Opt into the new audio system.",
5680                    field: Box::new(SettingField {
5681                        json_path: Some("audio.experimental.rodio_audio"),
5682                        pick: |settings_content| {
5683                            settings_content.audio.as_ref()?.rodio_audio.as_ref()
5684                        },
5685                        write: |settings_content, value| {
5686                            settings_content.audio.get_or_insert_default().rodio_audio = value;
5687                        },
5688                    }),
5689                    metadata: None,
5690                    files: USER,
5691                }),
5692                SettingsPageItem::SettingItem(SettingItem {
5693                    title: "Auto Microphone Volume",
5694                    description: "Automatically adjust microphone volume (requires rodio audio).",
5695                    field: Box::new(SettingField {
5696                        json_path: Some("audio.experimental.auto_microphone_volume"),
5697                        pick: |settings_content| {
5698                            settings_content
5699                                .audio
5700                                .as_ref()?
5701                                .auto_microphone_volume
5702                                .as_ref()
5703                        },
5704                        write: |settings_content, value| {
5705                            settings_content
5706                                .audio
5707                                .get_or_insert_default()
5708                                .auto_microphone_volume = value;
5709                        },
5710                    }),
5711                    metadata: None,
5712                    files: USER,
5713                }),
5714                SettingsPageItem::SettingItem(SettingItem {
5715                    title: "Auto Speaker Volume",
5716                    description: "Automatically adjust volume of other call members (requires rodio audio).",
5717                    field: Box::new(SettingField {
5718                        json_path: Some("audio.experimental.auto_speaker_volume"),
5719                        pick: |settings_content| {
5720                            settings_content
5721                                .audio
5722                                .as_ref()?
5723                                .auto_speaker_volume
5724                                .as_ref()
5725                        },
5726                        write: |settings_content, value| {
5727                            settings_content
5728                                .audio
5729                                .get_or_insert_default()
5730                                .auto_speaker_volume = value;
5731                        },
5732                    }),
5733                    metadata: None,
5734                    files: USER,
5735                }),
5736                SettingsPageItem::SettingItem(SettingItem {
5737                    title: "Denoise",
5738                    description: "Remove background noises (requires rodio audio).",
5739                    field: Box::new(SettingField {
5740                        json_path: Some("audio.experimental.denoise"),
5741                        pick: |settings_content| settings_content.audio.as_ref()?.denoise.as_ref(),
5742                        write: |settings_content, value| {
5743                            settings_content.audio.get_or_insert_default().denoise = value;
5744                        },
5745                    }),
5746                    metadata: None,
5747                    files: USER,
5748                }),
5749                SettingsPageItem::SettingItem(SettingItem {
5750                    title: "Legacy Audio Compatible",
5751                    description: "Use audio parameters compatible with previous versions (requires rodio audio).",
5752                    field: Box::new(SettingField {
5753                        json_path: Some("audio.experimental.legacy_audio_compatible"),
5754                        pick: |settings_content| {
5755                            settings_content
5756                                .audio
5757                                .as_ref()?
5758                                .legacy_audio_compatible
5759                                .as_ref()
5760                        },
5761                        write: |settings_content, value| {
5762                            settings_content
5763                                .audio
5764                                .get_or_insert_default()
5765                                .legacy_audio_compatible = value;
5766                        },
5767                    }),
5768                    metadata: None,
5769                    files: USER,
5770                }),
5771            ],
5772        },
5773        SettingsPage {
5774            title: "AI",
5775            items: {
5776                let mut items = vec![
5777                    SettingsPageItem::SectionHeader("General"),
5778                    SettingsPageItem::SettingItem(SettingItem {
5779                        title: "Disable AI",
5780                        description: "Whether to disable all AI features in Zed.",
5781                        field: Box::new(SettingField {
5782                            json_path: Some("disable_ai"),
5783                            pick: |settings_content| settings_content.disable_ai.as_ref(),
5784                            write: |settings_content, value| {
5785                                settings_content.disable_ai = value;
5786                            },
5787                        }),
5788                        metadata: None,
5789                        files: USER,
5790                    }),
5791                    SettingsPageItem::SectionHeader("Agent Configuration"),
5792                    SettingsPageItem::SettingItem(SettingItem {
5793                        title: "Always Allow Tool Actions",
5794                        description: "When enabled, the agent can run potentially destructive actions without asking for your confirmation. This setting has no effect on external agents.",
5795                        field: Box::new(SettingField {
5796                            json_path: Some("agent.always_allow_tool_actions"),
5797                            pick: |settings_content| {
5798                                settings_content
5799                                    .agent
5800                                    .as_ref()?
5801                                    .always_allow_tool_actions
5802                                    .as_ref()
5803                            },
5804                            write: |settings_content, value| {
5805                                settings_content
5806                                    .agent
5807                                    .get_or_insert_default()
5808                                    .always_allow_tool_actions = value;
5809                            },
5810                        }),
5811                        metadata: None,
5812                        files: USER,
5813                    }),
5814                    SettingsPageItem::SettingItem(SettingItem {
5815                        title: "Single File Review",
5816                        description: "When enabled, agent edits will also be displayed in single-file buffers for review.",
5817                        field: Box::new(SettingField {
5818                            json_path: Some("agent.single_file_review"),
5819                            pick: |settings_content| {
5820                                settings_content.agent.as_ref()?.single_file_review.as_ref()
5821                            },
5822                            write: |settings_content, value| {
5823                                settings_content
5824                                    .agent
5825                                    .get_or_insert_default()
5826                                    .single_file_review = value;
5827                            },
5828                        }),
5829                        metadata: None,
5830                        files: USER,
5831                    }),
5832                    SettingsPageItem::SettingItem(SettingItem {
5833                        title: "Enable Feedback",
5834                        description: "Show voting thumbs up/down icon buttons for feedback on agent edits.",
5835                        field: Box::new(SettingField {
5836                            json_path: Some("agent.enable_feedback"),
5837                            pick: |settings_content| {
5838                                settings_content.agent.as_ref()?.enable_feedback.as_ref()
5839                            },
5840                            write: |settings_content, value| {
5841                                settings_content
5842                                    .agent
5843                                    .get_or_insert_default()
5844                                    .enable_feedback = value;
5845                            },
5846                        }),
5847                        metadata: None,
5848                        files: USER,
5849                    }),
5850                    SettingsPageItem::SettingItem(SettingItem {
5851                        title: "Notify When Agent Waiting",
5852                        description: "Where to show notifications when the agent has completed its response or needs confirmation before running a tool action.",
5853                        field: Box::new(SettingField {
5854                            json_path: Some("agent.notify_when_agent_waiting"),
5855                            pick: |settings_content| {
5856                                settings_content
5857                                    .agent
5858                                    .as_ref()?
5859                                    .notify_when_agent_waiting
5860                                    .as_ref()
5861                            },
5862                            write: |settings_content, value| {
5863                                settings_content
5864                                    .agent
5865                                    .get_or_insert_default()
5866                                    .notify_when_agent_waiting = value;
5867                            },
5868                        }),
5869                        metadata: None,
5870                        files: USER,
5871                    }),
5872                    SettingsPageItem::SettingItem(SettingItem {
5873                        title: "Play Sound When Agent Done",
5874                        description: "Whether to play a sound when the agent has either completed its response, or needs user input.",
5875                        field: Box::new(SettingField {
5876                            json_path: Some("agent.play_sound_when_agent_done"),
5877                            pick: |settings_content| {
5878                                settings_content
5879                                    .agent
5880                                    .as_ref()?
5881                                    .play_sound_when_agent_done
5882                                    .as_ref()
5883                            },
5884                            write: |settings_content, value| {
5885                                settings_content
5886                                    .agent
5887                                    .get_or_insert_default()
5888                                    .play_sound_when_agent_done = value;
5889                            },
5890                        }),
5891                        metadata: None,
5892                        files: USER,
5893                    }),
5894                    SettingsPageItem::SettingItem(SettingItem {
5895                        title: "Expand Edit Card",
5896                        description: "Whether to have edit cards in the agent panel expanded, showing a Preview of the diff.",
5897                        field: Box::new(SettingField {
5898                            json_path: Some("agent.expand_edit_card"),
5899                            pick: |settings_content| {
5900                                settings_content.agent.as_ref()?.expand_edit_card.as_ref()
5901                            },
5902                            write: |settings_content, value| {
5903                                settings_content
5904                                    .agent
5905                                    .get_or_insert_default()
5906                                    .expand_edit_card = value;
5907                            },
5908                        }),
5909                        metadata: None,
5910                        files: USER,
5911                    }),
5912                    SettingsPageItem::SettingItem(SettingItem {
5913                        title: "Expand Terminal Card",
5914                        description: "Whether to have terminal cards in the agent panel expanded, showing the whole command output.",
5915                        field: Box::new(SettingField {
5916                            json_path: Some("agent.expand_terminal_card"),
5917                            pick: |settings_content| {
5918                                settings_content
5919                                    .agent
5920                                    .as_ref()?
5921                                    .expand_terminal_card
5922                                    .as_ref()
5923                            },
5924                            write: |settings_content, value| {
5925                                settings_content
5926                                    .agent
5927                                    .get_or_insert_default()
5928                                    .expand_terminal_card = value;
5929                            },
5930                        }),
5931                        metadata: None,
5932                        files: USER,
5933                    }),
5934                    SettingsPageItem::SettingItem(SettingItem {
5935                        title: "Use Modifier To Send",
5936                        description: "Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages.",
5937                        field: Box::new(SettingField {
5938                            json_path: Some("agent.use_modifier_to_send"),
5939                            pick: |settings_content| {
5940                                settings_content
5941                                    .agent
5942                                    .as_ref()?
5943                                    .use_modifier_to_send
5944                                    .as_ref()
5945                            },
5946                            write: |settings_content, value| {
5947                                settings_content
5948                                    .agent
5949                                    .get_or_insert_default()
5950                                    .use_modifier_to_send = value;
5951                            },
5952                        }),
5953                        metadata: None,
5954                        files: USER,
5955                    }),
5956                    SettingsPageItem::SettingItem(SettingItem {
5957                        title: "Message Editor Min Lines",
5958                        description: "Minimum number of lines to display in the agent message editor.",
5959                        field: Box::new(SettingField {
5960                            json_path: Some("agent.message_editor_min_lines"),
5961                            pick: |settings_content| {
5962                                settings_content
5963                                    .agent
5964                                    .as_ref()?
5965                                    .message_editor_min_lines
5966                                    .as_ref()
5967                            },
5968                            write: |settings_content, value| {
5969                                settings_content
5970                                    .agent
5971                                    .get_or_insert_default()
5972                                    .message_editor_min_lines = value;
5973                            },
5974                        }),
5975                        metadata: None,
5976                        files: USER,
5977                    }),
5978                ];
5979                items.extend(edit_prediction_language_settings_section());
5980                items.extend(
5981                    [
5982                        SettingsPageItem::SettingItem(SettingItem {
5983                            title: "Display Mode",
5984                            description: "When to show edit predictions previews in buffer. The eager mode displays them inline, while the subtle mode displays them only when holding a modifier key.",
5985                            field: Box::new(SettingField {
5986                                json_path: Some("edit_prediction.display_mode"),
5987                                pick: |settings_content| {
5988                                    settings_content.project.all_languages.edit_predictions.as_ref()?.mode.as_ref()
5989                                },
5990                                write: |settings_content, value| {
5991                                    settings_content.project.all_languages.edit_predictions.get_or_insert_default().mode = value;
5992                                },
5993                            }),
5994                            metadata: None,
5995                            files: USER,
5996                        }),
5997                        SettingsPageItem::SettingItem(SettingItem {
5998                            title: "In Text Threads",
5999                            description: "Whether edit predictions are enabled when editing text threads in the agent panel.",
6000                            field: Box::new(SettingField {
6001                                json_path: Some("edit_prediction.in_text_threads"),
6002                                pick: |settings_content| {
6003                                    settings_content.project.all_languages.edit_predictions.as_ref()?.enabled_in_text_threads.as_ref()
6004                                },
6005                                write: |settings_content, value| {
6006                                    settings_content.project.all_languages.edit_predictions.get_or_insert_default().enabled_in_text_threads = value;
6007                                },
6008                            }),
6009                            metadata: None,
6010                            files: USER,
6011                        }),
6012                        SettingsPageItem::SettingItem(SettingItem {
6013                            title: "Copilot Provider",
6014                            description: "Use GitHub Copilot as your edit prediction provider.",
6015                            field: Box::new(
6016                                SettingField {
6017                                    json_path: Some("edit_prediction.copilot_provider"),
6018                                    pick: |settings_content| {
6019                                        settings_content.project.all_languages.edit_predictions.as_ref()?.copilot.as_ref()
6020                                    },
6021                                    write: |settings_content, value| {
6022                                        settings_content.project.all_languages.edit_predictions.get_or_insert_default().copilot = value;
6023                                    },
6024                                }
6025                                .unimplemented(),
6026                            ),
6027                            metadata: None,
6028                            files: USER | PROJECT,
6029                        }),
6030                        SettingsPageItem::SettingItem(SettingItem {
6031                            title: "Codestral Provider",
6032                            description: "Use Mistral's Codestral as your edit prediction provider.",
6033                            field: Box::new(
6034                                SettingField {
6035                                    json_path: Some("edit_prediction.codestral_provider"),
6036                                    pick: |settings_content| {
6037                                        settings_content.project.all_languages.edit_predictions.as_ref()?.codestral.as_ref()
6038                                    },
6039                                    write: |settings_content, value| {
6040                                        settings_content.project.all_languages.edit_predictions.get_or_insert_default().codestral = value;
6041                                    },
6042                                }
6043                                .unimplemented(),
6044                            ),
6045                            metadata: None,
6046                            files: USER | PROJECT,
6047                        }),
6048                    ]
6049                );
6050                items
6051            },
6052        },
6053        SettingsPage {
6054            title: "Network",
6055            items: vec![
6056                SettingsPageItem::SectionHeader("Network"),
6057                // todo(settings_ui): Proxy needs a default
6058                SettingsPageItem::SettingItem(SettingItem {
6059                    title: "Proxy",
6060                    description: "The proxy to use for network requests.",
6061                    field: Box::new(
6062                        SettingField {
6063                            json_path: Some("proxy"),
6064                            pick: |settings_content| settings_content.proxy.as_ref(),
6065                            write: |settings_content, value| {
6066                                settings_content.proxy = value;
6067                            },
6068                        }
6069                        .unimplemented(),
6070                    ),
6071                    metadata: Some(Box::new(SettingsFieldMetadata {
6072                        placeholder: Some("socks5h://localhost:10808"),
6073                        ..Default::default()
6074                    })),
6075                    files: USER,
6076                }),
6077                SettingsPageItem::SettingItem(SettingItem {
6078                    title: "Server URL",
6079                    description: "The URL of the Zed server to connect to.",
6080                    field: Box::new(SettingField {
6081                        json_path: Some("server_url"),
6082                        pick: |settings_content| settings_content.server_url.as_ref(),
6083                        write: |settings_content, value| {
6084                            settings_content.server_url = value;
6085                        },
6086                    }),
6087                    metadata: Some(Box::new(SettingsFieldMetadata {
6088                        placeholder: Some("https://zed.dev"),
6089                        ..Default::default()
6090                    })),
6091                    files: USER,
6092                }),
6093            ],
6094        },
6095    ]
6096}
6097
6098const LANGUAGES_SECTION_HEADER: &'static str = "Languages";
6099
6100fn current_language() -> Option<SharedString> {
6101    sub_page_stack().iter().find_map(|page| {
6102        (page.section_header == LANGUAGES_SECTION_HEADER).then(|| page.link.title.clone())
6103    })
6104}
6105
6106fn language_settings_field<T>(
6107    settings_content: &SettingsContent,
6108    get: fn(&LanguageSettingsContent) -> Option<&T>,
6109) -> Option<&T> {
6110    let all_languages = &settings_content.project.all_languages;
6111    if let Some(current_language_name) = current_language() {
6112        if let Some(current_language) = all_languages.languages.0.get(&current_language_name) {
6113            let value = get(current_language);
6114            if value.is_some() {
6115                return value;
6116            }
6117        }
6118    }
6119    let default_value = get(&all_languages.defaults);
6120    return default_value;
6121}
6122
6123fn language_settings_field_mut<T>(
6124    settings_content: &mut SettingsContent,
6125    value: Option<T>,
6126    write: fn(&mut LanguageSettingsContent, Option<T>),
6127) {
6128    let all_languages = &mut settings_content.project.all_languages;
6129    let language_content = if let Some(current_language) = current_language() {
6130        all_languages
6131            .languages
6132            .0
6133            .entry(current_language)
6134            .or_default()
6135    } else {
6136        &mut all_languages.defaults
6137    };
6138    write(language_content, value);
6139}
6140
6141fn language_settings_data() -> Vec<SettingsPageItem> {
6142    let mut items = vec![
6143        SettingsPageItem::SectionHeader("Indentation"),
6144        SettingsPageItem::SettingItem(SettingItem {
6145            title: "Tab Size",
6146            description: "How many columns a tab should occupy.",
6147            field: Box::new(SettingField {
6148                json_path: Some("languages.$(language).tab_size"), // TODO(cameron): not JQ syntax because not URL-safe
6149                pick: |settings_content| {
6150                    language_settings_field(settings_content, |language| language.tab_size.as_ref())
6151                },
6152                write: |settings_content, value| {
6153                    language_settings_field_mut(settings_content, value, |language, value| {
6154                        language.tab_size = value;
6155                    })
6156                },
6157            }),
6158            metadata: None,
6159            files: USER | PROJECT,
6160        }),
6161        SettingsPageItem::SettingItem(SettingItem {
6162            title: "Hard Tabs",
6163            description: "Whether to indent lines using tab characters, as opposed to multiple spaces.",
6164            field: Box::new(SettingField {
6165                json_path: Some("languages.$(language).hard_tabs"),
6166                pick: |settings_content| {
6167                    language_settings_field(settings_content, |language| {
6168                        language.hard_tabs.as_ref()
6169                    })
6170                },
6171                write: |settings_content, value| {
6172                    language_settings_field_mut(settings_content, value, |language, value| {
6173                        language.hard_tabs = value;
6174                    })
6175                },
6176            }),
6177            metadata: None,
6178            files: USER | PROJECT,
6179        }),
6180        SettingsPageItem::SettingItem(SettingItem {
6181            title: "Auto Indent",
6182            description: "Whether indentation should be adjusted based on the context whilst typing.",
6183            field: Box::new(SettingField {
6184                json_path: Some("languages.$(language).auto_indent"),
6185                pick: |settings_content| {
6186                    language_settings_field(settings_content, |language| {
6187                        language.auto_indent.as_ref()
6188                    })
6189                },
6190                write: |settings_content, value| {
6191                    language_settings_field_mut(settings_content, value, |language, value| {
6192                        language.auto_indent = value;
6193                    })
6194                },
6195            }),
6196            metadata: None,
6197            files: USER | PROJECT,
6198        }),
6199        SettingsPageItem::SettingItem(SettingItem {
6200            title: "Auto Indent On Paste",
6201            description: "Whether indentation of pasted content should be adjusted based on the context.",
6202            field: Box::new(SettingField {
6203                json_path: Some("languages.$(language).auto_indent_on_paste"),
6204                pick: |settings_content| {
6205                    language_settings_field(settings_content, |language| {
6206                        language.auto_indent_on_paste.as_ref()
6207                    })
6208                },
6209                write: |settings_content, value| {
6210                    language_settings_field_mut(settings_content, value, |language, value| {
6211                        language.auto_indent_on_paste = value;
6212                    })
6213                },
6214            }),
6215            metadata: None,
6216            files: USER | PROJECT,
6217        }),
6218        SettingsPageItem::SectionHeader("Wrapping"),
6219        SettingsPageItem::SettingItem(SettingItem {
6220            title: "Soft Wrap",
6221            description: "How to soft-wrap long lines of text.",
6222            field: Box::new(SettingField {
6223                json_path: Some("languages.$(language).soft_wrap"),
6224                pick: |settings_content| {
6225                    language_settings_field(settings_content, |language| {
6226                        language.soft_wrap.as_ref()
6227                    })
6228                },
6229                write: |settings_content, value| {
6230                    language_settings_field_mut(settings_content, value, |language, value| {
6231                        language.soft_wrap = value;
6232                    })
6233                },
6234            }),
6235            metadata: None,
6236            files: USER | PROJECT,
6237        }),
6238        SettingsPageItem::SettingItem(SettingItem {
6239            title: "Show Wrap Guides",
6240            description: "Show wrap guides in the editor.",
6241            field: Box::new(SettingField {
6242                json_path: Some("languages.$(language).show_wrap_guides"),
6243                pick: |settings_content| {
6244                    language_settings_field(settings_content, |language| {
6245                        language.show_wrap_guides.as_ref()
6246                    })
6247                },
6248                write: |settings_content, value| {
6249                    language_settings_field_mut(settings_content, value, |language, value| {
6250                        language.show_wrap_guides = value;
6251                    })
6252                },
6253            }),
6254            metadata: None,
6255            files: USER | PROJECT,
6256        }),
6257        SettingsPageItem::SettingItem(SettingItem {
6258            title: "Preferred Line Length",
6259            description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled.",
6260            field: Box::new(SettingField {
6261                json_path: Some("languages.$(language).preferred_line_length"),
6262                pick: |settings_content| {
6263                    language_settings_field(settings_content, |language| {
6264                        language.preferred_line_length.as_ref()
6265                    })
6266                },
6267                write: |settings_content, value| {
6268                    language_settings_field_mut(settings_content, value, |language, value| {
6269                        language.preferred_line_length = value;
6270                    })
6271                },
6272            }),
6273            metadata: None,
6274            files: USER | PROJECT,
6275        }),
6276        SettingsPageItem::SettingItem(SettingItem {
6277            title: "Wrap Guides",
6278            description: "Character counts at which to show wrap guides in the editor.",
6279            field: Box::new(
6280                SettingField {
6281                    json_path: Some("languages.$(language).wrap_guides"),
6282                    pick: |settings_content| {
6283                        language_settings_field(settings_content, |language| {
6284                            language.wrap_guides.as_ref()
6285                        })
6286                    },
6287                    write: |settings_content, value| {
6288                        language_settings_field_mut(settings_content, value, |language, value| {
6289                            language.wrap_guides = value;
6290                        })
6291                    },
6292                }
6293                .unimplemented(),
6294            ),
6295            metadata: None,
6296            files: USER | PROJECT,
6297        }),
6298        SettingsPageItem::SettingItem(SettingItem {
6299            title: "Allow Rewrap",
6300            description: "Controls where the `editor::rewrap` action is allowed for this language.",
6301            field: Box::new(SettingField {
6302                json_path: Some("languages.$(language).allow_rewrap"),
6303                pick: |settings_content| {
6304                    language_settings_field(settings_content, |language| {
6305                        language.allow_rewrap.as_ref()
6306                    })
6307                },
6308                write: |settings_content, value| {
6309                    language_settings_field_mut(settings_content, value, |language, value| {
6310                        language.allow_rewrap = value;
6311                    })
6312                },
6313            }),
6314            metadata: None,
6315            files: USER | PROJECT,
6316        }),
6317        SettingsPageItem::SectionHeader("Indent Guides"),
6318        SettingsPageItem::SettingItem(SettingItem {
6319            title: "Enabled",
6320            description: "Display indent guides in the editor.",
6321            field: Box::new(SettingField {
6322                json_path: Some("languages.$(language).indent_guides.enabled"),
6323                pick: |settings_content| {
6324                    language_settings_field(settings_content, |language| {
6325                        language
6326                            .indent_guides
6327                            .as_ref()
6328                            .and_then(|indent_guides| indent_guides.enabled.as_ref())
6329                    })
6330                },
6331                write: |settings_content, value| {
6332                    language_settings_field_mut(settings_content, value, |language, value| {
6333                        language.indent_guides.get_or_insert_default().enabled = value;
6334                    })
6335                },
6336            }),
6337            metadata: None,
6338            files: USER | PROJECT,
6339        }),
6340        SettingsPageItem::SettingItem(SettingItem {
6341            title: "Line Width",
6342            description: "The width of the indent guides in pixels, between 1 and 10.",
6343            field: Box::new(SettingField {
6344                json_path: Some("languages.$(language).indent_guides.line_width"),
6345                pick: |settings_content| {
6346                    language_settings_field(settings_content, |language| {
6347                        language
6348                            .indent_guides
6349                            .as_ref()
6350                            .and_then(|indent_guides| indent_guides.line_width.as_ref())
6351                    })
6352                },
6353                write: |settings_content, value| {
6354                    language_settings_field_mut(settings_content, value, |language, value| {
6355                        language.indent_guides.get_or_insert_default().line_width = value;
6356                    })
6357                },
6358            }),
6359            metadata: None,
6360            files: USER | PROJECT,
6361        }),
6362        SettingsPageItem::SettingItem(SettingItem {
6363            title: "Active Line Width",
6364            description: "The width of the active indent guide in pixels, between 1 and 10.",
6365            field: Box::new(SettingField {
6366                json_path: Some("languages.$(language).indent_guides.active_line_width"),
6367                pick: |settings_content| {
6368                    language_settings_field(settings_content, |language| {
6369                        language
6370                            .indent_guides
6371                            .as_ref()
6372                            .and_then(|indent_guides| indent_guides.active_line_width.as_ref())
6373                    })
6374                },
6375                write: |settings_content, value| {
6376                    language_settings_field_mut(settings_content, value, |language, value| {
6377                        language
6378                            .indent_guides
6379                            .get_or_insert_default()
6380                            .active_line_width = value;
6381                    })
6382                },
6383            }),
6384            metadata: None,
6385            files: USER | PROJECT,
6386        }),
6387        SettingsPageItem::SettingItem(SettingItem {
6388            title: "Coloring",
6389            description: "Determines how indent guides are colored.",
6390            field: Box::new(SettingField {
6391                json_path: Some("languages.$(language).indent_guides.coloring"),
6392                pick: |settings_content| {
6393                    language_settings_field(settings_content, |language| {
6394                        language
6395                            .indent_guides
6396                            .as_ref()
6397                            .and_then(|indent_guides| indent_guides.coloring.as_ref())
6398                    })
6399                },
6400                write: |settings_content, value| {
6401                    language_settings_field_mut(settings_content, value, |language, value| {
6402                        language.indent_guides.get_or_insert_default().coloring = value;
6403                    })
6404                },
6405            }),
6406            metadata: None,
6407            files: USER | PROJECT,
6408        }),
6409        SettingsPageItem::SettingItem(SettingItem {
6410            title: "Background Coloring",
6411            description: "Determines how indent guide backgrounds are colored.",
6412            field: Box::new(SettingField {
6413                json_path: Some("languages.$(language).indent_guides.background_coloring"),
6414                pick: |settings_content| {
6415                    language_settings_field(settings_content, |language| {
6416                        language
6417                            .indent_guides
6418                            .as_ref()
6419                            .and_then(|indent_guides| indent_guides.background_coloring.as_ref())
6420                    })
6421                },
6422                write: |settings_content, value| {
6423                    language_settings_field_mut(settings_content, value, |language, value| {
6424                        language
6425                            .indent_guides
6426                            .get_or_insert_default()
6427                            .background_coloring = value;
6428                    })
6429                },
6430            }),
6431            metadata: None,
6432            files: USER | PROJECT,
6433        }),
6434        SettingsPageItem::SectionHeader("Formatting"),
6435        SettingsPageItem::SettingItem(SettingItem {
6436            title: "Format On Save",
6437            description: "Whether or not to perform a buffer format before saving.",
6438            field: Box::new(
6439                // TODO(settings_ui): this setting should just be a bool
6440                SettingField {
6441                    json_path: Some("languages.$(language).format_on_save"),
6442                    pick: |settings_content| {
6443                        language_settings_field(settings_content, |language| {
6444                            language.format_on_save.as_ref()
6445                        })
6446                    },
6447                    write: |settings_content, value| {
6448                        language_settings_field_mut(settings_content, value, |language, value| {
6449                            language.format_on_save = value;
6450                        })
6451                    },
6452                },
6453            ),
6454            metadata: None,
6455            files: USER | PROJECT,
6456        }),
6457        SettingsPageItem::SettingItem(SettingItem {
6458            title: "Remove Trailing Whitespace On Save",
6459            description: "Whether or not to remove any trailing whitespace from lines of a buffer before saving it.",
6460            field: Box::new(SettingField {
6461                json_path: Some("languages.$(language).remove_trailing_whitespace_on_save"),
6462                pick: |settings_content| {
6463                    language_settings_field(settings_content, |language| {
6464                        language.remove_trailing_whitespace_on_save.as_ref()
6465                    })
6466                },
6467                write: |settings_content, value| {
6468                    language_settings_field_mut(settings_content, value, |language, value| {
6469                        language.remove_trailing_whitespace_on_save = value;
6470                    })
6471                },
6472            }),
6473            metadata: None,
6474            files: USER | PROJECT,
6475        }),
6476        SettingsPageItem::SettingItem(SettingItem {
6477            title: "Ensure Final Newline On Save",
6478            description: "Whether or not to ensure there's a single newline at the end of a buffer when saving it.",
6479            field: Box::new(SettingField {
6480                json_path: Some("languages.$(language).ensure_final_newline_on_save"),
6481                pick: |settings_content| {
6482                    language_settings_field(settings_content, |language| {
6483                        language.ensure_final_newline_on_save.as_ref()
6484                    })
6485                },
6486                write: |settings_content, value| {
6487                    language_settings_field_mut(settings_content, value, |language, value| {
6488                        language.ensure_final_newline_on_save = value;
6489                    })
6490                },
6491            }),
6492            metadata: None,
6493            files: USER | PROJECT,
6494        }),
6495        SettingsPageItem::SettingItem(SettingItem {
6496            title: "Formatter",
6497            description: "How to perform a buffer format.",
6498            field: Box::new(
6499                SettingField {
6500                    json_path: Some("languages.$(language).formatter"),
6501                    pick: |settings_content| {
6502                        language_settings_field(settings_content, |language| {
6503                            language.formatter.as_ref()
6504                        })
6505                    },
6506                    write: |settings_content, value| {
6507                        language_settings_field_mut(settings_content, value, |language, value| {
6508                            language.formatter = value;
6509                        })
6510                    },
6511                }
6512                .unimplemented(),
6513            ),
6514            metadata: None,
6515            files: USER | PROJECT,
6516        }),
6517        SettingsPageItem::SettingItem(SettingItem {
6518            title: "Use On Type Format",
6519            description: "Whether to use additional LSP queries to format (and amend) the code after every \"trigger\" symbol input, defined by LSP server capabilities",
6520            field: Box::new(SettingField {
6521                json_path: Some("languages.$(language).use_on_type_format"),
6522                pick: |settings_content| {
6523                    language_settings_field(settings_content, |language| {
6524                        language.use_on_type_format.as_ref()
6525                    })
6526                },
6527                write: |settings_content, value| {
6528                    language_settings_field_mut(settings_content, value, |language, value| {
6529                        language.use_on_type_format = value;
6530                    })
6531                },
6532            }),
6533            metadata: None,
6534            files: USER | PROJECT,
6535        }),
6536        SettingsPageItem::SettingItem(SettingItem {
6537            title: "Code Actions On Format",
6538            description: "Additional code actions to run when formatting.",
6539            field: Box::new(
6540                SettingField {
6541                    json_path: Some("languages.$(language).code_actions_on_format"),
6542                    pick: |settings_content| {
6543                        language_settings_field(settings_content, |language| {
6544                            language.code_actions_on_format.as_ref()
6545                        })
6546                    },
6547                    write: |settings_content, value| {
6548                        language_settings_field_mut(settings_content, value, |language, value| {
6549                            language.code_actions_on_format = value;
6550                        })
6551                    },
6552                }
6553                .unimplemented(),
6554            ),
6555            metadata: None,
6556            files: USER | PROJECT,
6557        }),
6558        SettingsPageItem::SectionHeader("Autoclose"),
6559        SettingsPageItem::SettingItem(SettingItem {
6560            title: "Use Autoclose",
6561            description: "Whether to automatically type closing characters for you. For example, when you type '(', Zed will automatically add a closing ')' at the correct position.",
6562            field: Box::new(SettingField {
6563                json_path: Some("languages.$(language).use_autoclose"),
6564                pick: |settings_content| {
6565                    language_settings_field(settings_content, |language| {
6566                        language.use_autoclose.as_ref()
6567                    })
6568                },
6569                write: |settings_content, value| {
6570                    language_settings_field_mut(settings_content, value, |language, value| {
6571                        language.use_autoclose = value;
6572                    })
6573                },
6574            }),
6575            metadata: None,
6576            files: USER | PROJECT,
6577        }),
6578        SettingsPageItem::SettingItem(SettingItem {
6579            title: "Use Auto Surround",
6580            description: "Whether to automatically surround text with characters for you. For example, when you select text and type '(', Zed will automatically surround text with ().",
6581            field: Box::new(SettingField {
6582                json_path: Some("languages.$(language).use_auto_surround"),
6583                pick: |settings_content| {
6584                    language_settings_field(settings_content, |language| {
6585                        language.use_auto_surround.as_ref()
6586                    })
6587                },
6588                write: |settings_content, value| {
6589                    language_settings_field_mut(settings_content, value, |language, value| {
6590                        language.use_auto_surround = value;
6591                    })
6592                },
6593            }),
6594            metadata: None,
6595            files: USER | PROJECT,
6596        }),
6597        SettingsPageItem::SettingItem(SettingItem {
6598            title: "Always Treat Brackets As Autoclosed",
6599            description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted.",
6600            field: Box::new(SettingField {
6601                json_path: Some("languages.$(language).always_treat_brackets_as_autoclosed"),
6602                pick: |settings_content| {
6603                    language_settings_field(settings_content, |language| {
6604                        language.always_treat_brackets_as_autoclosed.as_ref()
6605                    })
6606                },
6607                write: |settings_content, value| {
6608                    language_settings_field_mut(settings_content, value, |language, value| {
6609                        language.always_treat_brackets_as_autoclosed = value;
6610                    })
6611                },
6612            }),
6613            metadata: None,
6614            files: USER | PROJECT,
6615        }),
6616        SettingsPageItem::SettingItem(SettingItem {
6617            title: "JSX Tag Auto Close",
6618            description: "Whether to automatically close JSX tags.",
6619            field: Box::new(SettingField {
6620                json_path: Some("languages.$(language).jsx_tag_auto_close"),
6621                // TODO(settings_ui): this setting should just be a bool
6622                pick: |settings_content| {
6623                    language_settings_field(settings_content, |language| {
6624                        language.jsx_tag_auto_close.as_ref()?.enabled.as_ref()
6625                    })
6626                },
6627                write: |settings_content, value| {
6628                    language_settings_field_mut(settings_content, value, |language, value| {
6629                        language.jsx_tag_auto_close.get_or_insert_default().enabled = value;
6630                    })
6631                },
6632            }),
6633            metadata: None,
6634            files: USER | PROJECT,
6635        }),
6636        SettingsPageItem::SectionHeader("Whitespace"),
6637        SettingsPageItem::SettingItem(SettingItem {
6638            title: "Show Whitespaces",
6639            description: "Whether to show tabs and spaces in the editor.",
6640            field: Box::new(SettingField {
6641                json_path: Some("languages.$(language).show_whitespaces"),
6642                pick: |settings_content| {
6643                    language_settings_field(settings_content, |language| {
6644                        language.show_whitespaces.as_ref()
6645                    })
6646                },
6647                write: |settings_content, value| {
6648                    language_settings_field_mut(settings_content, value, |language, value| {
6649                        language.show_whitespaces = value;
6650                    })
6651                },
6652            }),
6653            metadata: None,
6654            files: USER | PROJECT,
6655        }),
6656        SettingsPageItem::SettingItem(SettingItem {
6657            title: "Space Whitespace Indicator",
6658            description: "Visible character used to render space characters when show_whitespaces is enabled (default: \"\")",
6659            field: Box::new(
6660                SettingField {
6661                    json_path: Some("languages.$(language).whitespace_map.space"),
6662                    pick: |settings_content| {
6663                        language_settings_field(settings_content, |language| {
6664                            language.whitespace_map.as_ref()?.space.as_ref()
6665                        })
6666                    },
6667                    write: |settings_content, value| {
6668                        language_settings_field_mut(settings_content, value, |language, value| {
6669                            language.whitespace_map.get_or_insert_default().space = value;
6670                        })
6671                    },
6672                }
6673                .unimplemented(),
6674            ),
6675            metadata: None,
6676            files: USER | PROJECT,
6677        }),
6678        SettingsPageItem::SettingItem(SettingItem {
6679            title: "Tab Whitespace Indicator",
6680            description: "Visible character used to render tab characters when show_whitespaces is enabled (default: \"\")",
6681            field: Box::new(
6682                SettingField {
6683                    json_path: Some("languages.$(language).whitespace_map.tab"),
6684                    pick: |settings_content| {
6685                        language_settings_field(settings_content, |language| {
6686                            language.whitespace_map.as_ref()?.tab.as_ref()
6687                        })
6688                    },
6689                    write: |settings_content, value| {
6690                        language_settings_field_mut(settings_content, value, |language, value| {
6691                            language.whitespace_map.get_or_insert_default().tab = value;
6692                        })
6693                    },
6694                }
6695                .unimplemented(),
6696            ),
6697            metadata: None,
6698            files: USER | PROJECT,
6699        }),
6700        SettingsPageItem::SectionHeader("Completions"),
6701        SettingsPageItem::SettingItem(SettingItem {
6702            title: "Show Completions On Input",
6703            description: "Whether to pop the completions menu while typing in an editor without explicitly requesting it.",
6704            field: Box::new(SettingField {
6705                json_path: Some("languages.$(language).show_completions_on_input"),
6706                pick: |settings_content| {
6707                    language_settings_field(settings_content, |language| {
6708                        language.show_completions_on_input.as_ref()
6709                    })
6710                },
6711                write: |settings_content, value| {
6712                    language_settings_field_mut(settings_content, value, |language, value| {
6713                        language.show_completions_on_input = value;
6714                    })
6715                },
6716            }),
6717            metadata: None,
6718            files: USER | PROJECT,
6719        }),
6720        SettingsPageItem::SettingItem(SettingItem {
6721            title: "Show Completion Documentation",
6722            description: "Whether to display inline and alongside documentation for items in the completions menu.",
6723            field: Box::new(SettingField {
6724                json_path: Some("languages.$(language).show_completion_documentation"),
6725                pick: |settings_content| {
6726                    language_settings_field(settings_content, |language| {
6727                        language.show_completion_documentation.as_ref()
6728                    })
6729                },
6730                write: |settings_content, value| {
6731                    language_settings_field_mut(settings_content, value, |language, value| {
6732                        language.show_completion_documentation = value;
6733                    })
6734                },
6735            }),
6736            metadata: None,
6737            files: USER | PROJECT,
6738        }),
6739        SettingsPageItem::SettingItem(SettingItem {
6740            title: "Words",
6741            description: "Controls how words are completed.",
6742            field: Box::new(SettingField {
6743                json_path: Some("languages.$(language).completions.words"),
6744                pick: |settings_content| {
6745                    language_settings_field(settings_content, |language| {
6746                        language.completions.as_ref()?.words.as_ref()
6747                    })
6748                },
6749                write: |settings_content, value| {
6750                    language_settings_field_mut(settings_content, value, |language, value| {
6751                        language.completions.get_or_insert_default().words = value;
6752                    })
6753                },
6754            }),
6755            metadata: None,
6756            files: USER | PROJECT,
6757        }),
6758        SettingsPageItem::SettingItem(SettingItem {
6759            title: "Words Min Length",
6760            description: "How many characters has to be in the completions query to automatically show the words-based completions.",
6761            field: Box::new(SettingField {
6762                json_path: Some("languages.$(language).completions.words_min_length"),
6763                pick: |settings_content| {
6764                    language_settings_field(settings_content, |language| {
6765                        language.completions.as_ref()?.words_min_length.as_ref()
6766                    })
6767                },
6768                write: |settings_content, value| {
6769                    language_settings_field_mut(settings_content, value, |language, value| {
6770                        language
6771                            .completions
6772                            .get_or_insert_default()
6773                            .words_min_length = value;
6774                    })
6775                },
6776            }),
6777            metadata: None,
6778            files: USER | PROJECT,
6779        }),
6780        SettingsPageItem::SettingItem(SettingItem {
6781            title: "Completion Menu Scrollbar",
6782            description: "When to show the scrollbar in the completion menu.",
6783            field: Box::new(SettingField {
6784                json_path: Some("editor.completion_menu_scrollbar"),
6785                pick: |settings_content| settings_content.editor.completion_menu_scrollbar.as_ref(),
6786                write: |settings_content, value| {
6787                    settings_content.editor.completion_menu_scrollbar = value;
6788                },
6789            }),
6790            metadata: None,
6791            files: USER,
6792        }),
6793        SettingsPageItem::SectionHeader("Inlay Hints"),
6794        SettingsPageItem::SettingItem(SettingItem {
6795            title: "Enabled",
6796            description: "Global switch to toggle hints on and off.",
6797            field: Box::new(SettingField {
6798                json_path: Some("languages.$(language).inlay_hints.enabled"),
6799                pick: |settings_content| {
6800                    language_settings_field(settings_content, |language| {
6801                        language.inlay_hints.as_ref()?.enabled.as_ref()
6802                    })
6803                },
6804                write: |settings_content, value| {
6805                    language_settings_field_mut(settings_content, value, |language, value| {
6806                        language.inlay_hints.get_or_insert_default().enabled = value;
6807                    })
6808                },
6809            }),
6810            metadata: None,
6811            files: USER | PROJECT,
6812        }),
6813        SettingsPageItem::SettingItem(SettingItem {
6814            title: "Show Value Hints",
6815            description: "Global switch to toggle inline values on and off when debugging.",
6816            field: Box::new(SettingField {
6817                json_path: Some("languages.$(language).inlay_hints.show_value_hints"),
6818                pick: |settings_content| {
6819                    language_settings_field(settings_content, |language| {
6820                        language.inlay_hints.as_ref()?.show_value_hints.as_ref()
6821                    })
6822                },
6823                write: |settings_content, value| {
6824                    language_settings_field_mut(settings_content, value, |language, value| {
6825                        language
6826                            .inlay_hints
6827                            .get_or_insert_default()
6828                            .show_value_hints = value;
6829                    })
6830                },
6831            }),
6832            metadata: None,
6833            files: USER | PROJECT,
6834        }),
6835        SettingsPageItem::SettingItem(SettingItem {
6836            title: "Show Type Hints",
6837            description: "Whether type hints should be shown.",
6838            field: Box::new(SettingField {
6839                json_path: Some("languages.$(language).inlay_hints.show_type_hints"),
6840                pick: |settings_content| {
6841                    language_settings_field(settings_content, |language| {
6842                        language.inlay_hints.as_ref()?.show_type_hints.as_ref()
6843                    })
6844                },
6845                write: |settings_content, value| {
6846                    language_settings_field_mut(settings_content, value, |language, value| {
6847                        language.inlay_hints.get_or_insert_default().show_type_hints = value;
6848                    })
6849                },
6850            }),
6851            metadata: None,
6852            files: USER | PROJECT,
6853        }),
6854        SettingsPageItem::SettingItem(SettingItem {
6855            title: "Show Parameter Hints",
6856            description: "Whether parameter hints should be shown.",
6857            field: Box::new(SettingField {
6858                json_path: Some("languages.$(language).inlay_hints.show_parameter_hints"),
6859                pick: |settings_content| {
6860                    language_settings_field(settings_content, |language| {
6861                        language.inlay_hints.as_ref()?.show_parameter_hints.as_ref()
6862                    })
6863                },
6864                write: |settings_content, value| {
6865                    language_settings_field_mut(settings_content, value, |language, value| {
6866                        language
6867                            .inlay_hints
6868                            .get_or_insert_default()
6869                            .show_parameter_hints = value;
6870                    })
6871                },
6872            }),
6873            metadata: None,
6874            files: USER | PROJECT,
6875        }),
6876        SettingsPageItem::SettingItem(SettingItem {
6877            title: "Show Other Hints",
6878            description: "Whether other hints should be shown.",
6879            field: Box::new(SettingField {
6880                json_path: Some("languages.$(language).inlay_hints.show_other_hints"),
6881                pick: |settings_content| {
6882                    language_settings_field(settings_content, |language| {
6883                        language.inlay_hints.as_ref()?.show_other_hints.as_ref()
6884                    })
6885                },
6886                write: |settings_content, value| {
6887                    language_settings_field_mut(settings_content, value, |language, value| {
6888                        language
6889                            .inlay_hints
6890                            .get_or_insert_default()
6891                            .show_other_hints = value;
6892                    })
6893                },
6894            }),
6895            metadata: None,
6896            files: USER | PROJECT,
6897        }),
6898        SettingsPageItem::SettingItem(SettingItem {
6899            title: "Show Background",
6900            description: "Show a background for inlay hints.",
6901            field: Box::new(SettingField {
6902                json_path: Some("languages.$(language).inlay_hints.show_background"),
6903                pick: |settings_content| {
6904                    language_settings_field(settings_content, |language| {
6905                        language.inlay_hints.as_ref()?.show_background.as_ref()
6906                    })
6907                },
6908                write: |settings_content, value| {
6909                    language_settings_field_mut(settings_content, value, |language, value| {
6910                        language.inlay_hints.get_or_insert_default().show_background = value;
6911                    })
6912                },
6913            }),
6914            metadata: None,
6915            files: USER | PROJECT,
6916        }),
6917        SettingsPageItem::SettingItem(SettingItem {
6918            title: "Edit Debounce Ms",
6919            description: "Whether or not to debounce inlay hints updates after buffer edits (set to 0 to disable debouncing).",
6920            field: Box::new(SettingField {
6921                json_path: Some("languages.$(language).inlay_hints.edit_debounce_ms"),
6922                pick: |settings_content| {
6923                    language_settings_field(settings_content, |language| {
6924                        language.inlay_hints.as_ref()?.edit_debounce_ms.as_ref()
6925                    })
6926                },
6927                write: |settings_content, value| {
6928                    language_settings_field_mut(settings_content, value, |language, value| {
6929                        language
6930                            .inlay_hints
6931                            .get_or_insert_default()
6932                            .edit_debounce_ms = value;
6933                    })
6934                },
6935            }),
6936            metadata: None,
6937            files: USER | PROJECT,
6938        }),
6939        SettingsPageItem::SettingItem(SettingItem {
6940            title: "Scroll Debounce Ms",
6941            description: "Whether or not to debounce inlay hints updates after buffer scrolls (set to 0 to disable debouncing).",
6942            field: Box::new(SettingField {
6943                json_path: Some("languages.$(language).inlay_hints.scroll_debounce_ms"),
6944                pick: |settings_content| {
6945                    language_settings_field(settings_content, |language| {
6946                        language.inlay_hints.as_ref()?.scroll_debounce_ms.as_ref()
6947                    })
6948                },
6949                write: |settings_content, value| {
6950                    language_settings_field_mut(settings_content, value, |language, value| {
6951                        language
6952                            .inlay_hints
6953                            .get_or_insert_default()
6954                            .scroll_debounce_ms = value;
6955                    })
6956                },
6957            }),
6958            metadata: None,
6959            files: USER | PROJECT,
6960        }),
6961        SettingsPageItem::SettingItem(SettingItem {
6962            title: "Toggle On Modifiers Press",
6963            description: "Toggles inlay hints (hides or shows) when the user presses the modifiers specified.",
6964            field: Box::new(
6965                SettingField {
6966                    json_path: Some("languages.$(language).inlay_hints.toggle_on_modifiers_press"),
6967                    pick: |settings_content| {
6968                        language_settings_field(settings_content, |language| {
6969                            language
6970                                .inlay_hints
6971                                .as_ref()?
6972                                .toggle_on_modifiers_press
6973                                .as_ref()
6974                        })
6975                    },
6976                    write: |settings_content, value| {
6977                        language_settings_field_mut(settings_content, value, |language, value| {
6978                            language
6979                                .inlay_hints
6980                                .get_or_insert_default()
6981                                .toggle_on_modifiers_press = value;
6982                        })
6983                    },
6984                }
6985                .unimplemented(),
6986            ),
6987            metadata: None,
6988            files: USER | PROJECT,
6989        }),
6990    ];
6991    if current_language().is_none() {
6992        items.push(SettingsPageItem::SettingItem(SettingItem {
6993            title: "LSP Document Colors",
6994            description: "How to render LSP color previews in the editor.",
6995            field: Box::new(SettingField {
6996                json_path: Some("lsp_document_colors"),
6997                pick: |settings_content| settings_content.editor.lsp_document_colors.as_ref(),
6998                write: |settings_content, value| {
6999                    settings_content.editor.lsp_document_colors = value;
7000                },
7001            }),
7002            metadata: None,
7003            files: USER,
7004        }))
7005    }
7006    items.extend([
7007        SettingsPageItem::SectionHeader("Tasks"),
7008        SettingsPageItem::SettingItem(SettingItem {
7009            title: "Enabled",
7010            description: "Whether tasks are enabled for this language.",
7011            field: Box::new(SettingField {
7012                json_path: Some("languages.$(language).tasks.enabled"),
7013                pick: |settings_content| {
7014                    language_settings_field(settings_content, |language| {
7015                        language.tasks.as_ref()?.enabled.as_ref()
7016                    })
7017                },
7018                write: |settings_content, value| {
7019                    language_settings_field_mut(settings_content, value, |language, value| {
7020                        language.tasks.get_or_insert_default().enabled = value;
7021
7022                    })
7023                },
7024            }),
7025            metadata: None,
7026            files: USER | PROJECT,
7027        }),
7028        SettingsPageItem::SettingItem(SettingItem {
7029            title: "Variables",
7030            description: "Extra task variables to set for a particular language.",
7031            field: Box::new(
7032                SettingField {
7033                    json_path: Some("languages.$(language).tasks.variables"),
7034                    pick: |settings_content| {
7035                        language_settings_field(settings_content, |language| {
7036                            language.tasks.as_ref()?.variables.as_ref()
7037                        })
7038                    },
7039                    write: |settings_content, value| {
7040                        language_settings_field_mut(settings_content, value, |language, value| {
7041                            language.tasks.get_or_insert_default().variables = value;
7042
7043                        })
7044                    },
7045                }
7046                .unimplemented(),
7047            ),
7048            metadata: None,
7049            files: USER | PROJECT,
7050        }),
7051        SettingsPageItem::SettingItem(SettingItem {
7052            title: "Prefer LSP",
7053            description: "Use LSP tasks over Zed language extension tasks.",
7054            field: Box::new(SettingField {
7055                json_path: Some("languages.$(language).tasks.prefer_lsp"),
7056                pick: |settings_content| {
7057                    language_settings_field(settings_content, |language| {
7058                        language.tasks.as_ref()?.prefer_lsp.as_ref()
7059                    })
7060                },
7061                write: |settings_content, value| {
7062                    language_settings_field_mut(settings_content, value, |language, value| {
7063                        language.tasks.get_or_insert_default().prefer_lsp = value;
7064
7065                    })
7066                },
7067            }),
7068            metadata: None,
7069            files: USER | PROJECT,
7070        }),
7071        SettingsPageItem::SectionHeader("Miscellaneous"),
7072        SettingsPageItem::SettingItem(SettingItem {
7073            title: "Word Diff Enabled",
7074            description: "Whether to enable word diff highlighting in the editor. When enabled, changed words within modified lines are highlighted to show exactly what changed.",
7075            field: Box::new(SettingField {
7076                json_path: Some("languages.$(language).word_diff_enabled"),
7077                pick: |settings_content| {
7078                    language_settings_field(settings_content, |language| {
7079                        language.word_diff_enabled.as_ref()
7080                    })
7081                },
7082                write: |settings_content, value| {
7083                    language_settings_field_mut(settings_content, value, |language, value| {
7084                        language.word_diff_enabled = value;
7085                    })
7086                },
7087            }),
7088            metadata: None,
7089            files: USER | PROJECT,
7090        }),
7091        SettingsPageItem::SettingItem(SettingItem {
7092            title: "Debuggers",
7093            description: "Preferred debuggers for this language.",
7094            field: Box::new(
7095                SettingField {
7096                    json_path: Some("languages.$(language).debuggers"),
7097                    pick: |settings_content| {
7098                        language_settings_field(settings_content, |language| language.debuggers.as_ref())
7099                    },
7100                    write: |settings_content, value| {
7101                        language_settings_field_mut(settings_content, value, |language, value| {
7102                            language.debuggers = value;
7103
7104                        })
7105                    },
7106                }
7107                .unimplemented(),
7108            ),
7109            metadata: None,
7110            files: USER | PROJECT,
7111        }),
7112        SettingsPageItem::SettingItem(SettingItem {
7113            title: "Middle Click Paste",
7114            description: "Enable middle-click paste on Linux.",
7115            field: Box::new(SettingField {
7116                json_path: Some("languages.$(language).editor.middle_click_paste"),
7117                pick: |settings_content| settings_content.editor.middle_click_paste.as_ref(),
7118                write: |settings_content, value| {settings_content.editor.middle_click_paste = value;},
7119            }),
7120            metadata: None,
7121            files: USER,
7122        }),
7123        SettingsPageItem::SettingItem(SettingItem {
7124            title: "Extend Comment On Newline",
7125            description: "Whether to start a new line with a comment when a previous line is a comment as well.",
7126            field: Box::new(SettingField {
7127                json_path: Some("languages.$(language).extend_comment_on_newline"),
7128                pick: |settings_content| {
7129                    language_settings_field(settings_content, |language| {
7130                        language.extend_comment_on_newline.as_ref()
7131                    })
7132                },
7133                write: |settings_content, value| {
7134                    language_settings_field_mut(settings_content, value, |language, value| {
7135                        language.extend_comment_on_newline = value;
7136
7137                    })
7138                },
7139            }),
7140            metadata: None,
7141            files: USER | PROJECT,
7142        }),
7143        SettingsPageItem::SettingItem(SettingItem {
7144            title: "Colorize Brackets",
7145            description: "Whether to colorize brackets in the editor.",
7146            field: Box::new(SettingField {
7147                json_path: Some("languages.$(language).colorize_brackets"),
7148                pick: |settings_content| {
7149                    language_settings_field(settings_content, |language| {
7150                        language.colorize_brackets.as_ref()
7151                    })
7152                },
7153                write: |settings_content, value| {
7154                    language_settings_field_mut(settings_content, value, |language, value| {
7155                        language.colorize_brackets = value;
7156                    })
7157                },
7158            }),
7159            metadata: None,
7160            files: USER | PROJECT,
7161        }),
7162    ]);
7163
7164    if current_language().is_none() {
7165        items.extend([
7166            SettingsPageItem::SettingItem(SettingItem {
7167                title: "Image Viewer",
7168                description: "The unit for image file sizes.",
7169                field: Box::new(SettingField {
7170                    json_path: Some("image_viewer.unit"),
7171                    pick: |settings_content| {
7172                        settings_content.image_viewer.as_ref().and_then(|image_viewer| image_viewer.unit.as_ref())
7173                    },
7174                    write: |settings_content, value| {
7175                        settings_content.image_viewer.get_or_insert_default().unit = value;
7176
7177                    },
7178                }),
7179                metadata: None,
7180                files: USER,
7181            }),
7182            SettingsPageItem::SettingItem(SettingItem {
7183                title: "Auto Replace Emoji Shortcode",
7184                description: "Whether to automatically replace emoji shortcodes with emoji characters.",
7185                field: Box::new(SettingField {
7186                    json_path: Some("message_editor.auto_replace_emoji_shortcode"),
7187                    pick: |settings_content| {
7188                        settings_content.message_editor.as_ref().and_then(|message_editor| message_editor.auto_replace_emoji_shortcode.as_ref())
7189                    },
7190                    write: |settings_content, value| {
7191                        settings_content.message_editor.get_or_insert_default().auto_replace_emoji_shortcode = value;
7192
7193                    },
7194                }),
7195                metadata: None,
7196                files: USER,
7197            }),
7198            SettingsPageItem::SettingItem(SettingItem {
7199                title: "Drop Size Target",
7200                description: "Relative size of the drop target in the editor that will open dropped file as a split pane.",
7201                field: Box::new(SettingField {
7202                    json_path: Some("drop_target_size"),
7203                    pick: |settings_content| {
7204                        settings_content.workspace.drop_target_size.as_ref()
7205                    },
7206                    write: |settings_content, value| {
7207                        settings_content.workspace.drop_target_size = value;
7208
7209                    },
7210                }),
7211                metadata: None,
7212                files: USER,
7213            }),
7214        ]);
7215    }
7216    items
7217}
7218
7219/// LanguageSettings items that should be included in the "Languages & Tools" page
7220/// not the "Editor" page
7221fn non_editor_language_settings_data() -> Vec<SettingsPageItem> {
7222    vec![
7223        SettingsPageItem::SectionHeader("LSP"),
7224        SettingsPageItem::SettingItem(SettingItem {
7225            title: "Enable Language Server",
7226            description: "Whether to use language servers to provide code intelligence.",
7227            field: Box::new(SettingField {
7228                json_path: Some("languages.$(language).enable_language_server"),
7229                pick: |settings_content| {
7230                    language_settings_field(settings_content, |language| {
7231                        language.enable_language_server.as_ref()
7232                    })
7233                },
7234                write: |settings_content, value| {
7235                    language_settings_field_mut(settings_content, value, |language, value| {
7236                        language.enable_language_server = value;
7237                    })
7238                },
7239            }),
7240            metadata: None,
7241            files: USER | PROJECT,
7242        }),
7243        SettingsPageItem::SettingItem(SettingItem {
7244            title: "Language Servers",
7245            description: "The list of language servers to use (or disable) for this language.",
7246            field: Box::new(
7247                SettingField {
7248                    json_path: Some("languages.$(language).language_servers"),
7249                    pick: |settings_content| {
7250                        language_settings_field(settings_content, |language| {
7251                            language.language_servers.as_ref()
7252                        })
7253                    },
7254                    write: |settings_content, value| {
7255                        language_settings_field_mut(settings_content, value, |language, value| {
7256                            language.language_servers = value;
7257                        })
7258                    },
7259                }
7260                .unimplemented(),
7261            ),
7262            metadata: None,
7263            files: USER | PROJECT,
7264        }),
7265        SettingsPageItem::SettingItem(SettingItem {
7266            title: "Linked Edits",
7267            description: "Whether to perform linked edits of associated ranges, if the LS supports it. For example, when editing opening <html> tag, the contents of the closing </html> tag will be edited as well.",
7268            field: Box::new(SettingField {
7269                json_path: Some("languages.$(language).linked_edits"),
7270                pick: |settings_content| {
7271                    language_settings_field(settings_content, |language| {
7272                        language.linked_edits.as_ref()
7273                    })
7274                },
7275                write: |settings_content, value| {
7276                    language_settings_field_mut(settings_content, value, |language, value| {
7277                        language.linked_edits = value;
7278                    })
7279                },
7280            }),
7281            metadata: None,
7282            files: USER | PROJECT,
7283        }),
7284        SettingsPageItem::SettingItem(SettingItem {
7285            title: "Go To Definition Fallback",
7286            description: "Whether to follow-up empty Go to definition responses from the language server.",
7287            field: Box::new(SettingField {
7288                json_path: Some("go_to_definition_fallback"),
7289                pick: |settings_content| settings_content.editor.go_to_definition_fallback.as_ref(),
7290                write: |settings_content, value| {
7291                    settings_content.editor.go_to_definition_fallback = value;
7292                },
7293            }),
7294            metadata: None,
7295            files: USER,
7296        }),
7297        SettingsPageItem::SectionHeader("LSP Completions"),
7298        SettingsPageItem::SettingItem(SettingItem {
7299            title: "Enabled",
7300            description: "Whether to fetch LSP completions or not.",
7301            field: Box::new(SettingField {
7302                json_path: Some("languages.$(language).completions.lsp"),
7303                pick: |settings_content| {
7304                    language_settings_field(settings_content, |language| {
7305                        language.completions.as_ref()?.lsp.as_ref()
7306                    })
7307                },
7308                write: |settings_content, value| {
7309                    language_settings_field_mut(settings_content, value, |language, value| {
7310                        language.completions.get_or_insert_default().lsp = value;
7311                    })
7312                },
7313            }),
7314            metadata: None,
7315            files: USER | PROJECT,
7316        }),
7317        SettingsPageItem::SettingItem(SettingItem {
7318            title: "Fetch Timeout (milliseconds)",
7319            description: "When fetching LSP completions, determines how long to wait for a response of a particular server (set to 0 to wait indefinitely).",
7320            field: Box::new(SettingField {
7321                json_path: Some("languages.$(language).completions.lsp_fetch_timeout_ms"),
7322                pick: |settings_content| {
7323                    language_settings_field(settings_content, |language| {
7324                        language.completions.as_ref()?.lsp_fetch_timeout_ms.as_ref()
7325                    })
7326                },
7327                write: |settings_content, value| {
7328                    language_settings_field_mut(settings_content, value, |language, value| {
7329                        language
7330                            .completions
7331                            .get_or_insert_default()
7332                            .lsp_fetch_timeout_ms = value;
7333                    })
7334                },
7335            }),
7336            metadata: None,
7337            files: USER | PROJECT,
7338        }),
7339        SettingsPageItem::SettingItem(SettingItem {
7340            title: "Insert Mode",
7341            description: "Controls how LSP completions are inserted.",
7342            field: Box::new(SettingField {
7343                json_path: Some("languages.$(language).completions.lsp_insert_mode"),
7344                pick: |settings_content| {
7345                    language_settings_field(settings_content, |language| {
7346                        language.completions.as_ref()?.lsp_insert_mode.as_ref()
7347                    })
7348                },
7349                write: |settings_content, value| {
7350                    language_settings_field_mut(settings_content, value, |language, value| {
7351                        language.completions.get_or_insert_default().lsp_insert_mode = value;
7352                    })
7353                },
7354            }),
7355            metadata: None,
7356            files: USER | PROJECT,
7357        }),
7358        SettingsPageItem::SectionHeader("Debuggers"),
7359        SettingsPageItem::SettingItem(SettingItem {
7360            title: "Debuggers",
7361            description: "Preferred debuggers for this language.",
7362            field: Box::new(
7363                SettingField {
7364                    json_path: Some("languages.$(language).debuggers"),
7365                    pick: |settings_content| {
7366                        language_settings_field(settings_content, |language| {
7367                            language.debuggers.as_ref()
7368                        })
7369                    },
7370                    write: |settings_content, value| {
7371                        language_settings_field_mut(settings_content, value, |language, value| {
7372                            language.debuggers = value;
7373                        })
7374                    },
7375                }
7376                .unimplemented(),
7377            ),
7378            metadata: None,
7379            files: USER | PROJECT,
7380        }),
7381        SettingsPageItem::SectionHeader("Prettier"),
7382        SettingsPageItem::SettingItem(SettingItem {
7383            title: "Allowed",
7384            description: "Enables or disables formatting with Prettier for a given language.",
7385            field: Box::new(SettingField {
7386                json_path: Some("languages.$(language).prettier.allowed"),
7387                pick: |settings_content| {
7388                    language_settings_field(settings_content, |language| {
7389                        language.prettier.as_ref()?.allowed.as_ref()
7390                    })
7391                },
7392                write: |settings_content, value| {
7393                    language_settings_field_mut(settings_content, value, |language, value| {
7394                        language.prettier.get_or_insert_default().allowed = value;
7395                    })
7396                },
7397            }),
7398            metadata: None,
7399            files: USER | PROJECT,
7400        }),
7401        SettingsPageItem::SettingItem(SettingItem {
7402            title: "Parser",
7403            description: "Forces Prettier integration to use a specific parser name when formatting files with the language.",
7404            field: Box::new(SettingField {
7405                json_path: Some("languages.$(language).prettier.parser"),
7406                pick: |settings_content| {
7407                    language_settings_field(settings_content, |language| {
7408                        language.prettier.as_ref()?.parser.as_ref()
7409                    })
7410                },
7411                write: |settings_content, value| {
7412                    language_settings_field_mut(settings_content, value, |language, value| {
7413                        language.prettier.get_or_insert_default().parser = value;
7414                    })
7415                },
7416            }),
7417            metadata: None,
7418            files: USER | PROJECT,
7419        }),
7420        SettingsPageItem::SettingItem(SettingItem {
7421            title: "Plugins",
7422            description: "Forces Prettier integration to use specific plugins when formatting files with the language.",
7423            field: Box::new(
7424                SettingField {
7425                    json_path: Some("languages.$(language).prettier.plugins"),
7426                    pick: |settings_content| {
7427                        language_settings_field(settings_content, |language| {
7428                            language.prettier.as_ref()?.plugins.as_ref()
7429                        })
7430                    },
7431                    write: |settings_content, value| {
7432                        language_settings_field_mut(settings_content, value, |language, value| {
7433                            language.prettier.get_or_insert_default().plugins = value;
7434                        })
7435                    },
7436                }
7437                .unimplemented(),
7438            ),
7439            metadata: None,
7440            files: USER | PROJECT,
7441        }),
7442        SettingsPageItem::SettingItem(SettingItem {
7443            title: "Options",
7444            description: "Default Prettier options, in the format as in package.json section for Prettier.",
7445            field: Box::new(
7446                SettingField {
7447                    json_path: Some("languages.$(language).prettier.options"),
7448                    pick: |settings_content| {
7449                        language_settings_field(settings_content, |language| {
7450                            language.prettier.as_ref()?.options.as_ref()
7451                        })
7452                    },
7453                    write: |settings_content, value| {
7454                        language_settings_field_mut(settings_content, value, |language, value| {
7455                            language.prettier.get_or_insert_default().options = value;
7456                        })
7457                    },
7458                }
7459                .unimplemented(),
7460            ),
7461            metadata: None,
7462            files: USER | PROJECT,
7463        }),
7464    ]
7465}
7466
7467fn edit_prediction_language_settings_section() -> Vec<SettingsPageItem> {
7468    vec![
7469        SettingsPageItem::SectionHeader("Edit Predictions"),
7470        SettingsPageItem::SettingItem(SettingItem {
7471            title: "Show Edit Predictions",
7472            description: "Controls whether edit predictions are shown immediately or manually by triggering `editor::showeditprediction` (false).",
7473            field: Box::new(SettingField {
7474                json_path: Some("languages.$(language).show_edit_predictions"),
7475                pick: |settings_content| {
7476                    language_settings_field(settings_content, |language| {
7477                        language.show_edit_predictions.as_ref()
7478                    })
7479                },
7480                write: |settings_content, value| {
7481                    language_settings_field_mut(settings_content, value, |language, value| {
7482                        language.show_edit_predictions = value;
7483                    })
7484                },
7485            }),
7486            metadata: None,
7487            files: USER | PROJECT,
7488        }),
7489        SettingsPageItem::SettingItem(SettingItem {
7490            title: "Edit Predictions Disabled In",
7491            description: "Controls whether edit predictions are shown in the given language scopes.",
7492            field: Box::new(
7493                SettingField {
7494                    json_path: Some("languages.$(language).edit_predictions_disabled_in"),
7495                    pick: |settings_content| {
7496                        language_settings_field(settings_content, |language| {
7497                            language.edit_predictions_disabled_in.as_ref()
7498                        })
7499                    },
7500                    write: |settings_content, value| {
7501                        language_settings_field_mut(settings_content, value, |language, value| {
7502                            language.edit_predictions_disabled_in = value;
7503                        })
7504                    },
7505                }
7506                .unimplemented(),
7507            ),
7508            metadata: None,
7509            files: USER | PROJECT,
7510        }),
7511    ]
7512}
7513
7514fn show_scrollbar_or_editor(
7515    settings_content: &SettingsContent,
7516    show: fn(&SettingsContent) -> Option<&settings::ShowScrollbar>,
7517) -> Option<&settings::ShowScrollbar> {
7518    show(settings_content).or(settings_content
7519        .editor
7520        .scrollbar
7521        .as_ref()
7522        .and_then(|scrollbar| scrollbar.show.as_ref()))
7523}
7524
7525fn dynamic_variants<T>() -> &'static [T::Discriminant]
7526where
7527    T: strum::IntoDiscriminant,
7528    T::Discriminant: strum::VariantArray,
7529{
7530    <<T as strum::IntoDiscriminant>::Discriminant as strum::VariantArray>::VARIANTS
7531}