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