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 File Finder",
3166                    description: "Whether to open tabs in Preview mode when selected from the file finder.",
3167                    field: Box::new(SettingField {
3168                        json_path: Some("preview_tabs.enable_preview_from_file_finder"),
3169                        pick: |settings_content| {
3170                            settings_content
3171                                .preview_tabs
3172                                .as_ref()?
3173                                .enable_preview_from_file_finder
3174                                .as_ref()
3175                        },
3176                        write: |settings_content, value| {
3177                            settings_content
3178                                .preview_tabs
3179                                .get_or_insert_default()
3180                                .enable_preview_from_file_finder = value;
3181                        },
3182                    }),
3183                    metadata: None,
3184                    files: USER,
3185                }),
3186                SettingsPageItem::SettingItem(SettingItem {
3187                    title: "Enable Preview From Code Navigation",
3188                    description: "Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.",
3189                    field: Box::new(SettingField {
3190                        json_path: Some("preview_tabs.enable_preview_from_code_navigation"),
3191                        pick: |settings_content| {
3192                            settings_content
3193                                .preview_tabs
3194                                .as_ref()?
3195                                .enable_preview_from_code_navigation
3196                                .as_ref()
3197                        },
3198                        write: |settings_content, value| {
3199                            settings_content
3200                                .preview_tabs
3201                                .get_or_insert_default()
3202                                .enable_preview_from_code_navigation = value;
3203                        },
3204                    }),
3205                    metadata: None,
3206                    files: USER,
3207                }),
3208                SettingsPageItem::SectionHeader("Layout"),
3209                SettingsPageItem::SettingItem(SettingItem {
3210                    title: "Bottom Dock Layout",
3211                    description: "Layout mode for the bottom dock.",
3212                    field: Box::new(SettingField {
3213                        json_path: Some("bottom_dock_layout"),
3214                        pick: |settings_content| {
3215                            settings_content.workspace.bottom_dock_layout.as_ref()
3216                        },
3217                        write: |settings_content, value| {
3218                            settings_content.workspace.bottom_dock_layout = value;
3219                        },
3220                    }),
3221                    metadata: None,
3222                    files: USER,
3223                }),
3224                SettingsPageItem::SettingItem(SettingItem {
3225                    files: USER,
3226                    title: "Centered Layout Left Padding",
3227                    description: "Left padding for centered layout.",
3228                    field: Box::new(SettingField {
3229                        json_path: Some("centered_layout.left_padding"),
3230                        pick: |settings_content| {
3231                            settings_content
3232                                .workspace
3233                                .centered_layout
3234                                .as_ref()?
3235                                .left_padding
3236                                .as_ref()
3237                        },
3238                        write: |settings_content, value| {
3239                            settings_content
3240                                .workspace
3241                                .centered_layout
3242                                .get_or_insert_default()
3243                                .left_padding = value;
3244                        },
3245                    }),
3246                    metadata: None,
3247                }),
3248                SettingsPageItem::SettingItem(SettingItem {
3249                    files: USER,
3250                    title: "Centered Layout Right Padding",
3251                    description: "Right padding for centered layout.",
3252                    field: Box::new(SettingField {
3253                        json_path: Some("centered_layout.right_padding"),
3254                        pick: |settings_content| {
3255                            settings_content
3256                                .workspace
3257                                .centered_layout
3258                                .as_ref()?
3259                                .right_padding
3260                                .as_ref()
3261                        },
3262                        write: |settings_content, value| {
3263                            settings_content
3264                                .workspace
3265                                .centered_layout
3266                                .get_or_insert_default()
3267                                .right_padding = value;
3268                        },
3269                    }),
3270                    metadata: None,
3271                }),
3272                SettingsPageItem::SectionHeader("Window"),
3273                // todo(settings_ui): Should we filter by platform.as_ref()?
3274                SettingsPageItem::SettingItem(SettingItem {
3275                    title: "Use System Window Tabs",
3276                    description: "(macOS only) whether to allow Windows to tab together.",
3277                    field: Box::new(SettingField {
3278                        json_path: Some("use_system_window_tabs"),
3279                        pick: |settings_content| {
3280                            settings_content.workspace.use_system_window_tabs.as_ref()
3281                        },
3282                        write: |settings_content, value| {
3283                            settings_content.workspace.use_system_window_tabs = value;
3284                        },
3285                    }),
3286                    metadata: None,
3287                    files: USER,
3288                }),
3289                SettingsPageItem::SettingItem(SettingItem {
3290                    title: "Window Decorations",
3291                    description: "(Linux only) whether Zed or your compositor should draw window decorations.",
3292                    field: Box::new(SettingField {
3293                        json_path: Some("window_decorations"),
3294                        pick: |settings_content| {
3295                            settings_content.workspace.window_decorations.as_ref()
3296                        },
3297                        write: |settings_content, value| {
3298                            settings_content.workspace.window_decorations = value;
3299                        },
3300                    }),
3301                    metadata: None,
3302                    files: USER,
3303                }),
3304                SettingsPageItem::SectionHeader("Pane Modifiers"),
3305                SettingsPageItem::SettingItem(SettingItem {
3306                    title: "Inactive Opacity",
3307                    description: "Opacity of inactive panels (0.0 - 1.0).",
3308                    field: Box::new(SettingField {
3309                        json_path: Some("active_pane_modifiers.inactive_opacity"),
3310                        pick: |settings_content| {
3311                            settings_content
3312                                .workspace
3313                                .active_pane_modifiers
3314                                .as_ref()?
3315                                .inactive_opacity
3316                                .as_ref()
3317                        },
3318                        write: |settings_content, value| {
3319                            settings_content
3320                                .workspace
3321                                .active_pane_modifiers
3322                                .get_or_insert_default()
3323                                .inactive_opacity = value;
3324                        },
3325                    }),
3326                    metadata: None,
3327                    files: USER,
3328                }),
3329                SettingsPageItem::SettingItem(SettingItem {
3330                    title: "Border Size",
3331                    description: "Size of the border surrounding the active pane.",
3332                    field: Box::new(SettingField {
3333                        json_path: Some("active_pane_modifiers.border_size"),
3334                        pick: |settings_content| {
3335                            settings_content
3336                                .workspace
3337                                .active_pane_modifiers
3338                                .as_ref()?
3339                                .border_size
3340                                .as_ref()
3341                        },
3342                        write: |settings_content, value| {
3343                            settings_content
3344                                .workspace
3345                                .active_pane_modifiers
3346                                .get_or_insert_default()
3347                                .border_size = value;
3348                        },
3349                    }),
3350                    metadata: None,
3351                    files: USER,
3352                }),
3353                SettingsPageItem::SettingItem(SettingItem {
3354                    title: "Zoomed Padding",
3355                    description: "Show padding for zoomed panes.",
3356                    field: Box::new(SettingField {
3357                        json_path: Some("zoomed_padding"),
3358                        pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
3359                        write: |settings_content, value| {
3360                            settings_content.workspace.zoomed_padding = value;
3361                        },
3362                    }),
3363                    metadata: None,
3364                    files: USER,
3365                }),
3366                SettingsPageItem::SectionHeader("Pane Split Direction"),
3367                SettingsPageItem::SettingItem(SettingItem {
3368                    title: "Vertical Split Direction",
3369                    description: "Direction to split vertically.",
3370                    field: Box::new(SettingField {
3371                        json_path: Some("pane_split_direction_vertical"),
3372                        pick: |settings_content| {
3373                            settings_content
3374                                .workspace
3375                                .pane_split_direction_vertical
3376                                .as_ref()
3377                        },
3378                        write: |settings_content, value| {
3379                            settings_content.workspace.pane_split_direction_vertical = value;
3380                        },
3381                    }),
3382                    metadata: None,
3383                    files: USER,
3384                }),
3385                SettingsPageItem::SettingItem(SettingItem {
3386                    title: "Horizontal Split Direction",
3387                    description: "Direction to split horizontally.",
3388                    field: Box::new(SettingField {
3389                        json_path: Some("pane_split_direction_horizontal"),
3390                        pick: |settings_content| {
3391                            settings_content
3392                                .workspace
3393                                .pane_split_direction_horizontal
3394                                .as_ref()
3395                        },
3396                        write: |settings_content, value| {
3397                            settings_content.workspace.pane_split_direction_horizontal = value;
3398                        },
3399                    }),
3400                    metadata: None,
3401                    files: USER,
3402                }),
3403            ],
3404        },
3405        SettingsPage {
3406            title: "Panels",
3407            items: vec![
3408                SettingsPageItem::SectionHeader("Project Panel"),
3409                SettingsPageItem::SettingItem(SettingItem {
3410                    title: "Project Panel Dock",
3411                    description: "Where to dock the project panel.",
3412                    field: Box::new(SettingField {
3413                        json_path: Some("project_panel.dock"),
3414                        pick: |settings_content| {
3415                            settings_content.project_panel.as_ref()?.dock.as_ref()
3416                        },
3417                        write: |settings_content, value| {
3418                            settings_content.project_panel.get_or_insert_default().dock = value;
3419                        },
3420                    }),
3421                    metadata: None,
3422                    files: USER,
3423                }),
3424                SettingsPageItem::SettingItem(SettingItem {
3425                    title: "Project Panel Default Width",
3426                    description: "Default width of the project panel in pixels.",
3427                    field: Box::new(SettingField {
3428                        json_path: Some("project_panel.default_width"),
3429                        pick: |settings_content| {
3430                            settings_content
3431                                .project_panel
3432                                .as_ref()?
3433                                .default_width
3434                                .as_ref()
3435                        },
3436                        write: |settings_content, value| {
3437                            settings_content
3438                                .project_panel
3439                                .get_or_insert_default()
3440                                .default_width = value;
3441                        },
3442                    }),
3443                    metadata: None,
3444                    files: USER,
3445                }),
3446                SettingsPageItem::SettingItem(SettingItem {
3447                    title: "Hide .gitignore",
3448                    description: "Whether to hide the gitignore entries in the project panel.",
3449                    field: Box::new(SettingField {
3450                        json_path: Some("project_panel.hide_gitignore"),
3451                        pick: |settings_content| {
3452                            settings_content
3453                                .project_panel
3454                                .as_ref()?
3455                                .hide_gitignore
3456                                .as_ref()
3457                        },
3458                        write: |settings_content, value| {
3459                            settings_content
3460                                .project_panel
3461                                .get_or_insert_default()
3462                                .hide_gitignore = value;
3463                        },
3464                    }),
3465                    metadata: None,
3466                    files: USER,
3467                }),
3468                SettingsPageItem::SettingItem(SettingItem {
3469                    title: "Entry Spacing",
3470                    description: "Spacing between worktree entries in the project panel.",
3471                    field: Box::new(SettingField {
3472                        json_path: Some("project_panel.entry_spacing"),
3473                        pick: |settings_content| {
3474                            settings_content
3475                                .project_panel
3476                                .as_ref()?
3477                                .entry_spacing
3478                                .as_ref()
3479                        },
3480                        write: |settings_content, value| {
3481                            settings_content
3482                                .project_panel
3483                                .get_or_insert_default()
3484                                .entry_spacing = value;
3485                        },
3486                    }),
3487                    metadata: None,
3488                    files: USER,
3489                }),
3490                SettingsPageItem::SettingItem(SettingItem {
3491                    title: "File Icons",
3492                    description: "Show file icons in the project panel.",
3493                    field: Box::new(SettingField {
3494                        json_path: Some("project_panel.file_icons"),
3495                        pick: |settings_content| {
3496                            settings_content.project_panel.as_ref()?.file_icons.as_ref()
3497                        },
3498                        write: |settings_content, value| {
3499                            settings_content
3500                                .project_panel
3501                                .get_or_insert_default()
3502                                .file_icons = value;
3503                        },
3504                    }),
3505                    metadata: None,
3506                    files: USER,
3507                }),
3508                SettingsPageItem::SettingItem(SettingItem {
3509                    title: "Folder Icons",
3510                    description: "Whether to show folder icons or chevrons for directories in the project panel.",
3511                    field: Box::new(SettingField {
3512                        json_path: Some("project_panel.folder_icons"),
3513                        pick: |settings_content| {
3514                            settings_content
3515                                .project_panel
3516                                .as_ref()?
3517                                .folder_icons
3518                                .as_ref()
3519                        },
3520                        write: |settings_content, value| {
3521                            settings_content
3522                                .project_panel
3523                                .get_or_insert_default()
3524                                .folder_icons = value;
3525                        },
3526                    }),
3527                    metadata: None,
3528                    files: USER,
3529                }),
3530                SettingsPageItem::SettingItem(SettingItem {
3531                    title: "Git Status",
3532                    description: "Show the Git status in the project panel.",
3533                    field: Box::new(SettingField {
3534                        json_path: Some("project_panel.git_status"),
3535                        pick: |settings_content| {
3536                            settings_content.project_panel.as_ref()?.git_status.as_ref()
3537                        },
3538                        write: |settings_content, value| {
3539                            settings_content
3540                                .project_panel
3541                                .get_or_insert_default()
3542                                .git_status = value;
3543                        },
3544                    }),
3545                    metadata: None,
3546                    files: USER,
3547                }),
3548                SettingsPageItem::SettingItem(SettingItem {
3549                    title: "Indent Size",
3550                    description: "Amount of indentation for nested items.",
3551                    field: Box::new(SettingField {
3552                        json_path: Some("project_panel.indent_size"),
3553                        pick: |settings_content| {
3554                            settings_content
3555                                .project_panel
3556                                .as_ref()?
3557                                .indent_size
3558                                .as_ref()
3559                        },
3560                        write: |settings_content, value| {
3561                            settings_content
3562                                .project_panel
3563                                .get_or_insert_default()
3564                                .indent_size = value;
3565                        },
3566                    }),
3567                    metadata: None,
3568                    files: USER,
3569                }),
3570                SettingsPageItem::SettingItem(SettingItem {
3571                    title: "Auto Reveal Entries",
3572                    description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
3573                    field: Box::new(SettingField {
3574                        json_path: Some("project_panel.auto_reveal_entries"),
3575                        pick: |settings_content| {
3576                            settings_content
3577                                .project_panel
3578                                .as_ref()?
3579                                .auto_reveal_entries
3580                                .as_ref()
3581                        },
3582                        write: |settings_content, value| {
3583                            settings_content
3584                                .project_panel
3585                                .get_or_insert_default()
3586                                .auto_reveal_entries = value;
3587                        },
3588                    }),
3589                    metadata: None,
3590                    files: USER,
3591                }),
3592                SettingsPageItem::SettingItem(SettingItem {
3593                    title: "Starts Open",
3594                    description: "Whether the project panel should open on startup.",
3595                    field: Box::new(SettingField {
3596                        json_path: Some("project_panel.starts_open"),
3597                        pick: |settings_content| {
3598                            settings_content
3599                                .project_panel
3600                                .as_ref()?
3601                                .starts_open
3602                                .as_ref()
3603                        },
3604                        write: |settings_content, value| {
3605                            settings_content
3606                                .project_panel
3607                                .get_or_insert_default()
3608                                .starts_open = value;
3609                        },
3610                    }),
3611                    metadata: None,
3612                    files: USER,
3613                }),
3614                SettingsPageItem::SettingItem(SettingItem {
3615                    title: "Auto Fold Directories",
3616                    description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
3617                    field: Box::new(SettingField {
3618                        json_path: Some("project_panel.auto_fold_dirs"),
3619                        pick: |settings_content| {
3620                            settings_content
3621                                .project_panel
3622                                .as_ref()?
3623                                .auto_fold_dirs
3624                                .as_ref()
3625                        },
3626                        write: |settings_content, value| {
3627                            settings_content
3628                                .project_panel
3629                                .get_or_insert_default()
3630                                .auto_fold_dirs = value;
3631                        },
3632                    }),
3633                    metadata: None,
3634                    files: USER,
3635                }),
3636                SettingsPageItem::SettingItem(SettingItem {
3637                    title: "Show Scrollbar",
3638                    description: "Show the scrollbar in the project panel.",
3639                    field: Box::new(SettingField {
3640                        json_path: Some("project_panel.scrollbar.show"),
3641                        pick: |settings_content| {
3642                            show_scrollbar_or_editor(settings_content, |settings_content| {
3643                                settings_content
3644                                    .project_panel
3645                                    .as_ref()?
3646                                    .scrollbar
3647                                    .as_ref()?
3648                                    .show
3649                                    .as_ref()
3650                            })
3651                        },
3652                        write: |settings_content, value| {
3653                            settings_content
3654                                .project_panel
3655                                .get_or_insert_default()
3656                                .scrollbar
3657                                .get_or_insert_default()
3658                                .show = value;
3659                        },
3660                    }),
3661                    metadata: None,
3662                    files: USER,
3663                }),
3664                SettingsPageItem::SettingItem(SettingItem {
3665                    title: "Show Diagnostics",
3666                    description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
3667                    field: Box::new(SettingField {
3668                        json_path: Some("project_panel.show_diagnostics"),
3669                        pick: |settings_content| {
3670                            settings_content
3671                                .project_panel
3672                                .as_ref()?
3673                                .show_diagnostics
3674                                .as_ref()
3675                        },
3676                        write: |settings_content, value| {
3677                            settings_content
3678                                .project_panel
3679                                .get_or_insert_default()
3680                                .show_diagnostics = value;
3681                        },
3682                    }),
3683                    metadata: None,
3684                    files: USER,
3685                }),
3686                SettingsPageItem::SettingItem(SettingItem {
3687                    title: "Sticky Scroll",
3688                    description: "Whether to stick parent directories at top of the project panel.",
3689                    field: Box::new(SettingField {
3690                        json_path: Some("project_panel.sticky_scroll"),
3691                        pick: |settings_content| {
3692                            settings_content
3693                                .project_panel
3694                                .as_ref()?
3695                                .sticky_scroll
3696                                .as_ref()
3697                        },
3698                        write: |settings_content, value| {
3699                            settings_content
3700                                .project_panel
3701                                .get_or_insert_default()
3702                                .sticky_scroll = value;
3703                        },
3704                    }),
3705                    metadata: None,
3706                    files: USER,
3707                }),
3708                SettingsPageItem::SettingItem(SettingItem {
3709                    files: USER,
3710                    title: "Show Indent Guides",
3711                    description: "Show indent guides in the project panel.",
3712                    field: Box::new(
3713                        SettingField {
3714                            json_path: Some("project_panel.indent_guides.show"),
3715                            pick: |settings_content| {
3716                                settings_content
3717                                    .project_panel
3718                                    .as_ref()?
3719                                    .indent_guides
3720                                    .as_ref()?
3721                                    .show
3722                                    .as_ref()
3723                            },
3724                            write: |settings_content, value| {
3725                                settings_content
3726                                    .project_panel
3727                                    .get_or_insert_default()
3728                                    .indent_guides
3729                                    .get_or_insert_default()
3730                                    .show = value;
3731                            },
3732                        }
3733                    ),
3734                    metadata: None,
3735                }),
3736                SettingsPageItem::SettingItem(SettingItem {
3737                    title: "Drag and Drop",
3738                    description: "Whether to enable drag-and-drop operations in the project panel.",
3739                    field: Box::new(SettingField {
3740                        json_path: Some("project_panel.drag_and_drop"),
3741                        pick: |settings_content| {
3742                            settings_content
3743                                .project_panel
3744                                .as_ref()?
3745                                .drag_and_drop
3746                                .as_ref()
3747                        },
3748                        write: |settings_content, value| {
3749                            settings_content
3750                                .project_panel
3751                                .get_or_insert_default()
3752                                .drag_and_drop = value;
3753                        },
3754                    }),
3755                    metadata: None,
3756                    files: USER,
3757                }),
3758                SettingsPageItem::SettingItem(SettingItem {
3759                    title: "Hide Root",
3760                    description: "Whether to hide the root entry when only one folder is open in the window.",
3761                    field: Box::new(SettingField {
3762                        json_path: Some("project_panel.drag_and_drop"),
3763                        pick: |settings_content| {
3764                            settings_content.project_panel.as_ref()?.hide_root.as_ref()
3765                        },
3766                        write: |settings_content, value| {
3767                            settings_content
3768                                .project_panel
3769                                .get_or_insert_default()
3770                                .hide_root = value;
3771                        },
3772                    }),
3773                    metadata: None,
3774                    files: USER,
3775                }),
3776                SettingsPageItem::SettingItem(SettingItem {
3777                    title: "Hide Hidden",
3778                    description: "Whether to hide the hidden entries in the project panel.",
3779                    field: Box::new(SettingField {
3780                        json_path: Some("project_panel.hide_hidden"),
3781                        pick: |settings_content| {
3782                            settings_content
3783                                .project_panel
3784                                .as_ref()?
3785                                .hide_hidden
3786                                .as_ref()
3787                        },
3788                        write: |settings_content, value| {
3789                            settings_content
3790                                .project_panel
3791                                .get_or_insert_default()
3792                                .hide_hidden = value;
3793                        },
3794                    }),
3795                    metadata: None,
3796                    files: USER,
3797                }),
3798                SettingsPageItem::SettingItem(SettingItem {
3799                    title: "Hidden Files",
3800                    description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
3801                    field: Box::new(
3802                        SettingField {
3803                            json_path: Some("worktree.hidden_files"),
3804                            pick: |settings_content| {
3805                                settings_content.project.worktree.hidden_files.as_ref()
3806                            },
3807                            write: |settings_content, value| {
3808                                settings_content.project.worktree.hidden_files = value;
3809                            },
3810                        }
3811                        .unimplemented(),
3812                    ),
3813                    metadata: None,
3814                    files: USER,
3815                }),
3816                SettingsPageItem::SectionHeader("Auto Open Files"),
3817                SettingsPageItem::SettingItem(SettingItem {
3818                    title: "On Create",
3819                    description: "Whether to automatically open newly created files in the editor.",
3820                    field: Box::new(SettingField {
3821                        json_path: Some("project_panel.auto_open.on_create"),
3822                        pick: |settings_content| {
3823                            settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_create.as_ref()
3824                        },
3825                        write: |settings_content, value| {
3826                            settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_create = value;
3827                        },
3828                    }),
3829                    metadata: None,
3830                    files: USER,
3831                }),
3832                SettingsPageItem::SettingItem(SettingItem {
3833                    title: "On Paste",
3834                    description: "Whether to automatically open files after pasting or duplicating them.",
3835                    field: Box::new(SettingField {
3836                        json_path: Some("project_panel.auto_open.on_paste"),
3837                        pick: |settings_content| {
3838                            settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_paste.as_ref()
3839                        },
3840                        write: |settings_content, value| {
3841                            settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_paste = value;
3842                        },
3843                    }),
3844                    metadata: None,
3845                    files: USER,
3846                }),
3847                SettingsPageItem::SettingItem(SettingItem {
3848                    title: "On Drop",
3849                    description: "Whether to automatically open files dropped from external sources.",
3850                    field: Box::new(SettingField {
3851                        json_path: Some("project_panel.auto_open.on_drop"),
3852                        pick: |settings_content| {
3853                            settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_drop.as_ref()
3854                        },
3855                        write: |settings_content, value| {
3856                            settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_drop = value;
3857                        },
3858                    }),
3859                    metadata: None,
3860                    files: USER,
3861                }),
3862                SettingsPageItem::SettingItem(SettingItem {
3863                    title: "Sort Mode",
3864                    description: "Sort order for entries in the project panel.",
3865                    field: Box::new(SettingField {
3866                        pick: |settings_content| {
3867                            settings_content.project_panel.as_ref()?.sort_mode.as_ref()
3868                        },
3869                        write: |settings_content, value| {
3870                            settings_content
3871                                .project_panel
3872                                .get_or_insert_default()
3873                                .sort_mode = value;
3874                        },
3875                        json_path: Some("project_panel.sort_mode"),
3876                    }),
3877                    metadata: None,
3878                    files: USER,
3879                }),
3880                SettingsPageItem::SectionHeader("Terminal Panel"),
3881                SettingsPageItem::SettingItem(SettingItem {
3882                    title: "Terminal Dock",
3883                    description: "Where to dock the terminal panel.",
3884                    field: Box::new(SettingField {
3885                        json_path: Some("terminal.dock"),
3886                        pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
3887                        write: |settings_content, value| {
3888                            settings_content.terminal.get_or_insert_default().dock = value;
3889                        },
3890                    }),
3891                    metadata: None,
3892                    files: USER,
3893                }),
3894                SettingsPageItem::SectionHeader("Outline Panel"),
3895                SettingsPageItem::SettingItem(SettingItem {
3896                    title: "Outline Panel Button",
3897                    description: "Show the outline panel button in the status bar.",
3898                    field: Box::new(SettingField {
3899                        json_path: Some("outline_panel.button"),
3900                        pick: |settings_content| {
3901                            settings_content.outline_panel.as_ref()?.button.as_ref()
3902                        },
3903                        write: |settings_content, value| {
3904                            settings_content
3905                                .outline_panel
3906                                .get_or_insert_default()
3907                                .button = value;
3908                        },
3909                    }),
3910                    metadata: None,
3911                    files: USER,
3912                }),
3913                SettingsPageItem::SettingItem(SettingItem {
3914                    title: "Outline Panel Dock",
3915                    description: "Where to dock the outline panel.",
3916                    field: Box::new(SettingField {
3917                        json_path: Some("outline_panel.dock"),
3918                        pick: |settings_content| {
3919                            settings_content.outline_panel.as_ref()?.dock.as_ref()
3920                        },
3921                        write: |settings_content, value| {
3922                            settings_content.outline_panel.get_or_insert_default().dock = value;
3923                        },
3924                    }),
3925                    metadata: None,
3926                    files: USER,
3927                }),
3928                SettingsPageItem::SettingItem(SettingItem {
3929                    title: "Outline Panel Default Width",
3930                    description: "Default width of the outline panel in pixels.",
3931                    field: Box::new(SettingField {
3932                        json_path: Some("outline_panel.default_width"),
3933                        pick: |settings_content| {
3934                            settings_content
3935                                .outline_panel
3936                                .as_ref()?
3937                                .default_width
3938                                .as_ref()
3939                        },
3940                        write: |settings_content, value| {
3941                            settings_content
3942                                .outline_panel
3943                                .get_or_insert_default()
3944                                .default_width = value;
3945                        },
3946                    }),
3947                    metadata: None,
3948                    files: USER,
3949                }),
3950                SettingsPageItem::SettingItem(SettingItem {
3951                    title: "File Icons",
3952                    description: "Show file icons in the outline panel.",
3953                    field: Box::new(SettingField {
3954                        json_path: Some("outline_panel.file_icons"),
3955                        pick: |settings_content| {
3956                            settings_content.outline_panel.as_ref()?.file_icons.as_ref()
3957                        },
3958                        write: |settings_content, value| {
3959                            settings_content
3960                                .outline_panel
3961                                .get_or_insert_default()
3962                                .file_icons = value;
3963                        },
3964                    }),
3965                    metadata: None,
3966                    files: USER,
3967                }),
3968                SettingsPageItem::SettingItem(SettingItem {
3969                    title: "Folder Icons",
3970                    description: "Whether to show folder icons or chevrons for directories in the outline panel.",
3971                    field: Box::new(SettingField {
3972                        json_path: Some("outline_panel.folder_icons"),
3973                        pick: |settings_content| {
3974                            settings_content
3975                                .outline_panel
3976                                .as_ref()?
3977                                .folder_icons
3978                                .as_ref()
3979                        },
3980                        write: |settings_content, value| {
3981                            settings_content
3982                                .outline_panel
3983                                .get_or_insert_default()
3984                                .folder_icons = value;
3985                        },
3986                    }),
3987                    metadata: None,
3988                    files: USER,
3989                }),
3990                SettingsPageItem::SettingItem(SettingItem {
3991                    title: "Git Status",
3992                    description: "Show the Git status in the outline panel.",
3993                    field: Box::new(SettingField {
3994                        json_path: Some("outline_panel.git_status"),
3995                        pick: |settings_content| {
3996                            settings_content.outline_panel.as_ref()?.git_status.as_ref()
3997                        },
3998                        write: |settings_content, value| {
3999                            settings_content
4000                                .outline_panel
4001                                .get_or_insert_default()
4002                                .git_status = value;
4003                        },
4004                    }),
4005                    metadata: None,
4006                    files: USER,
4007                }),
4008                SettingsPageItem::SettingItem(SettingItem {
4009                    title: "Indent Size",
4010                    description: "Amount of indentation for nested items.",
4011                    field: Box::new(SettingField {
4012                        json_path: Some("outline_panel.indent_size"),
4013                        pick: |settings_content| {
4014                            settings_content
4015                                .outline_panel
4016                                .as_ref()?
4017                                .indent_size
4018                                .as_ref()
4019                        },
4020                        write: |settings_content, value| {
4021                            settings_content
4022                                .outline_panel
4023                                .get_or_insert_default()
4024                                .indent_size = value;
4025                        },
4026                    }),
4027                    metadata: None,
4028                    files: USER,
4029                }),
4030                SettingsPageItem::SettingItem(SettingItem {
4031                    title: "Auto Reveal Entries",
4032                    description: "Whether to reveal when a corresponding outline entry becomes active.",
4033                    field: Box::new(SettingField {
4034                        json_path: Some("outline_panel.auto_reveal_entries"),
4035                        pick: |settings_content| {
4036                            settings_content
4037                                .outline_panel
4038                                .as_ref()?
4039                                .auto_reveal_entries
4040                                .as_ref()
4041                        },
4042                        write: |settings_content, value| {
4043                            settings_content
4044                                .outline_panel
4045                                .get_or_insert_default()
4046                                .auto_reveal_entries = value;
4047                        },
4048                    }),
4049                    metadata: None,
4050                    files: USER,
4051                }),
4052                SettingsPageItem::SettingItem(SettingItem {
4053                    title: "Auto Fold Directories",
4054                    description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
4055                    field: Box::new(SettingField {
4056                        json_path: Some("outline_panel.auto_fold_dirs"),
4057                        pick: |settings_content| {
4058                            settings_content
4059                                .outline_panel
4060                                .as_ref()?
4061                                .auto_fold_dirs
4062                                .as_ref()
4063                        },
4064                        write: |settings_content, value| {
4065                            settings_content
4066                                .outline_panel
4067                                .get_or_insert_default()
4068                                .auto_fold_dirs = value;
4069                        },
4070                    }),
4071                    metadata: None,
4072                    files: USER,
4073                }),
4074                SettingsPageItem::SettingItem(SettingItem {
4075                    files: USER,
4076                    title: "Show Indent Guides",
4077                    description: "When to show indent guides in the outline panel.",
4078                    field: Box::new(
4079                        SettingField {
4080                            json_path: Some("outline_panel.indent_guides.show"),
4081                            pick: |settings_content| {
4082                                settings_content
4083                                    .outline_panel
4084                                    .as_ref()?
4085                                    .indent_guides
4086                                    .as_ref()?
4087                                    .show
4088                                    .as_ref()
4089                            },
4090                            write: |settings_content, value| {
4091                                settings_content
4092                                    .outline_panel
4093                                    .get_or_insert_default()
4094                                    .indent_guides
4095                                    .get_or_insert_default()
4096                                    .show = value;
4097                            },
4098                        }
4099                    ),
4100                    metadata: None,
4101                }),
4102                SettingsPageItem::SectionHeader("Git Panel"),
4103                SettingsPageItem::SettingItem(SettingItem {
4104                    title: "Git Panel Button",
4105                    description: "Show the Git panel button in the status bar.",
4106                    field: Box::new(SettingField {
4107                        json_path: Some("git_panel.button"),
4108                        pick: |settings_content| {
4109                            settings_content.git_panel.as_ref()?.button.as_ref()
4110                        },
4111                        write: |settings_content, value| {
4112                            settings_content.git_panel.get_or_insert_default().button = value;
4113                        },
4114                    }),
4115                    metadata: None,
4116                    files: USER,
4117                }),
4118                SettingsPageItem::SettingItem(SettingItem {
4119                    title: "Git Panel Dock",
4120                    description: "Where to dock the Git panel.",
4121                    field: Box::new(SettingField {
4122                        json_path: Some("git_panel.dock"),
4123                        pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
4124                        write: |settings_content, value| {
4125                            settings_content.git_panel.get_or_insert_default().dock = value;
4126                        },
4127                    }),
4128                    metadata: None,
4129                    files: USER,
4130                }),
4131                SettingsPageItem::SettingItem(SettingItem {
4132                    title: "Git Panel Default Width",
4133                    description: "Default width of the Git panel in pixels.",
4134                    field: Box::new(SettingField {
4135                        json_path: Some("git_panel.default_width"),
4136                        pick: |settings_content| {
4137                            settings_content.git_panel.as_ref()?.default_width.as_ref()
4138                        },
4139                        write: |settings_content, value| {
4140                            settings_content
4141                                .git_panel
4142                                .get_or_insert_default()
4143                                .default_width = value;
4144                        },
4145                    }),
4146                    metadata: None,
4147                    files: USER,
4148                }),
4149                SettingsPageItem::SettingItem(SettingItem {
4150                    title: "Git Panel Status Style",
4151                    description: "How entry statuses are displayed.",
4152                    field: Box::new(SettingField {
4153                        json_path: Some("git_panel.status_style"),
4154                        pick: |settings_content| {
4155                            settings_content.git_panel.as_ref()?.status_style.as_ref()
4156                        },
4157                        write: |settings_content, value| {
4158                            settings_content
4159                                .git_panel
4160                                .get_or_insert_default()
4161                                .status_style = value;
4162                        },
4163                    }),
4164                    metadata: None,
4165                    files: USER,
4166                }),
4167                SettingsPageItem::SettingItem(SettingItem {
4168                    title: "Fallback Branch Name",
4169                    description: "Default branch name will be when init.defaultbranch is not set in Git.",
4170                    field: Box::new(SettingField {
4171                        json_path: Some("git_panel.fallback_branch_name"),
4172                        pick: |settings_content| {
4173                            settings_content
4174                                .git_panel
4175                                .as_ref()?
4176                                .fallback_branch_name
4177                                .as_ref()
4178                        },
4179                        write: |settings_content, value| {
4180                            settings_content
4181                                .git_panel
4182                                .get_or_insert_default()
4183                                .fallback_branch_name = value;
4184                        },
4185                    }),
4186                    metadata: None,
4187                    files: USER,
4188                }),
4189                SettingsPageItem::SettingItem(SettingItem {
4190                    title: "Sort By Path",
4191                    description: "Enable to sort entries in the panel by path, disable to sort by status.",
4192                    field: Box::new(SettingField {
4193                        json_path: Some("git_panel.sort_by_path"),
4194                        pick: |settings_content| {
4195                            settings_content.git_panel.as_ref()?.sort_by_path.as_ref()
4196                        },
4197                        write: |settings_content, value| {
4198                            settings_content
4199                                .git_panel
4200                                .get_or_insert_default()
4201                                .sort_by_path = value;
4202                        },
4203                    }),
4204                    metadata: None,
4205                    files: USER,
4206                }),
4207                SettingsPageItem::SettingItem(SettingItem {
4208                    title: "Collapse Untracked Diff",
4209                    description: "Whether to collapse untracked files in the diff panel.",
4210                    field: Box::new(SettingField {
4211                        json_path: Some("git_panel.collapse_untracked_diff"),
4212                        pick: |settings_content| {
4213                            settings_content
4214                                .git_panel
4215                                .as_ref()?
4216                                .collapse_untracked_diff
4217                                .as_ref()
4218                        },
4219                        write: |settings_content, value| {
4220                            settings_content
4221                                .git_panel
4222                                .get_or_insert_default()
4223                                .collapse_untracked_diff = value;
4224                        },
4225                    }),
4226                    metadata: None,
4227                    files: USER,
4228                }),
4229                SettingsPageItem::SettingItem(SettingItem {
4230                    title: "Scroll Bar",
4231                    description: "How and when the scrollbar should be displayed.",
4232                    field: Box::new(SettingField {
4233                        json_path: Some("git_panel.scrollbar.show"),
4234                        pick: |settings_content| {
4235                            show_scrollbar_or_editor(settings_content, |settings_content| {
4236                                settings_content
4237                                    .git_panel
4238                                    .as_ref()?
4239                                    .scrollbar
4240                                    .as_ref()?
4241                                    .show
4242                                    .as_ref()
4243                            })
4244                        },
4245                        write: |settings_content, value| {
4246                            settings_content
4247                                .git_panel
4248                                .get_or_insert_default()
4249                                .scrollbar
4250                                .get_or_insert_default()
4251                                .show = value;
4252                        },
4253                    }),
4254                    metadata: None,
4255                    files: USER,
4256                }),
4257                SettingsPageItem::SectionHeader("Debugger Panel"),
4258                SettingsPageItem::SettingItem(SettingItem {
4259                    title: "Debugger Panel Dock",
4260                    description: "The dock position of the debug panel.",
4261                    field: Box::new(SettingField {
4262                        json_path: Some("debugger.dock"),
4263                        pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
4264                        write: |settings_content, value| {
4265                            settings_content.debugger.get_or_insert_default().dock = value;
4266                        },
4267                    }),
4268                    metadata: None,
4269                    files: USER,
4270                }),
4271                SettingsPageItem::SectionHeader("Notification Panel"),
4272                SettingsPageItem::SettingItem(SettingItem {
4273                    title: "Notification Panel Button",
4274                    description: "Show the notification panel button in the status bar.",
4275                    field: Box::new(SettingField {
4276                        json_path: Some("notification_panel.button"),
4277                        pick: |settings_content| {
4278                            settings_content
4279                                .notification_panel
4280                                .as_ref()?
4281                                .button
4282                                .as_ref()
4283                        },
4284                        write: |settings_content, value| {
4285                            settings_content
4286                                .notification_panel
4287                                .get_or_insert_default()
4288                                .button = value;
4289                        },
4290                    }),
4291                    metadata: None,
4292                    files: USER,
4293                }),
4294                SettingsPageItem::SettingItem(SettingItem {
4295                    title: "Notification Panel Dock",
4296                    description: "Where to dock the notification panel.",
4297                    field: Box::new(SettingField {
4298                        json_path: Some("notification_panel.dock"),
4299                        pick: |settings_content| {
4300                            settings_content.notification_panel.as_ref()?.dock.as_ref()
4301                        },
4302                        write: |settings_content, value| {
4303                            settings_content
4304                                .notification_panel
4305                                .get_or_insert_default()
4306                                .dock = value;
4307                        },
4308                    }),
4309                    metadata: None,
4310                    files: USER,
4311                }),
4312                SettingsPageItem::SettingItem(SettingItem {
4313                    title: "Notification Panel Default Width",
4314                    description: "Default width of the notification panel in pixels.",
4315                    field: Box::new(SettingField {
4316                        json_path: Some("notification_panel.default_width"),
4317                        pick: |settings_content| {
4318                            settings_content
4319                                .notification_panel
4320                                .as_ref()?
4321                                .default_width
4322                                .as_ref()
4323                        },
4324                        write: |settings_content, value| {
4325                            settings_content
4326                                .notification_panel
4327                                .get_or_insert_default()
4328                                .default_width = value;
4329                        },
4330                    }),
4331                    metadata: None,
4332                    files: USER,
4333                }),
4334                SettingsPageItem::SectionHeader("Collaboration Panel"),
4335                SettingsPageItem::SettingItem(SettingItem {
4336                    title: "Collaboration Panel Button",
4337                    description: "Show the collaboration panel button in the status bar.",
4338                    field: Box::new(SettingField {
4339                        json_path: Some("collaboration_panel.button"),
4340                        pick: |settings_content| {
4341                            settings_content
4342                                .collaboration_panel
4343                                .as_ref()?
4344                                .button
4345                                .as_ref()
4346                        },
4347                        write: |settings_content, value| {
4348                            settings_content
4349                                .collaboration_panel
4350                                .get_or_insert_default()
4351                                .button = value;
4352                        },
4353                    }),
4354                    metadata: None,
4355                    files: USER,
4356                }),
4357                SettingsPageItem::SettingItem(SettingItem {
4358                    title: "Collaboration Panel Dock",
4359                    description: "Where to dock the collaboration panel.",
4360                    field: Box::new(SettingField {
4361                        json_path: Some("collaboration_panel.dock"),
4362                        pick: |settings_content| {
4363                            settings_content.collaboration_panel.as_ref()?.dock.as_ref()
4364                        },
4365                        write: |settings_content, value| {
4366                            settings_content
4367                                .collaboration_panel
4368                                .get_or_insert_default()
4369                                .dock = value;
4370                        },
4371                    }),
4372                    metadata: None,
4373                    files: USER,
4374                }),
4375                SettingsPageItem::SettingItem(SettingItem {
4376                    title: "Collaboration Panel Default Width",
4377                    description: "Default width of the collaboration panel in pixels.",
4378                    field: Box::new(SettingField {
4379                        json_path: Some("collaboration_panel.dock"),
4380                        pick: |settings_content| {
4381                            settings_content
4382                                .collaboration_panel
4383                                .as_ref()?
4384                                .default_width
4385                                .as_ref()
4386                        },
4387                        write: |settings_content, value| {
4388                            settings_content
4389                                .collaboration_panel
4390                                .get_or_insert_default()
4391                                .default_width = value;
4392                        },
4393                    }),
4394                    metadata: None,
4395                    files: USER,
4396                }),
4397                SettingsPageItem::SectionHeader("Agent Panel"),
4398                SettingsPageItem::SettingItem(SettingItem {
4399                    title: "Agent Panel Button",
4400                    description: "Whether to show the agent panel button in the status bar.",
4401                    field: Box::new(SettingField {
4402                        json_path: Some("agent.button"),
4403                        pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
4404                        write: |settings_content, value| {
4405                            settings_content.agent.get_or_insert_default().button = value;
4406                        },
4407                    }),
4408                    metadata: None,
4409                    files: USER,
4410                }),
4411                SettingsPageItem::SettingItem(SettingItem {
4412                    title: "Agent Panel Dock",
4413                    description: "Where to dock the agent panel.",
4414                    field: Box::new(SettingField {
4415                        json_path: Some("agent.dock"),
4416                        pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
4417                        write: |settings_content, value| {
4418                            settings_content.agent.get_or_insert_default().dock = value;
4419                        },
4420                    }),
4421                    metadata: None,
4422                    files: USER,
4423                }),
4424                SettingsPageItem::SettingItem(SettingItem {
4425                    title: "Agent Panel Default Width",
4426                    description: "Default width when the agent panel is docked to the left or right.",
4427                    field: Box::new(SettingField {
4428                        json_path: Some("agent.default_width"),
4429                        pick: |settings_content| {
4430                            settings_content.agent.as_ref()?.default_width.as_ref()
4431                        },
4432                        write: |settings_content, value| {
4433                            settings_content.agent.get_or_insert_default().default_width = value;
4434                        },
4435                    }),
4436                    metadata: None,
4437                    files: USER,
4438                }),
4439                SettingsPageItem::SettingItem(SettingItem {
4440                    title: "Agent Panel Default Height",
4441                    description: "Default height when the agent panel is docked to the bottom.",
4442                    field: Box::new(SettingField {
4443                        json_path: Some("agent.default_height"),
4444                        pick: |settings_content| {
4445                            settings_content.agent.as_ref()?.default_height.as_ref()
4446                        },
4447                        write: |settings_content, value| {
4448                            settings_content
4449                                .agent
4450                                .get_or_insert_default()
4451                                .default_height = value;
4452                        },
4453                    }),
4454                    metadata: None,
4455                    files: USER,
4456                }),
4457            ],
4458        },
4459        SettingsPage {
4460            title: "Debugger",
4461            items: vec![
4462                SettingsPageItem::SectionHeader("General"),
4463                SettingsPageItem::SettingItem(SettingItem {
4464                    title: "Stepping Granularity",
4465                    description: "Determines the stepping granularity for debug operations.",
4466                    field: Box::new(SettingField {
4467                        json_path: Some("debugger.stepping_granularity"),
4468                        pick: |settings_content| {
4469                            settings_content
4470                                .debugger
4471                                .as_ref()?
4472                                .stepping_granularity
4473                                .as_ref()
4474                        },
4475                        write: |settings_content, value| {
4476                            settings_content
4477                                .debugger
4478                                .get_or_insert_default()
4479                                .stepping_granularity = value;
4480                        },
4481                    }),
4482                    metadata: None,
4483                    files: USER,
4484                }),
4485                SettingsPageItem::SettingItem(SettingItem {
4486                    title: "Save Breakpoints",
4487                    description: "Whether breakpoints should be reused across Zed sessions.",
4488                    field: Box::new(SettingField {
4489                        json_path: Some("debugger.save_breakpoints"),
4490                        pick: |settings_content| {
4491                            settings_content
4492                                .debugger
4493                                .as_ref()?
4494                                .save_breakpoints
4495                                .as_ref()
4496                        },
4497                        write: |settings_content, value| {
4498                            settings_content
4499                                .debugger
4500                                .get_or_insert_default()
4501                                .save_breakpoints = value;
4502                        },
4503                    }),
4504                    metadata: None,
4505                    files: USER,
4506                }),
4507                SettingsPageItem::SettingItem(SettingItem {
4508                    title: "Timeout",
4509                    description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
4510                    field: Box::new(SettingField {
4511                        json_path: Some("debugger.timeout"),
4512                        pick: |settings_content| {
4513                            settings_content.debugger.as_ref()?.timeout.as_ref()
4514                        },
4515                        write: |settings_content, value| {
4516                            settings_content.debugger.get_or_insert_default().timeout = value;
4517                        },
4518                    }),
4519                    metadata: None,
4520                    files: USER,
4521                }),
4522                SettingsPageItem::SettingItem(SettingItem {
4523                    title: "Log DAP Communications",
4524                    description: "Whether to log messages between active debug adapters and Zed.",
4525                    field: Box::new(SettingField {
4526                        json_path: Some("debugger.log_dap_communications"),
4527                        pick: |settings_content| {
4528                            settings_content
4529                                .debugger
4530                                .as_ref()?
4531                                .log_dap_communications
4532                                .as_ref()
4533                        },
4534                        write: |settings_content, value| {
4535                            settings_content
4536                                .debugger
4537                                .get_or_insert_default()
4538                                .log_dap_communications = value;
4539                        },
4540                    }),
4541                    metadata: None,
4542                    files: USER,
4543                }),
4544                SettingsPageItem::SettingItem(SettingItem {
4545                    title: "Format DAP Log Messages",
4546                    description: "Whether to format DAP messages when adding them to debug adapter logger.",
4547                    field: Box::new(SettingField {
4548                        json_path: Some("debugger.format_dap_log_messages"),
4549                        pick: |settings_content| {
4550                            settings_content
4551                                .debugger
4552                                .as_ref()?
4553                                .format_dap_log_messages
4554                                .as_ref()
4555                        },
4556                        write: |settings_content, value| {
4557                            settings_content
4558                                .debugger
4559                                .get_or_insert_default()
4560                                .format_dap_log_messages = value;
4561                        },
4562                    }),
4563                    metadata: None,
4564                    files: USER,
4565                }),
4566            ],
4567        },
4568        SettingsPage {
4569            title: "Terminal",
4570            items: vec![
4571                SettingsPageItem::SectionHeader("Environment"),
4572                SettingsPageItem::DynamicItem(DynamicItem {
4573                    discriminant: SettingItem {
4574                        files: USER | PROJECT,
4575                        title: "Shell",
4576                        description: "What shell to use when opening a terminal.",
4577                        field: Box::new(SettingField {
4578                            json_path: Some("terminal.shell$"),
4579                            pick: |settings_content| {
4580                                Some(&dynamic_variants::<settings::Shell>()[
4581                                    settings_content
4582                                        .terminal
4583                                        .as_ref()?
4584                                        .project
4585                                        .shell
4586                                        .as_ref()?
4587                                        .discriminant() as usize])
4588                            },
4589                            write: |settings_content, value| {
4590                                let Some(value) = value else {
4591                                    if let Some(terminal) = settings_content.terminal.as_mut() {
4592                                        terminal.project.shell = None;
4593                                    }
4594                                    return;
4595                                };
4596                                let settings_value = settings_content
4597                                    .terminal
4598                                    .get_or_insert_default()
4599                                    .project
4600                                    .shell
4601                                    .get_or_insert_with(|| settings::Shell::default());
4602                                let default_shell = if cfg!(target_os = "windows") {
4603                                    "powershell.exe"
4604                                } else {
4605                                    "sh"
4606                                };
4607                                *settings_value = match value {
4608                                    settings::ShellDiscriminants::System => {
4609                                        settings::Shell::System
4610                                    },
4611                                    settings::ShellDiscriminants::Program => {
4612                                        let program = match settings_value {
4613                                            settings::Shell::Program(p) => p.clone(),
4614                                            settings::Shell::WithArguments { program, .. } => program.clone(),
4615                                            _ => String::from(default_shell),
4616                                        };
4617                                        settings::Shell::Program(program)
4618                                    },
4619                                    settings::ShellDiscriminants::WithArguments => {
4620                                        let (program, args, title_override) = match settings_value {
4621                                            settings::Shell::Program(p) => (p.clone(), vec![], None),
4622                                            settings::Shell::WithArguments { program, args, title_override } => {
4623                                                (program.clone(), args.clone(), title_override.clone())
4624                                            },
4625                                            _ => (String::from(default_shell), vec![], None),
4626                                        };
4627                                        settings::Shell::WithArguments {
4628                                            program,
4629                                            args,
4630                                            title_override,
4631                                        }
4632                                    },
4633                                };
4634                            },
4635                        }),
4636                        metadata: None,
4637                    },
4638                    pick_discriminant: |settings_content| {
4639                        Some(settings_content.terminal.as_ref()?.project.shell.as_ref()?.discriminant() as usize)
4640                    },
4641                    fields: dynamic_variants::<settings::Shell>().into_iter().map(|variant| {
4642                        match variant {
4643                            settings::ShellDiscriminants::System => vec![],
4644                            settings::ShellDiscriminants::Program => vec![
4645                                SettingItem {
4646                                    files: USER | PROJECT,
4647                                    title: "Program",
4648                                    description: "The shell program to use.",
4649                                    field: Box::new(SettingField {
4650                                        json_path: Some("terminal.shell"),
4651                                        pick: |settings_content| {
4652                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4653                                                Some(settings::Shell::Program(program)) => Some(program),
4654                                                _ => None
4655                                            }
4656                                        },
4657                                        write: |settings_content, value| {
4658                                            let Some(value) = value else {
4659                                                return;
4660                                            };
4661                                            match settings_content
4662                                                .terminal
4663                                                .get_or_insert_default()
4664                                                .project
4665                                                .shell.as_mut() {
4666                                                    Some(settings::Shell::Program(program)) => *program = value,
4667                                                    _ => return
4668                                                }
4669                                        },
4670                                    }),
4671                                    metadata: None,
4672                                }
4673                            ],
4674                            settings::ShellDiscriminants::WithArguments => vec![
4675                                SettingItem {
4676                                    files: USER | PROJECT,
4677                                    title: "Program",
4678                                    description: "The shell program to run.",
4679                                    field: Box::new(SettingField {
4680                                        json_path: Some("terminal.shell.program"),
4681                                        pick: |settings_content| {
4682                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4683                                                Some(settings::Shell::WithArguments { program, .. }) => Some(program),
4684                                                _ => None
4685                                            }
4686                                        },
4687                                        write: |settings_content, value| {
4688                                            let Some(value) = value else {
4689                                                return;
4690                                            };
4691                                            match settings_content
4692                                                .terminal
4693                                                .get_or_insert_default()
4694                                                .project
4695                                                .shell.as_mut() {
4696                                                    Some(settings::Shell::WithArguments { program, .. }) => *program = value,
4697                                                    _ => return
4698                                                }
4699                                        },
4700                                    }),
4701                                    metadata: None,
4702                                },
4703                                SettingItem {
4704                                    files: USER | PROJECT,
4705                                    title: "Arguments",
4706                                    description: "The arguments to pass to the shell program.",
4707                                    field: Box::new(
4708                                        SettingField {
4709                                            json_path: Some("terminal.shell.args"),
4710                                            pick: |settings_content| {
4711                                                match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4712                                                    Some(settings::Shell::WithArguments { args, .. }) => Some(args),
4713                                                    _ => None
4714                                                }
4715                                            },
4716                                            write: |settings_content, value| {
4717                                                let Some(value) = value else {
4718                                                    return;
4719                                                };
4720                                                match settings_content
4721                                                    .terminal
4722                                                    .get_or_insert_default()
4723                                                    .project
4724                                                    .shell.as_mut() {
4725                                                        Some(settings::Shell::WithArguments { args, .. }) => *args = value,
4726                                                        _ => return
4727                                                    }
4728                                            },
4729                                        }
4730                                        .unimplemented(),
4731                                    ),
4732                                    metadata: None,
4733                                },
4734                                SettingItem {
4735                                    files: USER | PROJECT,
4736                                    title: "Title Override",
4737                                    description: "An optional string to override the title of the terminal tab.",
4738                                    field: Box::new(SettingField {
4739                                        json_path: Some("terminal.shell.title_override"),
4740                                        pick: |settings_content| {
4741                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4742                                                Some(settings::Shell::WithArguments { title_override, .. }) => title_override.as_ref().or(DEFAULT_EMPTY_SHARED_STRING),
4743                                                _ => None
4744                                            }
4745                                        },
4746                                        write: |settings_content, value| {
4747                                            match settings_content
4748                                                .terminal
4749                                                .get_or_insert_default()
4750                                                .project
4751                                                .shell.as_mut() {
4752                                                    Some(settings::Shell::WithArguments { title_override, .. }) => *title_override = value.filter(|s| !s.is_empty()),
4753                                                    _ => return
4754                                                }
4755                                        },
4756                                    }),
4757                                    metadata: None,
4758                                }
4759                            ],
4760                        }
4761                    }).collect(),
4762                }),
4763                SettingsPageItem::DynamicItem(DynamicItem {
4764                    discriminant: SettingItem {
4765                        files: USER | PROJECT,
4766                        title: "Working Directory",
4767                        description: "What working directory to use when launching the terminal.",
4768                        field: Box::new(SettingField {
4769                            json_path: Some("terminal.working_directory$"),
4770                            pick: |settings_content| {
4771                                Some(&dynamic_variants::<settings::WorkingDirectory>()[
4772                                    settings_content
4773                                        .terminal
4774                                        .as_ref()?
4775                                        .project
4776                                        .working_directory
4777                                        .as_ref()?
4778                                        .discriminant() as usize])
4779                            },
4780                            write: |settings_content, value| {
4781                                let Some(value) = value else {
4782                                    if let Some(terminal) = settings_content.terminal.as_mut() {
4783                                        terminal.project.working_directory = None;
4784                                    }
4785                                    return;
4786                                };
4787                                let settings_value = settings_content
4788                                    .terminal
4789                                    .get_or_insert_default()
4790                                    .project
4791                                    .working_directory
4792                                    .get_or_insert_with(|| settings::WorkingDirectory::CurrentProjectDirectory);
4793                                *settings_value = match value {
4794                                    settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => {
4795                                        settings::WorkingDirectory::CurrentProjectDirectory
4796                                    },
4797                                    settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => {
4798                                        settings::WorkingDirectory::FirstProjectDirectory
4799                                    },
4800                                    settings::WorkingDirectoryDiscriminants::AlwaysHome => {
4801                                        settings::WorkingDirectory::AlwaysHome
4802                                    },
4803                                    settings::WorkingDirectoryDiscriminants::Always => {
4804                                        let directory = match settings_value {
4805                                            settings::WorkingDirectory::Always { .. } => return,
4806                                            _ => String::new(),
4807                                        };
4808                                        settings::WorkingDirectory::Always { directory }
4809                                    },
4810                                };
4811                            },
4812                        }),
4813                        metadata: None,
4814                    },
4815                    pick_discriminant: |settings_content| {
4816                        Some(settings_content.terminal.as_ref()?.project.working_directory.as_ref()?.discriminant() as usize)
4817                    },
4818                    fields: dynamic_variants::<settings::WorkingDirectory>().into_iter().map(|variant| {
4819                        match variant {
4820                            settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => vec![],
4821                            settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => vec![],
4822                            settings::WorkingDirectoryDiscriminants::AlwaysHome => vec![],
4823                            settings::WorkingDirectoryDiscriminants::Always => vec![
4824                                SettingItem {
4825                                    files: USER | PROJECT,
4826                                    title: "Directory",
4827                                    description: "The directory path to use (will be shell expanded).",
4828                                    field: Box::new(SettingField {
4829                                        json_path: Some("terminal.working_directory.always"),
4830                                        pick: |settings_content| {
4831                                            match settings_content.terminal.as_ref()?.project.working_directory.as_ref() {
4832                                                Some(settings::WorkingDirectory::Always { directory }) => Some(directory),
4833                                                _ => None
4834                                            }
4835                                        },
4836                                        write: |settings_content, value| {
4837                                            let value = value.unwrap_or_default();
4838                                            match settings_content
4839                                                .terminal
4840                                                .get_or_insert_default()
4841                                                .project
4842                                                .working_directory.as_mut() {
4843                                                    Some(settings::WorkingDirectory::Always { directory }) => *directory = value,
4844                                                    _ => return
4845                                                }
4846                                        },
4847                                    }),
4848                                    metadata: None,
4849                                }
4850                            ],
4851                        }
4852                    }).collect(),
4853                }),
4854                SettingsPageItem::SettingItem(SettingItem {
4855                    title: "Environment Variables",
4856                    description: "Key-value pairs to add to the terminal's environment.",
4857                    field: Box::new(
4858                        SettingField {
4859                            json_path: Some("terminal.env"),
4860                            pick: |settings_content| {
4861                                settings_content.terminal.as_ref()?.project.env.as_ref()
4862                            },
4863                            write: |settings_content, value| {
4864                                settings_content
4865                                    .terminal
4866                                    .get_or_insert_default()
4867                                    .project
4868                                    .env = value;
4869                            },
4870                        }
4871                        .unimplemented(),
4872                    ),
4873                    metadata: None,
4874                    files: USER | PROJECT,
4875                }),
4876                SettingsPageItem::SettingItem(SettingItem {
4877                    title: "Detect Virtual Environment",
4878                    description: "Activates the Python virtual environment, if one is found, in the terminal's working directory.",
4879                    field: Box::new(
4880                        SettingField {
4881                            json_path: Some("terminal.detect_venv"),
4882                            pick: |settings_content| {
4883                                settings_content
4884                                    .terminal
4885                                    .as_ref()?
4886                                    .project
4887                                    .detect_venv
4888                                    .as_ref()
4889                            },
4890                            write: |settings_content, value| {
4891                                settings_content
4892                                    .terminal
4893                                    .get_or_insert_default()
4894                                    .project
4895                                    .detect_venv = value;
4896                            },
4897                        }
4898                        .unimplemented(),
4899                    ),
4900                    metadata: None,
4901                    files: USER | PROJECT,
4902                }),
4903                SettingsPageItem::SectionHeader("Font"),
4904                SettingsPageItem::SettingItem(SettingItem {
4905                    title: "Font Size",
4906                    description: "Font size for terminal text. If not set, defaults to buffer font size.",
4907                    field: Box::new(SettingField {
4908                        json_path: Some("terminal.font_size"),
4909                        pick: |settings_content| {
4910                            settings_content
4911                                .terminal
4912                                .as_ref()
4913                                .and_then(|terminal| terminal.font_size.as_ref())
4914                                .or(settings_content.theme.buffer_font_size.as_ref())
4915                        },
4916                        write: |settings_content, value| {
4917                            settings_content.terminal.get_or_insert_default().font_size = value;
4918                        },
4919                    }),
4920                    metadata: None,
4921                    files: USER,
4922                }),
4923                SettingsPageItem::SettingItem(SettingItem {
4924                    title: "Font Family",
4925                    description: "Font family for terminal text. If not set, defaults to buffer font family.",
4926                    field: Box::new(SettingField {
4927                        json_path: Some("terminal.font_family"),
4928                        pick: |settings_content| {
4929                            settings_content
4930                                .terminal
4931                                .as_ref()
4932                                .and_then(|terminal| terminal.font_family.as_ref())
4933                                .or(settings_content.theme.buffer_font_family.as_ref())
4934                        },
4935                        write: |settings_content, value| {
4936                            settings_content
4937                                .terminal
4938                                .get_or_insert_default()
4939                                .font_family = value;
4940                        },
4941                    }),
4942                    metadata: None,
4943                    files: USER,
4944                }),
4945                SettingsPageItem::SettingItem(SettingItem {
4946                    title: "Font Fallbacks",
4947                    description: "Font fallbacks for terminal text. If not set, defaults to buffer font fallbacks.",
4948                    field: Box::new(
4949                        SettingField {
4950                            json_path: Some("terminal.font_fallbacks"),
4951                            pick: |settings_content| {
4952                                settings_content
4953                                    .terminal
4954                                    .as_ref()
4955                                    .and_then(|terminal| terminal.font_fallbacks.as_ref())
4956                                    .or(settings_content.theme.buffer_font_fallbacks.as_ref())
4957                            },
4958                            write: |settings_content, value| {
4959                                settings_content
4960                                    .terminal
4961                                    .get_or_insert_default()
4962                                    .font_fallbacks = value;
4963                            },
4964                        }
4965                        .unimplemented(),
4966                    ),
4967                    metadata: None,
4968                    files: USER,
4969                }),
4970                SettingsPageItem::SettingItem(SettingItem {
4971                    title: "Font Weight",
4972                    description: "Font weight for terminal text in CSS weight units (100-900).",
4973                    field: Box::new(SettingField {
4974                        json_path: Some("terminal.font_weight"),
4975                        pick: |settings_content| {
4976                            settings_content.terminal.as_ref()?.font_weight.as_ref()
4977                        },
4978                        write: |settings_content, value| {
4979                            settings_content
4980                                .terminal
4981                                .get_or_insert_default()
4982                                .font_weight = value;
4983                        },
4984                    }),
4985                    metadata: None,
4986                    files: USER,
4987                }),
4988                SettingsPageItem::SettingItem(SettingItem {
4989                    title: "Font Features",
4990                    description: "Font features for terminal text.",
4991                    field: Box::new(
4992                        SettingField {
4993                            json_path: Some("terminal.font_features"),
4994                            pick: |settings_content| {
4995                                settings_content
4996                                    .terminal
4997                                    .as_ref()
4998                                    .and_then(|terminal| terminal.font_features.as_ref())
4999                                    .or(settings_content.theme.buffer_font_features.as_ref())
5000                            },
5001                            write: |settings_content, value| {
5002                                settings_content
5003                                    .terminal
5004                                    .get_or_insert_default()
5005                                    .font_features = value;
5006                            },
5007                        }
5008                        .unimplemented(),
5009                    ),
5010                    metadata: None,
5011                    files: USER,
5012                }),
5013                SettingsPageItem::SectionHeader("Display Settings"),
5014                SettingsPageItem::SettingItem(SettingItem {
5015                    title: "Line Height",
5016                    description: "Line height for terminal text.",
5017                    field: Box::new(
5018                        SettingField {
5019                            json_path: Some("terminal.line_height"),
5020                            pick: |settings_content| {
5021                                settings_content.terminal.as_ref()?.line_height.as_ref()
5022                            },
5023                            write: |settings_content, value| {
5024                                settings_content
5025                                    .terminal
5026                                    .get_or_insert_default()
5027                                    .line_height = value;
5028                            },
5029                        }
5030                        .unimplemented(),
5031                    ),
5032                    metadata: None,
5033                    files: USER,
5034                }),
5035                SettingsPageItem::SettingItem(SettingItem {
5036                    title: "Cursor Shape",
5037                    description: "Default cursor shape for the terminal (bar, block, underline, or hollow).",
5038                    field: Box::new(SettingField {
5039                        json_path: Some("terminal.cursor_shape"),
5040                        pick: |settings_content| {
5041                            settings_content.terminal.as_ref()?.cursor_shape.as_ref()
5042                        },
5043                        write: |settings_content, value| {
5044                            settings_content
5045                                .terminal
5046                                .get_or_insert_default()
5047                                .cursor_shape = value;
5048                        },
5049                    }),
5050                    metadata: None,
5051                    files: USER,
5052                }),
5053                SettingsPageItem::SettingItem(SettingItem {
5054                    title: "Cursor Blinking",
5055                    description: "Sets the cursor blinking behavior in the terminal.",
5056                    field: Box::new(SettingField {
5057                        json_path: Some("terminal.blinking"),
5058                        pick: |settings_content| {
5059                            settings_content.terminal.as_ref()?.blinking.as_ref()
5060                        },
5061                        write: |settings_content, value| {
5062                            settings_content.terminal.get_or_insert_default().blinking = value;
5063                        },
5064                    }),
5065                    metadata: None,
5066                    files: USER,
5067                }),
5068                SettingsPageItem::SettingItem(SettingItem {
5069                    title: "Alternate Scroll",
5070                    description: "Whether alternate scroll mode is active by default (converts mouse scroll to arrow keys in apps like Vim).",
5071                    field: Box::new(SettingField {
5072                        json_path: Some("terminal.alternate_scroll"),
5073                        pick: |settings_content| {
5074                            settings_content
5075                                .terminal
5076                                .as_ref()?
5077                                .alternate_scroll
5078                                .as_ref()
5079                        },
5080                        write: |settings_content, value| {
5081                            settings_content
5082                                .terminal
5083                                .get_or_insert_default()
5084                                .alternate_scroll = value;
5085                        },
5086                    }),
5087                    metadata: None,
5088                    files: USER,
5089                }),
5090                SettingsPageItem::SettingItem(SettingItem {
5091                    title: "Minimum Contrast",
5092                    description: "The minimum APCA perceptual contrast between foreground and background colors (0-106).",
5093                    field: Box::new(SettingField {
5094                        json_path: Some("terminal.minimum_contrast"),
5095                        pick: |settings_content| {
5096                            settings_content
5097                                .terminal
5098                                .as_ref()?
5099                                .minimum_contrast
5100                                .as_ref()
5101                        },
5102                        write: |settings_content, value| {
5103                            settings_content
5104                                .terminal
5105                                .get_or_insert_default()
5106                                .minimum_contrast = value;
5107                        },
5108                    }),
5109                    metadata: None,
5110                    files: USER,
5111                }),
5112                SettingsPageItem::SectionHeader("Behavior Settings"),
5113                SettingsPageItem::SettingItem(SettingItem {
5114                    title: "Option As Meta",
5115                    description: "Whether the option key behaves as the meta key.",
5116                    field: Box::new(SettingField {
5117                        json_path: Some("terminal.option_as_meta"),
5118                        pick: |settings_content| {
5119                            settings_content.terminal.as_ref()?.option_as_meta.as_ref()
5120                        },
5121                        write: |settings_content, value| {
5122                            settings_content
5123                                .terminal
5124                                .get_or_insert_default()
5125                                .option_as_meta = value;
5126                        },
5127                    }),
5128                    metadata: None,
5129                    files: USER,
5130                }),
5131                SettingsPageItem::SettingItem(SettingItem {
5132                    title: "Copy On Select",
5133                    description: "Whether selecting text in the terminal automatically copies to the system clipboard.",
5134                    field: Box::new(SettingField {
5135                        json_path: Some("terminal.copy_on_select"),
5136                        pick: |settings_content| {
5137                            settings_content.terminal.as_ref()?.copy_on_select.as_ref()
5138                        },
5139                        write: |settings_content, value| {
5140                            settings_content
5141                                .terminal
5142                                .get_or_insert_default()
5143                                .copy_on_select = value;
5144                        },
5145                    }),
5146                    metadata: None,
5147                    files: USER,
5148                }),
5149                SettingsPageItem::SettingItem(SettingItem {
5150                    title: "Keep Selection On Copy",
5151                    description: "Whether to keep the text selection after copying it to the clipboard.",
5152                    field: Box::new(SettingField {
5153                        json_path: Some("terminal.keep_selection_on_copy"),
5154                        pick: |settings_content| {
5155                            settings_content
5156                                .terminal
5157                                .as_ref()?
5158                                .keep_selection_on_copy
5159                                .as_ref()
5160                        },
5161                        write: |settings_content, value| {
5162                            settings_content
5163                                .terminal
5164                                .get_or_insert_default()
5165                                .keep_selection_on_copy = value;
5166                        },
5167                    }),
5168                    metadata: None,
5169                    files: USER,
5170                }),
5171                SettingsPageItem::SectionHeader("Layout Settings"),
5172                SettingsPageItem::SettingItem(SettingItem {
5173                    title: "Default Width",
5174                    description: "Default width when the terminal is docked to the left or right (in pixels).",
5175                    field: Box::new(SettingField {
5176                        json_path: Some("terminal.default_width"),
5177                        pick: |settings_content| {
5178                            settings_content.terminal.as_ref()?.default_width.as_ref()
5179                        },
5180                        write: |settings_content, value| {
5181                            settings_content
5182                                .terminal
5183                                .get_or_insert_default()
5184                                .default_width = value;
5185                        },
5186                    }),
5187                    metadata: None,
5188                    files: USER,
5189                }),
5190                SettingsPageItem::SettingItem(SettingItem {
5191                    title: "Default Height",
5192                    description: "Default height when the terminal is docked to the bottom (in pixels).",
5193                    field: Box::new(SettingField {
5194                        json_path: Some("terminal.default_height"),
5195                        pick: |settings_content| {
5196                            settings_content.terminal.as_ref()?.default_height.as_ref()
5197                        },
5198                        write: |settings_content, value| {
5199                            settings_content
5200                                .terminal
5201                                .get_or_insert_default()
5202                                .default_height = value;
5203                        },
5204                    }),
5205                    metadata: None,
5206                    files: USER,
5207                }),
5208                SettingsPageItem::SectionHeader("Advanced Settings"),
5209                SettingsPageItem::SettingItem(SettingItem {
5210                    title: "Max Scroll History Lines",
5211                    description: "Maximum number of lines to keep in scrollback history (max: 100,000; 0 disables scrolling).",
5212                    field: Box::new(SettingField {
5213                        json_path: Some("terminal.max_scroll_history_lines"),
5214                        pick: |settings_content| {
5215                            settings_content
5216                                .terminal
5217                                .as_ref()?
5218                                .max_scroll_history_lines
5219                                .as_ref()
5220                        },
5221                        write: |settings_content, value| {
5222                            settings_content
5223                                .terminal
5224                                .get_or_insert_default()
5225                                .max_scroll_history_lines = value;
5226                        },
5227                    }),
5228                    metadata: None,
5229                    files: USER,
5230                }),
5231                SettingsPageItem::SettingItem(SettingItem {
5232                    title: "Scroll Multiplier",
5233                    description: "The multiplier for scrolling in the terminal with the mouse wheel",
5234                    field: Box::new(SettingField {
5235                        json_path: Some("terminal.scroll_multiplier"),
5236                        pick: |settings_content| {
5237                            settings_content.terminal.as_ref()?.scroll_multiplier.as_ref()
5238                        },
5239                        write: |settings_content, value| {
5240                            settings_content
5241                                .terminal
5242                                .get_or_insert_default()
5243                                .scroll_multiplier = value;
5244                        },
5245                    }),
5246                    metadata: None,
5247                    files: USER,
5248                }),
5249                SettingsPageItem::SectionHeader("Toolbar"),
5250                SettingsPageItem::SettingItem(SettingItem {
5251                    title: "Breadcrumbs",
5252                    description: "Display the terminal title in breadcrumbs inside the terminal pane.",
5253                    field: Box::new(SettingField {
5254                        json_path: Some("terminal.toolbar.breadcrumbs"),
5255                        pick: |settings_content| {
5256                            settings_content
5257                                .terminal
5258                                .as_ref()?
5259                                .toolbar
5260                                .as_ref()?
5261                                .breadcrumbs
5262                                .as_ref()
5263                        },
5264                        write: |settings_content, value| {
5265                            settings_content
5266                                .terminal
5267                                .get_or_insert_default()
5268                                .toolbar
5269                                .get_or_insert_default()
5270                                .breadcrumbs = value;
5271                        },
5272                    }),
5273                    metadata: None,
5274                    files: USER,
5275                }),
5276                SettingsPageItem::SectionHeader("Scrollbar"),
5277                SettingsPageItem::SettingItem(SettingItem {
5278                    title: "Show Scrollbar",
5279                    description: "When to show the scrollbar in the terminal.",
5280                    field: Box::new(SettingField {
5281                        json_path: Some("terminal.scrollbar.show"),
5282                        pick: |settings_content| {
5283                            show_scrollbar_or_editor(settings_content, |settings_content| {
5284                                settings_content
5285                                    .terminal
5286                                    .as_ref()?
5287                                    .scrollbar
5288                                    .as_ref()?
5289                                    .show
5290                                    .as_ref()
5291                            })
5292                        },
5293                        write: |settings_content, value| {
5294                            settings_content
5295                                .terminal
5296                                .get_or_insert_default()
5297                                .scrollbar
5298                                .get_or_insert_default()
5299                                .show = value;
5300                        },
5301                    }),
5302                    metadata: None,
5303                    files: USER,
5304                }),
5305            ],
5306        },
5307        SettingsPage {
5308            title: "Version Control",
5309            items: vec![
5310                SettingsPageItem::SectionHeader("Git Gutter"),
5311                SettingsPageItem::SettingItem(SettingItem {
5312                    title: "Visibility",
5313                    description: "Control whether Git status is shown in the editor's gutter.",
5314                    field: Box::new(SettingField {
5315                        json_path: Some("git.git_gutter"),
5316                        pick: |settings_content| settings_content.git.as_ref()?.git_gutter.as_ref(),
5317                        write: |settings_content, value| {
5318                            settings_content.git.get_or_insert_default().git_gutter = value;
5319                        },
5320                    }),
5321                    metadata: None,
5322                    files: USER,
5323                }),
5324                // todo(settings_ui): Figure out the right default for this value in default.json
5325                SettingsPageItem::SettingItem(SettingItem {
5326                    title: "Debounce",
5327                    description: "Debounce threshold in milliseconds after which changes are reflected in the Git gutter.",
5328                    field: Box::new(SettingField {
5329                        json_path: Some("git.gutter_debounce"),
5330                        pick: |settings_content| {
5331                            settings_content.git.as_ref()?.gutter_debounce.as_ref()
5332                        },
5333                        write: |settings_content, value| {
5334                            settings_content.git.get_or_insert_default().gutter_debounce = value;
5335                        },
5336                    }),
5337                    metadata: None,
5338                    files: USER,
5339                }),
5340                SettingsPageItem::SectionHeader("Inline Git Blame"),
5341                SettingsPageItem::SettingItem(SettingItem {
5342                    title: "Enabled",
5343                    description: "Whether or not to show Git blame data inline in the currently focused line.",
5344                    field: Box::new(SettingField {
5345                        json_path: Some("git.inline_blame.enabled"),
5346                        pick: |settings_content| {
5347                            settings_content
5348                                .git
5349                                .as_ref()?
5350                                .inline_blame
5351                                .as_ref()?
5352                                .enabled
5353                                .as_ref()
5354                        },
5355                        write: |settings_content, value| {
5356                            settings_content
5357                                .git
5358                                .get_or_insert_default()
5359                                .inline_blame
5360                                .get_or_insert_default()
5361                                .enabled = value;
5362                        },
5363                    }),
5364                    metadata: None,
5365                    files: USER,
5366                }),
5367                SettingsPageItem::SettingItem(SettingItem {
5368                    title: "Delay",
5369                    description: "The delay after which the inline blame information is shown.",
5370                    field: Box::new(SettingField {
5371                        json_path: Some("git.inline_blame.delay_ms"),
5372                        pick: |settings_content| {
5373                            settings_content
5374                                .git
5375                                .as_ref()?
5376                                .inline_blame
5377                                .as_ref()?
5378                                .delay_ms
5379                                .as_ref()
5380                        },
5381                        write: |settings_content, value| {
5382                            settings_content
5383                                .git
5384                                .get_or_insert_default()
5385                                .inline_blame
5386                                .get_or_insert_default()
5387                                .delay_ms = value;
5388                        },
5389                    }),
5390                    metadata: None,
5391                    files: USER,
5392                }),
5393                SettingsPageItem::SettingItem(SettingItem {
5394                    title: "Padding",
5395                    description: "Padding between the end of the source line and the start of the inline blame in columns.",
5396                    field: Box::new(SettingField {
5397                        json_path: Some("git.inline_blame.padding"),
5398                        pick: |settings_content| {
5399                            settings_content
5400                                .git
5401                                .as_ref()?
5402                                .inline_blame
5403                                .as_ref()?
5404                                .padding
5405                                .as_ref()
5406                        },
5407                        write: |settings_content, value| {
5408                            settings_content
5409                                .git
5410                                .get_or_insert_default()
5411                                .inline_blame
5412                                .get_or_insert_default()
5413                                .padding = value;
5414                        },
5415                    }),
5416                    metadata: None,
5417                    files: USER,
5418                }),
5419                SettingsPageItem::SettingItem(SettingItem {
5420                    title: "Minimum Column",
5421                    description: "The minimum column number at which to show the inline blame information.",
5422                    field: Box::new(SettingField {
5423                        json_path: Some("git.inline_blame.min_column"),
5424                        pick: |settings_content| {
5425                            settings_content
5426                                .git
5427                                .as_ref()?
5428                                .inline_blame
5429                                .as_ref()?
5430                                .min_column
5431                                .as_ref()
5432                        },
5433                        write: |settings_content, value| {
5434                            settings_content
5435                                .git
5436                                .get_or_insert_default()
5437                                .inline_blame
5438                                .get_or_insert_default()
5439                                .min_column = value;
5440                        },
5441                    }),
5442                    metadata: None,
5443                    files: USER,
5444                }),
5445                SettingsPageItem::SettingItem(SettingItem {
5446                    title: "Show Commit Summary",
5447                    description: "Show commit summary as part of the inline blame.",
5448                    field: Box::new(SettingField {
5449                        json_path: Some("git.inline_blame.show_commit_summary"),
5450                        pick: |settings_content| {
5451                            settings_content
5452                                .git
5453                                .as_ref()?
5454                                .inline_blame
5455                                .as_ref()?
5456                                .show_commit_summary
5457                                .as_ref()
5458                        },
5459                        write: |settings_content, value| {
5460                            settings_content
5461                                .git
5462                                .get_or_insert_default()
5463                                .inline_blame
5464                                .get_or_insert_default()
5465                                .show_commit_summary = value;
5466                        },
5467                    }),
5468                    metadata: None,
5469                    files: USER,
5470                }),
5471                SettingsPageItem::SectionHeader("Git Blame View"),
5472                SettingsPageItem::SettingItem(SettingItem {
5473                    title: "Show Avatar",
5474                    description: "Show the avatar of the author of the commit.",
5475                    field: Box::new(SettingField {
5476                        json_path: Some("git.blame.show_avatar"),
5477                        pick: |settings_content| {
5478                            settings_content
5479                                .git
5480                                .as_ref()?
5481                                .blame
5482                                .as_ref()?
5483                                .show_avatar
5484                                .as_ref()
5485                        },
5486                        write: |settings_content, value| {
5487                            settings_content
5488                                .git
5489                                .get_or_insert_default()
5490                                .blame
5491                                .get_or_insert_default()
5492                                .show_avatar = value;
5493                        },
5494                    }),
5495                    metadata: None,
5496                    files: USER,
5497                }),
5498                SettingsPageItem::SectionHeader("Branch Picker"),
5499                SettingsPageItem::SettingItem(SettingItem {
5500                    title: "Show Author Name",
5501                    description: "Show author name as part of the commit information in branch picker.",
5502                    field: Box::new(SettingField {
5503                        json_path: Some("git.branch_picker.show_author_name"),
5504                        pick: |settings_content| {
5505                            settings_content
5506                                .git
5507                                .as_ref()?
5508                                .branch_picker
5509                                .as_ref()?
5510                                .show_author_name
5511                                .as_ref()
5512                        },
5513                        write: |settings_content, value| {
5514                            settings_content
5515                                .git
5516                                .get_or_insert_default()
5517                                .branch_picker
5518                                .get_or_insert_default()
5519                                .show_author_name = value;
5520                        },
5521                    }),
5522                    metadata: None,
5523                    files: USER,
5524                }),
5525                SettingsPageItem::SectionHeader("Git Hunks"),
5526                SettingsPageItem::SettingItem(SettingItem {
5527                    title: "Hunk Style",
5528                    description: "How Git hunks are displayed visually in the editor.",
5529                    field: Box::new(SettingField {
5530                        json_path: Some("git.hunk_style"),
5531                        pick: |settings_content| settings_content.git.as_ref()?.hunk_style.as_ref(),
5532                        write: |settings_content, value| {
5533                            settings_content.git.get_or_insert_default().hunk_style = value;
5534                        },
5535                    }),
5536                    metadata: None,
5537                    files: USER,
5538                }),
5539                SettingsPageItem::SettingItem(SettingItem {
5540                    title: "Path Style",
5541                    description: "Should the name or path be displayed first in the git view.",
5542                    field: Box::new(SettingField {
5543                        json_path: Some("git.path_style"),
5544                        pick: |settings_content| settings_content.git.as_ref()?.path_style.as_ref(),
5545                        write: |settings_content, value| {
5546                            settings_content.git.get_or_insert_default().path_style = value;
5547                        },
5548                    }),
5549                    metadata: None,
5550                    files: USER,
5551                }),
5552            ],
5553        },
5554        SettingsPage {
5555            title: "Collaboration",
5556            items: vec![
5557                SettingsPageItem::SectionHeader("Calls"),
5558                SettingsPageItem::SettingItem(SettingItem {
5559                    title: "Mute On Join",
5560                    description: "Whether the microphone should be muted when joining a channel or a call.",
5561                    field: Box::new(SettingField {
5562                        json_path: Some("calls.mute_on_join"),
5563                        pick: |settings_content| {
5564                            settings_content.calls.as_ref()?.mute_on_join.as_ref()
5565                        },
5566                        write: |settings_content, value| {
5567                            settings_content.calls.get_or_insert_default().mute_on_join = value;
5568                        },
5569                    }),
5570                    metadata: None,
5571                    files: USER,
5572                }),
5573                SettingsPageItem::SettingItem(SettingItem {
5574                    title: "Share On Join",
5575                    description: "Whether your current project should be shared when joining an empty channel.",
5576                    field: Box::new(SettingField {
5577                        json_path: Some("calls.share_on_join"),
5578                        pick: |settings_content| {
5579                            settings_content.calls.as_ref()?.share_on_join.as_ref()
5580                        },
5581                        write: |settings_content, value| {
5582                            settings_content.calls.get_or_insert_default().share_on_join = value;
5583                        },
5584                    }),
5585                    metadata: None,
5586                    files: USER,
5587                }),
5588                SettingsPageItem::SectionHeader("Experimental"),
5589                SettingsPageItem::SettingItem(SettingItem {
5590                    title: "Rodio Audio",
5591                    description: "Opt into the new audio system.",
5592                    field: Box::new(SettingField {
5593                        json_path: Some("audio.experimental.rodio_audio"),
5594                        pick: |settings_content| {
5595                            settings_content.audio.as_ref()?.rodio_audio.as_ref()
5596                        },
5597                        write: |settings_content, value| {
5598                            settings_content.audio.get_or_insert_default().rodio_audio = value;
5599                        },
5600                    }),
5601                    metadata: None,
5602                    files: USER,
5603                }),
5604                SettingsPageItem::SettingItem(SettingItem {
5605                    title: "Auto Microphone Volume",
5606                    description: "Automatically adjust microphone volume (requires rodio audio).",
5607                    field: Box::new(SettingField {
5608                        json_path: Some("audio.experimental.auto_microphone_volume"),
5609                        pick: |settings_content| {
5610                            settings_content
5611                                .audio
5612                                .as_ref()?
5613                                .auto_microphone_volume
5614                                .as_ref()
5615                        },
5616                        write: |settings_content, value| {
5617                            settings_content
5618                                .audio
5619                                .get_or_insert_default()
5620                                .auto_microphone_volume = value;
5621                        },
5622                    }),
5623                    metadata: None,
5624                    files: USER,
5625                }),
5626                SettingsPageItem::SettingItem(SettingItem {
5627                    title: "Auto Speaker Volume",
5628                    description: "Automatically adjust volume of other call members (requires rodio audio).",
5629                    field: Box::new(SettingField {
5630                        json_path: Some("audio.experimental.auto_speaker_volume"),
5631                        pick: |settings_content| {
5632                            settings_content
5633                                .audio
5634                                .as_ref()?
5635                                .auto_speaker_volume
5636                                .as_ref()
5637                        },
5638                        write: |settings_content, value| {
5639                            settings_content
5640                                .audio
5641                                .get_or_insert_default()
5642                                .auto_speaker_volume = value;
5643                        },
5644                    }),
5645                    metadata: None,
5646                    files: USER,
5647                }),
5648                SettingsPageItem::SettingItem(SettingItem {
5649                    title: "Denoise",
5650                    description: "Remove background noises (requires rodio audio).",
5651                    field: Box::new(SettingField {
5652                        json_path: Some("audio.experimental.denoise"),
5653                        pick: |settings_content| settings_content.audio.as_ref()?.denoise.as_ref(),
5654                        write: |settings_content, value| {
5655                            settings_content.audio.get_or_insert_default().denoise = value;
5656                        },
5657                    }),
5658                    metadata: None,
5659                    files: USER,
5660                }),
5661                SettingsPageItem::SettingItem(SettingItem {
5662                    title: "Legacy Audio Compatible",
5663                    description: "Use audio parameters compatible with previous versions (requires rodio audio).",
5664                    field: Box::new(SettingField {
5665                        json_path: Some("audio.experimental.legacy_audio_compatible"),
5666                        pick: |settings_content| {
5667                            settings_content
5668                                .audio
5669                                .as_ref()?
5670                                .legacy_audio_compatible
5671                                .as_ref()
5672                        },
5673                        write: |settings_content, value| {
5674                            settings_content
5675                                .audio
5676                                .get_or_insert_default()
5677                                .legacy_audio_compatible = value;
5678                        },
5679                    }),
5680                    metadata: None,
5681                    files: USER,
5682                }),
5683            ],
5684        },
5685        SettingsPage {
5686            title: "AI",
5687            items: {
5688                let mut items = vec![
5689                    SettingsPageItem::SectionHeader("General"),
5690                    SettingsPageItem::SettingItem(SettingItem {
5691                        title: "Disable AI",
5692                        description: "Whether to disable all AI features in Zed.",
5693                        field: Box::new(SettingField {
5694                            json_path: Some("disable_ai"),
5695                            pick: |settings_content| settings_content.disable_ai.as_ref(),
5696                            write: |settings_content, value| {
5697                                settings_content.disable_ai = value;
5698                            },
5699                        }),
5700                        metadata: None,
5701                        files: USER,
5702                    }),
5703                    SettingsPageItem::SectionHeader("Agent Configuration"),
5704                    SettingsPageItem::SettingItem(SettingItem {
5705                        title: "Always Allow Tool Actions",
5706                        description: "When enabled, the agent can run potentially destructive actions without asking for your confirmation. This setting has no effect on external agents.",
5707                        field: Box::new(SettingField {
5708                            json_path: Some("agent.always_allow_tool_actions"),
5709                            pick: |settings_content| {
5710                                settings_content
5711                                    .agent
5712                                    .as_ref()?
5713                                    .always_allow_tool_actions
5714                                    .as_ref()
5715                            },
5716                            write: |settings_content, value| {
5717                                settings_content
5718                                    .agent
5719                                    .get_or_insert_default()
5720                                    .always_allow_tool_actions = value;
5721                            },
5722                        }),
5723                        metadata: None,
5724                        files: USER,
5725                    }),
5726                    SettingsPageItem::SettingItem(SettingItem {
5727                        title: "Single File Review",
5728                        description: "When enabled, agent edits will also be displayed in single-file buffers for review.",
5729                        field: Box::new(SettingField {
5730                            json_path: Some("agent.single_file_review"),
5731                            pick: |settings_content| {
5732                                settings_content.agent.as_ref()?.single_file_review.as_ref()
5733                            },
5734                            write: |settings_content, value| {
5735                                settings_content
5736                                    .agent
5737                                    .get_or_insert_default()
5738                                    .single_file_review = value;
5739                            },
5740                        }),
5741                        metadata: None,
5742                        files: USER,
5743                    }),
5744                    SettingsPageItem::SettingItem(SettingItem {
5745                        title: "Enable Feedback",
5746                        description: "Show voting thumbs up/down icon buttons for feedback on agent edits.",
5747                        field: Box::new(SettingField {
5748                            json_path: Some("agent.enable_feedback"),
5749                            pick: |settings_content| {
5750                                settings_content.agent.as_ref()?.enable_feedback.as_ref()
5751                            },
5752                            write: |settings_content, value| {
5753                                settings_content
5754                                    .agent
5755                                    .get_or_insert_default()
5756                                    .enable_feedback = value;
5757                            },
5758                        }),
5759                        metadata: None,
5760                        files: USER,
5761                    }),
5762                    SettingsPageItem::SettingItem(SettingItem {
5763                        title: "Notify When Agent Waiting",
5764                        description: "Where to show notifications when the agent has completed its response or needs confirmation before running a tool action.",
5765                        field: Box::new(SettingField {
5766                            json_path: Some("agent.notify_when_agent_waiting"),
5767                            pick: |settings_content| {
5768                                settings_content
5769                                    .agent
5770                                    .as_ref()?
5771                                    .notify_when_agent_waiting
5772                                    .as_ref()
5773                            },
5774                            write: |settings_content, value| {
5775                                settings_content
5776                                    .agent
5777                                    .get_or_insert_default()
5778                                    .notify_when_agent_waiting = value;
5779                            },
5780                        }),
5781                        metadata: None,
5782                        files: USER,
5783                    }),
5784                    SettingsPageItem::SettingItem(SettingItem {
5785                        title: "Play Sound When Agent Done",
5786                        description: "Whether to play a sound when the agent has either completed its response, or needs user input.",
5787                        field: Box::new(SettingField {
5788                            json_path: Some("agent.play_sound_when_agent_done"),
5789                            pick: |settings_content| {
5790                                settings_content
5791                                    .agent
5792                                    .as_ref()?
5793                                    .play_sound_when_agent_done
5794                                    .as_ref()
5795                            },
5796                            write: |settings_content, value| {
5797                                settings_content
5798                                    .agent
5799                                    .get_or_insert_default()
5800                                    .play_sound_when_agent_done = value;
5801                            },
5802                        }),
5803                        metadata: None,
5804                        files: USER,
5805                    }),
5806                    SettingsPageItem::SettingItem(SettingItem {
5807                        title: "Expand Edit Card",
5808                        description: "Whether to have edit cards in the agent panel expanded, showing a Preview of the diff.",
5809                        field: Box::new(SettingField {
5810                            json_path: Some("agent.expand_edit_card"),
5811                            pick: |settings_content| {
5812                                settings_content.agent.as_ref()?.expand_edit_card.as_ref()
5813                            },
5814                            write: |settings_content, value| {
5815                                settings_content
5816                                    .agent
5817                                    .get_or_insert_default()
5818                                    .expand_edit_card = value;
5819                            },
5820                        }),
5821                        metadata: None,
5822                        files: USER,
5823                    }),
5824                    SettingsPageItem::SettingItem(SettingItem {
5825                        title: "Expand Terminal Card",
5826                        description: "Whether to have terminal cards in the agent panel expanded, showing the whole command output.",
5827                        field: Box::new(SettingField {
5828                            json_path: Some("agent.expand_terminal_card"),
5829                            pick: |settings_content| {
5830                                settings_content
5831                                    .agent
5832                                    .as_ref()?
5833                                    .expand_terminal_card
5834                                    .as_ref()
5835                            },
5836                            write: |settings_content, value| {
5837                                settings_content
5838                                    .agent
5839                                    .get_or_insert_default()
5840                                    .expand_terminal_card = value;
5841                            },
5842                        }),
5843                        metadata: None,
5844                        files: USER,
5845                    }),
5846                    SettingsPageItem::SettingItem(SettingItem {
5847                        title: "Use Modifier To Send",
5848                        description: "Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages.",
5849                        field: Box::new(SettingField {
5850                            json_path: Some("agent.use_modifier_to_send"),
5851                            pick: |settings_content| {
5852                                settings_content
5853                                    .agent
5854                                    .as_ref()?
5855                                    .use_modifier_to_send
5856                                    .as_ref()
5857                            },
5858                            write: |settings_content, value| {
5859                                settings_content
5860                                    .agent
5861                                    .get_or_insert_default()
5862                                    .use_modifier_to_send = value;
5863                            },
5864                        }),
5865                        metadata: None,
5866                        files: USER,
5867                    }),
5868                    SettingsPageItem::SettingItem(SettingItem {
5869                        title: "Message Editor Min Lines",
5870                        description: "Minimum number of lines to display in the agent message editor.",
5871                        field: Box::new(SettingField {
5872                            json_path: Some("agent.message_editor_min_lines"),
5873                            pick: |settings_content| {
5874                                settings_content
5875                                    .agent
5876                                    .as_ref()?
5877                                    .message_editor_min_lines
5878                                    .as_ref()
5879                            },
5880                            write: |settings_content, value| {
5881                                settings_content
5882                                    .agent
5883                                    .get_or_insert_default()
5884                                    .message_editor_min_lines = value;
5885                            },
5886                        }),
5887                        metadata: None,
5888                        files: USER,
5889                    }),
5890                ];
5891                items.extend(edit_prediction_language_settings_section());
5892                items.extend(
5893                    [
5894                        SettingsPageItem::SettingItem(SettingItem {
5895                            title: "Display Mode",
5896                            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.",
5897                            field: Box::new(SettingField {
5898                                json_path: Some("edit_prediction.display_mode"),
5899                                pick: |settings_content| {
5900                                    settings_content.project.all_languages.edit_predictions.as_ref()?.mode.as_ref()
5901                                },
5902                                write: |settings_content, value| {
5903                                    settings_content.project.all_languages.edit_predictions.get_or_insert_default().mode = value;
5904                                },
5905                            }),
5906                            metadata: None,
5907                            files: USER,
5908                        }),
5909                        SettingsPageItem::SettingItem(SettingItem {
5910                            title: "In Text Threads",
5911                            description: "Whether edit predictions are enabled when editing text threads in the agent panel.",
5912                            field: Box::new(SettingField {
5913                                json_path: Some("edit_prediction.in_text_threads"),
5914                                pick: |settings_content| {
5915                                    settings_content.project.all_languages.edit_predictions.as_ref()?.enabled_in_text_threads.as_ref()
5916                                },
5917                                write: |settings_content, value| {
5918                                    settings_content.project.all_languages.edit_predictions.get_or_insert_default().enabled_in_text_threads = value;
5919                                },
5920                            }),
5921                            metadata: None,
5922                            files: USER,
5923                        }),
5924                        SettingsPageItem::SettingItem(SettingItem {
5925                            title: "Copilot Provider",
5926                            description: "Use GitHub Copilot as your edit prediction provider.",
5927                            field: Box::new(
5928                                SettingField {
5929                                    json_path: Some("edit_prediction.copilot_provider"),
5930                                    pick: |settings_content| {
5931                                        settings_content.project.all_languages.edit_predictions.as_ref()?.copilot.as_ref()
5932                                    },
5933                                    write: |settings_content, value| {
5934                                        settings_content.project.all_languages.edit_predictions.get_or_insert_default().copilot = value;
5935                                    },
5936                                }
5937                                .unimplemented(),
5938                            ),
5939                            metadata: None,
5940                            files: USER | PROJECT,
5941                        }),
5942                        SettingsPageItem::SettingItem(SettingItem {
5943                            title: "Codestral Provider",
5944                            description: "Use Mistral's Codestral as your edit prediction provider.",
5945                            field: Box::new(
5946                                SettingField {
5947                                    json_path: Some("edit_prediction.codestral_provider"),
5948                                    pick: |settings_content| {
5949                                        settings_content.project.all_languages.edit_predictions.as_ref()?.codestral.as_ref()
5950                                    },
5951                                    write: |settings_content, value| {
5952                                        settings_content.project.all_languages.edit_predictions.get_or_insert_default().codestral = value;
5953                                    },
5954                                }
5955                                .unimplemented(),
5956                            ),
5957                            metadata: None,
5958                            files: USER | PROJECT,
5959                        }),
5960                    ]
5961                );
5962                items
5963            },
5964        },
5965        SettingsPage {
5966            title: "Network",
5967            items: vec![
5968                SettingsPageItem::SectionHeader("Network"),
5969                // todo(settings_ui): Proxy needs a default
5970                SettingsPageItem::SettingItem(SettingItem {
5971                    title: "Proxy",
5972                    description: "The proxy to use for network requests.",
5973                    field: Box::new(
5974                        SettingField {
5975                            json_path: Some("proxy"),
5976                            pick: |settings_content| settings_content.proxy.as_ref(),
5977                            write: |settings_content, value| {
5978                                settings_content.proxy = value;
5979                            },
5980                        }
5981                        .unimplemented(),
5982                    ),
5983                    metadata: Some(Box::new(SettingsFieldMetadata {
5984                        placeholder: Some("socks5h://localhost:10808"),
5985                        ..Default::default()
5986                    })),
5987                    files: USER,
5988                }),
5989                SettingsPageItem::SettingItem(SettingItem {
5990                    title: "Server URL",
5991                    description: "The URL of the Zed server to connect to.",
5992                    field: Box::new(SettingField {
5993                        json_path: Some("server_url"),
5994                        pick: |settings_content| settings_content.server_url.as_ref(),
5995                        write: |settings_content, value| {
5996                            settings_content.server_url = value;
5997                        },
5998                    }),
5999                    metadata: Some(Box::new(SettingsFieldMetadata {
6000                        placeholder: Some("https://zed.dev"),
6001                        ..Default::default()
6002                    })),
6003                    files: USER,
6004                }),
6005            ],
6006        },
6007    ]
6008}
6009
6010const LANGUAGES_SECTION_HEADER: &'static str = "Languages";
6011
6012fn current_language() -> Option<SharedString> {
6013    sub_page_stack().iter().find_map(|page| {
6014        (page.section_header == LANGUAGES_SECTION_HEADER).then(|| page.link.title.clone())
6015    })
6016}
6017
6018fn language_settings_field<T>(
6019    settings_content: &SettingsContent,
6020    get: fn(&LanguageSettingsContent) -> Option<&T>,
6021) -> Option<&T> {
6022    let all_languages = &settings_content.project.all_languages;
6023    if let Some(current_language_name) = current_language() {
6024        if let Some(current_language) = all_languages.languages.0.get(&current_language_name) {
6025            let value = get(current_language);
6026            if value.is_some() {
6027                return value;
6028            }
6029        }
6030    }
6031    let default_value = get(&all_languages.defaults);
6032    return default_value;
6033}
6034
6035fn language_settings_field_mut<T>(
6036    settings_content: &mut SettingsContent,
6037    value: Option<T>,
6038    write: fn(&mut LanguageSettingsContent, Option<T>),
6039) {
6040    let all_languages = &mut settings_content.project.all_languages;
6041    let language_content = if let Some(current_language) = current_language() {
6042        all_languages
6043            .languages
6044            .0
6045            .entry(current_language)
6046            .or_default()
6047    } else {
6048        &mut all_languages.defaults
6049    };
6050    write(language_content, value);
6051}
6052
6053fn language_settings_data() -> Vec<SettingsPageItem> {
6054    let mut items = vec![
6055        SettingsPageItem::SectionHeader("Indentation"),
6056        SettingsPageItem::SettingItem(SettingItem {
6057            title: "Tab Size",
6058            description: "How many columns a tab should occupy.",
6059            field: Box::new(SettingField {
6060                json_path: Some("languages.$(language).tab_size"), // TODO(cameron): not JQ syntax because not URL-safe
6061                pick: |settings_content| {
6062                    language_settings_field(settings_content, |language| language.tab_size.as_ref())
6063                },
6064                write: |settings_content, value| {
6065                    language_settings_field_mut(settings_content, value, |language, value| {
6066                        language.tab_size = value;
6067                    })
6068                },
6069            }),
6070            metadata: None,
6071            files: USER | PROJECT,
6072        }),
6073        SettingsPageItem::SettingItem(SettingItem {
6074            title: "Hard Tabs",
6075            description: "Whether to indent lines using tab characters, as opposed to multiple spaces.",
6076            field: Box::new(SettingField {
6077                json_path: Some("languages.$(language).hard_tabs"),
6078                pick: |settings_content| {
6079                    language_settings_field(settings_content, |language| {
6080                        language.hard_tabs.as_ref()
6081                    })
6082                },
6083                write: |settings_content, value| {
6084                    language_settings_field_mut(settings_content, value, |language, value| {
6085                        language.hard_tabs = value;
6086                    })
6087                },
6088            }),
6089            metadata: None,
6090            files: USER | PROJECT,
6091        }),
6092        SettingsPageItem::SettingItem(SettingItem {
6093            title: "Auto Indent",
6094            description: "Whether indentation should be adjusted based on the context whilst typing.",
6095            field: Box::new(SettingField {
6096                json_path: Some("languages.$(language).auto_indent"),
6097                pick: |settings_content| {
6098                    language_settings_field(settings_content, |language| {
6099                        language.auto_indent.as_ref()
6100                    })
6101                },
6102                write: |settings_content, value| {
6103                    language_settings_field_mut(settings_content, value, |language, value| {
6104                        language.auto_indent = value;
6105                    })
6106                },
6107            }),
6108            metadata: None,
6109            files: USER | PROJECT,
6110        }),
6111        SettingsPageItem::SettingItem(SettingItem {
6112            title: "Auto Indent On Paste",
6113            description: "Whether indentation of pasted content should be adjusted based on the context.",
6114            field: Box::new(SettingField {
6115                json_path: Some("languages.$(language).auto_indent_on_paste"),
6116                pick: |settings_content| {
6117                    language_settings_field(settings_content, |language| {
6118                        language.auto_indent_on_paste.as_ref()
6119                    })
6120                },
6121                write: |settings_content, value| {
6122                    language_settings_field_mut(settings_content, value, |language, value| {
6123                        language.auto_indent_on_paste = value;
6124                    })
6125                },
6126            }),
6127            metadata: None,
6128            files: USER | PROJECT,
6129        }),
6130        SettingsPageItem::SectionHeader("Wrapping"),
6131        SettingsPageItem::SettingItem(SettingItem {
6132            title: "Soft Wrap",
6133            description: "How to soft-wrap long lines of text.",
6134            field: Box::new(SettingField {
6135                json_path: Some("languages.$(language).soft_wrap"),
6136                pick: |settings_content| {
6137                    language_settings_field(settings_content, |language| {
6138                        language.soft_wrap.as_ref()
6139                    })
6140                },
6141                write: |settings_content, value| {
6142                    language_settings_field_mut(settings_content, value, |language, value| {
6143                        language.soft_wrap = value;
6144                    })
6145                },
6146            }),
6147            metadata: None,
6148            files: USER | PROJECT,
6149        }),
6150        SettingsPageItem::SettingItem(SettingItem {
6151            title: "Show Wrap Guides",
6152            description: "Show wrap guides in the editor.",
6153            field: Box::new(SettingField {
6154                json_path: Some("languages.$(language).show_wrap_guides"),
6155                pick: |settings_content| {
6156                    language_settings_field(settings_content, |language| {
6157                        language.show_wrap_guides.as_ref()
6158                    })
6159                },
6160                write: |settings_content, value| {
6161                    language_settings_field_mut(settings_content, value, |language, value| {
6162                        language.show_wrap_guides = value;
6163                    })
6164                },
6165            }),
6166            metadata: None,
6167            files: USER | PROJECT,
6168        }),
6169        SettingsPageItem::SettingItem(SettingItem {
6170            title: "Preferred Line Length",
6171            description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled.",
6172            field: Box::new(SettingField {
6173                json_path: Some("languages.$(language).preferred_line_length"),
6174                pick: |settings_content| {
6175                    language_settings_field(settings_content, |language| {
6176                        language.preferred_line_length.as_ref()
6177                    })
6178                },
6179                write: |settings_content, value| {
6180                    language_settings_field_mut(settings_content, value, |language, value| {
6181                        language.preferred_line_length = value;
6182                    })
6183                },
6184            }),
6185            metadata: None,
6186            files: USER | PROJECT,
6187        }),
6188        SettingsPageItem::SettingItem(SettingItem {
6189            title: "Wrap Guides",
6190            description: "Character counts at which to show wrap guides in the editor.",
6191            field: Box::new(
6192                SettingField {
6193                    json_path: Some("languages.$(language).wrap_guides"),
6194                    pick: |settings_content| {
6195                        language_settings_field(settings_content, |language| {
6196                            language.wrap_guides.as_ref()
6197                        })
6198                    },
6199                    write: |settings_content, value| {
6200                        language_settings_field_mut(settings_content, value, |language, value| {
6201                            language.wrap_guides = value;
6202                        })
6203                    },
6204                }
6205                .unimplemented(),
6206            ),
6207            metadata: None,
6208            files: USER | PROJECT,
6209        }),
6210        SettingsPageItem::SettingItem(SettingItem {
6211            title: "Allow Rewrap",
6212            description: "Controls where the `editor::rewrap` action is allowed for this language.",
6213            field: Box::new(SettingField {
6214                json_path: Some("languages.$(language).allow_rewrap"),
6215                pick: |settings_content| {
6216                    language_settings_field(settings_content, |language| {
6217                        language.allow_rewrap.as_ref()
6218                    })
6219                },
6220                write: |settings_content, value| {
6221                    language_settings_field_mut(settings_content, value, |language, value| {
6222                        language.allow_rewrap = value;
6223                    })
6224                },
6225            }),
6226            metadata: None,
6227            files: USER | PROJECT,
6228        }),
6229        SettingsPageItem::SectionHeader("Indent Guides"),
6230        SettingsPageItem::SettingItem(SettingItem {
6231            title: "Enabled",
6232            description: "Display indent guides in the editor.",
6233            field: Box::new(SettingField {
6234                json_path: Some("languages.$(language).indent_guides.enabled"),
6235                pick: |settings_content| {
6236                    language_settings_field(settings_content, |language| {
6237                        language
6238                            .indent_guides
6239                            .as_ref()
6240                            .and_then(|indent_guides| indent_guides.enabled.as_ref())
6241                    })
6242                },
6243                write: |settings_content, value| {
6244                    language_settings_field_mut(settings_content, value, |language, value| {
6245                        language.indent_guides.get_or_insert_default().enabled = value;
6246                    })
6247                },
6248            }),
6249            metadata: None,
6250            files: USER | PROJECT,
6251        }),
6252        SettingsPageItem::SettingItem(SettingItem {
6253            title: "Line Width",
6254            description: "The width of the indent guides in pixels, between 1 and 10.",
6255            field: Box::new(SettingField {
6256                json_path: Some("languages.$(language).indent_guides.line_width"),
6257                pick: |settings_content| {
6258                    language_settings_field(settings_content, |language| {
6259                        language
6260                            .indent_guides
6261                            .as_ref()
6262                            .and_then(|indent_guides| indent_guides.line_width.as_ref())
6263                    })
6264                },
6265                write: |settings_content, value| {
6266                    language_settings_field_mut(settings_content, value, |language, value| {
6267                        language.indent_guides.get_or_insert_default().line_width = value;
6268                    })
6269                },
6270            }),
6271            metadata: None,
6272            files: USER | PROJECT,
6273        }),
6274        SettingsPageItem::SettingItem(SettingItem {
6275            title: "Active Line Width",
6276            description: "The width of the active indent guide in pixels, between 1 and 10.",
6277            field: Box::new(SettingField {
6278                json_path: Some("languages.$(language).indent_guides.active_line_width"),
6279                pick: |settings_content| {
6280                    language_settings_field(settings_content, |language| {
6281                        language
6282                            .indent_guides
6283                            .as_ref()
6284                            .and_then(|indent_guides| indent_guides.active_line_width.as_ref())
6285                    })
6286                },
6287                write: |settings_content, value| {
6288                    language_settings_field_mut(settings_content, value, |language, value| {
6289                        language
6290                            .indent_guides
6291                            .get_or_insert_default()
6292                            .active_line_width = value;
6293                    })
6294                },
6295            }),
6296            metadata: None,
6297            files: USER | PROJECT,
6298        }),
6299        SettingsPageItem::SettingItem(SettingItem {
6300            title: "Coloring",
6301            description: "Determines how indent guides are colored.",
6302            field: Box::new(SettingField {
6303                json_path: Some("languages.$(language).indent_guides.coloring"),
6304                pick: |settings_content| {
6305                    language_settings_field(settings_content, |language| {
6306                        language
6307                            .indent_guides
6308                            .as_ref()
6309                            .and_then(|indent_guides| indent_guides.coloring.as_ref())
6310                    })
6311                },
6312                write: |settings_content, value| {
6313                    language_settings_field_mut(settings_content, value, |language, value| {
6314                        language.indent_guides.get_or_insert_default().coloring = value;
6315                    })
6316                },
6317            }),
6318            metadata: None,
6319            files: USER | PROJECT,
6320        }),
6321        SettingsPageItem::SettingItem(SettingItem {
6322            title: "Background Coloring",
6323            description: "Determines how indent guide backgrounds are colored.",
6324            field: Box::new(SettingField {
6325                json_path: Some("languages.$(language).indent_guides.background_coloring"),
6326                pick: |settings_content| {
6327                    language_settings_field(settings_content, |language| {
6328                        language
6329                            .indent_guides
6330                            .as_ref()
6331                            .and_then(|indent_guides| indent_guides.background_coloring.as_ref())
6332                    })
6333                },
6334                write: |settings_content, value| {
6335                    language_settings_field_mut(settings_content, value, |language, value| {
6336                        language
6337                            .indent_guides
6338                            .get_or_insert_default()
6339                            .background_coloring = value;
6340                    })
6341                },
6342            }),
6343            metadata: None,
6344            files: USER | PROJECT,
6345        }),
6346        SettingsPageItem::SectionHeader("Formatting"),
6347        SettingsPageItem::SettingItem(SettingItem {
6348            title: "Format On Save",
6349            description: "Whether or not to perform a buffer format before saving.",
6350            field: Box::new(
6351                // TODO(settings_ui): this setting should just be a bool
6352                SettingField {
6353                    json_path: Some("languages.$(language).format_on_save"),
6354                    pick: |settings_content| {
6355                        language_settings_field(settings_content, |language| {
6356                            language.format_on_save.as_ref()
6357                        })
6358                    },
6359                    write: |settings_content, value| {
6360                        language_settings_field_mut(settings_content, value, |language, value| {
6361                            language.format_on_save = value;
6362                        })
6363                    },
6364                },
6365            ),
6366            metadata: None,
6367            files: USER | PROJECT,
6368        }),
6369        SettingsPageItem::SettingItem(SettingItem {
6370            title: "Remove Trailing Whitespace On Save",
6371            description: "Whether or not to remove any trailing whitespace from lines of a buffer before saving it.",
6372            field: Box::new(SettingField {
6373                json_path: Some("languages.$(language).remove_trailing_whitespace_on_save"),
6374                pick: |settings_content| {
6375                    language_settings_field(settings_content, |language| {
6376                        language.remove_trailing_whitespace_on_save.as_ref()
6377                    })
6378                },
6379                write: |settings_content, value| {
6380                    language_settings_field_mut(settings_content, value, |language, value| {
6381                        language.remove_trailing_whitespace_on_save = value;
6382                    })
6383                },
6384            }),
6385            metadata: None,
6386            files: USER | PROJECT,
6387        }),
6388        SettingsPageItem::SettingItem(SettingItem {
6389            title: "Ensure Final Newline On Save",
6390            description: "Whether or not to ensure there's a single newline at the end of a buffer when saving it.",
6391            field: Box::new(SettingField {
6392                json_path: Some("languages.$(language).ensure_final_newline_on_save"),
6393                pick: |settings_content| {
6394                    language_settings_field(settings_content, |language| {
6395                        language.ensure_final_newline_on_save.as_ref()
6396                    })
6397                },
6398                write: |settings_content, value| {
6399                    language_settings_field_mut(settings_content, value, |language, value| {
6400                        language.ensure_final_newline_on_save = value;
6401                    })
6402                },
6403            }),
6404            metadata: None,
6405            files: USER | PROJECT,
6406        }),
6407        SettingsPageItem::SettingItem(SettingItem {
6408            title: "Formatter",
6409            description: "How to perform a buffer format.",
6410            field: Box::new(
6411                SettingField {
6412                    json_path: Some("languages.$(language).formatter"),
6413                    pick: |settings_content| {
6414                        language_settings_field(settings_content, |language| {
6415                            language.formatter.as_ref()
6416                        })
6417                    },
6418                    write: |settings_content, value| {
6419                        language_settings_field_mut(settings_content, value, |language, value| {
6420                            language.formatter = value;
6421                        })
6422                    },
6423                }
6424                .unimplemented(),
6425            ),
6426            metadata: None,
6427            files: USER | PROJECT,
6428        }),
6429        SettingsPageItem::SettingItem(SettingItem {
6430            title: "Use On Type Format",
6431            description: "Whether to use additional LSP queries to format (and amend) the code after every \"trigger\" symbol input, defined by LSP server capabilities",
6432            field: Box::new(SettingField {
6433                json_path: Some("languages.$(language).use_on_type_format"),
6434                pick: |settings_content| {
6435                    language_settings_field(settings_content, |language| {
6436                        language.use_on_type_format.as_ref()
6437                    })
6438                },
6439                write: |settings_content, value| {
6440                    language_settings_field_mut(settings_content, value, |language, value| {
6441                        language.use_on_type_format = value;
6442                    })
6443                },
6444            }),
6445            metadata: None,
6446            files: USER | PROJECT,
6447        }),
6448        SettingsPageItem::SettingItem(SettingItem {
6449            title: "Code Actions On Format",
6450            description: "Additional code actions to run when formatting.",
6451            field: Box::new(
6452                SettingField {
6453                    json_path: Some("languages.$(language).code_actions_on_format"),
6454                    pick: |settings_content| {
6455                        language_settings_field(settings_content, |language| {
6456                            language.code_actions_on_format.as_ref()
6457                        })
6458                    },
6459                    write: |settings_content, value| {
6460                        language_settings_field_mut(settings_content, value, |language, value| {
6461                            language.code_actions_on_format = value;
6462                        })
6463                    },
6464                }
6465                .unimplemented(),
6466            ),
6467            metadata: None,
6468            files: USER | PROJECT,
6469        }),
6470        SettingsPageItem::SectionHeader("Autoclose"),
6471        SettingsPageItem::SettingItem(SettingItem {
6472            title: "Use Autoclose",
6473            description: "Whether to automatically type closing characters for you. For example, when you type '(', Zed will automatically add a closing ')' at the correct position.",
6474            field: Box::new(SettingField {
6475                json_path: Some("languages.$(language).use_autoclose"),
6476                pick: |settings_content| {
6477                    language_settings_field(settings_content, |language| {
6478                        language.use_autoclose.as_ref()
6479                    })
6480                },
6481                write: |settings_content, value| {
6482                    language_settings_field_mut(settings_content, value, |language, value| {
6483                        language.use_autoclose = value;
6484                    })
6485                },
6486            }),
6487            metadata: None,
6488            files: USER | PROJECT,
6489        }),
6490        SettingsPageItem::SettingItem(SettingItem {
6491            title: "Use Auto Surround",
6492            description: "Whether to automatically surround text with characters for you. For example, when you select text and type '(', Zed will automatically surround text with ().",
6493            field: Box::new(SettingField {
6494                json_path: Some("languages.$(language).use_auto_surround"),
6495                pick: |settings_content| {
6496                    language_settings_field(settings_content, |language| {
6497                        language.use_auto_surround.as_ref()
6498                    })
6499                },
6500                write: |settings_content, value| {
6501                    language_settings_field_mut(settings_content, value, |language, value| {
6502                        language.use_auto_surround = value;
6503                    })
6504                },
6505            }),
6506            metadata: None,
6507            files: USER | PROJECT,
6508        }),
6509        SettingsPageItem::SettingItem(SettingItem {
6510            title: "Always Treat Brackets As Autoclosed",
6511            description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted.",
6512            field: Box::new(SettingField {
6513                json_path: Some("languages.$(language).always_treat_brackets_as_autoclosed"),
6514                pick: |settings_content| {
6515                    language_settings_field(settings_content, |language| {
6516                        language.always_treat_brackets_as_autoclosed.as_ref()
6517                    })
6518                },
6519                write: |settings_content, value| {
6520                    language_settings_field_mut(settings_content, value, |language, value| {
6521                        language.always_treat_brackets_as_autoclosed = value;
6522                    })
6523                },
6524            }),
6525            metadata: None,
6526            files: USER | PROJECT,
6527        }),
6528        SettingsPageItem::SettingItem(SettingItem {
6529            title: "Jsx Tag Auto Close",
6530            description: "Whether to automatically close JSX tags.",
6531            field: Box::new(SettingField {
6532                json_path: Some("languages.$(language).jsx_tag_auto_close"),
6533                // TODO(settings_ui): this setting should just be a bool
6534                pick: |settings_content| {
6535                    language_settings_field(settings_content, |language| {
6536                        language.jsx_tag_auto_close.as_ref()?.enabled.as_ref()
6537                    })
6538                },
6539                write: |settings_content, value| {
6540                    language_settings_field_mut(settings_content, value, |language, value| {
6541                        language.jsx_tag_auto_close.get_or_insert_default().enabled = value;
6542                    })
6543                },
6544            }),
6545            metadata: None,
6546            files: USER | PROJECT,
6547        }),
6548        SettingsPageItem::SectionHeader("Whitespace"),
6549        SettingsPageItem::SettingItem(SettingItem {
6550            title: "Show Whitespaces",
6551            description: "Whether to show tabs and spaces in the editor.",
6552            field: Box::new(SettingField {
6553                json_path: Some("languages.$(language).show_whitespaces"),
6554                pick: |settings_content| {
6555                    language_settings_field(settings_content, |language| {
6556                        language.show_whitespaces.as_ref()
6557                    })
6558                },
6559                write: |settings_content, value| {
6560                    language_settings_field_mut(settings_content, value, |language, value| {
6561                        language.show_whitespaces = value;
6562                    })
6563                },
6564            }),
6565            metadata: None,
6566            files: USER | PROJECT,
6567        }),
6568        SettingsPageItem::SettingItem(SettingItem {
6569            title: "Space Whitespace Indicator",
6570            description: "Visible character used to render space characters when show_whitespaces is enabled (default: \"\")",
6571            field: Box::new(
6572                SettingField {
6573                    json_path: Some("languages.$(language).whitespace_map.space"),
6574                    pick: |settings_content| {
6575                        language_settings_field(settings_content, |language| {
6576                            language.whitespace_map.as_ref()?.space.as_ref()
6577                        })
6578                    },
6579                    write: |settings_content, value| {
6580                        language_settings_field_mut(settings_content, value, |language, value| {
6581                            language.whitespace_map.get_or_insert_default().space = value;
6582                        })
6583                    },
6584                }
6585                .unimplemented(),
6586            ),
6587            metadata: None,
6588            files: USER | PROJECT,
6589        }),
6590        SettingsPageItem::SettingItem(SettingItem {
6591            title: "Tab Whitespace Indicator",
6592            description: "Visible character used to render tab characters when show_whitespaces is enabled (default: \"\")",
6593            field: Box::new(
6594                SettingField {
6595                    json_path: Some("languages.$(language).whitespace_map.tab"),
6596                    pick: |settings_content| {
6597                        language_settings_field(settings_content, |language| {
6598                            language.whitespace_map.as_ref()?.tab.as_ref()
6599                        })
6600                    },
6601                    write: |settings_content, value| {
6602                        language_settings_field_mut(settings_content, value, |language, value| {
6603                            language.whitespace_map.get_or_insert_default().tab = value;
6604                        })
6605                    },
6606                }
6607                .unimplemented(),
6608            ),
6609            metadata: None,
6610            files: USER | PROJECT,
6611        }),
6612        SettingsPageItem::SectionHeader("Completions"),
6613        SettingsPageItem::SettingItem(SettingItem {
6614            title: "Show Completions On Input",
6615            description: "Whether to pop the completions menu while typing in an editor without explicitly requesting it.",
6616            field: Box::new(SettingField {
6617                json_path: Some("languages.$(language).show_completions_on_input"),
6618                pick: |settings_content| {
6619                    language_settings_field(settings_content, |language| {
6620                        language.show_completions_on_input.as_ref()
6621                    })
6622                },
6623                write: |settings_content, value| {
6624                    language_settings_field_mut(settings_content, value, |language, value| {
6625                        language.show_completions_on_input = value;
6626                    })
6627                },
6628            }),
6629            metadata: None,
6630            files: USER | PROJECT,
6631        }),
6632        SettingsPageItem::SettingItem(SettingItem {
6633            title: "Show Completion Documentation",
6634            description: "Whether to display inline and alongside documentation for items in the completions menu.",
6635            field: Box::new(SettingField {
6636                json_path: Some("languages.$(language).show_completion_documentation"),
6637                pick: |settings_content| {
6638                    language_settings_field(settings_content, |language| {
6639                        language.show_completion_documentation.as_ref()
6640                    })
6641                },
6642                write: |settings_content, value| {
6643                    language_settings_field_mut(settings_content, value, |language, value| {
6644                        language.show_completion_documentation = value;
6645                    })
6646                },
6647            }),
6648            metadata: None,
6649            files: USER | PROJECT,
6650        }),
6651        SettingsPageItem::SettingItem(SettingItem {
6652            title: "Words",
6653            description: "Controls how words are completed.",
6654            field: Box::new(SettingField {
6655                json_path: Some("languages.$(language).completions.words"),
6656                pick: |settings_content| {
6657                    language_settings_field(settings_content, |language| {
6658                        language.completions.as_ref()?.words.as_ref()
6659                    })
6660                },
6661                write: |settings_content, value| {
6662                    language_settings_field_mut(settings_content, value, |language, value| {
6663                        language.completions.get_or_insert_default().words = value;
6664                    })
6665                },
6666            }),
6667            metadata: None,
6668            files: USER | PROJECT,
6669        }),
6670        SettingsPageItem::SettingItem(SettingItem {
6671            title: "Words Min Length",
6672            description: "How many characters has to be in the completions query to automatically show the words-based completions.",
6673            field: Box::new(SettingField {
6674                json_path: Some("languages.$(language).completions.words_min_length"),
6675                pick: |settings_content| {
6676                    language_settings_field(settings_content, |language| {
6677                        language.completions.as_ref()?.words_min_length.as_ref()
6678                    })
6679                },
6680                write: |settings_content, value| {
6681                    language_settings_field_mut(settings_content, value, |language, value| {
6682                        language
6683                            .completions
6684                            .get_or_insert_default()
6685                            .words_min_length = value;
6686                    })
6687                },
6688            }),
6689            metadata: None,
6690            files: USER | PROJECT,
6691        }),
6692        SettingsPageItem::SettingItem(SettingItem {
6693            title: "Completion Menu Scrollbar",
6694            description: "When to show the scrollbar in the completion menu.",
6695            field: Box::new(SettingField {
6696                json_path: Some("editor.completion_menu_scrollbar"),
6697                pick: |settings_content| settings_content.editor.completion_menu_scrollbar.as_ref(),
6698                write: |settings_content, value| {
6699                    settings_content.editor.completion_menu_scrollbar = value;
6700                },
6701            }),
6702            metadata: None,
6703            files: USER,
6704        }),
6705        SettingsPageItem::SectionHeader("Inlay Hints"),
6706        SettingsPageItem::SettingItem(SettingItem {
6707            title: "Enabled",
6708            description: "Global switch to toggle hints on and off.",
6709            field: Box::new(SettingField {
6710                json_path: Some("languages.$(language).inlay_hints.enabled"),
6711                pick: |settings_content| {
6712                    language_settings_field(settings_content, |language| {
6713                        language.inlay_hints.as_ref()?.enabled.as_ref()
6714                    })
6715                },
6716                write: |settings_content, value| {
6717                    language_settings_field_mut(settings_content, value, |language, value| {
6718                        language.inlay_hints.get_or_insert_default().enabled = value;
6719                    })
6720                },
6721            }),
6722            metadata: None,
6723            files: USER | PROJECT,
6724        }),
6725        SettingsPageItem::SettingItem(SettingItem {
6726            title: "Show Value Hints",
6727            description: "Global switch to toggle inline values on and off when debugging.",
6728            field: Box::new(SettingField {
6729                json_path: Some("languages.$(language).inlay_hints.show_value_hints"),
6730                pick: |settings_content| {
6731                    language_settings_field(settings_content, |language| {
6732                        language.inlay_hints.as_ref()?.show_value_hints.as_ref()
6733                    })
6734                },
6735                write: |settings_content, value| {
6736                    language_settings_field_mut(settings_content, value, |language, value| {
6737                        language
6738                            .inlay_hints
6739                            .get_or_insert_default()
6740                            .show_value_hints = value;
6741                    })
6742                },
6743            }),
6744            metadata: None,
6745            files: USER | PROJECT,
6746        }),
6747        SettingsPageItem::SettingItem(SettingItem {
6748            title: "Show Type Hints",
6749            description: "Whether type hints should be shown.",
6750            field: Box::new(SettingField {
6751                json_path: Some("languages.$(language).inlay_hints.show_type_hints"),
6752                pick: |settings_content| {
6753                    language_settings_field(settings_content, |language| {
6754                        language.inlay_hints.as_ref()?.show_type_hints.as_ref()
6755                    })
6756                },
6757                write: |settings_content, value| {
6758                    language_settings_field_mut(settings_content, value, |language, value| {
6759                        language.inlay_hints.get_or_insert_default().show_type_hints = value;
6760                    })
6761                },
6762            }),
6763            metadata: None,
6764            files: USER | PROJECT,
6765        }),
6766        SettingsPageItem::SettingItem(SettingItem {
6767            title: "Show Parameter Hints",
6768            description: "Whether parameter hints should be shown.",
6769            field: Box::new(SettingField {
6770                json_path: Some("languages.$(language).inlay_hints.show_parameter_hints"),
6771                pick: |settings_content| {
6772                    language_settings_field(settings_content, |language| {
6773                        language.inlay_hints.as_ref()?.show_parameter_hints.as_ref()
6774                    })
6775                },
6776                write: |settings_content, value| {
6777                    language_settings_field_mut(settings_content, value, |language, value| {
6778                        language
6779                            .inlay_hints
6780                            .get_or_insert_default()
6781                            .show_parameter_hints = value;
6782                    })
6783                },
6784            }),
6785            metadata: None,
6786            files: USER | PROJECT,
6787        }),
6788        SettingsPageItem::SettingItem(SettingItem {
6789            title: "Show Other Hints",
6790            description: "Whether other hints should be shown.",
6791            field: Box::new(SettingField {
6792                json_path: Some("languages.$(language).inlay_hints.show_other_hints"),
6793                pick: |settings_content| {
6794                    language_settings_field(settings_content, |language| {
6795                        language.inlay_hints.as_ref()?.show_other_hints.as_ref()
6796                    })
6797                },
6798                write: |settings_content, value| {
6799                    language_settings_field_mut(settings_content, value, |language, value| {
6800                        language
6801                            .inlay_hints
6802                            .get_or_insert_default()
6803                            .show_other_hints = value;
6804                    })
6805                },
6806            }),
6807            metadata: None,
6808            files: USER | PROJECT,
6809        }),
6810        SettingsPageItem::SettingItem(SettingItem {
6811            title: "Show Background",
6812            description: "Show a background for inlay hints.",
6813            field: Box::new(SettingField {
6814                json_path: Some("languages.$(language).inlay_hints.show_background"),
6815                pick: |settings_content| {
6816                    language_settings_field(settings_content, |language| {
6817                        language.inlay_hints.as_ref()?.show_background.as_ref()
6818                    })
6819                },
6820                write: |settings_content, value| {
6821                    language_settings_field_mut(settings_content, value, |language, value| {
6822                        language.inlay_hints.get_or_insert_default().show_background = value;
6823                    })
6824                },
6825            }),
6826            metadata: None,
6827            files: USER | PROJECT,
6828        }),
6829        SettingsPageItem::SettingItem(SettingItem {
6830            title: "Edit Debounce Ms",
6831            description: "Whether or not to debounce inlay hints updates after buffer edits (set to 0 to disable debouncing).",
6832            field: Box::new(SettingField {
6833                json_path: Some("languages.$(language).inlay_hints.edit_debounce_ms"),
6834                pick: |settings_content| {
6835                    language_settings_field(settings_content, |language| {
6836                        language.inlay_hints.as_ref()?.edit_debounce_ms.as_ref()
6837                    })
6838                },
6839                write: |settings_content, value| {
6840                    language_settings_field_mut(settings_content, value, |language, value| {
6841                        language
6842                            .inlay_hints
6843                            .get_or_insert_default()
6844                            .edit_debounce_ms = value;
6845                    })
6846                },
6847            }),
6848            metadata: None,
6849            files: USER | PROJECT,
6850        }),
6851        SettingsPageItem::SettingItem(SettingItem {
6852            title: "Scroll Debounce Ms",
6853            description: "Whether or not to debounce inlay hints updates after buffer scrolls (set to 0 to disable debouncing).",
6854            field: Box::new(SettingField {
6855                json_path: Some("languages.$(language).inlay_hints.scroll_debounce_ms"),
6856                pick: |settings_content| {
6857                    language_settings_field(settings_content, |language| {
6858                        language.inlay_hints.as_ref()?.scroll_debounce_ms.as_ref()
6859                    })
6860                },
6861                write: |settings_content, value| {
6862                    language_settings_field_mut(settings_content, value, |language, value| {
6863                        language
6864                            .inlay_hints
6865                            .get_or_insert_default()
6866                            .scroll_debounce_ms = value;
6867                    })
6868                },
6869            }),
6870            metadata: None,
6871            files: USER | PROJECT,
6872        }),
6873        SettingsPageItem::SettingItem(SettingItem {
6874            title: "Toggle On Modifiers Press",
6875            description: "Toggles inlay hints (hides or shows) when the user presses the modifiers specified.",
6876            field: Box::new(
6877                SettingField {
6878                    json_path: Some("languages.$(language).inlay_hints.toggle_on_modifiers_press"),
6879                    pick: |settings_content| {
6880                        language_settings_field(settings_content, |language| {
6881                            language
6882                                .inlay_hints
6883                                .as_ref()?
6884                                .toggle_on_modifiers_press
6885                                .as_ref()
6886                        })
6887                    },
6888                    write: |settings_content, value| {
6889                        language_settings_field_mut(settings_content, value, |language, value| {
6890                            language
6891                                .inlay_hints
6892                                .get_or_insert_default()
6893                                .toggle_on_modifiers_press = value;
6894                        })
6895                    },
6896                }
6897                .unimplemented(),
6898            ),
6899            metadata: None,
6900            files: USER | PROJECT,
6901        }),
6902    ];
6903    if current_language().is_none() {
6904        items.push(SettingsPageItem::SettingItem(SettingItem {
6905            title: "LSP Document Colors",
6906            description: "How to render LSP color previews in the editor.",
6907            field: Box::new(SettingField {
6908                json_path: Some("lsp_document_colors"),
6909                pick: |settings_content| settings_content.editor.lsp_document_colors.as_ref(),
6910                write: |settings_content, value| {
6911                    settings_content.editor.lsp_document_colors = value;
6912                },
6913            }),
6914            metadata: None,
6915            files: USER,
6916        }))
6917    }
6918    items.extend([
6919        SettingsPageItem::SectionHeader("Tasks"),
6920        SettingsPageItem::SettingItem(SettingItem {
6921            title: "Enabled",
6922            description: "Whether tasks are enabled for this language.",
6923            field: Box::new(SettingField {
6924                json_path: Some("languages.$(language).tasks.enabled"),
6925                pick: |settings_content| {
6926                    language_settings_field(settings_content, |language| {
6927                        language.tasks.as_ref()?.enabled.as_ref()
6928                    })
6929                },
6930                write: |settings_content, value| {
6931                    language_settings_field_mut(settings_content, value, |language, value| {
6932                        language.tasks.get_or_insert_default().enabled = value;
6933
6934                    })
6935                },
6936            }),
6937            metadata: None,
6938            files: USER | PROJECT,
6939        }),
6940        SettingsPageItem::SettingItem(SettingItem {
6941            title: "Variables",
6942            description: "Extra task variables to set for a particular language.",
6943            field: Box::new(
6944                SettingField {
6945                    json_path: Some("languages.$(language).tasks.variables"),
6946                    pick: |settings_content| {
6947                        language_settings_field(settings_content, |language| {
6948                            language.tasks.as_ref()?.variables.as_ref()
6949                        })
6950                    },
6951                    write: |settings_content, value| {
6952                        language_settings_field_mut(settings_content, value, |language, value| {
6953                            language.tasks.get_or_insert_default().variables = value;
6954
6955                        })
6956                    },
6957                }
6958                .unimplemented(),
6959            ),
6960            metadata: None,
6961            files: USER | PROJECT,
6962        }),
6963        SettingsPageItem::SettingItem(SettingItem {
6964            title: "Prefer LSP",
6965            description: "Use LSP tasks over Zed language extension tasks.",
6966            field: Box::new(SettingField {
6967                json_path: Some("languages.$(language).tasks.prefer_lsp"),
6968                pick: |settings_content| {
6969                    language_settings_field(settings_content, |language| {
6970                        language.tasks.as_ref()?.prefer_lsp.as_ref()
6971                    })
6972                },
6973                write: |settings_content, value| {
6974                    language_settings_field_mut(settings_content, value, |language, value| {
6975                        language.tasks.get_or_insert_default().prefer_lsp = value;
6976
6977                    })
6978                },
6979            }),
6980            metadata: None,
6981            files: USER | PROJECT,
6982        }),
6983        SettingsPageItem::SectionHeader("Miscellaneous"),
6984        SettingsPageItem::SettingItem(SettingItem {
6985            title: "Debuggers",
6986            description: "Preferred debuggers for this language.",
6987            field: Box::new(
6988                SettingField {
6989                    json_path: Some("languages.$(language).debuggers"),
6990                    pick: |settings_content| {
6991                        language_settings_field(settings_content, |language| language.debuggers.as_ref())
6992                    },
6993                    write: |settings_content, value| {
6994                        language_settings_field_mut(settings_content, value, |language, value| {
6995                            language.debuggers = value;
6996
6997                        })
6998                    },
6999                }
7000                .unimplemented(),
7001            ),
7002            metadata: None,
7003            files: USER | PROJECT,
7004        }),
7005        SettingsPageItem::SettingItem(SettingItem {
7006            title: "Middle Click Paste",
7007            description: "Enable middle-click paste on Linux.",
7008            field: Box::new(SettingField {
7009                json_path: Some("languages.$(language).editor.middle_click_paste"),
7010                pick: |settings_content| settings_content.editor.middle_click_paste.as_ref(),
7011                write: |settings_content, value| {settings_content.editor.middle_click_paste = value;},
7012            }),
7013            metadata: None,
7014            files: USER,
7015        }),
7016        SettingsPageItem::SettingItem(SettingItem {
7017            title: "Extend Comment On Newline",
7018            description: "Whether to start a new line with a comment when a previous line is a comment as well.",
7019            field: Box::new(SettingField {
7020                json_path: Some("languages.$(language).extend_comment_on_newline"),
7021                pick: |settings_content| {
7022                    language_settings_field(settings_content, |language| {
7023                        language.extend_comment_on_newline.as_ref()
7024                    })
7025                },
7026                write: |settings_content, value| {
7027                    language_settings_field_mut(settings_content, value, |language, value| {
7028                        language.extend_comment_on_newline = value;
7029
7030                    })
7031                },
7032            }),
7033            metadata: None,
7034            files: USER | PROJECT,
7035        }),
7036        SettingsPageItem::SettingItem(SettingItem {
7037            title: "Colorize brackets",
7038            description: "Whether to colorize brackets in the editor.",
7039            field: Box::new(SettingField {
7040                json_path: Some("languages.$(language).colorize_brackets"),
7041                pick: |settings_content| {
7042                    language_settings_field(settings_content, |language| {
7043                        language.colorize_brackets.as_ref()
7044                    })
7045                },
7046                write: |settings_content, value| {
7047                    language_settings_field_mut(settings_content, value, |language, value| {
7048                        language.colorize_brackets = value;
7049                    })
7050                },
7051            }),
7052            metadata: None,
7053            files: USER | PROJECT,
7054        }),
7055    ]);
7056
7057    if current_language().is_none() {
7058        items.extend([
7059            SettingsPageItem::SettingItem(SettingItem {
7060                title: "Image Viewer",
7061                description: "The unit for image file sizes.",
7062                field: Box::new(SettingField {
7063                    json_path: Some("image_viewer.unit"),
7064                    pick: |settings_content| {
7065                        settings_content.image_viewer.as_ref().and_then(|image_viewer| image_viewer.unit.as_ref())
7066                    },
7067                    write: |settings_content, value| {
7068                        settings_content.image_viewer.get_or_insert_default().unit = value;
7069
7070                    },
7071                }),
7072                metadata: None,
7073                files: USER,
7074            }),
7075            SettingsPageItem::SettingItem(SettingItem {
7076                title: "Auto Replace Emoji Shortcode",
7077                description: "Whether to automatically replace emoji shortcodes with emoji characters.",
7078                field: Box::new(SettingField {
7079                    json_path: Some("message_editor.auto_replace_emoji_shortcode"),
7080                    pick: |settings_content| {
7081                        settings_content.message_editor.as_ref().and_then(|message_editor| message_editor.auto_replace_emoji_shortcode.as_ref())
7082                    },
7083                    write: |settings_content, value| {
7084                        settings_content.message_editor.get_or_insert_default().auto_replace_emoji_shortcode = value;
7085
7086                    },
7087                }),
7088                metadata: None,
7089                files: USER,
7090            }),
7091            SettingsPageItem::SettingItem(SettingItem {
7092                title: "Drop Size Target",
7093                description: "Relative size of the drop target in the editor that will open dropped file as a split pane.",
7094                field: Box::new(SettingField {
7095                    json_path: Some("drop_target_size"),
7096                    pick: |settings_content| {
7097                        settings_content.workspace.drop_target_size.as_ref()
7098                    },
7099                    write: |settings_content, value| {
7100                        settings_content.workspace.drop_target_size = value;
7101
7102                    },
7103                }),
7104                metadata: None,
7105                files: USER,
7106            }),
7107        ]);
7108    }
7109    items
7110}
7111
7112/// LanguageSettings items that should be included in the "Languages & Tools" page
7113/// not the "Editor" page
7114fn non_editor_language_settings_data() -> Vec<SettingsPageItem> {
7115    vec![
7116        SettingsPageItem::SectionHeader("LSP"),
7117        SettingsPageItem::SettingItem(SettingItem {
7118            title: "Enable Language Server",
7119            description: "Whether to use language servers to provide code intelligence.",
7120            field: Box::new(SettingField {
7121                json_path: Some("languages.$(language).enable_language_server"),
7122                pick: |settings_content| {
7123                    language_settings_field(settings_content, |language| {
7124                        language.enable_language_server.as_ref()
7125                    })
7126                },
7127                write: |settings_content, value| {
7128                    language_settings_field_mut(settings_content, value, |language, value| {
7129                        language.enable_language_server = value;
7130                    })
7131                },
7132            }),
7133            metadata: None,
7134            files: USER | PROJECT,
7135        }),
7136        SettingsPageItem::SettingItem(SettingItem {
7137            title: "Language Servers",
7138            description: "The list of language servers to use (or disable) for this language.",
7139            field: Box::new(
7140                SettingField {
7141                    json_path: Some("languages.$(language).language_servers"),
7142                    pick: |settings_content| {
7143                        language_settings_field(settings_content, |language| {
7144                            language.language_servers.as_ref()
7145                        })
7146                    },
7147                    write: |settings_content, value| {
7148                        language_settings_field_mut(settings_content, value, |language, value| {
7149                            language.language_servers = value;
7150                        })
7151                    },
7152                }
7153                .unimplemented(),
7154            ),
7155            metadata: None,
7156            files: USER | PROJECT,
7157        }),
7158        SettingsPageItem::SettingItem(SettingItem {
7159            title: "Linked Edits",
7160            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.",
7161            field: Box::new(SettingField {
7162                json_path: Some("languages.$(language).linked_edits"),
7163                pick: |settings_content| {
7164                    language_settings_field(settings_content, |language| {
7165                        language.linked_edits.as_ref()
7166                    })
7167                },
7168                write: |settings_content, value| {
7169                    language_settings_field_mut(settings_content, value, |language, value| {
7170                        language.linked_edits = value;
7171                    })
7172                },
7173            }),
7174            metadata: None,
7175            files: USER | PROJECT,
7176        }),
7177        SettingsPageItem::SettingItem(SettingItem {
7178            title: "Go To Definition Fallback",
7179            description: "Whether to follow-up empty Go to definition responses from the language server.",
7180            field: Box::new(SettingField {
7181                json_path: Some("go_to_definition_fallback"),
7182                pick: |settings_content| settings_content.editor.go_to_definition_fallback.as_ref(),
7183                write: |settings_content, value| {
7184                    settings_content.editor.go_to_definition_fallback = value;
7185                },
7186            }),
7187            metadata: None,
7188            files: USER,
7189        }),
7190        SettingsPageItem::SectionHeader("LSP Completions"),
7191        SettingsPageItem::SettingItem(SettingItem {
7192            title: "Enabled",
7193            description: "Whether to fetch LSP completions or not.",
7194            field: Box::new(SettingField {
7195                json_path: Some("languages.$(language).completions.lsp"),
7196                pick: |settings_content| {
7197                    language_settings_field(settings_content, |language| {
7198                        language.completions.as_ref()?.lsp.as_ref()
7199                    })
7200                },
7201                write: |settings_content, value| {
7202                    language_settings_field_mut(settings_content, value, |language, value| {
7203                        language.completions.get_or_insert_default().lsp = value;
7204                    })
7205                },
7206            }),
7207            metadata: None,
7208            files: USER | PROJECT,
7209        }),
7210        SettingsPageItem::SettingItem(SettingItem {
7211            title: "Fetch Timeout (milliseconds)",
7212            description: "When fetching LSP completions, determines how long to wait for a response of a particular server (set to 0 to wait indefinitely).",
7213            field: Box::new(SettingField {
7214                json_path: Some("languages.$(language).completions.lsp_fetch_timeout_ms"),
7215                pick: |settings_content| {
7216                    language_settings_field(settings_content, |language| {
7217                        language.completions.as_ref()?.lsp_fetch_timeout_ms.as_ref()
7218                    })
7219                },
7220                write: |settings_content, value| {
7221                    language_settings_field_mut(settings_content, value, |language, value| {
7222                        language
7223                            .completions
7224                            .get_or_insert_default()
7225                            .lsp_fetch_timeout_ms = value;
7226                    })
7227                },
7228            }),
7229            metadata: None,
7230            files: USER | PROJECT,
7231        }),
7232        SettingsPageItem::SettingItem(SettingItem {
7233            title: "Insert Mode",
7234            description: "Controls how LSP completions are inserted.",
7235            field: Box::new(SettingField {
7236                json_path: Some("languages.$(language).completions.lsp_insert_mode"),
7237                pick: |settings_content| {
7238                    language_settings_field(settings_content, |language| {
7239                        language.completions.as_ref()?.lsp_insert_mode.as_ref()
7240                    })
7241                },
7242                write: |settings_content, value| {
7243                    language_settings_field_mut(settings_content, value, |language, value| {
7244                        language.completions.get_or_insert_default().lsp_insert_mode = value;
7245                    })
7246                },
7247            }),
7248            metadata: None,
7249            files: USER | PROJECT,
7250        }),
7251        SettingsPageItem::SectionHeader("Debuggers"),
7252        SettingsPageItem::SettingItem(SettingItem {
7253            title: "Debuggers",
7254            description: "Preferred debuggers for this language.",
7255            field: Box::new(
7256                SettingField {
7257                    json_path: Some("languages.$(language).debuggers"),
7258                    pick: |settings_content| {
7259                        language_settings_field(settings_content, |language| {
7260                            language.debuggers.as_ref()
7261                        })
7262                    },
7263                    write: |settings_content, value| {
7264                        language_settings_field_mut(settings_content, value, |language, value| {
7265                            language.debuggers = value;
7266                        })
7267                    },
7268                }
7269                .unimplemented(),
7270            ),
7271            metadata: None,
7272            files: USER | PROJECT,
7273        }),
7274        SettingsPageItem::SectionHeader("Prettier"),
7275        SettingsPageItem::SettingItem(SettingItem {
7276            title: "Allowed",
7277            description: "Enables or disables formatting with Prettier for a given language.",
7278            field: Box::new(SettingField {
7279                json_path: Some("languages.$(language).prettier.allowed"),
7280                pick: |settings_content| {
7281                    language_settings_field(settings_content, |language| {
7282                        language.prettier.as_ref()?.allowed.as_ref()
7283                    })
7284                },
7285                write: |settings_content, value| {
7286                    language_settings_field_mut(settings_content, value, |language, value| {
7287                        language.prettier.get_or_insert_default().allowed = value;
7288                    })
7289                },
7290            }),
7291            metadata: None,
7292            files: USER | PROJECT,
7293        }),
7294        SettingsPageItem::SettingItem(SettingItem {
7295            title: "Parser",
7296            description: "Forces Prettier integration to use a specific parser name when formatting files with the language.",
7297            field: Box::new(SettingField {
7298                json_path: Some("languages.$(language).prettier.parser"),
7299                pick: |settings_content| {
7300                    language_settings_field(settings_content, |language| {
7301                        language.prettier.as_ref()?.parser.as_ref()
7302                    })
7303                },
7304                write: |settings_content, value| {
7305                    language_settings_field_mut(settings_content, value, |language, value| {
7306                        language.prettier.get_or_insert_default().parser = value;
7307                    })
7308                },
7309            }),
7310            metadata: None,
7311            files: USER | PROJECT,
7312        }),
7313        SettingsPageItem::SettingItem(SettingItem {
7314            title: "Plugins",
7315            description: "Forces Prettier integration to use specific plugins when formatting files with the language.",
7316            field: Box::new(
7317                SettingField {
7318                    json_path: Some("languages.$(language).prettier.plugins"),
7319                    pick: |settings_content| {
7320                        language_settings_field(settings_content, |language| {
7321                            language.prettier.as_ref()?.plugins.as_ref()
7322                        })
7323                    },
7324                    write: |settings_content, value| {
7325                        language_settings_field_mut(settings_content, value, |language, value| {
7326                            language.prettier.get_or_insert_default().plugins = value;
7327                        })
7328                    },
7329                }
7330                .unimplemented(),
7331            ),
7332            metadata: None,
7333            files: USER | PROJECT,
7334        }),
7335        SettingsPageItem::SettingItem(SettingItem {
7336            title: "Options",
7337            description: "Default Prettier options, in the format as in package.json section for Prettier.",
7338            field: Box::new(
7339                SettingField {
7340                    json_path: Some("languages.$(language).prettier.options"),
7341                    pick: |settings_content| {
7342                        language_settings_field(settings_content, |language| {
7343                            language.prettier.as_ref()?.options.as_ref()
7344                        })
7345                    },
7346                    write: |settings_content, value| {
7347                        language_settings_field_mut(settings_content, value, |language, value| {
7348                            language.prettier.get_or_insert_default().options = value;
7349                        })
7350                    },
7351                }
7352                .unimplemented(),
7353            ),
7354            metadata: None,
7355            files: USER | PROJECT,
7356        }),
7357    ]
7358}
7359
7360fn edit_prediction_language_settings_section() -> Vec<SettingsPageItem> {
7361    vec![
7362        SettingsPageItem::SectionHeader("Edit Predictions"),
7363        SettingsPageItem::SettingItem(SettingItem {
7364            title: "Show Edit Predictions",
7365            description: "Controls whether edit predictions are shown immediately or manually by triggering `editor::showeditprediction` (false).",
7366            field: Box::new(SettingField {
7367                json_path: Some("languages.$(language).show_edit_predictions"),
7368                pick: |settings_content| {
7369                    language_settings_field(settings_content, |language| {
7370                        language.show_edit_predictions.as_ref()
7371                    })
7372                },
7373                write: |settings_content, value| {
7374                    language_settings_field_mut(settings_content, value, |language, value| {
7375                        language.show_edit_predictions = value;
7376                    })
7377                },
7378            }),
7379            metadata: None,
7380            files: USER | PROJECT,
7381        }),
7382        SettingsPageItem::SettingItem(SettingItem {
7383            title: "Edit Predictions Disabled In",
7384            description: "Controls whether edit predictions are shown in the given language scopes.",
7385            field: Box::new(
7386                SettingField {
7387                    json_path: Some("languages.$(language).edit_predictions_disabled_in"),
7388                    pick: |settings_content| {
7389                        language_settings_field(settings_content, |language| {
7390                            language.edit_predictions_disabled_in.as_ref()
7391                        })
7392                    },
7393                    write: |settings_content, value| {
7394                        language_settings_field_mut(settings_content, value, |language, value| {
7395                            language.edit_predictions_disabled_in = value;
7396                        })
7397                    },
7398                }
7399                .unimplemented(),
7400            ),
7401            metadata: None,
7402            files: USER | PROJECT,
7403        }),
7404    ]
7405}
7406
7407fn show_scrollbar_or_editor(
7408    settings_content: &SettingsContent,
7409    show: fn(&SettingsContent) -> Option<&settings::ShowScrollbar>,
7410) -> Option<&settings::ShowScrollbar> {
7411    show(settings_content).or(settings_content
7412        .editor
7413        .scrollbar
7414        .as_ref()
7415        .and_then(|scrollbar| scrollbar.show.as_ref()))
7416}
7417
7418fn dynamic_variants<T>() -> &'static [T::Discriminant]
7419where
7420    T: strum::IntoDiscriminant,
7421    T::Discriminant: strum::VariantArray,
7422{
7423    <<T as strum::IntoDiscriminant>::Discriminant as strum::VariantArray>::VARIANTS
7424}