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