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