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