page_data.rs

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