Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:37:50.656Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

page_data.rs

10659 lines · 485.9 KB · rust
1use gpui::{Action as _, App};
2use itertools::Itertools as _;
3use settings::{
4    AudioInputDeviceName, AudioOutputDeviceName, EditPredictionDataCollectionChoice,
5    LanguageSettingsContent, SemanticTokens, SettingsContent,
6};
7use std::sync::{Arc, OnceLock};
8use strum::{EnumMessage, IntoDiscriminant as _, VariantArray};
9use theme::SystemAppearance;
10use ui::IntoElement;
11
12use crate::{
13    ActionLink, DynamicItem, PROJECT, SettingField, SettingItem, SettingsFieldMetadata,
14    SettingsPage, SettingsPageItem, SubPageLink, USER, active_language, all_language_names,
15    pages::{
16        open_audio_test_window, render_edit_prediction_setup_page, render_external_agents_page,
17        render_llm_providers_page, render_mcp_servers_page, render_sandbox_settings_page,
18        render_skills_setup_page, render_tool_permissions_setup_page,
19    },
20};
21
22const DEFAULT_STRING: String = String::new();
23/// A default empty string reference. Useful in `pick` functions for cases either in dynamic item fields, or when dealing with `settings::Maybe`
24/// to avoid the "NO DEFAULT" case.
25const DEFAULT_EMPTY_STRING: Option<&String> = Some(&DEFAULT_STRING);
26
27const DEFAULT_AUDIO_OUTPUT: AudioOutputDeviceName = AudioOutputDeviceName(None);
28const DEFAULT_EMPTY_AUDIO_OUTPUT: Option<&AudioOutputDeviceName> = Some(&DEFAULT_AUDIO_OUTPUT);
29const DEFAULT_AUDIO_INPUT: AudioInputDeviceName = AudioInputDeviceName(None);
30const DEFAULT_EMPTY_AUDIO_INPUT: Option<&AudioInputDeviceName> = Some(&DEFAULT_AUDIO_INPUT);
31
32macro_rules! concat_sections {
33    (@vec, $($arr:expr),+ $(,)?) => {{
34        let total_len = 0_usize $(+ $arr.len())+;
35        let mut out = Vec::with_capacity(total_len);
36
37        $(
38            out.extend($arr);
39        )+
40
41        out
42    }};
43
44    ($($arr:expr),+ $(,)?) => {{
45        let total_len = 0_usize $(+ $arr.len())+;
46
47        let mut out: Box<[std::mem::MaybeUninit<_>]> = Box::new_uninit_slice(total_len);
48
49        let mut index = 0usize;
50        $(
51            let array = $arr;
52            for item in array {
53                out[index].write(item);
54                index += 1;
55            }
56        )+
57
58        debug_assert_eq!(index, total_len);
59
60        // SAFETY: we wrote exactly `total_len` elements.
61        unsafe { out.assume_init() }
62    }};
63}
64
65pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
66    vec![
67        general_page(cx),
68        appearance_page(),
69        keymap_page(),
70        editor_page(),
71        languages_and_tools_page(cx),
72        search_and_files_page(),
73        window_and_layout_page(),
74        panels_page(),
75        debugger_page(),
76        terminal_page(),
77        version_control_page(),
78        collaboration_page(),
79        ai_page(cx),
80        network_page(),
81        developer_page(cx),
82    ]
83}
84
85fn developer_page(cx: &App) -> SettingsPage {
86    use feature_flags::FeatureFlagAppExt as _;
87
88    let mut items: Vec<SettingsPageItem> = Vec::new();
89
90    // Feature flag overrides are a staff-only affordance, so only surface the section when the overrides are enabled.
91    if cx.feature_flag_overrides_enabled() {
92        items.push(SettingsPageItem::SectionHeader("Feature Flags"));
93        items.push(SettingsPageItem::SubPageLink(SubPageLink {
94            title: "Feature Flags".into(),
95            r#type: Default::default(),
96            description: None,
97            search_aliases: &[],
98            json_path: Some("feature_flags"),
99            in_json: true,
100            files: USER,
101            render: crate::pages::render_feature_flags_page,
102        }));
103    }
104
105    items.push(SettingsPageItem::SectionHeader("Instrumentation"));
106    items.push(SettingsPageItem::SettingItem(SettingItem {
107        title: "Performance Profiler",
108        description: "Collect timing data for foreground and background executor tasks so they can be inspected via `omega: open performance profiler`. May lead to increased memory usage.",
109        field: Box::new(SettingField {
110            organization_override: None,
111            json_path: Some("instrumentation.performance_profiler.enabled"),
112            pick: |settings_content| {
113                settings_content
114                    .instrumentation
115                    .as_ref()
116                    .and_then(|i| i.performance_profiler.as_ref())
117                    .and_then(|p| p.enabled.as_ref())
118            },
119            write: |settings_content, value, _| {
120                settings_content
121                    .instrumentation
122                    .get_or_insert_default()
123                    .performance_profiler
124                    .get_or_insert_default()
125                    .enabled = value;
126            },
127        }),
128        metadata: None,
129        files: USER,
130    }));
131
132    SettingsPage {
133        title: "Developer",
134        items: items.into_boxed_slice(),
135    }
136}
137
138fn general_page(cx: &App) -> SettingsPage {
139    fn general_settings_section(_cx: &App) -> Vec<SettingsPageItem> {
140        vec![
141            SettingsPageItem::SectionHeader("General Settings"),
142            SettingsPageItem::SettingItem(SettingItem {
143                title: "Accessible Mode",
144                description: "Optimize Omega's interface for assistive technology such as screen readers. When enabled, otherwise-collapsed controls stay expanded and keyboard-reachable.",
145                field: Box::new(SettingField {
146                    organization_override: None,
147                    json_path: Some("accessible_mode"),
148                    pick: |settings_content| settings_content.workspace.accessible_mode.as_ref(),
149                    write: |settings_content, value, _| {
150                        settings_content.workspace.accessible_mode = value;
151                    },
152                }),
153                metadata: None,
154                files: USER,
155            }),
156            SettingsPageItem::SettingItem(SettingItem {
157                title: "When Closing With No Tabs",
158                description: "What to do when using the 'close active item' action with no tabs.",
159                field: Box::new(SettingField {
160                    organization_override: None,
161                    json_path: Some("when_closing_with_no_tabs"),
162                    pick: |settings_content| {
163                        settings_content
164                            .workspace
165                            .when_closing_with_no_tabs
166                            .as_ref()
167                    },
168                    write: |settings_content, value, _| {
169                        settings_content.workspace.when_closing_with_no_tabs = value;
170                    },
171                }),
172                metadata: None,
173                files: USER,
174            }),
175            SettingsPageItem::SettingItem(SettingItem {
176                title: "On Last Window Closed",
177                description: "What to do when the last window is closed.",
178                field: Box::new(SettingField {
179                    organization_override: None,
180                    json_path: Some("on_last_window_closed"),
181                    pick: |settings_content| {
182                        settings_content.workspace.on_last_window_closed.as_ref()
183                    },
184                    write: |settings_content, value, _| {
185                        settings_content.workspace.on_last_window_closed = value;
186                    },
187                }),
188                metadata: None,
189                files: USER,
190            }),
191            SettingsPageItem::SettingItem(SettingItem {
192                title: "Use System Path Prompts",
193                description: "Use native OS dialogs for 'Open' and 'Save As'.",
194                field: Box::new(SettingField {
195                    organization_override: None,
196                    json_path: Some("use_system_path_prompts"),
197                    pick: |settings_content| {
198                        settings_content.workspace.use_system_path_prompts.as_ref()
199                    },
200                    write: |settings_content, value, _| {
201                        settings_content.workspace.use_system_path_prompts = value;
202                    },
203                }),
204                metadata: None,
205                files: USER,
206            }),
207            SettingsPageItem::SettingItem(SettingItem {
208                title: "Use System Prompts",
209                description: "Use native OS dialogs for confirmations.",
210                field: Box::new(SettingField {
211                    organization_override: None,
212                    json_path: Some("use_system_prompts"),
213                    pick: |settings_content| settings_content.workspace.use_system_prompts.as_ref(),
214                    write: |settings_content, value, _| {
215                        settings_content.workspace.use_system_prompts = value;
216                    },
217                }),
218                metadata: None,
219                files: USER,
220            }),
221            SettingsPageItem::SettingItem(SettingItem {
222                title: "Redact Private Values",
223                description: "Hide the values of variables in private files.",
224                field: Box::new(SettingField {
225                    organization_override: None,
226                    json_path: Some("redact_private_values"),
227                    pick: |settings_content| settings_content.editor.redact_private_values.as_ref(),
228                    write: |settings_content, value, _| {
229                        settings_content.editor.redact_private_values = value;
230                    },
231                }),
232                metadata: None,
233                files: USER,
234            }),
235            SettingsPageItem::SettingItem(SettingItem {
236                title: "Private Files",
237                description: "Globs to match against file paths to determine if a file is private.",
238                field: Box::new(
239                    SettingField {
240                        organization_override: None,
241                        json_path: Some("worktree.private_files"),
242                        pick: |settings_content| {
243                            settings_content.project.worktree.private_files.as_ref()
244                        },
245                        write: |settings_content, value, _| {
246                            settings_content.project.worktree.private_files = value;
247                        },
248                    }
249                    .unimplemented(),
250                ),
251                metadata: None,
252                files: USER,
253            }),
254            SettingsPageItem::SettingItem(SettingItem {
255                title: "CLI Default Open Behavior",
256                description: "How `omega <path>` opens directories when no flag is specified.",
257                field: Box::new(SettingField {
258                    organization_override: None,
259                    json_path: Some("cli_default_open_behavior"),
260                    pick: |settings_content| {
261                        settings_content
262                            .workspace
263                            .cli_default_open_behavior
264                            .as_ref()
265                    },
266                    write: |settings_content, value, _| {
267                        settings_content.workspace.cli_default_open_behavior = value;
268                    },
269                }),
270                metadata: Some(Box::new(SettingsFieldMetadata {
271                    should_do_titlecase: Some(false),
272                    ..Default::default()
273                })),
274                files: USER,
275            }),
276            SettingsPageItem::SettingItem(SettingItem {
277                title: "Default Open Behavior",
278                description: "How projects open from the UI by default.",
279                field: Box::new(SettingField {
280                    organization_override: None,
281                    json_path: Some("default_open_behavior"),
282                    pick: |settings_content| {
283                        settings_content.workspace.default_open_behavior.as_ref()
284                    },
285                    write: |settings_content, value, _| {
286                        settings_content.workspace.default_open_behavior = value;
287                    },
288                }),
289                metadata: Some(Box::new(SettingsFieldMetadata {
290                    should_do_titlecase: Some(false),
291                    ..Default::default()
292                })),
293                files: USER,
294            }),
295        ]
296    }
297    fn security_section() -> [SettingsPageItem; 2] {
298        [
299            SettingsPageItem::SectionHeader("Security"),
300            SettingsPageItem::SettingItem(SettingItem {
301                title: "Trust All Projects By Default",
302                description: "Trust every project automatically. Omega defaults this on, so all features work in any project without per-project permission.",
303                field: Box::new(SettingField {
304                    organization_override: None,
305                    json_path: Some("session.trust_all_projects"),
306                    pick: |settings_content| {
307                        settings_content
308                            .session
309                            .as_ref()
310                            .and_then(|session| session.trust_all_worktrees.as_ref())
311                    },
312                    write: |settings_content, value, _| {
313                        settings_content
314                            .session
315                            .get_or_insert_default()
316                            .trust_all_worktrees = value;
317                    },
318                }),
319                metadata: None,
320                files: USER,
321            }),
322        ]
323    }
324
325    fn workspace_restoration_section() -> [SettingsPageItem; 3] {
326        [
327            SettingsPageItem::SectionHeader("Workspace Restoration"),
328            SettingsPageItem::SettingItem(SettingItem {
329                title: "Restore Unsaved Buffers",
330                description: "Whether or not to restore unsaved buffers on restart.",
331                field: Box::new(SettingField {
332                    organization_override: None,
333                    json_path: Some("session.restore_unsaved_buffers"),
334                    pick: |settings_content| {
335                        settings_content
336                            .session
337                            .as_ref()
338                            .and_then(|session| session.restore_unsaved_buffers.as_ref())
339                    },
340                    write: |settings_content, value, _| {
341                        settings_content
342                            .session
343                            .get_or_insert_default()
344                            .restore_unsaved_buffers = value;
345                    },
346                }),
347                metadata: None,
348                files: USER,
349            }),
350            SettingsPageItem::SettingItem(SettingItem {
351                title: "Restore On Startup",
352                description: "What to restore from the previous session when opening Omega.",
353                field: Box::new(SettingField {
354                    organization_override: None,
355                    json_path: Some("restore_on_startup"),
356                    pick: |settings_content| settings_content.workspace.restore_on_startup.as_ref(),
357                    write: |settings_content, value, _| {
358                        settings_content.workspace.restore_on_startup = value;
359                    },
360                }),
361                metadata: None,
362                files: USER,
363            }),
364        ]
365    }
366
367    fn scoped_settings_section() -> [SettingsPageItem; 3] {
368        [
369            SettingsPageItem::SectionHeader("Scoped Settings"),
370            SettingsPageItem::SettingItem(SettingItem {
371                files: USER,
372                title: "Preview Channel",
373                description: "Which settings should be activated only in Preview build of Omega.",
374                field: Box::new(
375                    SettingField {
376                        organization_override: None,
377                        json_path: Some("preview_channel_settings"),
378                        pick: |settings_content| Some(settings_content),
379                        write: |_settings_content, _value, _| {},
380                    }
381                    .unimplemented(),
382                ),
383                metadata: None,
384            }),
385            SettingsPageItem::SettingItem(SettingItem {
386                files: USER,
387                title: "Settings Profiles",
388                description: "Any number of settings profiles that are temporarily applied on top of your existing user settings.",
389                field: Box::new(
390                    SettingField {
391                        organization_override: None,
392                        json_path: Some("settings_profiles"),
393                        pick: |settings_content| Some(settings_content),
394                        write: |_settings_content, _value, _| {},
395                    }
396                    .unimplemented(),
397                ),
398                metadata: None,
399            }),
400        ]
401    }
402
403    fn privacy_section() -> [SettingsPageItem; 4] {
404        [
405            SettingsPageItem::SectionHeader("Privacy"),
406            SettingsPageItem::SettingItem(SettingItem {
407                title: "Telemetry Diagnostics",
408                description: "Send debug information like crash reports.",
409                field: Box::new(SettingField {
410                    organization_override: None,
411                    json_path: Some("telemetry.diagnostics"),
412                    pick: |settings_content| {
413                        settings_content
414                            .telemetry
415                            .as_ref()
416                            .and_then(|telemetry| telemetry.diagnostics.as_ref())
417                    },
418                    write: |settings_content, value, _| {
419                        settings_content
420                            .telemetry
421                            .get_or_insert_default()
422                            .diagnostics = value;
423                    },
424                }),
425                metadata: None,
426                files: USER,
427            }),
428            SettingsPageItem::SettingItem(SettingItem {
429                title: "Telemetry Metrics",
430                description: "Send anonymized usage data like what languages you're using Omega with.",
431                field: Box::new(SettingField {
432                    organization_override: None,
433                    json_path: Some("telemetry.metrics"),
434                    pick: |settings_content| {
435                        settings_content
436                            .telemetry
437                            .as_ref()
438                            .and_then(|telemetry| telemetry.metrics.as_ref())
439                    },
440                    write: |settings_content, value, _| {
441                        settings_content.telemetry.get_or_insert_default().metrics = value;
442                    },
443                }),
444                metadata: None,
445                files: USER,
446            }),
447            SettingsPageItem::SettingItem(SettingItem {
448                title: "Anthropic Data Retention",
449                description: "Allow sending requests to Anthropic models that cannot be offered with Zero Data Retention.",
450                field: Box::new(SettingField {
451                    organization_override: None,
452                    json_path: Some("telemetry.anthropic_retention"),
453                    pick: |settings_content| {
454                        settings_content
455                            .telemetry
456                            .as_ref()
457                            .and_then(|telemetry| telemetry.anthropic_retention.as_ref())
458                    },
459                    write: |settings_content, value, _| {
460                        settings_content
461                            .telemetry
462                            .get_or_insert_default()
463                            .anthropic_retention = value;
464                    },
465                }),
466                metadata: None,
467                files: USER,
468            }),
469        ]
470    }
471
472    fn auto_update_section() -> [SettingsPageItem; 2] {
473        [
474            SettingsPageItem::SectionHeader("Auto Update"),
475            SettingsPageItem::SettingItem(SettingItem {
476                title: "Auto Update",
477                description: "Whether or not to automatically check for updates.",
478                field: Box::new(SettingField {
479                    organization_override: None,
480                    json_path: Some("auto_update"),
481                    pick: |settings_content| settings_content.auto_update.as_ref(),
482                    write: |settings_content, value, _| {
483                        settings_content.auto_update = value;
484                    },
485                }),
486                metadata: None,
487                files: USER,
488            }),
489        ]
490    }
491
492    SettingsPage {
493        title: "General",
494        items: concat_sections!(
495            @vec,
496            general_settings_section(cx),
497            security_section(),
498            workspace_restoration_section(),
499            scoped_settings_section(),
500            privacy_section(),
501            auto_update_section(),
502        )
503        .into(),
504    }
505}
506
507fn appearance_page() -> SettingsPage {
508    fn theme_section() -> [SettingsPageItem; 3] {
509        [
510            SettingsPageItem::SectionHeader("Theme"),
511            SettingsPageItem::DynamicItem(DynamicItem {
512                discriminant: SettingItem {
513                    files: USER,
514                    title: "Theme Mode",
515                    description: "Choose a static, fixed theme or dynamically select themes based on appearance and light/dark modes.",
516                    field: Box::new(SettingField {
517                        organization_override: None,
518                        json_path: Some("theme$"),
519                        pick: |settings_content| {
520                            Some(&dynamic_variants::<settings::ThemeSelection>()[
521                                settings_content
522                                    .theme
523                                    .theme
524                                    .as_ref()?
525                                    .discriminant() as usize])
526                        },
527                        write: |settings_content, value, app: &App| {
528                            let Some(value) = value else {
529                                settings_content.theme.theme = None;
530                                return;
531                            };
532                            let settings_value = settings_content.theme.theme.get_or_insert_default();
533                            *settings_value = match value {
534                                settings::ThemeSelectionDiscriminants::Static => {
535                                    let name = match settings_value {
536                                        settings::ThemeSelection::Static(_) => return,
537                                        settings::ThemeSelection::Dynamic { mode, light, dark } => {
538                                            match mode {
539                                                theme_settings::ThemeAppearanceMode::Light => light.clone(),
540                                                theme_settings::ThemeAppearanceMode::Dark => dark.clone(),
541                                                theme_settings::ThemeAppearanceMode::System => {
542                                                    if SystemAppearance::global(app).is_light() {
543                                                        light.clone()
544                                                    } else {
545                                                        dark.clone()
546                                                    }
547                                                }
548                                            }
549                                        },
550                                    };
551                                    settings::ThemeSelection::Static(name)
552                                },
553                                settings::ThemeSelectionDiscriminants::Dynamic => {
554                                    let static_name = match settings_value {
555                                        settings::ThemeSelection::Static(theme_name) => theme_name.clone(),
556                                        settings::ThemeSelection::Dynamic {..} => return,
557                                    };
558
559                                    settings::ThemeSelection::Dynamic {
560                                        mode: settings::ThemeAppearanceMode::System,
561                                        light: static_name.clone(),
562                                        dark: static_name,
563                                    }
564                                },
565                            };
566                        },
567                    }),
568                    metadata: None,
569                },
570                pick_discriminant: |settings_content| {
571                    Some(settings_content.theme.theme.as_ref()?.discriminant() as usize)
572                },
573                fields: dynamic_variants::<settings::ThemeSelection>().into_iter().map(|variant| {
574                    match variant {
575                        settings::ThemeSelectionDiscriminants::Static => vec![
576                            SettingItem {
577                                files: USER,
578                                title: "Theme Name",
579                                description: "The name of your selected theme.",
580                                field: Box::new(SettingField {
581                                    organization_override: None,
582                                    json_path: Some("theme"),
583                                    pick: |settings_content| {
584                                        match settings_content.theme.theme.as_ref() {
585                                            Some(settings::ThemeSelection::Static(name)) => Some(name),
586                                            _ => None
587                                        }
588                                    },
589                                    write: |settings_content, value, _| {
590                                        let Some(value) = value else {
591                                            return;
592                                        };
593                                        match settings_content
594                                            .theme
595                                            .theme.get_or_insert_default() {
596                                                settings::ThemeSelection::Static(theme_name) => *theme_name = value,
597                                                _ => return
598                                            }
599                                    },
600                                }),
601                                metadata: None,
602                            }
603                        ],
604                        settings::ThemeSelectionDiscriminants::Dynamic => vec![
605                            SettingItem {
606                                files: USER,
607                                title: "Mode",
608                                description: "Choose whether to use the selected light or dark theme or to follow your OS appearance configuration.",
609                                field: Box::new(SettingField {
610                                    organization_override: None,
611                                    json_path: Some("theme.mode"),
612                                    pick: |settings_content| {
613                                        match settings_content.theme.theme.as_ref() {
614                                            Some(settings::ThemeSelection::Dynamic { mode, ..}) => Some(mode),
615                                            _ => None
616                                        }
617                                    },
618                                    write: |settings_content, value, _| {
619                                        let Some(value) = value else {
620                                            return;
621                                        };
622                                        match settings_content
623                                            .theme
624                                            .theme.get_or_insert_default() {
625                                                settings::ThemeSelection::Dynamic{ mode, ..} => *mode = value,
626                                                _ => return
627                                            }
628                                    },
629                                }),
630                                metadata: None,
631                            },
632                            SettingItem {
633                                files: USER,
634                                title: "Light Theme",
635                                description: "The theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
636                                field: Box::new(SettingField {
637                                    organization_override: None,
638                                    json_path: Some("theme.light"),
639                                    pick: |settings_content| {
640                                        match settings_content.theme.theme.as_ref() {
641                                            Some(settings::ThemeSelection::Dynamic { light, ..}) => Some(light),
642                                            _ => None
643                                        }
644                                    },
645                                    write: |settings_content, value, _| {
646                                        let Some(value) = value else {
647                                            return;
648                                        };
649                                        match settings_content
650                                            .theme
651                                            .theme.get_or_insert_default() {
652                                                settings::ThemeSelection::Dynamic{ light, ..} => *light = value,
653                                                _ => return
654                                            }
655                                    },
656                                }),
657                                metadata: None,
658                            },
659                            SettingItem {
660                                files: USER,
661                                title: "Dark Theme",
662                                description: "The theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
663                                field: Box::new(SettingField {
664                                    organization_override: None,
665                                    json_path: Some("theme.dark"),
666                                    pick: |settings_content| {
667                                        match settings_content.theme.theme.as_ref() {
668                                            Some(settings::ThemeSelection::Dynamic { dark, ..}) => Some(dark),
669                                            _ => None
670                                        }
671                                    },
672                                    write: |settings_content, value, _| {
673                                        let Some(value) = value else {
674                                            return;
675                                        };
676                                        match settings_content
677                                            .theme
678                                            .theme.get_or_insert_default() {
679                                                settings::ThemeSelection::Dynamic{ dark, ..} => *dark = value,
680                                                _ => return
681                                            }
682                                    },
683                                }),
684                                metadata: None,
685                            }
686                        ],
687                    }
688                }).collect(),
689            }),
690            SettingsPageItem::DynamicItem(DynamicItem {
691                discriminant: SettingItem {
692                    files: USER,
693                    title: "Icon Theme",
694                    description: "The custom set of icons Omega will associate with files and directories.",
695                    field: Box::new(SettingField {
696                        organization_override: None,
697                        json_path: Some("icon_theme$"),
698                        pick: |settings_content| {
699                            Some(&dynamic_variants::<settings::IconThemeSelection>()[
700                                settings_content
701                                    .theme
702                                    .icon_theme
703                                    .as_ref()?
704                                    .discriminant() as usize])
705                        },
706                        write: |settings_content, value, app| {
707                            let Some(value) = value else {
708                                settings_content.theme.icon_theme = None;
709                                return;
710                            };
711                            let settings_value = settings_content.theme.icon_theme.get_or_insert_with(|| {
712                                settings::IconThemeSelection::Static(settings::IconThemeName(theme::default_icon_theme().name.clone().into()))
713                            });
714                            *settings_value = match value {
715                                settings::IconThemeSelectionDiscriminants::Static => {
716                                    let name = match settings_value {
717                                        settings::IconThemeSelection::Static(_) => return,
718                                        settings::IconThemeSelection::Dynamic { mode, light, dark } => {
719                                            match mode {
720                                                theme_settings::ThemeAppearanceMode::Light => light.clone(),
721                                                theme_settings::ThemeAppearanceMode::Dark => dark.clone(),
722                                                theme_settings::ThemeAppearanceMode::System => {
723                                                    if SystemAppearance::global(app).is_light() {
724                                                        light.clone()
725                                                    } else {
726                                                        dark.clone()
727                                                    }
728                                                }
729                                            }
730                                        },
731                                    };
732                                    settings::IconThemeSelection::Static(name)
733                                },
734                                settings::IconThemeSelectionDiscriminants::Dynamic => {
735                                    let static_name = match settings_value {
736                                        settings::IconThemeSelection::Static(theme_name) => theme_name.clone(),
737                                        settings::IconThemeSelection::Dynamic {..} => return,
738                                    };
739
740                                    settings::IconThemeSelection::Dynamic {
741                                        mode: settings::ThemeAppearanceMode::System,
742                                        light: static_name.clone(),
743                                        dark: static_name,
744                                    }
745                                },
746                            };
747                        },
748                    }),
749                    metadata: None,
750                },
751                pick_discriminant: |settings_content| {
752                    Some(settings_content.theme.icon_theme.as_ref()?.discriminant() as usize)
753                },
754                fields: dynamic_variants::<settings::IconThemeSelection>().into_iter().map(|variant| {
755                    match variant {
756                        settings::IconThemeSelectionDiscriminants::Static => vec![
757                            SettingItem {
758                                files: USER,
759                                title: "Icon Theme Name",
760                                description: "The name of your selected icon theme.",
761                                field: Box::new(SettingField {
762                                    organization_override: None,
763                                    json_path: Some("icon_theme$string"),
764                                    pick: |settings_content| {
765                                        match settings_content.theme.icon_theme.as_ref() {
766                                            Some(settings::IconThemeSelection::Static(name)) => Some(name),
767                                            _ => None
768                                        }
769                                    },
770                                    write: |settings_content, value, _| {
771                                        let Some(value) = value else {
772                                            return;
773                                        };
774                                        match settings_content
775                                            .theme
776                                            .icon_theme.as_mut() {
777                                                Some(settings::IconThemeSelection::Static(theme_name)) => *theme_name = value,
778                                                _ => return
779                                            }
780                                    },
781                                }),
782                                metadata: None,
783                            }
784                        ],
785                        settings::IconThemeSelectionDiscriminants::Dynamic => vec![
786                            SettingItem {
787                                files: USER,
788                                title: "Mode",
789                                description: "Choose whether to use the selected light or dark icon theme or to follow your OS appearance configuration.",
790                                field: Box::new(SettingField {
791                                    organization_override: None,
792                                    json_path: Some("icon_theme"),
793                                    pick: |settings_content| {
794                                        match settings_content.theme.icon_theme.as_ref() {
795                                            Some(settings::IconThemeSelection::Dynamic { mode, ..}) => Some(mode),
796                                            _ => None
797                                        }
798                                    },
799                                    write: |settings_content, value, _| {
800                                        let Some(value) = value else {
801                                            return;
802                                        };
803                                        match settings_content
804                                            .theme
805                                            .icon_theme.as_mut() {
806                                                Some(settings::IconThemeSelection::Dynamic{ mode, ..}) => *mode = value,
807                                                _ => return
808                                            }
809                                    },
810                                }),
811                                metadata: None,
812                            },
813                            SettingItem {
814                                files: USER,
815                                title: "Light Icon Theme",
816                                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.",
817                                field: Box::new(SettingField {
818                                    organization_override: None,
819                                    json_path: Some("icon_theme.light"),
820                                    pick: |settings_content| {
821                                        match settings_content.theme.icon_theme.as_ref() {
822                                            Some(settings::IconThemeSelection::Dynamic { light, ..}) => Some(light),
823                                            _ => None
824                                        }
825                                    },
826                                    write: |settings_content, value, _| {
827                                        let Some(value) = value else {
828                                            return;
829                                        };
830                                        match settings_content
831                                            .theme
832                                            .icon_theme.as_mut() {
833                                                Some(settings::IconThemeSelection::Dynamic{ light, ..}) => *light = value,
834                                                _ => return
835                                            }
836                                    },
837                                }),
838                                metadata: None,
839                            },
840                            SettingItem {
841                                files: USER,
842                                title: "Dark Icon Theme",
843                                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.",
844                                field: Box::new(SettingField {
845                                    organization_override: None,
846                                    json_path: Some("icon_theme.dark"),
847                                    pick: |settings_content| {
848                                        match settings_content.theme.icon_theme.as_ref() {
849                                            Some(settings::IconThemeSelection::Dynamic { dark, ..}) => Some(dark),
850                                            _ => None
851                                        }
852                                    },
853                                    write: |settings_content, value, _| {
854                                        let Some(value) = value else {
855                                            return;
856                                        };
857                                        match settings_content
858                                            .theme
859                                            .icon_theme.as_mut() {
860                                                Some(settings::IconThemeSelection::Dynamic{ dark, ..}) => *dark = value,
861                                                _ => return
862                                            }
863                                    },
864                                }),
865                                metadata: None,
866                            }
867                        ],
868                    }
869                }).collect(),
870            }),
871        ]
872    }
873
874    fn buffer_font_section() -> [SettingsPageItem; 7] {
875        [
876            SettingsPageItem::SectionHeader("Buffer Font"),
877            SettingsPageItem::SettingItem(SettingItem {
878                title: "Font Family",
879                description: "Font family for editor text.",
880                field: Box::new(SettingField {
881                    organization_override: None,
882                    json_path: Some("buffer_font_family"),
883                    pick: |settings_content| settings_content.theme.buffer_font_family.as_ref(),
884                    write: |settings_content, value, _| {
885                        settings_content.theme.buffer_font_family = value;
886                    },
887                }),
888                metadata: None,
889                files: USER,
890            }),
891            SettingsPageItem::SettingItem(SettingItem {
892                title: "Font Size",
893                description: "Font size for editor text.",
894                field: Box::new(SettingField {
895                    organization_override: None,
896                    json_path: Some("buffer_font_size"),
897                    pick: |settings_content| settings_content.theme.buffer_font_size.as_ref(),
898                    write: |settings_content, value, _| {
899                        settings_content.theme.buffer_font_size = value;
900                    },
901                }),
902                metadata: None,
903                files: USER,
904            }),
905            SettingsPageItem::SettingItem(SettingItem {
906                title: "Font Weight",
907                description: "Font weight for editor text (100-900).",
908                field: Box::new(SettingField {
909                    organization_override: None,
910                    json_path: Some("buffer_font_weight"),
911                    pick: |settings_content| settings_content.theme.buffer_font_weight.as_ref(),
912                    write: |settings_content, value, _| {
913                        settings_content.theme.buffer_font_weight = value;
914                    },
915                }),
916                metadata: None,
917                files: USER,
918            }),
919            SettingsPageItem::DynamicItem(DynamicItem {
920                discriminant: SettingItem {
921                    files: USER,
922                    title: "Line Height",
923                    description: "Line height for editor text.",
924                    field: Box::new(SettingField {
925                        organization_override: None,
926                        json_path: Some("buffer_line_height$"),
927                        pick: |settings_content| {
928                            Some(
929                                &dynamic_variants::<settings::BufferLineHeight>()[settings_content
930                                    .theme
931                                    .buffer_line_height
932                                    .as_ref()?
933                                    .discriminant()
934                                    as usize],
935                            )
936                        },
937                        write: |settings_content, value, _| {
938                            let Some(value) = value else {
939                                settings_content.theme.buffer_line_height = None;
940                                return;
941                            };
942                            let settings_value = settings_content
943                                .theme
944                                .buffer_line_height
945                                .get_or_insert_with(|| settings::BufferLineHeight::default());
946                            *settings_value = match value {
947                                settings::BufferLineHeightDiscriminants::Comfortable => {
948                                    settings::BufferLineHeight::Comfortable
949                                }
950                                settings::BufferLineHeightDiscriminants::Standard => {
951                                    settings::BufferLineHeight::Standard
952                                }
953                                settings::BufferLineHeightDiscriminants::Custom => {
954                                    let custom_value =
955                                        theme_settings::BufferLineHeight::from(*settings_value)
956                                            .value();
957                                    settings::BufferLineHeight::Custom(custom_value)
958                                }
959                            };
960                        },
961                    }),
962                    metadata: None,
963                },
964                pick_discriminant: |settings_content| {
965                    Some(
966                        settings_content
967                            .theme
968                            .buffer_line_height
969                            .as_ref()?
970                            .discriminant() as usize,
971                    )
972                },
973                fields: dynamic_variants::<settings::BufferLineHeight>()
974                    .into_iter()
975                    .map(|variant| match variant {
976                        settings::BufferLineHeightDiscriminants::Comfortable => vec![],
977                        settings::BufferLineHeightDiscriminants::Standard => vec![],
978                        settings::BufferLineHeightDiscriminants::Custom => vec![SettingItem {
979                            files: USER,
980                            title: "Custom Line Height",
981                            description: "Custom line height value (must be at least 1.0).",
982                            field: Box::new(SettingField {
983                                organization_override: None,
984                                json_path: Some("buffer_line_height"),
985                                pick: |settings_content| match settings_content
986                                    .theme
987                                    .buffer_line_height
988                                    .as_ref()
989                                {
990                                    Some(settings::BufferLineHeight::Custom(value)) => Some(value),
991                                    _ => None,
992                                },
993                                write: |settings_content, value, _| {
994                                    let Some(value) = value else {
995                                        return;
996                                    };
997                                    match settings_content.theme.buffer_line_height.as_mut() {
998                                        Some(settings::BufferLineHeight::Custom(line_height)) => {
999                                            *line_height = f32::max(value, 1.0)
1000                                        }
1001                                        _ => return,
1002                                    }
1003                                },
1004                            }),
1005                            metadata: None,
1006                        }],
1007                    })
1008                    .collect(),
1009            }),
1010            SettingsPageItem::SettingItem(SettingItem {
1011                files: USER,
1012                title: "Font Features",
1013                description: "The OpenType features to enable for rendering in text buffers.",
1014                field: Box::new(
1015                    SettingField {
1016                        organization_override: None,
1017                        json_path: Some("buffer_font_features"),
1018                        pick: |settings_content| {
1019                            settings_content.theme.buffer_font_features.as_ref()
1020                        },
1021                        write: |settings_content, value, _| {
1022                            settings_content.theme.buffer_font_features = value;
1023                        },
1024                    }
1025                    .unimplemented(),
1026                ),
1027                metadata: None,
1028            }),
1029            SettingsPageItem::SettingItem(SettingItem {
1030                files: USER,
1031                title: "Font Fallbacks",
1032                description: "The font fallbacks to use for rendering in text buffers.",
1033                field: Box::new(
1034                    SettingField {
1035                        organization_override: None,
1036                        json_path: Some("buffer_font_fallbacks"),
1037                        pick: |settings_content| {
1038                            settings_content.theme.buffer_font_fallbacks.as_ref()
1039                        },
1040                        write: |settings_content, value, _| {
1041                            settings_content.theme.buffer_font_fallbacks = value;
1042                        },
1043                    }
1044                    .unimplemented(),
1045                ),
1046                metadata: None,
1047            }),
1048        ]
1049    }
1050
1051    fn ui_font_section() -> [SettingsPageItem; 6] {
1052        [
1053            SettingsPageItem::SectionHeader("UI Font"),
1054            SettingsPageItem::SettingItem(SettingItem {
1055                title: "Font Family",
1056                description: "Font family for UI elements.",
1057                field: Box::new(SettingField {
1058                    organization_override: None,
1059                    json_path: Some("ui_font_family"),
1060                    pick: |settings_content| settings_content.theme.ui_font_family.as_ref(),
1061                    write: |settings_content, value, _| {
1062                        settings_content.theme.ui_font_family = value;
1063                    },
1064                }),
1065                metadata: None,
1066                files: USER,
1067            }),
1068            SettingsPageItem::SettingItem(SettingItem {
1069                title: "Font Size",
1070                description: "Font size for UI elements.",
1071                field: Box::new(SettingField {
1072                    organization_override: None,
1073                    json_path: Some("ui_font_size"),
1074                    pick: |settings_content| settings_content.theme.ui_font_size.as_ref(),
1075                    write: |settings_content, value, _| {
1076                        settings_content.theme.ui_font_size = value;
1077                    },
1078                }),
1079                metadata: None,
1080                files: USER,
1081            }),
1082            SettingsPageItem::SettingItem(SettingItem {
1083                title: "Font Weight",
1084                description: "Font weight for UI elements (100-900).",
1085                field: Box::new(SettingField {
1086                    organization_override: None,
1087                    json_path: Some("ui_font_weight"),
1088                    pick: |settings_content| settings_content.theme.ui_font_weight.as_ref(),
1089                    write: |settings_content, value, _| {
1090                        settings_content.theme.ui_font_weight = value;
1091                    },
1092                }),
1093                metadata: None,
1094                files: USER,
1095            }),
1096            SettingsPageItem::SettingItem(SettingItem {
1097                files: USER,
1098                title: "Font Features",
1099                description: "The OpenType features to enable for rendering in UI elements.",
1100                field: Box::new(
1101                    SettingField {
1102                        organization_override: None,
1103                        json_path: Some("ui_font_features"),
1104                        pick: |settings_content| settings_content.theme.ui_font_features.as_ref(),
1105                        write: |settings_content, value, _| {
1106                            settings_content.theme.ui_font_features = value;
1107                        },
1108                    }
1109                    .unimplemented(),
1110                ),
1111                metadata: None,
1112            }),
1113            SettingsPageItem::SettingItem(SettingItem {
1114                files: USER,
1115                title: "Font Fallbacks",
1116                description: "The font fallbacks to use for rendering in the UI.",
1117                field: Box::new(
1118                    SettingField {
1119                        organization_override: None,
1120                        json_path: Some("ui_font_fallbacks"),
1121                        pick: |settings_content| settings_content.theme.ui_font_fallbacks.as_ref(),
1122                        write: |settings_content, value, _| {
1123                            settings_content.theme.ui_font_fallbacks = value;
1124                        },
1125                    }
1126                    .unimplemented(),
1127                ),
1128                metadata: None,
1129            }),
1130        ]
1131    }
1132
1133    fn agent_panel_font_section() -> [SettingsPageItem; 3] {
1134        [
1135            SettingsPageItem::SectionHeader("Agent Panel Font"),
1136            SettingsPageItem::SettingItem(SettingItem {
1137                title: "UI Font Size",
1138                description: "Font size for agent response text in the agent panel. Falls back to the regular UI font size.",
1139                field: Box::new(SettingField {
1140                    organization_override: None,
1141                    json_path: Some("agent_ui_font_size"),
1142                    pick: |settings_content| {
1143                        settings_content
1144                            .theme
1145                            .agent_ui_font_size
1146                            .as_ref()
1147                            .or(settings_content.theme.ui_font_size.as_ref())
1148                    },
1149                    write: |settings_content, value, _| {
1150                        settings_content.theme.agent_ui_font_size = value;
1151                    },
1152                }),
1153                metadata: None,
1154                files: USER,
1155            }),
1156            SettingsPageItem::SettingItem(SettingItem {
1157                title: "Buffer Font Size",
1158                description: "Font size for user messages text in the agent panel.",
1159                field: Box::new(SettingField {
1160                    organization_override: None,
1161                    json_path: Some("agent_buffer_font_size"),
1162                    pick: |settings_content| {
1163                        settings_content
1164                            .theme
1165                            .agent_buffer_font_size
1166                            .as_ref()
1167                            .or(settings_content.theme.buffer_font_size.as_ref())
1168                    },
1169                    write: |settings_content, value, _| {
1170                        settings_content.theme.agent_buffer_font_size = value;
1171                    },
1172                }),
1173                metadata: None,
1174                files: USER,
1175            }),
1176        ]
1177    }
1178
1179    fn markdown_preview_font_section() -> [SettingsPageItem; 4] {
1180        [
1181            SettingsPageItem::SectionHeader("Markdown Preview Font"),
1182            SettingsPageItem::SettingItem(SettingItem {
1183                title: "Font Family",
1184                description: "Font family for the markdown preview. Falls back to the UI font family.",
1185                field: Box::new(SettingField {
1186                    organization_override: None,
1187                    json_path: Some("markdown_preview_font_family"),
1188                    pick: |settings_content| {
1189                        settings_content.theme.markdown_preview_font_family.as_ref()
1190                    },
1191                    write: |settings_content, value, _| {
1192                        settings_content.theme.markdown_preview_font_family = value;
1193                    },
1194                }),
1195                metadata: None,
1196                files: USER,
1197            }),
1198            SettingsPageItem::SettingItem(SettingItem {
1199                title: "Code Font Family",
1200                description: "Font family for code blocks in the markdown preview. Falls back to the editor font family.",
1201                field: Box::new(SettingField {
1202                    organization_override: None,
1203                    json_path: Some("markdown_preview_code_font_family"),
1204                    pick: |settings_content| {
1205                        settings_content
1206                            .theme
1207                            .markdown_preview_code_font_family
1208                            .as_ref()
1209                    },
1210                    write: |settings_content, value, _| {
1211                        settings_content.theme.markdown_preview_code_font_family = value;
1212                    },
1213                }),
1214                metadata: None,
1215                files: USER,
1216            }),
1217            SettingsPageItem::SettingItem(SettingItem {
1218                title: "Font Size",
1219                description: "Font size for the markdown preview. Falls back to the editor font size.",
1220                field: Box::new(SettingField {
1221                    organization_override: None,
1222                    json_path: Some("markdown_preview_font_size"),
1223                    pick: |settings_content| {
1224                        settings_content
1225                            .theme
1226                            .markdown_preview_font_size
1227                            .as_ref()
1228                            .or(settings_content.theme.buffer_font_size.as_ref())
1229                    },
1230                    write: |settings_content, value, _| {
1231                        settings_content.theme.markdown_preview_font_size = value;
1232                    },
1233                }),
1234                metadata: None,
1235                files: USER,
1236            }),
1237        ]
1238    }
1239
1240    fn text_rendering_section() -> [SettingsPageItem; 2] {
1241        [
1242            SettingsPageItem::SectionHeader("Text Rendering"),
1243            SettingsPageItem::SettingItem(SettingItem {
1244                title: "Text Rendering Mode",
1245                description: "The text rendering mode to use.",
1246                field: Box::new(SettingField {
1247                    organization_override: None,
1248                    json_path: Some("text_rendering_mode"),
1249                    pick: |settings_content| {
1250                        settings_content.workspace.text_rendering_mode.as_ref()
1251                    },
1252                    write: |settings_content, value, _| {
1253                        settings_content.workspace.text_rendering_mode = value;
1254                    },
1255                }),
1256                metadata: None,
1257                files: USER,
1258            }),
1259        ]
1260    }
1261
1262    fn cursor_section() -> [SettingsPageItem; 6] {
1263        [
1264            SettingsPageItem::SectionHeader("Cursor"),
1265            SettingsPageItem::SettingItem(SettingItem {
1266                title: "Multi Cursor Modifier",
1267                description: "Modifier key for adding multiple cursors.",
1268                field: Box::new(SettingField {
1269                    organization_override: None,
1270                    json_path: Some("multi_cursor_modifier"),
1271                    pick: |settings_content| settings_content.editor.multi_cursor_modifier.as_ref(),
1272                    write: |settings_content, value, _| {
1273                        settings_content.editor.multi_cursor_modifier = value;
1274                    },
1275                }),
1276                metadata: None,
1277                files: USER,
1278            }),
1279            SettingsPageItem::SettingItem(SettingItem {
1280                title: "Cursor Blink",
1281                description: "Whether the cursor blinks in the editor.",
1282                field: Box::new(SettingField {
1283                    organization_override: None,
1284                    json_path: Some("cursor_blink"),
1285                    pick: |settings_content| settings_content.editor.cursor_blink.as_ref(),
1286                    write: |settings_content, value, _| {
1287                        settings_content.editor.cursor_blink = value;
1288                    },
1289                }),
1290                metadata: None,
1291                files: USER,
1292            }),
1293            SettingsPageItem::SettingItem(SettingItem {
1294                title: "Cursor Shape",
1295                description: "Cursor shape for the editor.",
1296                field: Box::new(SettingField {
1297                    organization_override: None,
1298                    json_path: Some("cursor_shape"),
1299                    pick: |settings_content| settings_content.editor.cursor_shape.as_ref(),
1300                    write: |settings_content, value, _| {
1301                        settings_content.editor.cursor_shape = value;
1302                    },
1303                }),
1304                metadata: None,
1305                files: USER,
1306            }),
1307            SettingsPageItem::SettingItem(SettingItem {
1308                title: "Hide Mouse",
1309                description: "When to hide the mouse cursor.",
1310                field: Box::new(SettingField {
1311                    organization_override: None,
1312                    json_path: Some("hide_mouse"),
1313                    pick: |settings_content| settings_content.hide_mouse.as_ref(),
1314                    write: |settings_content, value, _| {
1315                        settings_content.hide_mouse = value;
1316                    },
1317                }),
1318                metadata: None,
1319                files: USER,
1320            }),
1321            SettingsPageItem::SettingItem(SettingItem {
1322                title: "Reduce Motion",
1323                description: "Whether to reduce non-essential motion, such as loading spinners, by rendering them in a static state.",
1324                field: Box::new(SettingField {
1325                    organization_override: None,
1326                    json_path: Some("reduce_motion"),
1327                    pick: |settings_content| settings_content.reduce_motion.as_ref(),
1328                    write: |settings_content, value, _| {
1329                        settings_content.reduce_motion = value;
1330                    },
1331                }),
1332                metadata: None,
1333                files: USER,
1334            }),
1335        ]
1336    }
1337
1338    fn highlighting_section() -> [SettingsPageItem; 6] {
1339        [
1340            SettingsPageItem::SectionHeader("Highlighting"),
1341            SettingsPageItem::SettingItem(SettingItem {
1342                title: "Unnecessary Code Fade",
1343                description: "How much to fade out unused code (0.0 - 0.9).",
1344                field: Box::new(SettingField {
1345                    organization_override: None,
1346                    json_path: Some("unnecessary_code_fade"),
1347                    pick: |settings_content| settings_content.theme.unnecessary_code_fade.as_ref(),
1348                    write: |settings_content, value, _| {
1349                        settings_content.theme.unnecessary_code_fade = value;
1350                    },
1351                }),
1352                metadata: None,
1353                files: USER,
1354            }),
1355            SettingsPageItem::SettingItem(SettingItem {
1356                title: "Current Line Highlight",
1357                description: "How to highlight the current line.",
1358                field: Box::new(SettingField {
1359                    organization_override: None,
1360                    json_path: Some("current_line_highlight"),
1361                    pick: |settings_content| {
1362                        settings_content.editor.current_line_highlight.as_ref()
1363                    },
1364                    write: |settings_content, value, _| {
1365                        settings_content.editor.current_line_highlight = value;
1366                    },
1367                }),
1368                metadata: None,
1369                files: USER,
1370            }),
1371            SettingsPageItem::SettingItem(SettingItem {
1372                title: "Selection Highlight",
1373                description: "Highlight all occurrences of selected text.",
1374                field: Box::new(SettingField {
1375                    organization_override: None,
1376                    json_path: Some("selection_highlight"),
1377                    pick: |settings_content| settings_content.editor.selection_highlight.as_ref(),
1378                    write: |settings_content, value, _| {
1379                        settings_content.editor.selection_highlight = value;
1380                    },
1381                }),
1382                metadata: None,
1383                files: USER,
1384            }),
1385            SettingsPageItem::SettingItem(SettingItem {
1386                title: "Rounded Selection",
1387                description: "Whether the text selection should have rounded corners.",
1388                field: Box::new(SettingField {
1389                    organization_override: None,
1390                    json_path: Some("rounded_selection"),
1391                    pick: |settings_content| settings_content.editor.rounded_selection.as_ref(),
1392                    write: |settings_content, value, _| {
1393                        settings_content.editor.rounded_selection = value;
1394                    },
1395                }),
1396                metadata: None,
1397                files: USER,
1398            }),
1399            SettingsPageItem::SettingItem(SettingItem {
1400                title: "Minimum Contrast For Highlights",
1401                description: "The minimum APCA perceptual contrast to maintain when rendering text over highlight backgrounds.",
1402                field: Box::new(SettingField {
1403                    organization_override: None,
1404                    json_path: Some("minimum_contrast_for_highlights"),
1405                    pick: |settings_content| {
1406                        settings_content
1407                            .editor
1408                            .minimum_contrast_for_highlights
1409                            .as_ref()
1410                    },
1411                    write: |settings_content, value, _| {
1412                        settings_content.editor.minimum_contrast_for_highlights = value;
1413                    },
1414                }),
1415                metadata: None,
1416                files: USER,
1417            }),
1418        ]
1419    }
1420
1421    fn guides_section() -> [SettingsPageItem; 3] {
1422        [
1423            SettingsPageItem::SectionHeader("Guides"),
1424            SettingsPageItem::SettingItem(SettingItem {
1425                title: "Show Wrap Guides",
1426                description: "Show wrap guides (vertical rulers).",
1427                field: Box::new(SettingField {
1428                    organization_override: None,
1429                    json_path: Some("show_wrap_guides"),
1430                    pick: |settings_content| {
1431                        settings_content
1432                            .project
1433                            .all_languages
1434                            .defaults
1435                            .show_wrap_guides
1436                            .as_ref()
1437                    },
1438                    write: |settings_content, value, _| {
1439                        settings_content
1440                            .project
1441                            .all_languages
1442                            .defaults
1443                            .show_wrap_guides = value;
1444                    },
1445                }),
1446                metadata: None,
1447                files: USER | PROJECT,
1448            }),
1449            // todo(settings_ui): This needs a custom component
1450            SettingsPageItem::SettingItem(SettingItem {
1451                title: "Wrap Guides",
1452                description: "Character counts at which to show wrap guides.",
1453                field: Box::new(
1454                    SettingField {
1455                        organization_override: None,
1456                        json_path: Some("wrap_guides"),
1457                        pick: |settings_content| {
1458                            settings_content
1459                                .project
1460                                .all_languages
1461                                .defaults
1462                                .wrap_guides
1463                                .as_ref()
1464                        },
1465                        write: |settings_content, value, _| {
1466                            settings_content.project.all_languages.defaults.wrap_guides = value;
1467                        },
1468                    }
1469                    .unimplemented(),
1470                ),
1471                metadata: None,
1472                files: USER | PROJECT,
1473            }),
1474        ]
1475    }
1476
1477    let items: Box<[SettingsPageItem]> = concat_sections!(
1478        theme_section(),
1479        buffer_font_section(),
1480        ui_font_section(),
1481        agent_panel_font_section(),
1482        markdown_preview_font_section(),
1483        text_rendering_section(),
1484        cursor_section(),
1485        highlighting_section(),
1486        guides_section(),
1487    );
1488
1489    SettingsPage {
1490        title: "Appearance",
1491        items,
1492    }
1493}
1494
1495fn keymap_page() -> SettingsPage {
1496    fn keybindings_section() -> [SettingsPageItem; 2] {
1497        [
1498            SettingsPageItem::SectionHeader("Keybindings"),
1499            SettingsPageItem::ActionLink(ActionLink {
1500                title: "Edit Keybindings".into(),
1501                description: Some("Customize keybindings in the keymap editor.".into()),
1502                button_text: "Open Keymap".into(),
1503                on_click: Arc::new(|settings_window, window, cx| {
1504                    let Some(original_window) = settings_window.original_window else {
1505                        return;
1506                    };
1507                    original_window
1508                        .update(cx, |_workspace, original_window, cx| {
1509                            original_window
1510                                .dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx);
1511                            original_window.activate_window();
1512                        })
1513                        .ok();
1514                    window.remove_window();
1515                }),
1516                files: USER,
1517            }),
1518        ]
1519    }
1520
1521    fn base_keymap_section() -> [SettingsPageItem; 2] {
1522        [
1523            SettingsPageItem::SectionHeader("Base Keymap"),
1524            SettingsPageItem::SettingItem(SettingItem {
1525                title: "Base Keymap",
1526                description: "The name of a base set of key bindings to use.",
1527                field: Box::new(SettingField {
1528                    organization_override: None,
1529                    json_path: Some("base_keymap"),
1530                    pick: |settings_content| settings_content.base_keymap.as_ref(),
1531                    write: |settings_content, value, _| {
1532                        settings_content.base_keymap = value;
1533                    },
1534                }),
1535                metadata: Some(Box::new(SettingsFieldMetadata {
1536                    should_do_titlecase: Some(false),
1537                    ..Default::default()
1538                })),
1539                files: USER,
1540            }),
1541        ]
1542    }
1543
1544    fn modal_editing_section() -> [SettingsPageItem; 3] {
1545        [
1546            SettingsPageItem::SectionHeader("Modal Editing"),
1547            SettingsPageItem::SettingItem(SettingItem {
1548                title: "Vim Mode",
1549                description: "Enable Vim mode and key bindings.",
1550                field: Box::new(SettingField {
1551                    organization_override: None,
1552                    json_path: Some("vim_mode"),
1553                    pick: |settings_content| settings_content.vim_mode.as_ref(),
1554                    write: write_vim_mode,
1555                }),
1556                metadata: None,
1557                files: USER,
1558            }),
1559            SettingsPageItem::SettingItem(SettingItem {
1560                title: "Helix Mode",
1561                description: "Enable Helix mode and key bindings.",
1562                field: Box::new(SettingField {
1563                    organization_override: None,
1564                    json_path: Some("helix_mode"),
1565                    pick: |settings_content| settings_content.helix_mode.as_ref(),
1566                    write: write_helix_mode,
1567                }),
1568                metadata: None,
1569                files: USER,
1570            }),
1571        ]
1572    }
1573
1574    let items: Box<[SettingsPageItem]> = concat_sections!(
1575        keybindings_section(),
1576        base_keymap_section(),
1577        modal_editing_section(),
1578    );
1579
1580    SettingsPage {
1581        title: "Keymap",
1582        items,
1583    }
1584}
1585
1586fn editor_page() -> SettingsPage {
1587    fn auto_save_section() -> [SettingsPageItem; 2] {
1588        [
1589            SettingsPageItem::SectionHeader("Auto Save"),
1590            SettingsPageItem::DynamicItem(DynamicItem {
1591                discriminant: SettingItem {
1592                    files: USER,
1593                    title: "Auto Save Mode",
1594                    description: "When to auto save buffer changes.",
1595                    field: Box::new(SettingField {
1596                        organization_override: None,
1597                        json_path: Some("autosave$"),
1598                        pick: |settings_content| {
1599                            Some(
1600                                &dynamic_variants::<settings::AutosaveSetting>()[settings_content
1601                                    .workspace
1602                                    .autosave
1603                                    .as_ref()?
1604                                    .discriminant()
1605                                    as usize],
1606                            )
1607                        },
1608                        write: |settings_content, value, _| {
1609                            let Some(value) = value else {
1610                                settings_content.workspace.autosave = None;
1611                                return;
1612                            };
1613                            let settings_value = settings_content
1614                                .workspace
1615                                .autosave
1616                                .get_or_insert_with(|| settings::AutosaveSetting::Off);
1617                            *settings_value = match value {
1618                                settings::AutosaveSettingDiscriminants::Off => {
1619                                    settings::AutosaveSetting::Off
1620                                }
1621                                settings::AutosaveSettingDiscriminants::AfterDelay => {
1622                                    let milliseconds = match settings_value {
1623                                        settings::AutosaveSetting::AfterDelay { milliseconds } => {
1624                                            *milliseconds
1625                                        }
1626                                        _ => settings::DelayMs(1000),
1627                                    };
1628                                    settings::AutosaveSetting::AfterDelay { milliseconds }
1629                                }
1630                                settings::AutosaveSettingDiscriminants::OnFocusChange => {
1631                                    settings::AutosaveSetting::OnFocusChange
1632                                }
1633                                settings::AutosaveSettingDiscriminants::OnWindowChange => {
1634                                    settings::AutosaveSetting::OnWindowChange
1635                                }
1636                            };
1637                        },
1638                    }),
1639                    metadata: None,
1640                },
1641                pick_discriminant: |settings_content| {
1642                    Some(settings_content.workspace.autosave.as_ref()?.discriminant() as usize)
1643                },
1644                fields: dynamic_variants::<settings::AutosaveSetting>()
1645                    .into_iter()
1646                    .map(|variant| match variant {
1647                        settings::AutosaveSettingDiscriminants::Off => vec![],
1648                        settings::AutosaveSettingDiscriminants::AfterDelay => vec![SettingItem {
1649                            files: USER,
1650                            title: "Delay (milliseconds)",
1651                            description: "Save after inactivity period (in milliseconds).",
1652                            field: Box::new(SettingField {
1653                                organization_override: None,
1654                                json_path: Some("autosave.after_delay.milliseconds"),
1655                                pick: |settings_content| match settings_content
1656                                    .workspace
1657                                    .autosave
1658                                    .as_ref()
1659                                {
1660                                    Some(settings::AutosaveSetting::AfterDelay {
1661                                        milliseconds,
1662                                    }) => Some(milliseconds),
1663                                    _ => None,
1664                                },
1665                                write: |settings_content, value, _| {
1666                                    let Some(value) = value else {
1667                                        settings_content.workspace.autosave = None;
1668                                        return;
1669                                    };
1670                                    match settings_content.workspace.autosave.as_mut() {
1671                                        Some(settings::AutosaveSetting::AfterDelay {
1672                                            milliseconds,
1673                                        }) => *milliseconds = value,
1674                                        _ => return,
1675                                    }
1676                                },
1677                            }),
1678                            metadata: None,
1679                        }],
1680                        settings::AutosaveSettingDiscriminants::OnFocusChange => vec![],
1681                        settings::AutosaveSettingDiscriminants::OnWindowChange => vec![],
1682                    })
1683                    .collect(),
1684            }),
1685        ]
1686    }
1687
1688    fn which_key_section() -> [SettingsPageItem; 3] {
1689        [
1690            SettingsPageItem::SectionHeader("Which-key Menu"),
1691            SettingsPageItem::SettingItem(SettingItem {
1692                title: "Show Which-key Menu",
1693                description: "Display the which-key menu with matching bindings while a multi-stroke binding is pending.",
1694                field: Box::new(SettingField {
1695                    organization_override: None,
1696                    json_path: Some("which_key.enabled"),
1697                    pick: |settings_content| {
1698                        settings_content
1699                            .which_key
1700                            .as_ref()
1701                            .and_then(|settings| settings.enabled.as_ref())
1702                    },
1703                    write: |settings_content, value, _| {
1704                        settings_content.which_key.get_or_insert_default().enabled = value;
1705                    },
1706                }),
1707                metadata: None,
1708                files: USER,
1709            }),
1710            SettingsPageItem::SettingItem(SettingItem {
1711                title: "Menu Delay",
1712                description: "Delay in milliseconds before the which-key menu appears.",
1713                field: Box::new(SettingField {
1714                    organization_override: None,
1715                    json_path: Some("which_key.delay_ms"),
1716                    pick: |settings_content| {
1717                        settings_content
1718                            .which_key
1719                            .as_ref()
1720                            .and_then(|settings| settings.delay_ms.as_ref())
1721                    },
1722                    write: |settings_content, value, _| {
1723                        settings_content.which_key.get_or_insert_default().delay_ms = value;
1724                    },
1725                }),
1726                metadata: None,
1727                files: USER,
1728            }),
1729        ]
1730    }
1731
1732    fn multibuffer_section() -> [SettingsPageItem; 7] {
1733        [
1734            SettingsPageItem::SectionHeader("Multibuffer"),
1735            SettingsPageItem::SettingItem(SettingItem {
1736                title: "Double Click In Multibuffer",
1737                description: "What to do when multibuffer is double-clicked in some of its excerpts.",
1738                field: Box::new(SettingField {
1739                    organization_override: None,
1740                    json_path: Some("double_click_in_multibuffer"),
1741                    pick: |settings_content| {
1742                        settings_content.editor.double_click_in_multibuffer.as_ref()
1743                    },
1744                    write: |settings_content, value, _| {
1745                        settings_content.editor.double_click_in_multibuffer = value;
1746                    },
1747                }),
1748                metadata: None,
1749                files: USER,
1750            }),
1751            SettingsPageItem::SettingItem(SettingItem {
1752                title: "Expand Excerpt Lines",
1753                description: "How many lines to expand the multibuffer excerpts by default.",
1754                field: Box::new(SettingField {
1755                    organization_override: None,
1756                    json_path: Some("expand_excerpt_lines"),
1757                    pick: |settings_content| settings_content.editor.expand_excerpt_lines.as_ref(),
1758                    write: |settings_content, value, _| {
1759                        settings_content.editor.expand_excerpt_lines = value;
1760                    },
1761                }),
1762                metadata: None,
1763                files: USER,
1764            }),
1765            SettingsPageItem::SettingItem(SettingItem {
1766                title: "Excerpt Context Lines",
1767                description: "How many lines of context to provide in multibuffer excerpts by default.",
1768                field: Box::new(SettingField {
1769                    organization_override: None,
1770                    json_path: Some("excerpt_context_lines"),
1771                    pick: |settings_content| settings_content.editor.excerpt_context_lines.as_ref(),
1772                    write: |settings_content, value, _| {
1773                        settings_content.editor.excerpt_context_lines = value;
1774                    },
1775                }),
1776                metadata: None,
1777                files: USER,
1778            }),
1779            SettingsPageItem::SettingItem(SettingItem {
1780                title: "Expand Outlines With Depth",
1781                description: "Default depth to expand outline items in the current file.",
1782                field: Box::new(SettingField {
1783                    organization_override: None,
1784                    json_path: Some("outline_panel.expand_outlines_with_depth"),
1785                    pick: |settings_content| {
1786                        settings_content
1787                            .outline_panel
1788                            .as_ref()
1789                            .and_then(|outline_panel| {
1790                                outline_panel.expand_outlines_with_depth.as_ref()
1791                            })
1792                    },
1793                    write: |settings_content, value, _| {
1794                        settings_content
1795                            .outline_panel
1796                            .get_or_insert_default()
1797                            .expand_outlines_with_depth = value;
1798                    },
1799                }),
1800                metadata: None,
1801                files: USER,
1802            }),
1803            SettingsPageItem::SettingItem(SettingItem {
1804                title: "Diff View Style",
1805                description: "How to display diffs in the editor.",
1806                field: Box::new(SettingField {
1807                    organization_override: None,
1808                    json_path: Some("diff_view_style"),
1809                    pick: |settings_content| settings_content.editor.diff_view_style.as_ref(),
1810                    write: |settings_content, value, _| {
1811                        settings_content.editor.diff_view_style = value;
1812                    },
1813                }),
1814                metadata: None,
1815                files: USER,
1816            }),
1817            SettingsPageItem::SettingItem(SettingItem {
1818                title: "Minimum Split Diff Width",
1819                description: "The minimum width (in columns) at which the split diff view is used. When the editor is narrower, the diff view automatically switches to unified mode. Set to 0 to disable.",
1820                field: Box::new(SettingField {
1821                    organization_override: None,
1822                    json_path: Some("minimum_split_diff_width"),
1823                    pick: |settings_content| {
1824                        settings_content.editor.minimum_split_diff_width.as_ref()
1825                    },
1826                    write: |settings_content, value, _| {
1827                        settings_content.editor.minimum_split_diff_width = value;
1828                    },
1829                }),
1830                metadata: None,
1831                files: USER,
1832            }),
1833        ]
1834    }
1835
1836    fn scrolling_section() -> [SettingsPageItem; 9] {
1837        [
1838            SettingsPageItem::SectionHeader("Scrolling"),
1839            SettingsPageItem::SettingItem(SettingItem {
1840                title: "Scroll Beyond Last Line",
1841                description: "Whether the editor will scroll beyond the last line.",
1842                field: Box::new(SettingField {
1843                    organization_override: None,
1844                    json_path: Some("scroll_beyond_last_line"),
1845                    pick: |settings_content| {
1846                        settings_content.editor.scroll_beyond_last_line.as_ref()
1847                    },
1848                    write: |settings_content, value, _| {
1849                        settings_content.editor.scroll_beyond_last_line = value;
1850                    },
1851                }),
1852                metadata: None,
1853                files: USER,
1854            }),
1855            SettingsPageItem::SettingItem(SettingItem {
1856                title: "Vertical Scroll Margin",
1857                description: "The number of lines to keep above/below the cursor when auto-scrolling.",
1858                field: Box::new(SettingField {
1859                    organization_override: None,
1860                    json_path: Some("vertical_scroll_margin"),
1861                    pick: |settings_content| {
1862                        settings_content.editor.vertical_scroll_margin.as_ref()
1863                    },
1864                    write: |settings_content, value, _| {
1865                        settings_content.editor.vertical_scroll_margin = value;
1866                    },
1867                }),
1868                metadata: None,
1869                files: USER,
1870            }),
1871            SettingsPageItem::SettingItem(SettingItem {
1872                title: "Horizontal Scroll Margin",
1873                description: "The number of characters to keep on either side when scrolling with the mouse.",
1874                field: Box::new(SettingField {
1875                    organization_override: None,
1876                    json_path: Some("horizontal_scroll_margin"),
1877                    pick: |settings_content| {
1878                        settings_content.editor.horizontal_scroll_margin.as_ref()
1879                    },
1880                    write: |settings_content, value, _| {
1881                        settings_content.editor.horizontal_scroll_margin = value;
1882                    },
1883                }),
1884                metadata: None,
1885                files: USER,
1886            }),
1887            SettingsPageItem::SettingItem(SettingItem {
1888                title: "Scroll Sensitivity",
1889                description: "Scroll sensitivity multiplier for both horizontal and vertical scrolling.",
1890                field: Box::new(SettingField {
1891                    organization_override: None,
1892                    json_path: Some("scroll_sensitivity"),
1893                    pick: |settings_content| settings_content.editor.scroll_sensitivity.as_ref(),
1894                    write: |settings_content, value, _| {
1895                        settings_content.editor.scroll_sensitivity = value;
1896                    },
1897                }),
1898                metadata: None,
1899                files: USER,
1900            }),
1901            SettingsPageItem::SettingItem(SettingItem {
1902                title: "Mouse Wheel Zoom",
1903                description: "Whether to zoom the editor font size with the mouse wheel while holding the primary modifier key.",
1904                field: Box::new(SettingField {
1905                    organization_override: None,
1906                    json_path: Some("mouse_wheel_zoom"),
1907                    pick: |settings_content| settings_content.editor.mouse_wheel_zoom.as_ref(),
1908                    write: |settings_content, value, _| {
1909                        settings_content.editor.mouse_wheel_zoom = value;
1910                    },
1911                }),
1912                metadata: None,
1913                files: USER,
1914            }),
1915            SettingsPageItem::SettingItem(SettingItem {
1916                title: "Fast Scroll Sensitivity",
1917                description: "Fast scroll sensitivity multiplier for both horizontal and vertical scrolling.",
1918                field: Box::new(SettingField {
1919                    organization_override: None,
1920                    json_path: Some("fast_scroll_sensitivity"),
1921                    pick: |settings_content| {
1922                        settings_content.editor.fast_scroll_sensitivity.as_ref()
1923                    },
1924                    write: |settings_content, value, _| {
1925                        settings_content.editor.fast_scroll_sensitivity = value;
1926                    },
1927                }),
1928                metadata: None,
1929                files: USER,
1930            }),
1931            SettingsPageItem::SettingItem(SettingItem {
1932                title: "Autoscroll On Clicks",
1933                description: "Whether to scroll when clicking near the edge of the visible text area.",
1934                field: Box::new(SettingField {
1935                    organization_override: None,
1936                    json_path: Some("autoscroll_on_clicks"),
1937                    pick: |settings_content| settings_content.editor.autoscroll_on_clicks.as_ref(),
1938                    write: |settings_content, value, _| {
1939                        settings_content.editor.autoscroll_on_clicks = value;
1940                    },
1941                }),
1942                metadata: None,
1943                files: USER,
1944            }),
1945            SettingsPageItem::SettingItem(SettingItem {
1946                title: "Sticky Scroll",
1947                description: "Whether to stick scopes to the top of the editor",
1948                field: Box::new(SettingField {
1949                    organization_override: None,
1950                    json_path: Some("sticky_scroll.enabled"),
1951                    pick: |settings_content| {
1952                        settings_content
1953                            .editor
1954                            .sticky_scroll
1955                            .as_ref()
1956                            .and_then(|sticky_scroll| sticky_scroll.enabled.as_ref())
1957                    },
1958                    write: |settings_content, value, _| {
1959                        settings_content
1960                            .editor
1961                            .sticky_scroll
1962                            .get_or_insert_default()
1963                            .enabled = value;
1964                    },
1965                }),
1966                metadata: None,
1967                files: USER,
1968            }),
1969        ]
1970    }
1971
1972    fn signature_help_section() -> [SettingsPageItem; 4] {
1973        [
1974            SettingsPageItem::SectionHeader("Signature Help"),
1975            SettingsPageItem::SettingItem(SettingItem {
1976                title: "Auto Signature Help",
1977                description: "Automatically show a signature help pop-up.",
1978                field: Box::new(SettingField {
1979                    organization_override: None,
1980                    json_path: Some("auto_signature_help"),
1981                    pick: |settings_content| settings_content.editor.auto_signature_help.as_ref(),
1982                    write: |settings_content, value, _| {
1983                        settings_content.editor.auto_signature_help = value;
1984                    },
1985                }),
1986                metadata: None,
1987                files: USER,
1988            }),
1989            SettingsPageItem::SettingItem(SettingItem {
1990                title: "Show Signature Help After Edits",
1991                description: "Show the signature help pop-up after completions or bracket pairs are inserted.",
1992                field: Box::new(SettingField {
1993                    organization_override: None,
1994                    json_path: Some("show_signature_help_after_edits"),
1995                    pick: |settings_content| {
1996                        settings_content
1997                            .editor
1998                            .show_signature_help_after_edits
1999                            .as_ref()
2000                    },
2001                    write: |settings_content, value, _| {
2002                        settings_content.editor.show_signature_help_after_edits = value;
2003                    },
2004                }),
2005                metadata: None,
2006                files: USER,
2007            }),
2008            SettingsPageItem::SettingItem(SettingItem {
2009                title: "Snippet Sort Order",
2010                description: "Determines how snippets are sorted relative to other completion items.",
2011                field: Box::new(SettingField {
2012                    organization_override: None,
2013                    json_path: Some("snippet_sort_order"),
2014                    pick: |settings_content| settings_content.editor.snippet_sort_order.as_ref(),
2015                    write: |settings_content, value, _| {
2016                        settings_content.editor.snippet_sort_order = value;
2017                    },
2018                }),
2019                metadata: None,
2020                files: USER,
2021            }),
2022        ]
2023    }
2024
2025    fn hover_popover_section() -> [SettingsPageItem; 5] {
2026        [
2027            SettingsPageItem::SectionHeader("Hover Popover"),
2028            SettingsPageItem::SettingItem(SettingItem {
2029                title: "Enabled",
2030                description: "Show the informational hover box when moving the mouse over symbols in the editor.",
2031                field: Box::new(SettingField {
2032                    organization_override: None,
2033                    json_path: Some("hover_popover_enabled"),
2034                    pick: |settings_content| settings_content.editor.hover_popover_enabled.as_ref(),
2035                    write: |settings_content, value, _| {
2036                        settings_content.editor.hover_popover_enabled = value;
2037                    },
2038                }),
2039                metadata: None,
2040                files: USER,
2041            }),
2042            // todo(settings ui): add units to this number input
2043            SettingsPageItem::SettingItem(SettingItem {
2044                title: "Delay",
2045                description: "Time to wait in milliseconds before showing the informational hover box.",
2046                field: Box::new(SettingField {
2047                    organization_override: None,
2048                    json_path: Some("hover_popover_delay"),
2049                    pick: |settings_content| settings_content.editor.hover_popover_delay.as_ref(),
2050                    write: |settings_content, value, _| {
2051                        settings_content.editor.hover_popover_delay = value;
2052                    },
2053                }),
2054                metadata: None,
2055                files: USER,
2056            }),
2057            SettingsPageItem::SettingItem(SettingItem {
2058                title: "Sticky",
2059                description: "Whether the hover popover sticks when the mouse moves toward it, allowing interaction with its contents.",
2060                field: Box::new(SettingField {
2061                    organization_override: None,
2062                    json_path: Some("hover_popover_sticky"),
2063                    pick: |settings_content| settings_content.editor.hover_popover_sticky.as_ref(),
2064                    write: |settings_content, value, _| {
2065                        settings_content.editor.hover_popover_sticky = value;
2066                    },
2067                }),
2068                metadata: None,
2069                files: USER,
2070            }),
2071            // todo(settings ui): add units to this number input
2072            SettingsPageItem::SettingItem(SettingItem {
2073                title: "Hiding Delay",
2074                description: "Time to wait in milliseconds before hiding the hover popover after the mouse moves away.",
2075                field: Box::new(SettingField {
2076                    organization_override: None,
2077                    json_path: Some("hover_popover_hiding_delay"),
2078                    pick: |settings_content| {
2079                        settings_content.editor.hover_popover_hiding_delay.as_ref()
2080                    },
2081                    write: |settings_content, value, _| {
2082                        settings_content.editor.hover_popover_hiding_delay = value;
2083                    },
2084                }),
2085                metadata: None,
2086                files: USER,
2087            }),
2088        ]
2089    }
2090
2091    fn drag_and_drop_selection_section() -> [SettingsPageItem; 3] {
2092        [
2093            SettingsPageItem::SectionHeader("Drag And Drop Selection"),
2094            SettingsPageItem::SettingItem(SettingItem {
2095                title: "Enabled",
2096                description: "Enable drag and drop selection.",
2097                field: Box::new(SettingField {
2098                    organization_override: None,
2099                    json_path: Some("drag_and_drop_selection.enabled"),
2100                    pick: |settings_content| {
2101                        settings_content
2102                            .editor
2103                            .drag_and_drop_selection
2104                            .as_ref()
2105                            .and_then(|drag_and_drop| drag_and_drop.enabled.as_ref())
2106                    },
2107                    write: |settings_content, value, _| {
2108                        settings_content
2109                            .editor
2110                            .drag_and_drop_selection
2111                            .get_or_insert_default()
2112                            .enabled = value;
2113                    },
2114                }),
2115                metadata: None,
2116                files: USER,
2117            }),
2118            SettingsPageItem::SettingItem(SettingItem {
2119                title: "Delay",
2120                description: "Delay in milliseconds before drag and drop selection starts.",
2121                field: Box::new(SettingField {
2122                    organization_override: None,
2123                    json_path: Some("drag_and_drop_selection.delay"),
2124                    pick: |settings_content| {
2125                        settings_content
2126                            .editor
2127                            .drag_and_drop_selection
2128                            .as_ref()
2129                            .and_then(|drag_and_drop| drag_and_drop.delay.as_ref())
2130                    },
2131                    write: |settings_content, value, _| {
2132                        settings_content
2133                            .editor
2134                            .drag_and_drop_selection
2135                            .get_or_insert_default()
2136                            .delay = value;
2137                    },
2138                }),
2139                metadata: None,
2140                files: USER,
2141            }),
2142        ]
2143    }
2144
2145    fn gutter_section() -> [SettingsPageItem; 9] {
2146        [
2147            SettingsPageItem::SectionHeader("Gutter"),
2148            SettingsPageItem::SettingItem(SettingItem {
2149                title: "Show Line Numbers",
2150                description: "Show line numbers in the gutter.",
2151                field: Box::new(SettingField {
2152                    organization_override: None,
2153                    json_path: Some("gutter.line_numbers"),
2154                    pick: |settings_content| {
2155                        settings_content
2156                            .editor
2157                            .gutter
2158                            .as_ref()
2159                            .and_then(|gutter| gutter.line_numbers.as_ref())
2160                    },
2161                    write: |settings_content, value, _| {
2162                        settings_content
2163                            .editor
2164                            .gutter
2165                            .get_or_insert_default()
2166                            .line_numbers = value;
2167                    },
2168                }),
2169                metadata: None,
2170                files: USER,
2171            }),
2172            SettingsPageItem::SettingItem(SettingItem {
2173                title: "Relative Line Numbers",
2174                description: "Controls line number display in the editor's gutter. \"disabled\" shows absolute line numbers, \"enabled\" shows relative line numbers for each absolute line, and \"wrapped\" shows relative line numbers for every line, absolute or wrapped.",
2175                field: Box::new(SettingField {
2176                    organization_override: None,
2177                    json_path: Some("relative_line_numbers"),
2178                    pick: |settings_content| settings_content.editor.relative_line_numbers.as_ref(),
2179                    write: |settings_content, value, _| {
2180                        settings_content.editor.relative_line_numbers = value;
2181                    },
2182                }),
2183                metadata: None,
2184                files: USER,
2185            }),
2186            SettingsPageItem::SettingItem(SettingItem {
2187                title: "Show Runnables",
2188                description: "Show runnable buttons in the gutter.",
2189                field: Box::new(SettingField {
2190                    organization_override: None,
2191                    json_path: Some("gutter.runnables"),
2192                    pick: |settings_content| {
2193                        settings_content
2194                            .editor
2195                            .gutter
2196                            .as_ref()
2197                            .and_then(|gutter| gutter.runnables.as_ref())
2198                    },
2199                    write: |settings_content, value, _| {
2200                        settings_content
2201                            .editor
2202                            .gutter
2203                            .get_or_insert_default()
2204                            .runnables = value;
2205                    },
2206                }),
2207                metadata: None,
2208                files: USER,
2209            }),
2210            SettingsPageItem::SettingItem(SettingItem {
2211                title: "Show Breakpoints",
2212                description: "Show breakpoints in the gutter.",
2213                field: Box::new(SettingField {
2214                    organization_override: None,
2215                    json_path: Some("gutter.breakpoints"),
2216                    pick: |settings_content| {
2217                        settings_content
2218                            .editor
2219                            .gutter
2220                            .as_ref()
2221                            .and_then(|gutter| gutter.breakpoints.as_ref())
2222                    },
2223                    write: |settings_content, value, _| {
2224                        settings_content
2225                            .editor
2226                            .gutter
2227                            .get_or_insert_default()
2228                            .breakpoints = value;
2229                    },
2230                }),
2231                metadata: None,
2232                files: USER,
2233            }),
2234            SettingsPageItem::SettingItem(SettingItem {
2235                title: "Show Bookmarks",
2236                description: "Show bookmarks in the gutter.",
2237                field: Box::new(SettingField {
2238                    organization_override: None,
2239                    json_path: Some("gutter.bookmarks"),
2240                    pick: |settings_content| {
2241                        settings_content
2242                            .editor
2243                            .gutter
2244                            .as_ref()
2245                            .and_then(|gutter| gutter.bookmarks.as_ref())
2246                    },
2247                    write: |settings_content, value, _| {
2248                        settings_content
2249                            .editor
2250                            .gutter
2251                            .get_or_insert_default()
2252                            .bookmarks = value;
2253                    },
2254                }),
2255                metadata: None,
2256                files: USER,
2257            }),
2258            SettingsPageItem::SettingItem(SettingItem {
2259                title: "Show Folds",
2260                description: "Show code folding controls in the gutter.",
2261                field: Box::new(SettingField {
2262                    organization_override: None,
2263                    json_path: Some("gutter.folds"),
2264                    pick: |settings_content| {
2265                        settings_content
2266                            .editor
2267                            .gutter
2268                            .as_ref()
2269                            .and_then(|gutter| gutter.folds.as_ref())
2270                    },
2271                    write: |settings_content, value, _| {
2272                        settings_content.editor.gutter.get_or_insert_default().folds = value;
2273                    },
2274                }),
2275                metadata: None,
2276                files: USER,
2277            }),
2278            SettingsPageItem::SettingItem(SettingItem {
2279                title: "Min Line Number Digits",
2280                description: "Minimum number of characters to reserve space for in the gutter.",
2281                field: Box::new(SettingField {
2282                    organization_override: None,
2283                    json_path: Some("gutter.min_line_number_digits"),
2284                    pick: |settings_content| {
2285                        settings_content
2286                            .editor
2287                            .gutter
2288                            .as_ref()
2289                            .and_then(|gutter| gutter.min_line_number_digits.as_ref())
2290                    },
2291                    write: |settings_content, value, _| {
2292                        settings_content
2293                            .editor
2294                            .gutter
2295                            .get_or_insert_default()
2296                            .min_line_number_digits = value;
2297                    },
2298                }),
2299                metadata: None,
2300                files: USER,
2301            }),
2302            SettingsPageItem::SettingItem(SettingItem {
2303                title: "Inline Code Actions",
2304                description: "Show code action button at start of buffer line.",
2305                field: Box::new(SettingField {
2306                    organization_override: None,
2307                    json_path: Some("inline_code_actions"),
2308                    pick: |settings_content| settings_content.editor.inline_code_actions.as_ref(),
2309                    write: |settings_content, value, _| {
2310                        settings_content.editor.inline_code_actions = value;
2311                    },
2312                }),
2313                metadata: None,
2314                files: USER,
2315            }),
2316        ]
2317    }
2318
2319    fn scrollbar_section() -> [SettingsPageItem; 10] {
2320        [
2321            SettingsPageItem::SectionHeader("Scrollbar"),
2322            SettingsPageItem::SettingItem(SettingItem {
2323                title: "Show",
2324                description: "When to show the scrollbar in the editor.",
2325                field: Box::new(SettingField {
2326                    organization_override: None,
2327                    json_path: Some("scrollbar"),
2328                    pick: |settings_content| {
2329                        settings_content.editor.scrollbar.as_ref()?.show.as_ref()
2330                    },
2331                    write: |settings_content, value, _| {
2332                        settings_content
2333                            .editor
2334                            .scrollbar
2335                            .get_or_insert_default()
2336                            .show = value;
2337                    },
2338                }),
2339                metadata: None,
2340                files: USER,
2341            }),
2342            SettingsPageItem::SettingItem(SettingItem {
2343                title: "Cursors",
2344                description: "Show cursor positions in the scrollbar.",
2345                field: Box::new(SettingField {
2346                    organization_override: None,
2347                    json_path: Some("scrollbar.cursors"),
2348                    pick: |settings_content| {
2349                        settings_content.editor.scrollbar.as_ref()?.cursors.as_ref()
2350                    },
2351                    write: |settings_content, value, _| {
2352                        settings_content
2353                            .editor
2354                            .scrollbar
2355                            .get_or_insert_default()
2356                            .cursors = value;
2357                    },
2358                }),
2359                metadata: None,
2360                files: USER,
2361            }),
2362            SettingsPageItem::SettingItem(SettingItem {
2363                title: "Git Diff",
2364                description: "Show Git diff indicators in the scrollbar.",
2365                field: Box::new(SettingField {
2366                    organization_override: None,
2367                    json_path: Some("scrollbar.git_diff"),
2368                    pick: |settings_content| {
2369                        settings_content
2370                            .editor
2371                            .scrollbar
2372                            .as_ref()?
2373                            .git_diff
2374                            .as_ref()
2375                    },
2376                    write: |settings_content, value, _| {
2377                        settings_content
2378                            .editor
2379                            .scrollbar
2380                            .get_or_insert_default()
2381                            .git_diff = value;
2382                    },
2383                }),
2384                metadata: None,
2385                files: USER,
2386            }),
2387            SettingsPageItem::SettingItem(SettingItem {
2388                title: "Search Results",
2389                description: "Show buffer search result indicators in the scrollbar.",
2390                field: Box::new(SettingField {
2391                    organization_override: None,
2392                    json_path: Some("scrollbar.search_results"),
2393                    pick: |settings_content| {
2394                        settings_content
2395                            .editor
2396                            .scrollbar
2397                            .as_ref()?
2398                            .search_results
2399                            .as_ref()
2400                    },
2401                    write: |settings_content, value, _| {
2402                        settings_content
2403                            .editor
2404                            .scrollbar
2405                            .get_or_insert_default()
2406                            .search_results = value;
2407                    },
2408                }),
2409                metadata: None,
2410                files: USER,
2411            }),
2412            SettingsPageItem::SettingItem(SettingItem {
2413                title: "Selected Text",
2414                description: "Show selected text occurrences in the scrollbar.",
2415                field: Box::new(SettingField {
2416                    organization_override: None,
2417                    json_path: Some("scrollbar.selected_text"),
2418                    pick: |settings_content| {
2419                        settings_content
2420                            .editor
2421                            .scrollbar
2422                            .as_ref()?
2423                            .selected_text
2424                            .as_ref()
2425                    },
2426                    write: |settings_content, value, _| {
2427                        settings_content
2428                            .editor
2429                            .scrollbar
2430                            .get_or_insert_default()
2431                            .selected_text = value;
2432                    },
2433                }),
2434                metadata: None,
2435                files: USER,
2436            }),
2437            SettingsPageItem::SettingItem(SettingItem {
2438                title: "Selected Symbol",
2439                description: "Show selected symbol occurrences in the scrollbar.",
2440                field: Box::new(SettingField {
2441                    organization_override: None,
2442                    json_path: Some("scrollbar.selected_symbol"),
2443                    pick: |settings_content| {
2444                        settings_content
2445                            .editor
2446                            .scrollbar
2447                            .as_ref()?
2448                            .selected_symbol
2449                            .as_ref()
2450                    },
2451                    write: |settings_content, value, _| {
2452                        settings_content
2453                            .editor
2454                            .scrollbar
2455                            .get_or_insert_default()
2456                            .selected_symbol = value;
2457                    },
2458                }),
2459                metadata: None,
2460                files: USER,
2461            }),
2462            SettingsPageItem::SettingItem(SettingItem {
2463                title: "Diagnostics",
2464                description: "Which diagnostic indicators to show in the scrollbar.",
2465                field: Box::new(SettingField {
2466                    organization_override: None,
2467                    json_path: Some("scrollbar.diagnostics"),
2468                    pick: |settings_content| {
2469                        settings_content
2470                            .editor
2471                            .scrollbar
2472                            .as_ref()?
2473                            .diagnostics
2474                            .as_ref()
2475                    },
2476                    write: |settings_content, value, _| {
2477                        settings_content
2478                            .editor
2479                            .scrollbar
2480                            .get_or_insert_default()
2481                            .diagnostics = value;
2482                    },
2483                }),
2484                metadata: None,
2485                files: USER,
2486            }),
2487            SettingsPageItem::SettingItem(SettingItem {
2488                title: "Horizontal Scrollbar",
2489                description: "When false, forcefully disables the horizontal scrollbar.",
2490                field: Box::new(SettingField {
2491                    organization_override: None,
2492                    json_path: Some("scrollbar.axes.horizontal"),
2493                    pick: |settings_content| {
2494                        settings_content
2495                            .editor
2496                            .scrollbar
2497                            .as_ref()?
2498                            .axes
2499                            .as_ref()?
2500                            .horizontal
2501                            .as_ref()
2502                    },
2503                    write: |settings_content, value, _| {
2504                        settings_content
2505                            .editor
2506                            .scrollbar
2507                            .get_or_insert_default()
2508                            .axes
2509                            .get_or_insert_default()
2510                            .horizontal = value;
2511                    },
2512                }),
2513                metadata: None,
2514                files: USER,
2515            }),
2516            SettingsPageItem::SettingItem(SettingItem {
2517                title: "Vertical Scrollbar",
2518                description: "When false, forcefully disables the vertical scrollbar.",
2519                field: Box::new(SettingField {
2520                    organization_override: None,
2521                    json_path: Some("scrollbar.axes.vertical"),
2522                    pick: |settings_content| {
2523                        settings_content
2524                            .editor
2525                            .scrollbar
2526                            .as_ref()?
2527                            .axes
2528                            .as_ref()?
2529                            .vertical
2530                            .as_ref()
2531                    },
2532                    write: |settings_content, value, _| {
2533                        settings_content
2534                            .editor
2535                            .scrollbar
2536                            .get_or_insert_default()
2537                            .axes
2538                            .get_or_insert_default()
2539                            .vertical = value;
2540                    },
2541                }),
2542                metadata: None,
2543                files: USER,
2544            }),
2545        ]
2546    }
2547
2548    fn minimap_section() -> [SettingsPageItem; 7] {
2549        [
2550            SettingsPageItem::SectionHeader("Minimap"),
2551            SettingsPageItem::SettingItem(SettingItem {
2552                title: "Show",
2553                description: "When to show the minimap in the editor.",
2554                field: Box::new(SettingField {
2555                    organization_override: None,
2556                    json_path: Some("minimap.show"),
2557                    pick: |settings_content| {
2558                        settings_content.editor.minimap.as_ref()?.show.as_ref()
2559                    },
2560                    write: |settings_content, value, _| {
2561                        settings_content.editor.minimap.get_or_insert_default().show = value;
2562                    },
2563                }),
2564                metadata: None,
2565                files: USER,
2566            }),
2567            SettingsPageItem::SettingItem(SettingItem {
2568                title: "Display In",
2569                description: "Where to show the minimap in the editor.",
2570                field: Box::new(SettingField {
2571                    organization_override: None,
2572                    json_path: Some("minimap.display_in"),
2573                    pick: |settings_content| {
2574                        settings_content
2575                            .editor
2576                            .minimap
2577                            .as_ref()?
2578                            .display_in
2579                            .as_ref()
2580                    },
2581                    write: |settings_content, value, _| {
2582                        settings_content
2583                            .editor
2584                            .minimap
2585                            .get_or_insert_default()
2586                            .display_in = value;
2587                    },
2588                }),
2589                metadata: None,
2590                files: USER,
2591            }),
2592            SettingsPageItem::SettingItem(SettingItem {
2593                title: "Thumb",
2594                description: "When to show the minimap thumb.",
2595                field: Box::new(SettingField {
2596                    organization_override: None,
2597                    json_path: Some("minimap.thumb"),
2598                    pick: |settings_content| {
2599                        settings_content.editor.minimap.as_ref()?.thumb.as_ref()
2600                    },
2601                    write: |settings_content, value, _| {
2602                        settings_content
2603                            .editor
2604                            .minimap
2605                            .get_or_insert_default()
2606                            .thumb = value;
2607                    },
2608                }),
2609                metadata: None,
2610                files: USER,
2611            }),
2612            SettingsPageItem::SettingItem(SettingItem {
2613                title: "Thumb Border",
2614                description: "Border style for the minimap's scrollbar thumb.",
2615                field: Box::new(SettingField {
2616                    organization_override: None,
2617                    json_path: Some("minimap.thumb_border"),
2618                    pick: |settings_content| {
2619                        settings_content
2620                            .editor
2621                            .minimap
2622                            .as_ref()?
2623                            .thumb_border
2624                            .as_ref()
2625                    },
2626                    write: |settings_content, value, _| {
2627                        settings_content
2628                            .editor
2629                            .minimap
2630                            .get_or_insert_default()
2631                            .thumb_border = value;
2632                    },
2633                }),
2634                metadata: None,
2635                files: USER,
2636            }),
2637            SettingsPageItem::SettingItem(SettingItem {
2638                title: "Current Line Highlight",
2639                description: "How to highlight the current line in the minimap.",
2640                field: Box::new(SettingField {
2641                    organization_override: None,
2642                    json_path: Some("minimap.current_line_highlight"),
2643                    pick: |settings_content| {
2644                        settings_content
2645                            .editor
2646                            .minimap
2647                            .as_ref()
2648                            .and_then(|minimap| minimap.current_line_highlight.as_ref())
2649                            .or(settings_content.editor.current_line_highlight.as_ref())
2650                    },
2651                    write: |settings_content, value, _| {
2652                        settings_content
2653                            .editor
2654                            .minimap
2655                            .get_or_insert_default()
2656                            .current_line_highlight = value;
2657                    },
2658                }),
2659                metadata: None,
2660                files: USER,
2661            }),
2662            SettingsPageItem::SettingItem(SettingItem {
2663                title: "Max Width Columns",
2664                description: "Maximum number of columns to display in the minimap.",
2665                field: Box::new(SettingField {
2666                    organization_override: None,
2667                    json_path: Some("minimap.max_width_columns"),
2668                    pick: |settings_content| {
2669                        settings_content
2670                            .editor
2671                            .minimap
2672                            .as_ref()?
2673                            .max_width_columns
2674                            .as_ref()
2675                    },
2676                    write: |settings_content, value, _| {
2677                        settings_content
2678                            .editor
2679                            .minimap
2680                            .get_or_insert_default()
2681                            .max_width_columns = value;
2682                    },
2683                }),
2684                metadata: None,
2685                files: USER,
2686            }),
2687        ]
2688    }
2689
2690    fn toolbar_section() -> [SettingsPageItem; 6] {
2691        [
2692            SettingsPageItem::SectionHeader("Toolbar"),
2693            SettingsPageItem::SettingItem(SettingItem {
2694                title: "Breadcrumbs",
2695                description: "Show breadcrumbs.",
2696                field: Box::new(SettingField {
2697                    organization_override: None,
2698                    json_path: Some("toolbar.breadcrumbs"),
2699                    pick: |settings_content| {
2700                        settings_content
2701                            .editor
2702                            .toolbar
2703                            .as_ref()?
2704                            .breadcrumbs
2705                            .as_ref()
2706                    },
2707                    write: |settings_content, value, _| {
2708                        settings_content
2709                            .editor
2710                            .toolbar
2711                            .get_or_insert_default()
2712                            .breadcrumbs = value;
2713                    },
2714                }),
2715                metadata: None,
2716                files: USER,
2717            }),
2718            SettingsPageItem::SettingItem(SettingItem {
2719                title: "Quick Actions",
2720                description: "Show quick action buttons (e.g., search, selection, editor controls, etc.).",
2721                field: Box::new(SettingField {
2722                    organization_override: None,
2723                    json_path: Some("toolbar.quick_actions"),
2724                    pick: |settings_content| {
2725                        settings_content
2726                            .editor
2727                            .toolbar
2728                            .as_ref()?
2729                            .quick_actions
2730                            .as_ref()
2731                    },
2732                    write: |settings_content, value, _| {
2733                        settings_content
2734                            .editor
2735                            .toolbar
2736                            .get_or_insert_default()
2737                            .quick_actions = value;
2738                    },
2739                }),
2740                metadata: None,
2741                files: USER,
2742            }),
2743            SettingsPageItem::SettingItem(SettingItem {
2744                title: "Selections Menu",
2745                description: "Show the selections menu in the editor toolbar.",
2746                field: Box::new(SettingField {
2747                    organization_override: None,
2748                    json_path: Some("toolbar.selections_menu"),
2749                    pick: |settings_content| {
2750                        settings_content
2751                            .editor
2752                            .toolbar
2753                            .as_ref()?
2754                            .selections_menu
2755                            .as_ref()
2756                    },
2757                    write: |settings_content, value, _| {
2758                        settings_content
2759                            .editor
2760                            .toolbar
2761                            .get_or_insert_default()
2762                            .selections_menu = value;
2763                    },
2764                }),
2765                metadata: None,
2766                files: USER,
2767            }),
2768            SettingsPageItem::SettingItem(SettingItem {
2769                title: "Agent Review",
2770                description: "Show agent review buttons in the editor toolbar.",
2771                field: Box::new(SettingField {
2772                    organization_override: None,
2773                    json_path: Some("toolbar.agent_review"),
2774                    pick: |settings_content| {
2775                        settings_content
2776                            .editor
2777                            .toolbar
2778                            .as_ref()?
2779                            .agent_review
2780                            .as_ref()
2781                    },
2782                    write: |settings_content, value, _| {
2783                        settings_content
2784                            .editor
2785                            .toolbar
2786                            .get_or_insert_default()
2787                            .agent_review = value;
2788                    },
2789                }),
2790                metadata: None,
2791                files: USER,
2792            }),
2793            SettingsPageItem::SettingItem(SettingItem {
2794                title: "Code Actions",
2795                description: "Show code action buttons in the editor toolbar.",
2796                field: Box::new(SettingField {
2797                    organization_override: None,
2798                    json_path: Some("toolbar.code_actions"),
2799                    pick: |settings_content| {
2800                        settings_content
2801                            .editor
2802                            .toolbar
2803                            .as_ref()?
2804                            .code_actions
2805                            .as_ref()
2806                    },
2807                    write: |settings_content, value, _| {
2808                        settings_content
2809                            .editor
2810                            .toolbar
2811                            .get_or_insert_default()
2812                            .code_actions = value;
2813                    },
2814                }),
2815                metadata: None,
2816                files: USER,
2817            }),
2818        ]
2819    }
2820
2821    fn vim_settings_section() -> [SettingsPageItem; 14] {
2822        [
2823            SettingsPageItem::SectionHeader("Vim"),
2824            SettingsPageItem::SettingItem(SettingItem {
2825                title: "Default Mode",
2826                description: "The default mode when Vim starts.",
2827                field: Box::new(SettingField {
2828                    organization_override: None,
2829                    json_path: Some("vim.default_mode"),
2830                    pick: |settings_content| settings_content.vim.as_ref()?.default_mode.as_ref(),
2831                    write: |settings_content, value, _| {
2832                        settings_content.vim.get_or_insert_default().default_mode = value;
2833                    },
2834                }),
2835                metadata: None,
2836                files: USER,
2837            }),
2838            SettingsPageItem::SettingItem(SettingItem {
2839                title: "Toggle Relative Line Numbers",
2840                description: "Toggle relative line numbers in Vim mode.",
2841                field: Box::new(SettingField {
2842                    organization_override: None,
2843                    json_path: Some("vim.toggle_relative_line_numbers"),
2844                    pick: |settings_content| {
2845                        settings_content
2846                            .vim
2847                            .as_ref()?
2848                            .toggle_relative_line_numbers
2849                            .as_ref()
2850                    },
2851                    write: |settings_content, value, _| {
2852                        settings_content
2853                            .vim
2854                            .get_or_insert_default()
2855                            .toggle_relative_line_numbers = value;
2856                    },
2857                }),
2858                metadata: None,
2859                files: USER,
2860            }),
2861            SettingsPageItem::SettingItem(SettingItem {
2862                title: "Use System Clipboard",
2863                description: "Controls when to use system clipboard in Vim mode.",
2864                field: Box::new(SettingField {
2865                    organization_override: None,
2866                    json_path: Some("vim.use_system_clipboard"),
2867                    pick: |settings_content| {
2868                        settings_content.vim.as_ref()?.use_system_clipboard.as_ref()
2869                    },
2870                    write: |settings_content, value, _| {
2871                        settings_content
2872                            .vim
2873                            .get_or_insert_default()
2874                            .use_system_clipboard = value;
2875                    },
2876                }),
2877                metadata: None,
2878                files: USER,
2879            }),
2880            SettingsPageItem::SettingItem(SettingItem {
2881                title: "Use Smartcase Find",
2882                description: "Enable smartcase searching in Vim mode.",
2883                field: Box::new(SettingField {
2884                    organization_override: None,
2885                    json_path: Some("vim.use_smartcase_find"),
2886                    pick: |settings_content| {
2887                        settings_content.vim.as_ref()?.use_smartcase_find.as_ref()
2888                    },
2889                    write: |settings_content, value, _| {
2890                        settings_content
2891                            .vim
2892                            .get_or_insert_default()
2893                            .use_smartcase_find = value;
2894                    },
2895                }),
2896                metadata: None,
2897                files: USER,
2898            }),
2899            SettingsPageItem::SettingItem(SettingItem {
2900                title: "Global Substitution Default",
2901                description: "When enabled, the :substitute command replaces all matches in a line by default. The 'g' flag then toggles this behavior.",
2902                field: Box::new(SettingField {
2903                    organization_override: None,
2904                    json_path: Some("vim.gdefault"),
2905                    pick: |settings_content| settings_content.vim.as_ref()?.gdefault.as_ref(),
2906                    write: |settings_content, value, _| {
2907                        settings_content.vim.get_or_insert_default().gdefault = value;
2908                    },
2909                }),
2910                metadata: None,
2911                files: USER,
2912            }),
2913            SettingsPageItem::SettingItem(SettingItem {
2914                title: "Highlight on Yank Duration",
2915                description: "Duration in milliseconds to highlight yanked text in Vim mode.",
2916                field: Box::new(SettingField {
2917                    organization_override: None,
2918                    json_path: Some("vim.highlight_on_yank_duration"),
2919                    pick: |settings_content| {
2920                        settings_content
2921                            .vim
2922                            .as_ref()?
2923                            .highlight_on_yank_duration
2924                            .as_ref()
2925                    },
2926                    write: |settings_content, value, _| {
2927                        settings_content
2928                            .vim
2929                            .get_or_insert_default()
2930                            .highlight_on_yank_duration = value;
2931                    },
2932                }),
2933                metadata: None,
2934                files: USER,
2935            }),
2936            SettingsPageItem::SettingItem(SettingItem {
2937                title: "Regex Search",
2938                description: "Use regex search by default in Vim search.",
2939                field: Box::new(SettingField {
2940                    organization_override: None,
2941                    json_path: Some("vim.use_regex_search"),
2942                    pick: |settings_content| {
2943                        settings_content.vim.as_ref()?.use_regex_search.as_ref()
2944                    },
2945                    write: |settings_content, value, _| {
2946                        settings_content
2947                            .vim
2948                            .get_or_insert_default()
2949                            .use_regex_search = value;
2950                    },
2951                }),
2952                metadata: None,
2953                files: USER,
2954            }),
2955            SettingsPageItem::SettingItem(SettingItem {
2956                title: "Show Edit Predictions in Normal Mode",
2957                description: "Whether edit predictions are shown in normal mode. By default, edit predictions are only shown in insert and replace modes.",
2958                field: Box::new(SettingField {
2959                    organization_override: None,
2960                    json_path: Some("vim.show_edit_predictions_in_normal_mode"),
2961                    pick: |settings_content| {
2962                        settings_content
2963                            .vim
2964                            .as_ref()?
2965                            .show_edit_predictions_in_normal_mode
2966                            .as_ref()
2967                    },
2968                    write: |settings_content, value, _| {
2969                        settings_content
2970                            .vim
2971                            .get_or_insert_default()
2972                            .show_edit_predictions_in_normal_mode = value;
2973                    },
2974                }),
2975                metadata: None,
2976                files: USER,
2977            }),
2978            SettingsPageItem::SettingItem(SettingItem {
2979                title: "Cursor Shape - Normal Mode",
2980                description: "Cursor shape for normal mode.",
2981                field: Box::new(SettingField {
2982                    organization_override: None,
2983                    json_path: Some("vim.cursor_shape.normal"),
2984                    pick: |settings_content| {
2985                        settings_content
2986                            .vim
2987                            .as_ref()?
2988                            .cursor_shape
2989                            .as_ref()?
2990                            .normal
2991                            .as_ref()
2992                    },
2993                    write: |settings_content, value, _| {
2994                        settings_content
2995                            .vim
2996                            .get_or_insert_default()
2997                            .cursor_shape
2998                            .get_or_insert_default()
2999                            .normal = value;
3000                    },
3001                }),
3002                metadata: None,
3003                files: USER,
3004            }),
3005            SettingsPageItem::SettingItem(SettingItem {
3006                title: "Cursor Shape - Insert Mode",
3007                description: "Cursor shape for insert mode. Inherit uses the editor's cursor shape.",
3008                field: Box::new(SettingField {
3009                    organization_override: None,
3010                    json_path: Some("vim.cursor_shape.insert"),
3011                    pick: |settings_content| {
3012                        settings_content
3013                            .vim
3014                            .as_ref()?
3015                            .cursor_shape
3016                            .as_ref()?
3017                            .insert
3018                            .as_ref()
3019                    },
3020                    write: |settings_content, value, _| {
3021                        settings_content
3022                            .vim
3023                            .get_or_insert_default()
3024                            .cursor_shape
3025                            .get_or_insert_default()
3026                            .insert = value;
3027                    },
3028                }),
3029                metadata: None,
3030                files: USER,
3031            }),
3032            SettingsPageItem::SettingItem(SettingItem {
3033                title: "Cursor Shape - Replace Mode",
3034                description: "Cursor shape for replace mode.",
3035                field: Box::new(SettingField {
3036                    organization_override: None,
3037                    json_path: Some("vim.cursor_shape.replace"),
3038                    pick: |settings_content| {
3039                        settings_content
3040                            .vim
3041                            .as_ref()?
3042                            .cursor_shape
3043                            .as_ref()?
3044                            .replace
3045                            .as_ref()
3046                    },
3047                    write: |settings_content, value, _| {
3048                        settings_content
3049                            .vim
3050                            .get_or_insert_default()
3051                            .cursor_shape
3052                            .get_or_insert_default()
3053                            .replace = value;
3054                    },
3055                }),
3056                metadata: None,
3057                files: USER,
3058            }),
3059            SettingsPageItem::SettingItem(SettingItem {
3060                title: "Cursor Shape - Visual Mode",
3061                description: "Cursor shape for visual mode.",
3062                field: Box::new(SettingField {
3063                    organization_override: None,
3064                    json_path: Some("vim.cursor_shape.visual"),
3065                    pick: |settings_content| {
3066                        settings_content
3067                            .vim
3068                            .as_ref()?
3069                            .cursor_shape
3070                            .as_ref()?
3071                            .visual
3072                            .as_ref()
3073                    },
3074                    write: |settings_content, value, _| {
3075                        settings_content
3076                            .vim
3077                            .get_or_insert_default()
3078                            .cursor_shape
3079                            .get_or_insert_default()
3080                            .visual = value;
3081                    },
3082                }),
3083                metadata: None,
3084                files: USER,
3085            }),
3086            SettingsPageItem::SettingItem(SettingItem {
3087                title: "Custom Digraphs",
3088                description: "Custom digraph mappings for Vim mode.",
3089                field: Box::new(
3090                    SettingField {
3091                        organization_override: None,
3092                        json_path: Some("vim.custom_digraphs"),
3093                        pick: |settings_content| {
3094                            settings_content.vim.as_ref()?.custom_digraphs.as_ref()
3095                        },
3096                        write: |settings_content, value, _| {
3097                            settings_content.vim.get_or_insert_default().custom_digraphs = value;
3098                        },
3099                    }
3100                    .unimplemented(),
3101                ),
3102                metadata: None,
3103                files: USER,
3104            }),
3105        ]
3106    }
3107
3108    let items = concat_sections!(
3109        auto_save_section(),
3110        which_key_section(),
3111        multibuffer_section(),
3112        scrolling_section(),
3113        signature_help_section(),
3114        hover_popover_section(),
3115        drag_and_drop_selection_section(),
3116        gutter_section(),
3117        scrollbar_section(),
3118        minimap_section(),
3119        toolbar_section(),
3120        vim_settings_section(),
3121        language_settings_data(),
3122    );
3123
3124    SettingsPage {
3125        title: "Editor",
3126        items: items,
3127    }
3128}
3129
3130fn languages_and_tools_page(cx: &App) -> SettingsPage {
3131    fn file_types_section() -> [SettingsPageItem; 2] {
3132        [
3133            SettingsPageItem::SectionHeader("File Types"),
3134            SettingsPageItem::SettingItem(SettingItem {
3135                title: "File Type Associations",
3136                description: "A mapping from languages to files and file extensions that should be treated as that language.",
3137                field: Box::new(
3138                    SettingField {
3139                        organization_override: None,
3140                        json_path: Some("file_type_associations"),
3141                        pick: |settings_content| {
3142                            settings_content.project.all_languages.file_types.as_ref()
3143                        },
3144                        write: |settings_content, value, _| {
3145                            settings_content.project.all_languages.file_types = value;
3146                        },
3147                    }
3148                    .unimplemented(),
3149                ),
3150                metadata: None,
3151                files: USER | PROJECT,
3152            }),
3153        ]
3154    }
3155
3156    fn diagnostics_section() -> [SettingsPageItem; 3] {
3157        [
3158            SettingsPageItem::SectionHeader("Diagnostics"),
3159            SettingsPageItem::SettingItem(SettingItem {
3160                title: "Max Severity",
3161                description: "Which level to use to filter out diagnostics displayed in the editor.",
3162                field: Box::new(SettingField {
3163                    organization_override: None,
3164                    json_path: Some("diagnostics_max_severity"),
3165                    pick: |settings_content| {
3166                        settings_content.editor.diagnostics_max_severity.as_ref()
3167                    },
3168                    write: |settings_content, value, _| {
3169                        settings_content.editor.diagnostics_max_severity = value;
3170                    },
3171                }),
3172                metadata: None,
3173                files: USER,
3174            }),
3175            SettingsPageItem::SettingItem(SettingItem {
3176                title: "Include Warnings",
3177                description: "Whether to show warnings or not by default.",
3178                field: Box::new(SettingField {
3179                    organization_override: None,
3180                    json_path: Some("diagnostics.include_warnings"),
3181                    pick: |settings_content| {
3182                        settings_content
3183                            .diagnostics
3184                            .as_ref()?
3185                            .include_warnings
3186                            .as_ref()
3187                    },
3188                    write: |settings_content, value, _| {
3189                        settings_content
3190                            .diagnostics
3191                            .get_or_insert_default()
3192                            .include_warnings = value;
3193                    },
3194                }),
3195                metadata: None,
3196                files: USER,
3197            }),
3198        ]
3199    }
3200
3201    fn inline_diagnostics_section() -> [SettingsPageItem; 5] {
3202        [
3203            SettingsPageItem::SectionHeader("Inline Diagnostics"),
3204            SettingsPageItem::SettingItem(SettingItem {
3205                title: "Enabled",
3206                description: "Whether to show diagnostics inline or not.",
3207                field: Box::new(SettingField {
3208                    organization_override: None,
3209                    json_path: Some("diagnostics.inline.enabled"),
3210                    pick: |settings_content| {
3211                        settings_content
3212                            .diagnostics
3213                            .as_ref()?
3214                            .inline
3215                            .as_ref()?
3216                            .enabled
3217                            .as_ref()
3218                    },
3219                    write: |settings_content, value, _| {
3220                        settings_content
3221                            .diagnostics
3222                            .get_or_insert_default()
3223                            .inline
3224                            .get_or_insert_default()
3225                            .enabled = value;
3226                    },
3227                }),
3228                metadata: None,
3229                files: USER,
3230            }),
3231            SettingsPageItem::SettingItem(SettingItem {
3232                title: "Update Debounce",
3233                description: "The delay in milliseconds to show inline diagnostics after the last diagnostic update.",
3234                field: Box::new(SettingField {
3235                    organization_override: None,
3236                    json_path: Some("diagnostics.inline.update_debounce_ms"),
3237                    pick: |settings_content| {
3238                        settings_content
3239                            .diagnostics
3240                            .as_ref()?
3241                            .inline
3242                            .as_ref()?
3243                            .update_debounce_ms
3244                            .as_ref()
3245                    },
3246                    write: |settings_content, value, _| {
3247                        settings_content
3248                            .diagnostics
3249                            .get_or_insert_default()
3250                            .inline
3251                            .get_or_insert_default()
3252                            .update_debounce_ms = value;
3253                    },
3254                }),
3255                metadata: None,
3256                files: USER,
3257            }),
3258            SettingsPageItem::SettingItem(SettingItem {
3259                title: "Padding",
3260                description: "The amount of padding between the end of the source line and the start of the inline diagnostic.",
3261                field: Box::new(SettingField {
3262                    organization_override: None,
3263                    json_path: Some("diagnostics.inline.padding"),
3264                    pick: |settings_content| {
3265                        settings_content
3266                            .diagnostics
3267                            .as_ref()?
3268                            .inline
3269                            .as_ref()?
3270                            .padding
3271                            .as_ref()
3272                    },
3273                    write: |settings_content, value, _| {
3274                        settings_content
3275                            .diagnostics
3276                            .get_or_insert_default()
3277                            .inline
3278                            .get_or_insert_default()
3279                            .padding = value;
3280                    },
3281                }),
3282                metadata: None,
3283                files: USER,
3284            }),
3285            SettingsPageItem::SettingItem(SettingItem {
3286                title: "Minimum Column",
3287                description: "The minimum column at which to display inline diagnostics.",
3288                field: Box::new(SettingField {
3289                    organization_override: None,
3290                    json_path: Some("diagnostics.inline.min_column"),
3291                    pick: |settings_content| {
3292                        settings_content
3293                            .diagnostics
3294                            .as_ref()?
3295                            .inline
3296                            .as_ref()?
3297                            .min_column
3298                            .as_ref()
3299                    },
3300                    write: |settings_content, value, _| {
3301                        settings_content
3302                            .diagnostics
3303                            .get_or_insert_default()
3304                            .inline
3305                            .get_or_insert_default()
3306                            .min_column = value;
3307                    },
3308                }),
3309                metadata: None,
3310                files: USER,
3311            }),
3312        ]
3313    }
3314
3315    fn lsp_pull_diagnostics_section() -> [SettingsPageItem; 3] {
3316        [
3317            SettingsPageItem::SectionHeader("LSP Pull Diagnostics"),
3318            SettingsPageItem::SettingItem(SettingItem {
3319                title: "Enabled",
3320                description: "Whether to pull for language server-powered diagnostics or not.",
3321                field: Box::new(SettingField {
3322                    organization_override: None,
3323                    json_path: Some("diagnostics.lsp_pull_diagnostics.enabled"),
3324                    pick: |settings_content| {
3325                        settings_content
3326                            .diagnostics
3327                            .as_ref()?
3328                            .lsp_pull_diagnostics
3329                            .as_ref()?
3330                            .enabled
3331                            .as_ref()
3332                    },
3333                    write: |settings_content, value, _| {
3334                        settings_content
3335                            .diagnostics
3336                            .get_or_insert_default()
3337                            .lsp_pull_diagnostics
3338                            .get_or_insert_default()
3339                            .enabled = value;
3340                    },
3341                }),
3342                metadata: None,
3343                files: USER,
3344            }),
3345            // todo(settings_ui): Needs unit
3346            SettingsPageItem::SettingItem(SettingItem {
3347                title: "Debounce",
3348                description: "Minimum time to wait before pulling diagnostics from the language server(s).",
3349                field: Box::new(SettingField {
3350                    organization_override: None,
3351                    json_path: Some("diagnostics.lsp_pull_diagnostics.debounce_ms"),
3352                    pick: |settings_content| {
3353                        settings_content
3354                            .diagnostics
3355                            .as_ref()?
3356                            .lsp_pull_diagnostics
3357                            .as_ref()?
3358                            .debounce_ms
3359                            .as_ref()
3360                    },
3361                    write: |settings_content, value, _| {
3362                        settings_content
3363                            .diagnostics
3364                            .get_or_insert_default()
3365                            .lsp_pull_diagnostics
3366                            .get_or_insert_default()
3367                            .debounce_ms = value;
3368                    },
3369                }),
3370                metadata: None,
3371                files: USER,
3372            }),
3373        ]
3374    }
3375
3376    fn lsp_highlights_section() -> [SettingsPageItem; 2] {
3377        [
3378            SettingsPageItem::SectionHeader("LSP Highlights"),
3379            SettingsPageItem::SettingItem(SettingItem {
3380                title: "Debounce",
3381                description: "The debounce delay before querying highlights from the language.",
3382                field: Box::new(SettingField {
3383                    organization_override: None,
3384                    json_path: Some("lsp_highlight_debounce"),
3385                    pick: |settings_content| {
3386                        settings_content.editor.lsp_highlight_debounce.as_ref()
3387                    },
3388                    write: |settings_content, value, _| {
3389                        settings_content.editor.lsp_highlight_debounce = value;
3390                    },
3391                }),
3392                metadata: None,
3393                files: USER,
3394            }),
3395        ]
3396    }
3397
3398    fn languages_list_section(cx: &App) -> Box<[SettingsPageItem]> {
3399        // todo(settings_ui): Refresh on extension (un)/installed
3400        // Note that `crates/json_schema_store` solves the same problem, there is probably a way to unify the two
3401        std::iter::once(SettingsPageItem::SectionHeader("Languages"))
3402            .chain(all_language_names(cx).into_iter().map(|language_name| {
3403                let link = format!("languages.{language_name}");
3404                SettingsPageItem::SubPageLink(SubPageLink {
3405                    title: language_name,
3406                    r#type: crate::SubPageType::Language,
3407                    description: None,
3408                    search_aliases: &[],
3409                    json_path: Some(link.leak()),
3410                    in_json: true,
3411                    files: USER | PROJECT,
3412                    render: |this, scroll_handle, window, cx| {
3413                        let items: Box<[SettingsPageItem]> = concat_sections!(
3414                            language_settings_data(),
3415                            non_editor_language_settings_data(),
3416                            edit_prediction_language_settings_section()
3417                        );
3418                        this.render_sub_page_items(
3419                            items.iter().enumerate(),
3420                            scroll_handle,
3421                            window,
3422                            cx,
3423                        )
3424                        .into_any_element()
3425                    },
3426                })
3427            }))
3428            .collect()
3429    }
3430
3431    SettingsPage {
3432        title: "Languages & Tools",
3433        items: {
3434            concat_sections!(
3435                non_editor_language_settings_data(),
3436                file_types_section(),
3437                diagnostics_section(),
3438                inline_diagnostics_section(),
3439                lsp_pull_diagnostics_section(),
3440                lsp_highlights_section(),
3441                languages_list_section(cx),
3442            )
3443        },
3444    }
3445}
3446
3447fn search_and_files_page() -> SettingsPage {
3448    fn search_section() -> [SettingsPageItem; 9] {
3449        [
3450            SettingsPageItem::SectionHeader("Search"),
3451            SettingsPageItem::SettingItem(SettingItem {
3452                title: "Whole Word",
3453                description: "Search for whole words by default.",
3454                field: Box::new(SettingField {
3455                    organization_override: None,
3456                    json_path: Some("search.whole_word"),
3457                    pick: |settings_content| {
3458                        settings_content.editor.search.as_ref()?.whole_word.as_ref()
3459                    },
3460                    write: |settings_content, value, _| {
3461                        settings_content
3462                            .editor
3463                            .search
3464                            .get_or_insert_default()
3465                            .whole_word = value;
3466                    },
3467                }),
3468                metadata: None,
3469                files: USER,
3470            }),
3471            SettingsPageItem::SettingItem(SettingItem {
3472                title: "Case Sensitive",
3473                description: "Search case-sensitively by default.",
3474                field: Box::new(SettingField {
3475                    organization_override: None,
3476                    json_path: Some("search.case_sensitive"),
3477                    pick: |settings_content| {
3478                        settings_content
3479                            .editor
3480                            .search
3481                            .as_ref()?
3482                            .case_sensitive
3483                            .as_ref()
3484                    },
3485                    write: |settings_content, value, _| {
3486                        settings_content
3487                            .editor
3488                            .search
3489                            .get_or_insert_default()
3490                            .case_sensitive = value;
3491                    },
3492                }),
3493                metadata: None,
3494                files: USER,
3495            }),
3496            SettingsPageItem::SettingItem(SettingItem {
3497                title: "Use Smartcase Search",
3498                description: "Whether to automatically enable case-sensitive search based on the search query.",
3499                field: Box::new(SettingField {
3500                    organization_override: None,
3501                    json_path: Some("use_smartcase_search"),
3502                    pick: |settings_content| settings_content.editor.use_smartcase_search.as_ref(),
3503                    write: |settings_content, value, _| {
3504                        settings_content.editor.use_smartcase_search = value;
3505                    },
3506                }),
3507                metadata: None,
3508                files: USER,
3509            }),
3510            SettingsPageItem::SettingItem(SettingItem {
3511                title: "Include Ignored",
3512                description: "Include ignored files in search results by default.",
3513                field: Box::new(SettingField {
3514                    organization_override: None,
3515                    json_path: Some("search.include_ignored"),
3516                    pick: |settings_content| {
3517                        settings_content
3518                            .editor
3519                            .search
3520                            .as_ref()?
3521                            .include_ignored
3522                            .as_ref()
3523                    },
3524                    write: |settings_content, value, _| {
3525                        settings_content
3526                            .editor
3527                            .search
3528                            .get_or_insert_default()
3529                            .include_ignored = value;
3530                    },
3531                }),
3532                metadata: None,
3533                files: USER,
3534            }),
3535            SettingsPageItem::SettingItem(SettingItem {
3536                title: "Regex",
3537                description: "Use regex search by default.",
3538                field: Box::new(SettingField {
3539                    organization_override: None,
3540                    json_path: Some("search.regex"),
3541                    pick: |settings_content| {
3542                        settings_content.editor.search.as_ref()?.regex.as_ref()
3543                    },
3544                    write: |settings_content, value, _| {
3545                        settings_content.editor.search.get_or_insert_default().regex = value;
3546                    },
3547                }),
3548                metadata: None,
3549                files: USER,
3550            }),
3551            SettingsPageItem::SettingItem(SettingItem {
3552                title: "Search Wrap",
3553                description: "Whether the editor search results will loop.",
3554                field: Box::new(SettingField {
3555                    organization_override: None,
3556                    json_path: Some("search_wrap"),
3557                    pick: |settings_content| settings_content.editor.search_wrap.as_ref(),
3558                    write: |settings_content, value, _| {
3559                        settings_content.editor.search_wrap = value;
3560                    },
3561                }),
3562                metadata: None,
3563                files: USER,
3564            }),
3565            SettingsPageItem::SettingItem(SettingItem {
3566                title: "Center on Match",
3567                description: "Whether to center the current match in the editor",
3568                field: Box::new(SettingField {
3569                    organization_override: None,
3570                    json_path: Some("editor.search.center_on_match"),
3571                    pick: |settings_content| {
3572                        settings_content
3573                            .editor
3574                            .search
3575                            .as_ref()
3576                            .and_then(|search| search.center_on_match.as_ref())
3577                    },
3578                    write: |settings_content, value, _| {
3579                        settings_content
3580                            .editor
3581                            .search
3582                            .get_or_insert_default()
3583                            .center_on_match = value;
3584                    },
3585                }),
3586                metadata: None,
3587                files: USER,
3588            }),
3589            SettingsPageItem::SettingItem(SettingItem {
3590                title: "Seed Search Query From Cursor",
3591                description: "When to populate a new search's query based on the text under the cursor.",
3592                field: Box::new(SettingField {
3593                    organization_override: None,
3594                    json_path: Some("seed_search_query_from_cursor"),
3595                    pick: |settings_content| {
3596                        settings_content
3597                            .editor
3598                            .seed_search_query_from_cursor
3599                            .as_ref()
3600                    },
3601                    write: |settings_content, value, _| {
3602                        settings_content.editor.seed_search_query_from_cursor = value;
3603                    },
3604                }),
3605                metadata: None,
3606                files: USER,
3607            }),
3608        ]
3609    }
3610
3611    fn file_finder_section() -> [SettingsPageItem; 4] {
3612        [
3613            SettingsPageItem::SectionHeader("File Finder"),
3614            // todo: null by default
3615            SettingsPageItem::SettingItem(SettingItem {
3616                title: "Include Ignored in Search",
3617                description: "Use gitignored files when searching.",
3618                field: Box::new(SettingField {
3619                    organization_override: None,
3620                    json_path: Some("file_finder.include_ignored"),
3621                    pick: |settings_content| {
3622                        settings_content
3623                            .file_finder
3624                            .as_ref()?
3625                            .include_ignored
3626                            .as_ref()
3627                    },
3628                    write: |settings_content, value, _| {
3629                        settings_content
3630                            .file_finder
3631                            .get_or_insert_default()
3632                            .include_ignored = value;
3633                    },
3634                }),
3635                metadata: None,
3636                files: USER,
3637            }),
3638            SettingsPageItem::SettingItem(SettingItem {
3639                title: "File Icons",
3640                description: "Show file icons in the file finder.",
3641                field: Box::new(SettingField {
3642                    organization_override: None,
3643                    json_path: Some("file_finder.file_icons"),
3644                    pick: |settings_content| {
3645                        settings_content.file_finder.as_ref()?.file_icons.as_ref()
3646                    },
3647                    write: |settings_content, value, _| {
3648                        settings_content
3649                            .file_finder
3650                            .get_or_insert_default()
3651                            .file_icons = value;
3652                    },
3653                }),
3654                metadata: None,
3655                files: USER,
3656            }),
3657            SettingsPageItem::SettingItem(SettingItem {
3658                title: "Skip Focus For Active In Search",
3659                description: "Whether the file finder should skip focus for the active file in search results.",
3660                field: Box::new(SettingField {
3661                    organization_override: None,
3662                    json_path: Some("file_finder.skip_focus_for_active_in_search"),
3663                    pick: |settings_content| {
3664                        settings_content
3665                            .file_finder
3666                            .as_ref()?
3667                            .skip_focus_for_active_in_search
3668                            .as_ref()
3669                    },
3670                    write: |settings_content, value, _| {
3671                        settings_content
3672                            .file_finder
3673                            .get_or_insert_default()
3674                            .skip_focus_for_active_in_search = value;
3675                    },
3676                }),
3677                metadata: None,
3678                files: USER,
3679            }),
3680        ]
3681    }
3682
3683    fn file_scan_section() -> [SettingsPageItem; 6] {
3684        [
3685            SettingsPageItem::SectionHeader("File Scan"),
3686            SettingsPageItem::SettingItem(SettingItem {
3687                title: "File Scan Exclusions",
3688                description: "Files or globs of files that will be excluded by Omega 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\"",
3689                field: Box::new(
3690                    SettingField {
3691                        organization_override: None,
3692                        json_path: Some("file_scan_exclusions"),
3693                        pick: |settings_content| {
3694                            settings_content
3695                                .project
3696                                .worktree
3697                                .file_scan_exclusions
3698                                .as_ref()
3699                        },
3700                        write: |settings_content, value, _| {
3701                            settings_content.project.worktree.file_scan_exclusions = value;
3702                        },
3703                    }
3704                    .unimplemented(),
3705                ),
3706                metadata: None,
3707                files: USER,
3708            }),
3709            SettingsPageItem::SettingItem(SettingItem {
3710                title: "File Scan Inclusions",
3711                description: "Files or globs of files that will be included by Omega, 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 Omega's file scanning. \"File Scan Exclusions\" takes precedence over these inclusions",
3712                field: Box::new(
3713                    SettingField {
3714                        organization_override: None,
3715                        json_path: Some("file_scan_inclusions"),
3716                        pick: |settings_content| {
3717                            settings_content
3718                                .project
3719                                .worktree
3720                                .file_scan_inclusions
3721                                .as_ref()
3722                        },
3723                        write: |settings_content, value, _| {
3724                            settings_content.project.worktree.file_scan_inclusions = value;
3725                        },
3726                    }
3727                    .unimplemented(),
3728                ),
3729                metadata: None,
3730                files: USER,
3731            }),
3732            SettingsPageItem::SettingItem(SettingItem {
3733                title: "Scan Symbolic Links",
3734                description: "When to scan content of linked directories",
3735                field: Box::new(SettingField {
3736                    json_path: Some("scan_symlinks"),
3737                    organization_override: None,
3738                    pick: |settings_content| {
3739                        settings_content.project.worktree.scan_symlinks.as_ref()
3740                    },
3741                    write: |settings_content, value, _| {
3742                        settings_content.project.worktree.scan_symlinks = value;
3743                    },
3744                }),
3745                metadata: None,
3746                files: USER,
3747            }),
3748            SettingsPageItem::SettingItem(SettingItem {
3749                title: "Restore File State",
3750                description: "Restore previous file state when reopening.",
3751                field: Box::new(SettingField {
3752                    organization_override: None,
3753                    json_path: Some("restore_on_file_reopen"),
3754                    pick: |settings_content| {
3755                        settings_content.workspace.restore_on_file_reopen.as_ref()
3756                    },
3757                    write: |settings_content, value, _| {
3758                        settings_content.workspace.restore_on_file_reopen = value;
3759                    },
3760                }),
3761                metadata: None,
3762                files: USER,
3763            }),
3764            SettingsPageItem::SettingItem(SettingItem {
3765                title: "Close on File Delete",
3766                description: "Automatically close files that have been deleted.",
3767                field: Box::new(SettingField {
3768                    organization_override: None,
3769                    json_path: Some("close_on_file_delete"),
3770                    pick: |settings_content| {
3771                        settings_content.workspace.close_on_file_delete.as_ref()
3772                    },
3773                    write: |settings_content, value, _| {
3774                        settings_content.workspace.close_on_file_delete = value;
3775                    },
3776                }),
3777                metadata: None,
3778                files: USER,
3779            }),
3780        ]
3781    }
3782
3783    SettingsPage {
3784        title: "Search & Files",
3785        items: concat_sections![search_section(), file_finder_section(), file_scan_section()],
3786    }
3787}
3788
3789fn window_and_layout_page() -> SettingsPage {
3790    fn status_bar_section() -> [SettingsPageItem; 11] {
3791        [
3792            SettingsPageItem::SectionHeader("Status Bar"),
3793            SettingsPageItem::SettingItem(SettingItem {
3794                title: "Project Panel Button",
3795                description: "Show the project panel button in the status bar.",
3796                field: Box::new(SettingField {
3797                    organization_override: None,
3798                    json_path: Some("project_panel.button"),
3799                    pick: |settings_content| {
3800                        settings_content.project_panel.as_ref()?.button.as_ref()
3801                    },
3802                    write: |settings_content, value, _| {
3803                        settings_content
3804                            .project_panel
3805                            .get_or_insert_default()
3806                            .button = value;
3807                    },
3808                }),
3809                metadata: None,
3810                files: USER,
3811            }),
3812            SettingsPageItem::SettingItem(SettingItem {
3813                title: "Active Language Button",
3814                description: "Show the active language button in the status bar.",
3815                field: Box::new(SettingField {
3816                    organization_override: None,
3817                    json_path: Some("status_bar.active_language_button"),
3818                    pick: |settings_content| {
3819                        settings_content
3820                            .status_bar
3821                            .as_ref()?
3822                            .active_language_button
3823                            .as_ref()
3824                    },
3825                    write: |settings_content, value, _| {
3826                        settings_content
3827                            .status_bar
3828                            .get_or_insert_default()
3829                            .active_language_button = value;
3830                    },
3831                }),
3832                metadata: None,
3833                files: USER,
3834            }),
3835            SettingsPageItem::SettingItem(SettingItem {
3836                title: "Active Encoding Button",
3837                description: "Control when to show the active encoding in the status bar.",
3838                field: Box::new(SettingField {
3839                    organization_override: None,
3840                    json_path: Some("status_bar.active_encoding_button"),
3841                    pick: |settings_content| {
3842                        settings_content
3843                            .status_bar
3844                            .as_ref()?
3845                            .active_encoding_button
3846                            .as_ref()
3847                    },
3848                    write: |settings_content, value, _| {
3849                        settings_content
3850                            .status_bar
3851                            .get_or_insert_default()
3852                            .active_encoding_button = value;
3853                    },
3854                }),
3855                metadata: None,
3856                files: USER,
3857            }),
3858            SettingsPageItem::SettingItem(SettingItem {
3859                title: "Cursor Position Button",
3860                description: "Show the cursor position button in the status bar.",
3861                field: Box::new(SettingField {
3862                    organization_override: None,
3863                    json_path: Some("status_bar.cursor_position_button"),
3864                    pick: |settings_content| {
3865                        settings_content
3866                            .status_bar
3867                            .as_ref()?
3868                            .cursor_position_button
3869                            .as_ref()
3870                    },
3871                    write: |settings_content, value, _| {
3872                        settings_content
3873                            .status_bar
3874                            .get_or_insert_default()
3875                            .cursor_position_button = value;
3876                    },
3877                }),
3878                metadata: None,
3879                files: USER,
3880            }),
3881            SettingsPageItem::SettingItem(SettingItem {
3882                title: "Line Endings Button",
3883                description: "Show the active line endings button in the status bar.",
3884                field: Box::new(SettingField {
3885                    organization_override: None,
3886                    json_path: Some("status_bar.line_endings_button"),
3887                    pick: |settings_content| {
3888                        settings_content
3889                            .status_bar
3890                            .as_ref()?
3891                            .line_endings_button
3892                            .as_ref()
3893                    },
3894                    write: |settings_content, value, _| {
3895                        settings_content
3896                            .status_bar
3897                            .get_or_insert_default()
3898                            .line_endings_button = value;
3899                    },
3900                }),
3901                metadata: None,
3902                files: USER,
3903            }),
3904            SettingsPageItem::SettingItem(SettingItem {
3905                title: "Terminal Button",
3906                description: "Show the terminal button in the status bar.",
3907                field: Box::new(SettingField {
3908                    organization_override: None,
3909                    json_path: Some("terminal.button"),
3910                    pick: |settings_content| settings_content.terminal.as_ref()?.button.as_ref(),
3911                    write: |settings_content, value, _| {
3912                        settings_content.terminal.get_or_insert_default().button = value;
3913                    },
3914                }),
3915                metadata: None,
3916                files: USER,
3917            }),
3918            SettingsPageItem::SettingItem(SettingItem {
3919                title: "Diagnostics Button",
3920                description: "Show the project diagnostics button in the status bar.",
3921                field: Box::new(SettingField {
3922                    organization_override: None,
3923                    json_path: Some("diagnostics.button"),
3924                    pick: |settings_content| settings_content.diagnostics.as_ref()?.button.as_ref(),
3925                    write: |settings_content, value, _| {
3926                        settings_content.diagnostics.get_or_insert_default().button = value;
3927                    },
3928                }),
3929                metadata: None,
3930                files: USER,
3931            }),
3932            SettingsPageItem::SettingItem(SettingItem {
3933                title: "Project Search Button",
3934                description: "Show the project search button in the status bar.",
3935                field: Box::new(SettingField {
3936                    organization_override: None,
3937                    json_path: Some("search.button"),
3938                    pick: |settings_content| {
3939                        settings_content.editor.search.as_ref()?.button.as_ref()
3940                    },
3941                    write: |settings_content, value, _| {
3942                        settings_content
3943                            .editor
3944                            .search
3945                            .get_or_insert_default()
3946                            .button = value;
3947                    },
3948                }),
3949                metadata: None,
3950                files: USER,
3951            }),
3952            SettingsPageItem::SettingItem(SettingItem {
3953                title: "Debugger Button",
3954                description: "Show the debugger button in the status bar.",
3955                field: Box::new(SettingField {
3956                    organization_override: None,
3957                    json_path: Some("debugger.button"),
3958                    pick: |settings_content| settings_content.debugger.as_ref()?.button.as_ref(),
3959                    write: |settings_content, value, _| {
3960                        settings_content.debugger.get_or_insert_default().button = value;
3961                    },
3962                }),
3963                metadata: None,
3964                files: USER,
3965            }),
3966            SettingsPageItem::SettingItem(SettingItem {
3967                title: "Active File Name",
3968                description: "Show the name of the active file in the status bar.",
3969                field: Box::new(SettingField {
3970                    organization_override: None,
3971                    json_path: Some("status_bar.show_active_file"),
3972                    pick: |settings_content| {
3973                        settings_content
3974                            .status_bar
3975                            .as_ref()?
3976                            .show_active_file
3977                            .as_ref()
3978                    },
3979                    write: |settings_content, value, _| {
3980                        settings_content
3981                            .status_bar
3982                            .get_or_insert_default()
3983                            .show_active_file = value;
3984                    },
3985                }),
3986                metadata: None,
3987                files: USER,
3988            }),
3989        ]
3990    }
3991
3992    fn title_bar_section() -> [SettingsPageItem; 11] {
3993        [
3994            SettingsPageItem::SectionHeader("Title Bar"),
3995            SettingsPageItem::SettingItem(SettingItem {
3996                title: "Show Branch Status Icon",
3997                description: "Show git status indicators on the branch icon in the titlebar.",
3998                field: Box::new(SettingField {
3999                    organization_override: None,
4000                    json_path: Some("title_bar.show_branch_status_icon"),
4001                    pick: |settings_content| {
4002                        settings_content
4003                            .title_bar
4004                            .as_ref()?
4005                            .show_branch_status_icon
4006                            .as_ref()
4007                    },
4008                    write: |settings_content, value, _| {
4009                        settings_content
4010                            .title_bar
4011                            .get_or_insert_default()
4012                            .show_branch_status_icon = value;
4013                    },
4014                }),
4015                metadata: None,
4016                files: USER,
4017            }),
4018            SettingsPageItem::SettingItem(SettingItem {
4019                title: "Show Branch Name",
4020                description: "Show the branch name button in the titlebar.",
4021                field: Box::new(SettingField {
4022                    organization_override: None,
4023                    json_path: Some("title_bar.show_branch_name"),
4024                    pick: |settings_content| {
4025                        settings_content
4026                            .title_bar
4027                            .as_ref()?
4028                            .show_branch_name
4029                            .as_ref()
4030                    },
4031                    write: |settings_content, value, _| {
4032                        settings_content
4033                            .title_bar
4034                            .get_or_insert_default()
4035                            .show_branch_name = value;
4036                    },
4037                }),
4038                metadata: None,
4039                files: USER,
4040            }),
4041            SettingsPageItem::SettingItem(SettingItem {
4042                title: "Show Worktree Name",
4043                description: "Show the worktree name button in the titlebar.",
4044                field: Box::new(SettingField {
4045                    organization_override: None,
4046                    json_path: Some("title_bar.show_worktree_name"),
4047                    pick: |settings_content| {
4048                        settings_content
4049                            .title_bar
4050                            .as_ref()?
4051                            .show_worktree_name
4052                            .as_ref()
4053                    },
4054                    write: |settings_content, value, _| {
4055                        settings_content
4056                            .title_bar
4057                            .get_or_insert_default()
4058                            .show_worktree_name = value;
4059                    },
4060                }),
4061                metadata: None,
4062                files: USER,
4063            }),
4064            SettingsPageItem::SettingItem(SettingItem {
4065                title: "Show Project Items",
4066                description: "Show the project host and name in the titlebar.",
4067                field: Box::new(SettingField {
4068                    organization_override: None,
4069                    json_path: Some("title_bar.show_project_items"),
4070                    pick: |settings_content| {
4071                        settings_content
4072                            .title_bar
4073                            .as_ref()?
4074                            .show_project_items
4075                            .as_ref()
4076                    },
4077                    write: |settings_content, value, _| {
4078                        settings_content
4079                            .title_bar
4080                            .get_or_insert_default()
4081                            .show_project_items = value;
4082                    },
4083                }),
4084                metadata: None,
4085                files: USER,
4086            }),
4087            SettingsPageItem::SettingItem(SettingItem {
4088                title: "Show Onboarding Banner",
4089                description: "Show banners announcing new features in the titlebar.",
4090                field: Box::new(SettingField {
4091                    organization_override: None,
4092                    json_path: Some("title_bar.show_onboarding_banner"),
4093                    pick: |settings_content| {
4094                        settings_content
4095                            .title_bar
4096                            .as_ref()?
4097                            .show_onboarding_banner
4098                            .as_ref()
4099                    },
4100                    write: |settings_content, value, _| {
4101                        settings_content
4102                            .title_bar
4103                            .get_or_insert_default()
4104                            .show_onboarding_banner = value;
4105                    },
4106                }),
4107                metadata: None,
4108                files: USER,
4109            }),
4110            SettingsPageItem::SettingItem(SettingItem {
4111                title: "Show Sign In",
4112                description: "Show the sign in button in the titlebar.",
4113                field: Box::new(SettingField {
4114                    organization_override: None,
4115                    json_path: Some("title_bar.show_sign_in"),
4116                    pick: |settings_content| {
4117                        settings_content.title_bar.as_ref()?.show_sign_in.as_ref()
4118                    },
4119                    write: |settings_content, value, _| {
4120                        settings_content
4121                            .title_bar
4122                            .get_or_insert_default()
4123                            .show_sign_in = value;
4124                    },
4125                }),
4126                metadata: None,
4127                files: USER,
4128            }),
4129            SettingsPageItem::SettingItem(SettingItem {
4130                title: "Show User Menu",
4131                description: "Show the user menu button in the titlebar.",
4132                field: Box::new(SettingField {
4133                    organization_override: None,
4134                    json_path: Some("title_bar.show_user_menu"),
4135                    pick: |settings_content| {
4136                        settings_content.title_bar.as_ref()?.show_user_menu.as_ref()
4137                    },
4138                    write: |settings_content, value, _| {
4139                        settings_content
4140                            .title_bar
4141                            .get_or_insert_default()
4142                            .show_user_menu = value;
4143                    },
4144                }),
4145                metadata: None,
4146                files: USER,
4147            }),
4148            SettingsPageItem::SettingItem(SettingItem {
4149                title: "Show User Picture",
4150                description: "Show user picture in the titlebar.",
4151                field: Box::new(SettingField {
4152                    organization_override: None,
4153                    json_path: Some("title_bar.show_user_picture"),
4154                    pick: |settings_content| {
4155                        settings_content
4156                            .title_bar
4157                            .as_ref()?
4158                            .show_user_picture
4159                            .as_ref()
4160                    },
4161                    write: |settings_content, value, _| {
4162                        settings_content
4163                            .title_bar
4164                            .get_or_insert_default()
4165                            .show_user_picture = value;
4166                    },
4167                }),
4168                metadata: None,
4169                files: USER,
4170            }),
4171            SettingsPageItem::SettingItem(SettingItem {
4172                title: "Show Menus",
4173                description: "Show the menus in the titlebar.",
4174                field: Box::new(SettingField {
4175                    organization_override: None,
4176                    json_path: Some("title_bar.show_menus"),
4177                    pick: |settings_content| {
4178                        settings_content.title_bar.as_ref()?.show_menus.as_ref()
4179                    },
4180                    write: |settings_content, value, _| {
4181                        settings_content
4182                            .title_bar
4183                            .get_or_insert_default()
4184                            .show_menus = value;
4185                    },
4186                }),
4187                metadata: None,
4188                files: USER,
4189            }),
4190            SettingsPageItem::DynamicItem(DynamicItem {
4191                discriminant: SettingItem {
4192                    files: USER,
4193                    title: "Button Layout",
4194                    description:
4195                        "(Linux only) choose how window control buttons are laid out in the titlebar.",
4196                    field: Box::new(SettingField {
4197                        organization_override: None,
4198                        json_path: Some("title_bar.button_layout$"),
4199                        pick: |settings_content| {
4200                            Some(
4201                                &dynamic_variants::<settings::WindowButtonLayoutContent>()[settings_content
4202                                    .title_bar
4203                                    .as_ref()?
4204                                    .button_layout
4205                                    .as_ref()?
4206                                    .discriminant()
4207                                    as usize],
4208                            )
4209                        },
4210                        write: |settings_content, value, _| {
4211                            let Some(value) = value else {
4212                                settings_content
4213                                    .title_bar
4214                                    .get_or_insert_default()
4215                                    .button_layout = None;
4216                                return;
4217                            };
4218
4219                            let current_custom_layout = settings_content
4220                                .title_bar
4221                                .as_ref()
4222                                .and_then(|title_bar| title_bar.button_layout.as_ref())
4223                                .and_then(|button_layout| match button_layout {
4224                                    settings::WindowButtonLayoutContent::Custom(layout) => {
4225                                        Some(layout.clone())
4226                                    }
4227                                    _ => None,
4228                                });
4229
4230                            let button_layout = match value {
4231                                settings::WindowButtonLayoutContentDiscriminants::PlatformDefault => {
4232                                    settings::WindowButtonLayoutContent::PlatformDefault
4233                                }
4234                                settings::WindowButtonLayoutContentDiscriminants::Standard => {
4235                                    settings::WindowButtonLayoutContent::Standard
4236                                }
4237                                settings::WindowButtonLayoutContentDiscriminants::Custom => {
4238                                    settings::WindowButtonLayoutContent::Custom(
4239                                        current_custom_layout.unwrap_or_else(|| {
4240                                            "close:minimize,maximize".to_string()
4241                                        }),
4242                                    )
4243                                }
4244                            };
4245
4246                            settings_content
4247                                .title_bar
4248                                .get_or_insert_default()
4249                                .button_layout = Some(button_layout);
4250                        },
4251                    }),
4252                    metadata: None,
4253                },
4254                pick_discriminant: |settings_content| {
4255                    Some(
4256                        settings_content
4257                            .title_bar
4258                            .as_ref()?
4259                            .button_layout
4260                            .as_ref()?
4261                            .discriminant() as usize,
4262                    )
4263                },
4264                fields: dynamic_variants::<settings::WindowButtonLayoutContent>()
4265                    .into_iter()
4266                    .map(|variant| match variant {
4267                        settings::WindowButtonLayoutContentDiscriminants::PlatformDefault => {
4268                            vec![]
4269                        }
4270                        settings::WindowButtonLayoutContentDiscriminants::Standard => vec![],
4271                        settings::WindowButtonLayoutContentDiscriminants::Custom => vec![
4272                            SettingItem {
4273                                files: USER,
4274                                title: "Custom Button Layout",
4275                                description:
4276                                    "GNOME-style layout string such as \"close:minimize,maximize\".",
4277                                field: Box::new(SettingField {
4278                                    organization_override: None,
4279                                    json_path: Some("title_bar.button_layout"),
4280                                    pick: |settings_content| match settings_content
4281                                        .title_bar
4282                                        .as_ref()?
4283                                        .button_layout
4284                                        .as_ref()?
4285                                    {
4286                                        settings::WindowButtonLayoutContent::Custom(layout) => {
4287                                            Some(layout)
4288                                        }
4289                                        _ => DEFAULT_EMPTY_STRING,
4290                                    },
4291                                    write: |settings_content, value, _| {
4292                                        settings_content
4293                                            .title_bar
4294                                            .get_or_insert_default()
4295                                            .button_layout = value
4296                                            .map(settings::WindowButtonLayoutContent::Custom);
4297                                    },
4298                                }),
4299                                metadata: Some(Box::new(SettingsFieldMetadata {
4300                                    placeholder: Some("close:minimize,maximize"),
4301                                    ..Default::default()
4302                                })),
4303                            },
4304                        ],
4305                    })
4306                    .collect(),
4307            }),
4308        ]
4309    }
4310
4311    fn tab_bar_section() -> [SettingsPageItem; 9] {
4312        [
4313            SettingsPageItem::SectionHeader("Tab Bar"),
4314            SettingsPageItem::SettingItem(SettingItem {
4315                title: "Show Tab Bar",
4316                description: "Show the tab bar in the editor.",
4317                field: Box::new(SettingField {
4318                    organization_override: None,
4319                    json_path: Some("tab_bar.show"),
4320                    pick: |settings_content| settings_content.tab_bar.as_ref()?.show.as_ref(),
4321                    write: |settings_content, value, _| {
4322                        settings_content.tab_bar.get_or_insert_default().show = value;
4323                    },
4324                }),
4325                metadata: None,
4326                files: USER,
4327            }),
4328            SettingsPageItem::SettingItem(SettingItem {
4329                title: "Show Git Status In Tabs",
4330                description: "Show the Git file status on a tab item.",
4331                field: Box::new(SettingField {
4332                    organization_override: None,
4333                    json_path: Some("tabs.git_status"),
4334                    pick: |settings_content| settings_content.tabs.as_ref()?.git_status.as_ref(),
4335                    write: |settings_content, value, _| {
4336                        settings_content.tabs.get_or_insert_default().git_status = value;
4337                    },
4338                }),
4339                metadata: None,
4340                files: USER,
4341            }),
4342            SettingsPageItem::SettingItem(SettingItem {
4343                title: "Show File Icons In Tabs",
4344                description: "Show the file icon for a tab.",
4345                field: Box::new(SettingField {
4346                    organization_override: None,
4347                    json_path: Some("tabs.file_icons"),
4348                    pick: |settings_content| settings_content.tabs.as_ref()?.file_icons.as_ref(),
4349                    write: |settings_content, value, _| {
4350                        settings_content.tabs.get_or_insert_default().file_icons = value;
4351                    },
4352                }),
4353                metadata: None,
4354                files: USER,
4355            }),
4356            SettingsPageItem::SettingItem(SettingItem {
4357                title: "Tab Close Position",
4358                description: "Position of the close button in a tab.",
4359                field: Box::new(SettingField {
4360                    organization_override: None,
4361                    json_path: Some("tabs.close_position"),
4362                    pick: |settings_content| {
4363                        settings_content.tabs.as_ref()?.close_position.as_ref()
4364                    },
4365                    write: |settings_content, value, _| {
4366                        settings_content.tabs.get_or_insert_default().close_position = value;
4367                    },
4368                }),
4369                metadata: None,
4370                files: USER,
4371            }),
4372            SettingsPageItem::SettingItem(SettingItem {
4373                files: USER,
4374                title: "Maximum Tabs",
4375                description: "Maximum open tabs in a pane. Will not close an unsaved tab.",
4376                // todo(settings_ui): The default for this value is null and it's use in code
4377                // is complex, so I'm going to come back to this later
4378                field: Box::new(
4379                    SettingField {
4380                        organization_override: None,
4381                        json_path: Some("max_tabs"),
4382                        pick: |settings_content| settings_content.workspace.max_tabs.as_ref(),
4383                        write: |settings_content, value, _| {
4384                            settings_content.workspace.max_tabs = value;
4385                        },
4386                    }
4387                    .unimplemented(),
4388                ),
4389                metadata: None,
4390            }),
4391            SettingsPageItem::SettingItem(SettingItem {
4392                title: "Show Navigation History Buttons",
4393                description: "Show the navigation history buttons in the tab bar.",
4394                field: Box::new(SettingField {
4395                    organization_override: None,
4396                    json_path: Some("tab_bar.show_nav_history_buttons"),
4397                    pick: |settings_content| {
4398                        settings_content
4399                            .tab_bar
4400                            .as_ref()?
4401                            .show_nav_history_buttons
4402                            .as_ref()
4403                    },
4404                    write: |settings_content, value, _| {
4405                        settings_content
4406                            .tab_bar
4407                            .get_or_insert_default()
4408                            .show_nav_history_buttons = value;
4409                    },
4410                }),
4411                metadata: None,
4412                files: USER,
4413            }),
4414            SettingsPageItem::SettingItem(SettingItem {
4415                title: "Show Tab Bar Buttons",
4416                description: "Show the tab bar buttons (New, Split Pane, Zoom).",
4417                field: Box::new(SettingField {
4418                    organization_override: None,
4419                    json_path: Some("tab_bar.show_tab_bar_buttons"),
4420                    pick: |settings_content| {
4421                        settings_content
4422                            .tab_bar
4423                            .as_ref()?
4424                            .show_tab_bar_buttons
4425                            .as_ref()
4426                    },
4427                    write: |settings_content, value, _| {
4428                        settings_content
4429                            .tab_bar
4430                            .get_or_insert_default()
4431                            .show_tab_bar_buttons = value;
4432                    },
4433                }),
4434                metadata: None,
4435                files: USER,
4436            }),
4437            SettingsPageItem::SettingItem(SettingItem {
4438                title: "Pinned Tabs Layout",
4439                description: "Show pinned tabs in a separate row above unpinned tabs.",
4440                field: Box::new(SettingField {
4441                    organization_override: None,
4442                    json_path: Some("tab_bar.show_pinned_tabs_in_separate_row"),
4443                    pick: |settings_content| {
4444                        settings_content
4445                            .tab_bar
4446                            .as_ref()?
4447                            .show_pinned_tabs_in_separate_row
4448                            .as_ref()
4449                    },
4450                    write: |settings_content, value, _| {
4451                        settings_content
4452                            .tab_bar
4453                            .get_or_insert_default()
4454                            .show_pinned_tabs_in_separate_row = value;
4455                    },
4456                }),
4457                metadata: None,
4458                files: USER,
4459            }),
4460        ]
4461    }
4462
4463    fn tab_settings_section() -> [SettingsPageItem; 4] {
4464        [
4465            SettingsPageItem::SectionHeader("Tab Settings"),
4466            SettingsPageItem::SettingItem(SettingItem {
4467                title: "Activate On Close",
4468                description: "What to do after closing the current tab.",
4469                field: Box::new(SettingField {
4470                    organization_override: None,
4471                    json_path: Some("tabs.activate_on_close"),
4472                    pick: |settings_content| {
4473                        settings_content.tabs.as_ref()?.activate_on_close.as_ref()
4474                    },
4475                    write: |settings_content, value, _| {
4476                        settings_content
4477                            .tabs
4478                            .get_or_insert_default()
4479                            .activate_on_close = value;
4480                    },
4481                }),
4482                metadata: None,
4483                files: USER,
4484            }),
4485            SettingsPageItem::SettingItem(SettingItem {
4486                title: "Tab Show Diagnostics",
4487                description: "Which files containing diagnostic errors/warnings to mark in the tabs.",
4488                field: Box::new(SettingField {
4489                    organization_override: None,
4490                    json_path: Some("tabs.show_diagnostics"),
4491                    pick: |settings_content| {
4492                        settings_content.tabs.as_ref()?.show_diagnostics.as_ref()
4493                    },
4494                    write: |settings_content, value, _| {
4495                        settings_content
4496                            .tabs
4497                            .get_or_insert_default()
4498                            .show_diagnostics = value;
4499                    },
4500                }),
4501                metadata: None,
4502                files: USER,
4503            }),
4504            SettingsPageItem::SettingItem(SettingItem {
4505                title: "Show Close Button",
4506                description: "Controls the appearance behavior of the tab's close button.",
4507                field: Box::new(SettingField {
4508                    organization_override: None,
4509                    json_path: Some("tabs.show_close_button"),
4510                    pick: |settings_content| {
4511                        settings_content.tabs.as_ref()?.show_close_button.as_ref()
4512                    },
4513                    write: |settings_content, value, _| {
4514                        settings_content
4515                            .tabs
4516                            .get_or_insert_default()
4517                            .show_close_button = value;
4518                    },
4519                }),
4520                metadata: None,
4521                files: USER,
4522            }),
4523        ]
4524    }
4525
4526    fn preview_tabs_section() -> [SettingsPageItem; 8] {
4527        [
4528            SettingsPageItem::SectionHeader("Preview Tabs"),
4529            SettingsPageItem::SettingItem(SettingItem {
4530                title: "Preview Tabs Enabled",
4531                description: "Show opened editors as preview tabs.",
4532                field: Box::new(SettingField {
4533                    organization_override: None,
4534                    json_path: Some("preview_tabs.enabled"),
4535                    pick: |settings_content| {
4536                        settings_content.preview_tabs.as_ref()?.enabled.as_ref()
4537                    },
4538                    write: |settings_content, value, _| {
4539                        settings_content
4540                            .preview_tabs
4541                            .get_or_insert_default()
4542                            .enabled = value;
4543                    },
4544                }),
4545                metadata: None,
4546                files: USER,
4547            }),
4548            SettingsPageItem::SettingItem(SettingItem {
4549                title: "Enable Preview From Project Panel",
4550                description: "Whether to open tabs in preview mode when opened from the project panel with a single click.",
4551                field: Box::new(SettingField {
4552                    organization_override: None,
4553                    json_path: Some("preview_tabs.enable_preview_from_project_panel"),
4554                    pick: |settings_content| {
4555                        settings_content
4556                            .preview_tabs
4557                            .as_ref()?
4558                            .enable_preview_from_project_panel
4559                            .as_ref()
4560                    },
4561                    write: |settings_content, value, _| {
4562                        settings_content
4563                            .preview_tabs
4564                            .get_or_insert_default()
4565                            .enable_preview_from_project_panel = value;
4566                    },
4567                }),
4568                metadata: None,
4569                files: USER,
4570            }),
4571            SettingsPageItem::SettingItem(SettingItem {
4572                title: "Enable Preview From File Finder",
4573                description: "Whether to open tabs in preview mode when selected from the file finder.",
4574                field: Box::new(SettingField {
4575                    organization_override: None,
4576                    json_path: Some("preview_tabs.enable_preview_from_file_finder"),
4577                    pick: |settings_content| {
4578                        settings_content
4579                            .preview_tabs
4580                            .as_ref()?
4581                            .enable_preview_from_file_finder
4582                            .as_ref()
4583                    },
4584                    write: |settings_content, value, _| {
4585                        settings_content
4586                            .preview_tabs
4587                            .get_or_insert_default()
4588                            .enable_preview_from_file_finder = value;
4589                    },
4590                }),
4591                metadata: None,
4592                files: USER,
4593            }),
4594            SettingsPageItem::SettingItem(SettingItem {
4595                title: "Enable Preview From Multibuffer",
4596                description: "Whether to open tabs in preview mode when opened from a multibuffer.",
4597                field: Box::new(SettingField {
4598                    organization_override: None,
4599                    json_path: Some("preview_tabs.enable_preview_from_multibuffer"),
4600                    pick: |settings_content| {
4601                        settings_content
4602                            .preview_tabs
4603                            .as_ref()?
4604                            .enable_preview_from_multibuffer
4605                            .as_ref()
4606                    },
4607                    write: |settings_content, value, _| {
4608                        settings_content
4609                            .preview_tabs
4610                            .get_or_insert_default()
4611                            .enable_preview_from_multibuffer = value;
4612                    },
4613                }),
4614                metadata: None,
4615                files: USER,
4616            }),
4617            SettingsPageItem::SettingItem(SettingItem {
4618                title: "Enable Preview Multibuffer From Code Navigation",
4619                description: "Whether to open tabs in preview mode when code navigation is used to open a multibuffer.",
4620                field: Box::new(SettingField {
4621                    organization_override: None,
4622                    json_path: Some("preview_tabs.enable_preview_multibuffer_from_code_navigation"),
4623                    pick: |settings_content| {
4624                        settings_content
4625                            .preview_tabs
4626                            .as_ref()?
4627                            .enable_preview_multibuffer_from_code_navigation
4628                            .as_ref()
4629                    },
4630                    write: |settings_content, value, _| {
4631                        settings_content
4632                            .preview_tabs
4633                            .get_or_insert_default()
4634                            .enable_preview_multibuffer_from_code_navigation = value;
4635                    },
4636                }),
4637                metadata: None,
4638                files: USER,
4639            }),
4640            SettingsPageItem::SettingItem(SettingItem {
4641                title: "Enable Preview File From Code Navigation",
4642                description: "Whether to open tabs in preview mode when code navigation is used to open a single file.",
4643                field: Box::new(SettingField {
4644                    organization_override: None,
4645                    json_path: Some("preview_tabs.enable_preview_file_from_code_navigation"),
4646                    pick: |settings_content| {
4647                        settings_content
4648                            .preview_tabs
4649                            .as_ref()?
4650                            .enable_preview_file_from_code_navigation
4651                            .as_ref()
4652                    },
4653                    write: |settings_content, value, _| {
4654                        settings_content
4655                            .preview_tabs
4656                            .get_or_insert_default()
4657                            .enable_preview_file_from_code_navigation = value;
4658                    },
4659                }),
4660                metadata: None,
4661                files: USER,
4662            }),
4663            SettingsPageItem::SettingItem(SettingItem {
4664                title: "Enable Keep Preview On Code Navigation",
4665                description: "Whether to keep tabs in preview mode when code navigation is used to navigate away from them. If `enable_preview_file_from_code_navigation` or `enable_preview_multibuffer_from_code_navigation` is also true, the new tab may replace the existing one.",
4666                field: Box::new(SettingField {
4667                    organization_override: None,
4668                    json_path: Some("preview_tabs.enable_keep_preview_on_code_navigation"),
4669                    pick: |settings_content| {
4670                        settings_content
4671                            .preview_tabs
4672                            .as_ref()?
4673                            .enable_keep_preview_on_code_navigation
4674                            .as_ref()
4675                    },
4676                    write: |settings_content, value, _| {
4677                        settings_content
4678                            .preview_tabs
4679                            .get_or_insert_default()
4680                            .enable_keep_preview_on_code_navigation = value;
4681                    },
4682                }),
4683                metadata: None,
4684                files: USER,
4685            }),
4686        ]
4687    }
4688
4689    fn layout_section() -> [SettingsPageItem; 6] {
4690        [
4691            SettingsPageItem::SectionHeader("Layout"),
4692            SettingsPageItem::SettingItem(SettingItem {
4693                title: "Bottom Dock Layout",
4694                description: "Layout mode for the bottom dock.",
4695                field: Box::new(SettingField {
4696                    organization_override: None,
4697                    json_path: Some("bottom_dock_layout"),
4698                    pick: |settings_content| settings_content.workspace.bottom_dock_layout.as_ref(),
4699                    write: |settings_content, value, _| {
4700                        settings_content.workspace.bottom_dock_layout = value;
4701                    },
4702                }),
4703                metadata: None,
4704                files: USER,
4705            }),
4706            SettingsPageItem::SettingItem(SettingItem {
4707                files: USER,
4708                title: "Centered Layout Left Padding",
4709                description: "Left padding for centered layout.",
4710                field: Box::new(SettingField {
4711                    organization_override: None,
4712                    json_path: Some("centered_layout.left_padding"),
4713                    pick: |settings_content| {
4714                        settings_content
4715                            .workspace
4716                            .centered_layout
4717                            .as_ref()?
4718                            .left_padding
4719                            .as_ref()
4720                    },
4721                    write: |settings_content, value, _| {
4722                        settings_content
4723                            .workspace
4724                            .centered_layout
4725                            .get_or_insert_default()
4726                            .left_padding = value;
4727                    },
4728                }),
4729                metadata: None,
4730            }),
4731            SettingsPageItem::SettingItem(SettingItem {
4732                files: USER,
4733                title: "Centered Layout Right Padding",
4734                description: "Right padding for centered layout.",
4735                field: Box::new(SettingField {
4736                    organization_override: None,
4737                    json_path: Some("centered_layout.right_padding"),
4738                    pick: |settings_content| {
4739                        settings_content
4740                            .workspace
4741                            .centered_layout
4742                            .as_ref()?
4743                            .right_padding
4744                            .as_ref()
4745                    },
4746                    write: |settings_content, value, _| {
4747                        settings_content
4748                            .workspace
4749                            .centered_layout
4750                            .get_or_insert_default()
4751                            .right_padding = value;
4752                    },
4753                }),
4754                metadata: None,
4755            }),
4756            SettingsPageItem::SettingItem(SettingItem {
4757                title: "Focus Follows Mouse",
4758                description: "Whether to change focus to a pane when the mouse hovers over it.",
4759                field: Box::new(SettingField {
4760                    organization_override: None,
4761                    json_path: Some("focus_follows_mouse.enabled"),
4762                    pick: |settings_content| {
4763                        settings_content
4764                            .workspace
4765                            .focus_follows_mouse
4766                            .as_ref()
4767                            .and_then(|s| s.enabled.as_ref())
4768                    },
4769                    write: |settings_content, value, _| {
4770                        settings_content
4771                            .workspace
4772                            .focus_follows_mouse
4773                            .get_or_insert_default()
4774                            .enabled = value;
4775                    },
4776                }),
4777                metadata: None,
4778                files: USER,
4779            }),
4780            SettingsPageItem::SettingItem(SettingItem {
4781                title: "Focus Follows Mouse Debounce ms",
4782                description: "Amount of time to wait before changing focus.",
4783                field: Box::new(SettingField {
4784                    organization_override: None,
4785                    json_path: Some("focus_follows_mouse.debounce_ms"),
4786                    pick: |settings_content| {
4787                        settings_content
4788                            .workspace
4789                            .focus_follows_mouse
4790                            .as_ref()
4791                            .and_then(|s| s.debounce_ms.as_ref())
4792                    },
4793                    write: |settings_content, value, _| {
4794                        settings_content
4795                            .workspace
4796                            .focus_follows_mouse
4797                            .get_or_insert_default()
4798                            .debounce_ms = value;
4799                    },
4800                }),
4801                metadata: None,
4802                files: USER,
4803            }),
4804        ]
4805    }
4806
4807    fn window_section() -> [SettingsPageItem; 3] {
4808        [
4809            SettingsPageItem::SectionHeader("Window"),
4810            // todo(settings_ui): Should we filter by platform.as_ref()?
4811            SettingsPageItem::SettingItem(SettingItem {
4812                title: "Use System Window Tabs",
4813                description: "(macOS only) whether to allow Windows to tab together.",
4814                field: Box::new(SettingField {
4815                    organization_override: None,
4816                    json_path: Some("use_system_window_tabs"),
4817                    pick: |settings_content| {
4818                        settings_content.workspace.use_system_window_tabs.as_ref()
4819                    },
4820                    write: |settings_content, value, _| {
4821                        settings_content.workspace.use_system_window_tabs = value;
4822                    },
4823                }),
4824                metadata: None,
4825                files: USER,
4826            }),
4827            SettingsPageItem::SettingItem(SettingItem {
4828                title: "Window Decorations",
4829                description: "(Linux only) whether Omega or your compositor should draw window decorations.",
4830                field: Box::new(SettingField {
4831                    organization_override: None,
4832                    json_path: Some("window_decorations"),
4833                    pick: |settings_content| settings_content.workspace.window_decorations.as_ref(),
4834                    write: |settings_content, value, _| {
4835                        settings_content.workspace.window_decorations = value;
4836                    },
4837                }),
4838                metadata: None,
4839                files: USER,
4840            }),
4841        ]
4842    }
4843
4844    fn pane_modifiers_section() -> [SettingsPageItem; 4] {
4845        [
4846            SettingsPageItem::SectionHeader("Pane Modifiers"),
4847            SettingsPageItem::SettingItem(SettingItem {
4848                title: "Inactive Opacity",
4849                description: "Opacity of inactive panels (0.0 - 1.0).",
4850                field: Box::new(SettingField {
4851                    organization_override: None,
4852                    json_path: Some("active_pane_modifiers.inactive_opacity"),
4853                    pick: |settings_content| {
4854                        settings_content
4855                            .workspace
4856                            .active_pane_modifiers
4857                            .as_ref()?
4858                            .inactive_opacity
4859                            .as_ref()
4860                    },
4861                    write: |settings_content, value, _| {
4862                        settings_content
4863                            .workspace
4864                            .active_pane_modifiers
4865                            .get_or_insert_default()
4866                            .inactive_opacity = value;
4867                    },
4868                }),
4869                metadata: None,
4870                files: USER,
4871            }),
4872            SettingsPageItem::SettingItem(SettingItem {
4873                title: "Border Size",
4874                description: "Size of the border surrounding the active pane.",
4875                field: Box::new(SettingField {
4876                    organization_override: None,
4877                    json_path: Some("active_pane_modifiers.border_size"),
4878                    pick: |settings_content| {
4879                        settings_content
4880                            .workspace
4881                            .active_pane_modifiers
4882                            .as_ref()?
4883                            .border_size
4884                            .as_ref()
4885                    },
4886                    write: |settings_content, value, _| {
4887                        settings_content
4888                            .workspace
4889                            .active_pane_modifiers
4890                            .get_or_insert_default()
4891                            .border_size = value;
4892                    },
4893                }),
4894                metadata: None,
4895                files: USER,
4896            }),
4897            SettingsPageItem::SettingItem(SettingItem {
4898                title: "Zoomed Padding",
4899                description: "Show padding for zoomed panes.",
4900                field: Box::new(SettingField {
4901                    organization_override: None,
4902                    json_path: Some("zoomed_padding"),
4903                    pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
4904                    write: |settings_content, value, _| {
4905                        settings_content.workspace.zoomed_padding = value;
4906                    },
4907                }),
4908                metadata: None,
4909                files: USER,
4910            }),
4911        ]
4912    }
4913
4914    fn pane_split_direction_section() -> [SettingsPageItem; 3] {
4915        [
4916            SettingsPageItem::SectionHeader("Pane Split Direction"),
4917            SettingsPageItem::SettingItem(SettingItem {
4918                title: "Vertical Split Direction",
4919                description: "Direction to split vertically.",
4920                field: Box::new(SettingField {
4921                    organization_override: None,
4922                    json_path: Some("pane_split_direction_vertical"),
4923                    pick: |settings_content| {
4924                        settings_content
4925                            .workspace
4926                            .pane_split_direction_vertical
4927                            .as_ref()
4928                    },
4929                    write: |settings_content, value, _| {
4930                        settings_content.workspace.pane_split_direction_vertical = value;
4931                    },
4932                }),
4933                metadata: None,
4934                files: USER,
4935            }),
4936            SettingsPageItem::SettingItem(SettingItem {
4937                title: "Horizontal Split Direction",
4938                description: "Direction to split horizontally.",
4939                field: Box::new(SettingField {
4940                    organization_override: None,
4941                    json_path: Some("pane_split_direction_horizontal"),
4942                    pick: |settings_content| {
4943                        settings_content
4944                            .workspace
4945                            .pane_split_direction_horizontal
4946                            .as_ref()
4947                    },
4948                    write: |settings_content, value, _| {
4949                        settings_content.workspace.pane_split_direction_horizontal = value;
4950                    },
4951                }),
4952                metadata: None,
4953                files: USER,
4954            }),
4955        ]
4956    }
4957
4958    SettingsPage {
4959        title: "Window & Layout",
4960        items: concat_sections![
4961            status_bar_section(),
4962            title_bar_section(),
4963            tab_bar_section(),
4964            tab_settings_section(),
4965            preview_tabs_section(),
4966            layout_section(),
4967            window_section(),
4968            pane_modifiers_section(),
4969            pane_split_direction_section(),
4970        ],
4971    }
4972}
4973
4974fn panels_page() -> SettingsPage {
4975    fn project_panel_section() -> [SettingsPageItem; 29] {
4976        [
4977            SettingsPageItem::SectionHeader("Project Panel"),
4978            SettingsPageItem::SettingItem(SettingItem {
4979                title: "Project Panel Dock",
4980                description: "Where to dock the project panel.",
4981                field: Box::new(SettingField {
4982                    organization_override: None,
4983                    json_path: Some("project_panel.dock"),
4984                    pick: |settings_content| settings_content.project_panel.as_ref()?.dock.as_ref(),
4985                    write: |settings_content, value, _| {
4986                        settings_content.project_panel.get_or_insert_default().dock = value;
4987                    },
4988                }),
4989                metadata: None,
4990                files: USER,
4991            }),
4992            SettingsPageItem::SettingItem(SettingItem {
4993                title: "Project Panel Default Width",
4994                description: "Default width of the project panel in pixels.",
4995                field: Box::new(SettingField {
4996                    organization_override: None,
4997                    json_path: Some("project_panel.default_width"),
4998                    pick: |settings_content| {
4999                        settings_content
5000                            .project_panel
5001                            .as_ref()?
5002                            .default_width
5003                            .as_ref()
5004                    },
5005                    write: |settings_content, value, _| {
5006                        settings_content
5007                            .project_panel
5008                            .get_or_insert_default()
5009                            .default_width = value;
5010                    },
5011                }),
5012                metadata: None,
5013                files: USER,
5014            }),
5015            SettingsPageItem::SettingItem(SettingItem {
5016                title: "Hide .gitignore",
5017                description: "Whether to hide the gitignore entries in the project panel.",
5018                field: Box::new(SettingField {
5019                    organization_override: None,
5020                    json_path: Some("project_panel.hide_gitignore"),
5021                    pick: |settings_content| {
5022                        settings_content
5023                            .project_panel
5024                            .as_ref()?
5025                            .hide_gitignore
5026                            .as_ref()
5027                    },
5028                    write: |settings_content, value, _| {
5029                        settings_content
5030                            .project_panel
5031                            .get_or_insert_default()
5032                            .hide_gitignore = value;
5033                    },
5034                }),
5035                metadata: None,
5036                files: USER,
5037            }),
5038            SettingsPageItem::SettingItem(SettingItem {
5039                title: "Entry Spacing",
5040                description: "Spacing between worktree entries in the project panel.",
5041                field: Box::new(SettingField {
5042                    organization_override: None,
5043                    json_path: Some("project_panel.entry_spacing"),
5044                    pick: |settings_content| {
5045                        settings_content
5046                            .project_panel
5047                            .as_ref()?
5048                            .entry_spacing
5049                            .as_ref()
5050                    },
5051                    write: |settings_content, value, _| {
5052                        settings_content
5053                            .project_panel
5054                            .get_or_insert_default()
5055                            .entry_spacing = value;
5056                    },
5057                }),
5058                metadata: None,
5059                files: USER,
5060            }),
5061            SettingsPageItem::SettingItem(SettingItem {
5062                title: "File Icons",
5063                description: "Show file icons in the project panel.",
5064                field: Box::new(SettingField {
5065                    organization_override: None,
5066                    json_path: Some("project_panel.file_icons"),
5067                    pick: |settings_content| {
5068                        settings_content.project_panel.as_ref()?.file_icons.as_ref()
5069                    },
5070                    write: |settings_content, value, _| {
5071                        settings_content
5072                            .project_panel
5073                            .get_or_insert_default()
5074                            .file_icons = value;
5075                    },
5076                }),
5077                metadata: None,
5078                files: USER,
5079            }),
5080            SettingsPageItem::SettingItem(SettingItem {
5081                title: "Folder Icons",
5082                description: "Whether to show folder icons or chevrons for directories in the project panel.",
5083                field: Box::new(SettingField {
5084                    organization_override: None,
5085                    json_path: Some("project_panel.folder_icons"),
5086                    pick: |settings_content| {
5087                        settings_content
5088                            .project_panel
5089                            .as_ref()?
5090                            .folder_icons
5091                            .as_ref()
5092                    },
5093                    write: |settings_content, value, _| {
5094                        settings_content
5095                            .project_panel
5096                            .get_or_insert_default()
5097                            .folder_icons = value;
5098                    },
5099                }),
5100                metadata: None,
5101                files: USER,
5102            }),
5103            SettingsPageItem::SettingItem(SettingItem {
5104                title: "Git Status",
5105                description: "Show the Git status in the project panel.",
5106                field: Box::new(SettingField {
5107                    organization_override: None,
5108                    json_path: Some("project_panel.git_status"),
5109                    pick: |settings_content| {
5110                        settings_content.project_panel.as_ref()?.git_status.as_ref()
5111                    },
5112                    write: |settings_content, value, _| {
5113                        settings_content
5114                            .project_panel
5115                            .get_or_insert_default()
5116                            .git_status = value;
5117                    },
5118                }),
5119                metadata: None,
5120                files: USER,
5121            }),
5122            SettingsPageItem::SettingItem(SettingItem {
5123                title: "Indent Size",
5124                description: "Amount of indentation for nested items.",
5125                field: Box::new(SettingField {
5126                    organization_override: None,
5127                    json_path: Some("project_panel.indent_size"),
5128                    pick: |settings_content| {
5129                        settings_content
5130                            .project_panel
5131                            .as_ref()?
5132                            .indent_size
5133                            .as_ref()
5134                    },
5135                    write: |settings_content, value, _| {
5136                        settings_content
5137                            .project_panel
5138                            .get_or_insert_default()
5139                            .indent_size = value;
5140                    },
5141                }),
5142                metadata: None,
5143                files: USER,
5144            }),
5145            SettingsPageItem::SettingItem(SettingItem {
5146                title: "Auto Reveal Entries",
5147                description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
5148                field: Box::new(SettingField {
5149                    organization_override: None,
5150                    json_path: Some("project_panel.auto_reveal_entries"),
5151                    pick: |settings_content| {
5152                        settings_content
5153                            .project_panel
5154                            .as_ref()?
5155                            .auto_reveal_entries
5156                            .as_ref()
5157                    },
5158                    write: |settings_content, value, _| {
5159                        settings_content
5160                            .project_panel
5161                            .get_or_insert_default()
5162                            .auto_reveal_entries = value;
5163                    },
5164                }),
5165                metadata: None,
5166                files: USER,
5167            }),
5168            SettingsPageItem::SettingItem(SettingItem {
5169                title: "Starts Open",
5170                description: "Whether the project panel should open on startup.",
5171                field: Box::new(SettingField {
5172                    organization_override: None,
5173                    json_path: Some("project_panel.starts_open"),
5174                    pick: |settings_content| {
5175                        settings_content
5176                            .project_panel
5177                            .as_ref()?
5178                            .starts_open
5179                            .as_ref()
5180                    },
5181                    write: |settings_content, value, _| {
5182                        settings_content
5183                            .project_panel
5184                            .get_or_insert_default()
5185                            .starts_open = value;
5186                    },
5187                }),
5188                metadata: None,
5189                files: USER,
5190            }),
5191            SettingsPageItem::SettingItem(SettingItem {
5192                title: "Auto Fold Directories",
5193                description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
5194                field: Box::new(SettingField {
5195                    organization_override: None,
5196                    json_path: Some("project_panel.auto_fold_dirs"),
5197                    pick: |settings_content| {
5198                        settings_content
5199                            .project_panel
5200                            .as_ref()?
5201                            .auto_fold_dirs
5202                            .as_ref()
5203                    },
5204                    write: |settings_content, value, _| {
5205                        settings_content
5206                            .project_panel
5207                            .get_or_insert_default()
5208                            .auto_fold_dirs = value;
5209                    },
5210                }),
5211                metadata: None,
5212                files: USER,
5213            }),
5214            SettingsPageItem::SettingItem(SettingItem {
5215                title: "Bold Folder Labels",
5216                description: "Whether to show folder names with bold text in the project panel.",
5217                field: Box::new(SettingField {
5218                    organization_override: None,
5219                    json_path: Some("project_panel.bold_folder_labels"),
5220                    pick: |settings_content| {
5221                        settings_content
5222                            .project_panel
5223                            .as_ref()?
5224                            .bold_folder_labels
5225                            .as_ref()
5226                    },
5227                    write: |settings_content, value, _| {
5228                        settings_content
5229                            .project_panel
5230                            .get_or_insert_default()
5231                            .bold_folder_labels = value;
5232                    },
5233                }),
5234                metadata: None,
5235                files: USER,
5236            }),
5237            SettingsPageItem::SettingItem(SettingItem {
5238                title: "Show Scrollbar",
5239                description: "Show the scrollbar in the project panel.",
5240                field: Box::new(SettingField {
5241                    organization_override: None,
5242                    json_path: Some("project_panel.scrollbar.show"),
5243                    pick: |settings_content| {
5244                        show_scrollbar_or_editor(settings_content, |settings_content| {
5245                            settings_content
5246                                .project_panel
5247                                .as_ref()?
5248                                .scrollbar
5249                                .as_ref()?
5250                                .show
5251                                .as_ref()
5252                        })
5253                    },
5254                    write: |settings_content, value, _| {
5255                        settings_content
5256                            .project_panel
5257                            .get_or_insert_default()
5258                            .scrollbar
5259                            .get_or_insert_default()
5260                            .show = value;
5261                    },
5262                }),
5263                metadata: None,
5264                files: USER,
5265            }),
5266            SettingsPageItem::SettingItem(SettingItem {
5267                title: "Horizontal Scroll",
5268                description: "Whether to allow horizontal scrolling in the project panel. When disabled, the view is always locked to the leftmost position and long file names are clipped.",
5269                field: Box::new(SettingField {
5270                    organization_override: None,
5271                    json_path: Some("project_panel.scrollbar.horizontal_scroll"),
5272                    pick: |settings_content| {
5273                        settings_content
5274                            .project_panel
5275                            .as_ref()?
5276                            .scrollbar
5277                            .as_ref()?
5278                            .horizontal_scroll
5279                            .as_ref()
5280                    },
5281                    write: |settings_content, value, _| {
5282                        settings_content
5283                            .project_panel
5284                            .get_or_insert_default()
5285                            .scrollbar
5286                            .get_or_insert_default()
5287                            .horizontal_scroll = value;
5288                    },
5289                }),
5290                metadata: None,
5291                files: USER,
5292            }),
5293            SettingsPageItem::SettingItem(SettingItem {
5294                title: "Show Diagnostics",
5295                description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
5296                field: Box::new(SettingField {
5297                    organization_override: None,
5298                    json_path: Some("project_panel.show_diagnostics"),
5299                    pick: |settings_content| {
5300                        settings_content
5301                            .project_panel
5302                            .as_ref()?
5303                            .show_diagnostics
5304                            .as_ref()
5305                    },
5306                    write: |settings_content, value, _| {
5307                        settings_content
5308                            .project_panel
5309                            .get_or_insert_default()
5310                            .show_diagnostics = value;
5311                    },
5312                }),
5313                metadata: None,
5314                files: USER,
5315            }),
5316            SettingsPageItem::SettingItem(SettingItem {
5317                title: "Diagnostic Badges",
5318                description: "Show error and warning count badges next to file names in the project panel.",
5319                field: Box::new(SettingField {
5320                    organization_override: None,
5321                    json_path: Some("project_panel.diagnostic_badges"),
5322                    pick: |settings_content| {
5323                        settings_content
5324                            .project_panel
5325                            .as_ref()?
5326                            .diagnostic_badges
5327                            .as_ref()
5328                    },
5329                    write: |settings_content, value, _| {
5330                        settings_content
5331                            .project_panel
5332                            .get_or_insert_default()
5333                            .diagnostic_badges = value;
5334                    },
5335                }),
5336                metadata: None,
5337                files: USER,
5338            }),
5339            SettingsPageItem::SettingItem(SettingItem {
5340                title: "Git Status Indicator",
5341                description: "Show a git status indicator next to file names in the project panel.",
5342                field: Box::new(SettingField {
5343                    organization_override: None,
5344                    json_path: Some("project_panel.git_status_indicator"),
5345                    pick: |settings_content| {
5346                        settings_content
5347                            .project_panel
5348                            .as_ref()?
5349                            .git_status_indicator
5350                            .as_ref()
5351                    },
5352                    write: |settings_content, value, _| {
5353                        settings_content
5354                            .project_panel
5355                            .get_or_insert_default()
5356                            .git_status_indicator = value;
5357                    },
5358                }),
5359                metadata: None,
5360                files: USER,
5361            }),
5362            SettingsPageItem::SettingItem(SettingItem {
5363                title: "Sticky Scroll",
5364                description: "Whether to stick parent directories at top of the project panel.",
5365                field: Box::new(SettingField {
5366                    organization_override: None,
5367                    json_path: Some("project_panel.sticky_scroll"),
5368                    pick: |settings_content| {
5369                        settings_content
5370                            .project_panel
5371                            .as_ref()?
5372                            .sticky_scroll
5373                            .as_ref()
5374                    },
5375                    write: |settings_content, value, _| {
5376                        settings_content
5377                            .project_panel
5378                            .get_or_insert_default()
5379                            .sticky_scroll = value;
5380                    },
5381                }),
5382                metadata: None,
5383                files: USER,
5384            }),
5385            SettingsPageItem::SettingItem(SettingItem {
5386                files: USER,
5387                title: "Show Indent Guides",
5388                description: "Show indent guides in the project panel.",
5389                field: Box::new(SettingField {
5390                    organization_override: None,
5391                    json_path: Some("project_panel.indent_guides.show"),
5392                    pick: |settings_content| {
5393                        settings_content
5394                            .project_panel
5395                            .as_ref()?
5396                            .indent_guides
5397                            .as_ref()?
5398                            .show
5399                            .as_ref()
5400                    },
5401                    write: |settings_content, value, _| {
5402                        settings_content
5403                            .project_panel
5404                            .get_or_insert_default()
5405                            .indent_guides
5406                            .get_or_insert_default()
5407                            .show = value;
5408                    },
5409                }),
5410                metadata: None,
5411            }),
5412            SettingsPageItem::SettingItem(SettingItem {
5413                title: "Drag and Drop",
5414                description: "Whether to enable drag-and-drop operations in the project panel.",
5415                field: Box::new(SettingField {
5416                    organization_override: None,
5417                    json_path: Some("project_panel.drag_and_drop"),
5418                    pick: |settings_content| {
5419                        settings_content
5420                            .project_panel
5421                            .as_ref()?
5422                            .drag_and_drop
5423                            .as_ref()
5424                    },
5425                    write: |settings_content, value, _| {
5426                        settings_content
5427                            .project_panel
5428                            .get_or_insert_default()
5429                            .drag_and_drop = value;
5430                    },
5431                }),
5432                metadata: None,
5433                files: USER,
5434            }),
5435            SettingsPageItem::SettingItem(SettingItem {
5436                title: "Hide Root",
5437                description: "Whether to hide the root entry when only one folder is open in the window.",
5438                field: Box::new(SettingField {
5439                    organization_override: None,
5440                    json_path: Some("project_panel.hide_root"),
5441                    pick: |settings_content| {
5442                        settings_content.project_panel.as_ref()?.hide_root.as_ref()
5443                    },
5444                    write: |settings_content, value, _| {
5445                        settings_content
5446                            .project_panel
5447                            .get_or_insert_default()
5448                            .hide_root = value;
5449                    },
5450                }),
5451                metadata: None,
5452                files: USER,
5453            }),
5454            SettingsPageItem::SettingItem(SettingItem {
5455                title: "Hide Hidden",
5456                description: "Whether to hide the hidden entries in the project panel.",
5457                field: Box::new(SettingField {
5458                    organization_override: None,
5459                    json_path: Some("project_panel.hide_hidden"),
5460                    pick: |settings_content| {
5461                        settings_content
5462                            .project_panel
5463                            .as_ref()?
5464                            .hide_hidden
5465                            .as_ref()
5466                    },
5467                    write: |settings_content, value, _| {
5468                        settings_content
5469                            .project_panel
5470                            .get_or_insert_default()
5471                            .hide_hidden = value;
5472                    },
5473                }),
5474                metadata: None,
5475                files: USER,
5476            }),
5477            SettingsPageItem::SettingItem(SettingItem {
5478                title: "Sort Mode",
5479                description: "Sort order for entries in the project panel.",
5480                field: Box::new(SettingField {
5481                    organization_override: None,
5482                    json_path: Some("project_panel.sort_mode"),
5483                    pick: |settings_content| {
5484                        settings_content.project_panel.as_ref()?.sort_mode.as_ref()
5485                    },
5486                    write: |settings_content, value, _| {
5487                        settings_content
5488                            .project_panel
5489                            .get_or_insert_default()
5490                            .sort_mode = value;
5491                    },
5492                }),
5493                metadata: None,
5494                files: USER,
5495            }),
5496            SettingsPageItem::SettingItem(SettingItem {
5497                title: "Sort Order",
5498                description: "Whether to sort file and folder names case-sensitively in the project panel.",
5499                field: Box::new(SettingField {
5500                    organization_override: None,
5501                    pick: |settings_content| {
5502                        settings_content.project_panel.as_ref()?.sort_order.as_ref()
5503                    },
5504                    write: |settings_content, value, _| {
5505                        settings_content
5506                            .project_panel
5507                            .get_or_insert_default()
5508                            .sort_order = value;
5509                    },
5510                    json_path: Some("project_panel.sort_order"),
5511                }),
5512                metadata: None,
5513                files: USER,
5514            }),
5515            SettingsPageItem::SettingItem(SettingItem {
5516                title: "Auto Open Files On Create",
5517                description: "Whether to automatically open newly created files in the editor.",
5518                field: Box::new(SettingField {
5519                    organization_override: None,
5520                    json_path: Some("project_panel.auto_open.on_create"),
5521                    pick: |settings_content| {
5522                        settings_content
5523                            .project_panel
5524                            .as_ref()?
5525                            .auto_open
5526                            .as_ref()?
5527                            .on_create
5528                            .as_ref()
5529                    },
5530                    write: |settings_content, value, _| {
5531                        settings_content
5532                            .project_panel
5533                            .get_or_insert_default()
5534                            .auto_open
5535                            .get_or_insert_default()
5536                            .on_create = value;
5537                    },
5538                }),
5539                metadata: None,
5540                files: USER,
5541            }),
5542            SettingsPageItem::SettingItem(SettingItem {
5543                title: "Auto Open Files On Paste",
5544                description: "Whether to automatically open files after pasting or duplicating them.",
5545                field: Box::new(SettingField {
5546                    organization_override: None,
5547                    json_path: Some("project_panel.auto_open.on_paste"),
5548                    pick: |settings_content| {
5549                        settings_content
5550                            .project_panel
5551                            .as_ref()?
5552                            .auto_open
5553                            .as_ref()?
5554                            .on_paste
5555                            .as_ref()
5556                    },
5557                    write: |settings_content, value, _| {
5558                        settings_content
5559                            .project_panel
5560                            .get_or_insert_default()
5561                            .auto_open
5562                            .get_or_insert_default()
5563                            .on_paste = value;
5564                    },
5565                }),
5566                metadata: None,
5567                files: USER,
5568            }),
5569            SettingsPageItem::SettingItem(SettingItem {
5570                title: "Auto Open Files On Drop",
5571                description: "Whether to automatically open files dropped from external sources.",
5572                field: Box::new(SettingField {
5573                    organization_override: None,
5574                    json_path: Some("project_panel.auto_open.on_drop"),
5575                    pick: |settings_content| {
5576                        settings_content
5577                            .project_panel
5578                            .as_ref()?
5579                            .auto_open
5580                            .as_ref()?
5581                            .on_drop
5582                            .as_ref()
5583                    },
5584                    write: |settings_content, value, _| {
5585                        settings_content
5586                            .project_panel
5587                            .get_or_insert_default()
5588                            .auto_open
5589                            .get_or_insert_default()
5590                            .on_drop = value;
5591                    },
5592                }),
5593                metadata: None,
5594                files: USER,
5595            }),
5596            SettingsPageItem::SettingItem(SettingItem {
5597                title: "Hidden Files",
5598                description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
5599                field: Box::new(
5600                    SettingField {
5601                        organization_override: None,
5602                        json_path: Some("worktree.hidden_files"),
5603                        pick: |settings_content| {
5604                            settings_content.project.worktree.hidden_files.as_ref()
5605                        },
5606                        write: |settings_content, value, _| {
5607                            settings_content.project.worktree.hidden_files = value;
5608                        },
5609                    }
5610                    .unimplemented(),
5611                ),
5612                metadata: None,
5613                files: USER,
5614            }),
5615        ]
5616    }
5617
5618    fn terminal_panel_section() -> [SettingsPageItem; 4] {
5619        [
5620            SettingsPageItem::SectionHeader("Terminal Panel"),
5621            SettingsPageItem::SettingItem(SettingItem {
5622                title: "Terminal Dock",
5623                description: "Where to dock the terminal panel.",
5624                field: Box::new(SettingField {
5625                    organization_override: None,
5626                    json_path: Some("terminal.dock"),
5627                    pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
5628                    write: |settings_content, value, _| {
5629                        settings_content.terminal.get_or_insert_default().dock = value;
5630                    },
5631                }),
5632                metadata: None,
5633                files: USER,
5634            }),
5635            SettingsPageItem::SettingItem(SettingItem {
5636                title: "Terminal Panel Flexible Sizing",
5637                description: "Whether the terminal panel should use flexible (proportional) sizing when docked to the left or right.",
5638                field: Box::new(SettingField {
5639                    organization_override: None,
5640                    json_path: Some("terminal.flexible"),
5641                    pick: |settings_content| settings_content.terminal.as_ref()?.flexible.as_ref(),
5642                    write: |settings_content, value, _| {
5643                        settings_content.terminal.get_or_insert_default().flexible = value;
5644                    },
5645                }),
5646                metadata: None,
5647                files: USER,
5648            }),
5649            SettingsPageItem::SettingItem(SettingItem {
5650                title: "Show Count Badge",
5651                description: "Show a badge on the terminal panel icon with the count of open terminals.",
5652                field: Box::new(SettingField {
5653                    organization_override: None,
5654                    json_path: Some("terminal.show_count_badge"),
5655                    pick: |settings_content| {
5656                        settings_content
5657                            .terminal
5658                            .as_ref()?
5659                            .show_count_badge
5660                            .as_ref()
5661                    },
5662                    write: |settings_content, value, _| {
5663                        settings_content
5664                            .terminal
5665                            .get_or_insert_default()
5666                            .show_count_badge = value;
5667                    },
5668                }),
5669                metadata: None,
5670                files: USER,
5671            }),
5672        ]
5673    }
5674
5675    fn outline_panel_section() -> [SettingsPageItem; 11] {
5676        [
5677            SettingsPageItem::SectionHeader("Outline Panel"),
5678            SettingsPageItem::SettingItem(SettingItem {
5679                title: "Outline Panel Button",
5680                description: "Show the outline panel button in the status bar.",
5681                field: Box::new(SettingField {
5682                    organization_override: None,
5683                    json_path: Some("outline_panel.button"),
5684                    pick: |settings_content| {
5685                        settings_content.outline_panel.as_ref()?.button.as_ref()
5686                    },
5687                    write: |settings_content, value, _| {
5688                        settings_content
5689                            .outline_panel
5690                            .get_or_insert_default()
5691                            .button = value;
5692                    },
5693                }),
5694                metadata: None,
5695                files: USER,
5696            }),
5697            SettingsPageItem::SettingItem(SettingItem {
5698                title: "Outline Panel Dock",
5699                description: "Where to dock the outline panel.",
5700                field: Box::new(SettingField {
5701                    organization_override: None,
5702                    json_path: Some("outline_panel.dock"),
5703                    pick: |settings_content| settings_content.outline_panel.as_ref()?.dock.as_ref(),
5704                    write: |settings_content, value, _| {
5705                        settings_content.outline_panel.get_or_insert_default().dock = value;
5706                    },
5707                }),
5708                metadata: None,
5709                files: USER,
5710            }),
5711            SettingsPageItem::SettingItem(SettingItem {
5712                title: "Outline Panel Default Width",
5713                description: "Default width of the outline panel in pixels.",
5714                field: Box::new(SettingField {
5715                    organization_override: None,
5716                    json_path: Some("outline_panel.default_width"),
5717                    pick: |settings_content| {
5718                        settings_content
5719                            .outline_panel
5720                            .as_ref()?
5721                            .default_width
5722                            .as_ref()
5723                    },
5724                    write: |settings_content, value, _| {
5725                        settings_content
5726                            .outline_panel
5727                            .get_or_insert_default()
5728                            .default_width = value;
5729                    },
5730                }),
5731                metadata: None,
5732                files: USER,
5733            }),
5734            SettingsPageItem::SettingItem(SettingItem {
5735                title: "File Icons",
5736                description: "Show file icons in the outline panel.",
5737                field: Box::new(SettingField {
5738                    organization_override: None,
5739                    json_path: Some("outline_panel.file_icons"),
5740                    pick: |settings_content| {
5741                        settings_content.outline_panel.as_ref()?.file_icons.as_ref()
5742                    },
5743                    write: |settings_content, value, _| {
5744                        settings_content
5745                            .outline_panel
5746                            .get_or_insert_default()
5747                            .file_icons = value;
5748                    },
5749                }),
5750                metadata: None,
5751                files: USER,
5752            }),
5753            SettingsPageItem::SettingItem(SettingItem {
5754                title: "Folder Icons",
5755                description: "Whether to show folder icons or chevrons for directories in the outline panel.",
5756                field: Box::new(SettingField {
5757                    organization_override: None,
5758                    json_path: Some("outline_panel.folder_icons"),
5759                    pick: |settings_content| {
5760                        settings_content
5761                            .outline_panel
5762                            .as_ref()?
5763                            .folder_icons
5764                            .as_ref()
5765                    },
5766                    write: |settings_content, value, _| {
5767                        settings_content
5768                            .outline_panel
5769                            .get_or_insert_default()
5770                            .folder_icons = value;
5771                    },
5772                }),
5773                metadata: None,
5774                files: USER,
5775            }),
5776            SettingsPageItem::SettingItem(SettingItem {
5777                title: "Git Status",
5778                description: "Show the Git status in the outline panel.",
5779                field: Box::new(SettingField {
5780                    organization_override: None,
5781                    json_path: Some("outline_panel.git_status"),
5782                    pick: |settings_content| {
5783                        settings_content.outline_panel.as_ref()?.git_status.as_ref()
5784                    },
5785                    write: |settings_content, value, _| {
5786                        settings_content
5787                            .outline_panel
5788                            .get_or_insert_default()
5789                            .git_status = value;
5790                    },
5791                }),
5792                metadata: None,
5793                files: USER,
5794            }),
5795            SettingsPageItem::SettingItem(SettingItem {
5796                title: "Indent Size",
5797                description: "Amount of indentation for nested items.",
5798                field: Box::new(SettingField {
5799                    organization_override: None,
5800                    json_path: Some("outline_panel.indent_size"),
5801                    pick: |settings_content| {
5802                        settings_content
5803                            .outline_panel
5804                            .as_ref()?
5805                            .indent_size
5806                            .as_ref()
5807                    },
5808                    write: |settings_content, value, _| {
5809                        settings_content
5810                            .outline_panel
5811                            .get_or_insert_default()
5812                            .indent_size = value;
5813                    },
5814                }),
5815                metadata: None,
5816                files: USER,
5817            }),
5818            SettingsPageItem::SettingItem(SettingItem {
5819                title: "Auto Reveal Entries",
5820                description: "Whether to reveal when a corresponding outline entry becomes active.",
5821                field: Box::new(SettingField {
5822                    organization_override: None,
5823                    json_path: Some("outline_panel.auto_reveal_entries"),
5824                    pick: |settings_content| {
5825                        settings_content
5826                            .outline_panel
5827                            .as_ref()?
5828                            .auto_reveal_entries
5829                            .as_ref()
5830                    },
5831                    write: |settings_content, value, _| {
5832                        settings_content
5833                            .outline_panel
5834                            .get_or_insert_default()
5835                            .auto_reveal_entries = value;
5836                    },
5837                }),
5838                metadata: None,
5839                files: USER,
5840            }),
5841            SettingsPageItem::SettingItem(SettingItem {
5842                title: "Auto Fold Directories",
5843                description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
5844                field: Box::new(SettingField {
5845                    organization_override: None,
5846                    json_path: Some("outline_panel.auto_fold_dirs"),
5847                    pick: |settings_content| {
5848                        settings_content
5849                            .outline_panel
5850                            .as_ref()?
5851                            .auto_fold_dirs
5852                            .as_ref()
5853                    },
5854                    write: |settings_content, value, _| {
5855                        settings_content
5856                            .outline_panel
5857                            .get_or_insert_default()
5858                            .auto_fold_dirs = value;
5859                    },
5860                }),
5861                metadata: None,
5862                files: USER,
5863            }),
5864            SettingsPageItem::SettingItem(SettingItem {
5865                files: USER,
5866                title: "Show Indent Guides",
5867                description: "When to show indent guides in the outline panel.",
5868                field: Box::new(SettingField {
5869                    organization_override: None,
5870                    json_path: Some("outline_panel.indent_guides.show"),
5871                    pick: |settings_content| {
5872                        settings_content
5873                            .outline_panel
5874                            .as_ref()?
5875                            .indent_guides
5876                            .as_ref()?
5877                            .show
5878                            .as_ref()
5879                    },
5880                    write: |settings_content, value, _| {
5881                        settings_content
5882                            .outline_panel
5883                            .get_or_insert_default()
5884                            .indent_guides
5885                            .get_or_insert_default()
5886                            .show = value;
5887                    },
5888                }),
5889                metadata: None,
5890            }),
5891        ]
5892    }
5893
5894    fn git_panel_section() -> [SettingsPageItem; 17] {
5895        [
5896            SettingsPageItem::SectionHeader("Git Panel"),
5897            SettingsPageItem::SettingItem(SettingItem {
5898                title: "Git Panel Button",
5899                description: "Show the Git panel button in the status bar.",
5900                field: Box::new(SettingField {
5901                    organization_override: None,
5902                    json_path: Some("git_panel.button"),
5903                    pick: |settings_content| settings_content.git_panel.as_ref()?.button.as_ref(),
5904                    write: |settings_content, value, _| {
5905                        settings_content.git_panel.get_or_insert_default().button = value;
5906                    },
5907                }),
5908                metadata: None,
5909                files: USER,
5910            }),
5911            SettingsPageItem::SettingItem(SettingItem {
5912                title: "Git Panel Dock",
5913                description: "Where to dock the Git panel.",
5914                field: Box::new(SettingField {
5915                    organization_override: None,
5916                    json_path: Some("git_panel.dock"),
5917                    pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
5918                    write: |settings_content, value, _| {
5919                        settings_content.git_panel.get_or_insert_default().dock = value;
5920                    },
5921                }),
5922                metadata: None,
5923                files: USER,
5924            }),
5925            SettingsPageItem::SettingItem(SettingItem {
5926                title: "Git Panel Default Width",
5927                description: "Default width of the Git panel in pixels.",
5928                field: Box::new(SettingField {
5929                    organization_override: None,
5930                    json_path: Some("git_panel.default_width"),
5931                    pick: |settings_content| {
5932                        settings_content.git_panel.as_ref()?.default_width.as_ref()
5933                    },
5934                    write: |settings_content, value, _| {
5935                        settings_content
5936                            .git_panel
5937                            .get_or_insert_default()
5938                            .default_width = value;
5939                    },
5940                }),
5941                metadata: None,
5942                files: USER,
5943            }),
5944            SettingsPageItem::SettingItem(SettingItem {
5945                title: "Git Panel Status Style",
5946                description: "How entry statuses are displayed.",
5947                field: Box::new(SettingField {
5948                    organization_override: None,
5949                    json_path: Some("git_panel.status_style"),
5950                    pick: |settings_content| {
5951                        settings_content.git_panel.as_ref()?.status_style.as_ref()
5952                    },
5953                    write: |settings_content, value, _| {
5954                        settings_content
5955                            .git_panel
5956                            .get_or_insert_default()
5957                            .status_style = value;
5958                    },
5959                }),
5960                metadata: None,
5961                files: USER,
5962            }),
5963            SettingsPageItem::SettingItem(SettingItem {
5964                title: "Fallback Branch Name",
5965                description: "Default branch name will be when init.defaultbranch is not set in Git.",
5966                field: Box::new(SettingField {
5967                    organization_override: None,
5968                    json_path: Some("git_panel.fallback_branch_name"),
5969                    pick: |settings_content| {
5970                        settings_content
5971                            .git_panel
5972                            .as_ref()?
5973                            .fallback_branch_name
5974                            .as_ref()
5975                    },
5976                    write: |settings_content, value, _| {
5977                        settings_content
5978                            .git_panel
5979                            .get_or_insert_default()
5980                            .fallback_branch_name = value;
5981                    },
5982                }),
5983                metadata: None,
5984                files: USER,
5985            }),
5986            SettingsPageItem::SettingItem(SettingItem {
5987                title: "Sort By",
5988                description: "How to sort entries in the git panel.",
5989                field: Box::new(SettingField {
5990                    organization_override: None,
5991                    json_path: Some("git_panel.sort_by"),
5992                    pick: |settings_content| settings_content.git_panel.as_ref()?.sort_by.as_ref(),
5993                    write: |settings_content, value, _| {
5994                        settings_content.git_panel.get_or_insert_default().sort_by = value;
5995                    },
5996                }),
5997                metadata: None,
5998                files: USER,
5999            }),
6000            SettingsPageItem::SettingItem(SettingItem {
6001                title: "Group By",
6002                description: "How to group entries in the git panel.",
6003                field: Box::new(SettingField {
6004                    organization_override: None,
6005                    json_path: Some("git_panel.group_by"),
6006                    pick: |settings_content| settings_content.git_panel.as_ref()?.group_by.as_ref(),
6007                    write: |settings_content, value, _| {
6008                        settings_content.git_panel.get_or_insert_default().group_by = value;
6009                    },
6010                }),
6011                metadata: None,
6012                files: USER,
6013            }),
6014            SettingsPageItem::SettingItem(SettingItem {
6015                title: "Collapse Untracked Diff",
6016                description: "Whether to collapse untracked files in the diff panel.",
6017                field: Box::new(SettingField {
6018                    organization_override: None,
6019                    json_path: Some("git_panel.collapse_untracked_diff"),
6020                    pick: |settings_content| {
6021                        settings_content
6022                            .git_panel
6023                            .as_ref()?
6024                            .collapse_untracked_diff
6025                            .as_ref()
6026                    },
6027                    write: |settings_content, value, _| {
6028                        settings_content
6029                            .git_panel
6030                            .get_or_insert_default()
6031                            .collapse_untracked_diff = value;
6032                    },
6033                }),
6034                metadata: None,
6035                files: USER,
6036            }),
6037            SettingsPageItem::SettingItem(SettingItem {
6038                title: "Tree View",
6039                description: "Enable to show entries in tree view list, disable to show in flat view list.",
6040                field: Box::new(SettingField {
6041                    organization_override: None,
6042                    json_path: Some("git_panel.tree_view"),
6043                    pick: |settings_content| {
6044                        settings_content.git_panel.as_ref()?.tree_view.as_ref()
6045                    },
6046                    write: |settings_content, value, _| {
6047                        settings_content.git_panel.get_or_insert_default().tree_view = value;
6048                    },
6049                }),
6050                metadata: None,
6051                files: USER,
6052            }),
6053            SettingsPageItem::SettingItem(SettingItem {
6054                title: "File Icons",
6055                description: "Show file icons next to the Git status icon.",
6056                field: Box::new(SettingField {
6057                    organization_override: None,
6058                    json_path: Some("git_panel.file_icons"),
6059                    pick: |settings_content| {
6060                        settings_content.git_panel.as_ref()?.file_icons.as_ref()
6061                    },
6062                    write: |settings_content, value, _| {
6063                        settings_content
6064                            .git_panel
6065                            .get_or_insert_default()
6066                            .file_icons = value;
6067                    },
6068                }),
6069                metadata: None,
6070                files: USER,
6071            }),
6072            SettingsPageItem::SettingItem(SettingItem {
6073                title: "Folder Icons",
6074                description: "Whether to show folder icons or chevrons for directories in the git panel.",
6075                field: Box::new(SettingField {
6076                    organization_override: None,
6077                    json_path: Some("git_panel.folder_icons"),
6078                    pick: |settings_content| {
6079                        settings_content.git_panel.as_ref()?.folder_icons.as_ref()
6080                    },
6081                    write: |settings_content, value, _| {
6082                        settings_content
6083                            .git_panel
6084                            .get_or_insert_default()
6085                            .folder_icons = value;
6086                    },
6087                }),
6088                metadata: None,
6089                files: USER,
6090            }),
6091            SettingsPageItem::SettingItem(SettingItem {
6092                title: "Diff Stats",
6093                description: "Whether to show the addition/deletion change count next to each file in the Git panel.",
6094                field: Box::new(SettingField {
6095                    organization_override: None,
6096                    json_path: Some("git_panel.diff_stats"),
6097                    pick: |settings_content| {
6098                        settings_content.git_panel.as_ref()?.diff_stats.as_ref()
6099                    },
6100                    write: |settings_content, value, _| {
6101                        settings_content
6102                            .git_panel
6103                            .get_or_insert_default()
6104                            .diff_stats = value;
6105                    },
6106                }),
6107                metadata: None,
6108                files: USER,
6109            }),
6110            SettingsPageItem::SettingItem(SettingItem {
6111                title: "Primary Click Behavior",
6112                description: "Default action when clicking a changed file in the Git panel.",
6113                field: Box::new(SettingField {
6114                    organization_override: None,
6115                    json_path: Some("git_panel.entry_primary_click_action"),
6116                    pick: |settings_content| {
6117                        settings_content
6118                            .git_panel
6119                            .as_ref()?
6120                            .entry_primary_click_action
6121                            .as_ref()
6122                    },
6123                    write: |settings_content, value, _| {
6124                        settings_content
6125                            .git_panel
6126                            .get_or_insert_default()
6127                            .entry_primary_click_action = value;
6128                    },
6129                }),
6130                metadata: None,
6131                files: USER,
6132            }),
6133            SettingsPageItem::SettingItem(SettingItem {
6134                title: "Show Count Badge",
6135                description: "Whether to show a badge on the git panel icon with the count of uncommitted changes.",
6136                field: Box::new(SettingField {
6137                    organization_override: None,
6138                    json_path: Some("git_panel.show_count_badge"),
6139                    pick: |settings_content| {
6140                        settings_content
6141                            .git_panel
6142                            .as_ref()?
6143                            .show_count_badge
6144                            .as_ref()
6145                    },
6146                    write: |settings_content, value, _| {
6147                        settings_content
6148                            .git_panel
6149                            .get_or_insert_default()
6150                            .show_count_badge = value;
6151                    },
6152                }),
6153                metadata: None,
6154                files: USER,
6155            }),
6156            SettingsPageItem::SettingItem(SettingItem {
6157                title: "Commit Title Max Length",
6158                description: "Maximum length of the commit message title before a warning is shown. Set to 0 to disable.",
6159                field: Box::new(SettingField {
6160                    organization_override: None,
6161                    json_path: Some("git_panel.commit_title_max_length"),
6162                    pick: |settings_content| {
6163                        settings_content
6164                            .git_panel
6165                            .as_ref()?
6166                            .commit_title_max_length
6167                            .as_ref()
6168                    },
6169                    write: |settings_content, value, _| {
6170                        settings_content
6171                            .git_panel
6172                            .get_or_insert_default()
6173                            .commit_title_max_length = value;
6174                    },
6175                }),
6176                metadata: None,
6177                files: USER,
6178            }),
6179            SettingsPageItem::SettingItem(SettingItem {
6180                title: "Scroll Bar",
6181                description: "How and when the scrollbar should be displayed.",
6182                field: Box::new(SettingField {
6183                    organization_override: None,
6184                    json_path: Some("git_panel.scrollbar.show"),
6185                    pick: |settings_content| {
6186                        show_scrollbar_or_editor(settings_content, |settings_content| {
6187                            settings_content
6188                                .git_panel
6189                                .as_ref()?
6190                                .scrollbar
6191                                .as_ref()?
6192                                .show
6193                                .as_ref()
6194                        })
6195                    },
6196                    write: |settings_content, value, _| {
6197                        settings_content
6198                            .git_panel
6199                            .get_or_insert_default()
6200                            .scrollbar
6201                            .get_or_insert_default()
6202                            .show = value;
6203                    },
6204                }),
6205                metadata: None,
6206                files: USER,
6207            }),
6208        ]
6209    }
6210
6211    fn debugger_panel_section() -> [SettingsPageItem; 2] {
6212        [
6213            SettingsPageItem::SectionHeader("Debugger Panel"),
6214            SettingsPageItem::SettingItem(SettingItem {
6215                title: "Debugger Panel Dock",
6216                description: "The dock position of the debug panel.",
6217                field: Box::new(SettingField {
6218                    organization_override: None,
6219                    json_path: Some("debugger.dock"),
6220                    pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
6221                    write: |settings_content, value, _| {
6222                        settings_content.debugger.get_or_insert_default().dock = value;
6223                    },
6224                }),
6225                metadata: None,
6226                files: USER,
6227            }),
6228        ]
6229    }
6230
6231    fn collaboration_panel_section() -> [SettingsPageItem; 4] {
6232        [
6233            SettingsPageItem::SectionHeader("Collaboration Panel"),
6234            SettingsPageItem::SettingItem(SettingItem {
6235                title: "Collaboration Panel Button",
6236                description: "Show the collaboration panel button in the status bar.",
6237                field: Box::new(SettingField {
6238                    organization_override: None,
6239                    json_path: Some("collaboration_panel.button"),
6240                    pick: |settings_content| {
6241                        settings_content
6242                            .collaboration_panel
6243                            .as_ref()?
6244                            .button
6245                            .as_ref()
6246                    },
6247                    write: |settings_content, value, _| {
6248                        settings_content
6249                            .collaboration_panel
6250                            .get_or_insert_default()
6251                            .button = value;
6252                    },
6253                }),
6254                metadata: None,
6255                files: USER,
6256            }),
6257            SettingsPageItem::SettingItem(SettingItem {
6258                title: "Collaboration Panel Dock",
6259                description: "Where to dock the collaboration panel.",
6260                field: Box::new(SettingField {
6261                    organization_override: None,
6262                    json_path: Some("collaboration_panel.dock"),
6263                    pick: |settings_content| {
6264                        settings_content.collaboration_panel.as_ref()?.dock.as_ref()
6265                    },
6266                    write: |settings_content, value, _| {
6267                        settings_content
6268                            .collaboration_panel
6269                            .get_or_insert_default()
6270                            .dock = value;
6271                    },
6272                }),
6273                metadata: None,
6274                files: USER,
6275            }),
6276            SettingsPageItem::SettingItem(SettingItem {
6277                title: "Collaboration Panel Default Width",
6278                description: "Default width of the collaboration panel in pixels.",
6279                field: Box::new(SettingField {
6280                    organization_override: None,
6281                    json_path: Some("collaboration_panel.dock"),
6282                    pick: |settings_content| {
6283                        settings_content
6284                            .collaboration_panel
6285                            .as_ref()?
6286                            .default_width
6287                            .as_ref()
6288                    },
6289                    write: |settings_content, value, _| {
6290                        settings_content
6291                            .collaboration_panel
6292                            .get_or_insert_default()
6293                            .default_width = value;
6294                    },
6295                }),
6296                metadata: None,
6297                files: USER,
6298            }),
6299        ]
6300    }
6301
6302    fn agent_panel_section() -> [SettingsPageItem; 7] {
6303        [
6304            SettingsPageItem::SectionHeader("Agent Panel"),
6305            SettingsPageItem::SettingItem(SettingItem {
6306                title: "Agent Panel Button",
6307                description: "Whether to show the agent panel button in the status bar.",
6308                field: Box::new(SettingField {
6309                    organization_override: None,
6310                    json_path: Some("agent.button"),
6311                    pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
6312                    write: |settings_content, value, _| {
6313                        settings_content.agent.get_or_insert_default().button = value;
6314                    },
6315                }),
6316                metadata: None,
6317                files: USER,
6318            }),
6319            SettingsPageItem::SettingItem(SettingItem {
6320                title: "Agent Panel Dock",
6321                description: "Where to dock the agent panel.",
6322                field: Box::new(SettingField {
6323                    organization_override: None,
6324                    json_path: Some("agent.dock"),
6325                    pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
6326                    write: |settings_content, value, _| {
6327                        settings_content.agent.get_or_insert_default().dock = value;
6328                    },
6329                }),
6330                metadata: None,
6331                files: USER,
6332            }),
6333            SettingsPageItem::SettingItem(SettingItem {
6334                title: "Agent Panel Flexible Sizing",
6335                description: "Whether the agent panel should use flexible (proportional) sizing when docked to the left or right.",
6336                field: Box::new(SettingField {
6337                    organization_override: None,
6338                    json_path: Some("agent.flexible"),
6339                    pick: |settings_content| settings_content.agent.as_ref()?.flexible.as_ref(),
6340                    write: |settings_content, value, _| {
6341                        settings_content.agent.get_or_insert_default().flexible = value;
6342                    },
6343                }),
6344                metadata: None,
6345                files: USER,
6346            }),
6347            SettingsPageItem::SettingItem(SettingItem {
6348                title: "Agent Panel Default Width",
6349                description: "Default width when the agent panel is docked to the left or right.",
6350                field: Box::new(SettingField {
6351                    organization_override: None,
6352                    json_path: Some("agent.default_width"),
6353                    pick: |settings_content| {
6354                        settings_content.agent.as_ref()?.default_width.as_ref()
6355                    },
6356                    write: |settings_content, value, _| {
6357                        settings_content.agent.get_or_insert_default().default_width = value;
6358                    },
6359                }),
6360                metadata: None,
6361                files: USER,
6362            }),
6363            SettingsPageItem::SettingItem(SettingItem {
6364                title: "Agent Panel Default Height",
6365                description: "Default height when the agent panel is docked to the bottom.",
6366                field: Box::new(SettingField {
6367                    organization_override: None,
6368                    json_path: Some("agent.default_height"),
6369                    pick: |settings_content| {
6370                        settings_content.agent.as_ref()?.default_height.as_ref()
6371                    },
6372                    write: |settings_content, value, _| {
6373                        settings_content
6374                            .agent
6375                            .get_or_insert_default()
6376                            .default_height = value;
6377                    },
6378                }),
6379                metadata: None,
6380                files: USER,
6381            }),
6382            SettingsPageItem::DynamicItem(DynamicItem {
6383                discriminant: SettingItem {
6384                    files: USER,
6385                    title: "Limit Content Width",
6386                    description: "Whether to constrain the agent panel content to a maximum width, centering it when the panel is wider, for optimal readability.",
6387                    field: Box::new(SettingField::<bool> {
6388                        organization_override: None,
6389                        json_path: Some("agent.limit_content_width"),
6390                        pick: |settings_content| {
6391                            settings_content
6392                                .agent
6393                                .as_ref()?
6394                                .limit_content_width
6395                                .as_ref()
6396                        },
6397                        write: |settings_content, value, _| {
6398                            settings_content
6399                                .agent
6400                                .get_or_insert_default()
6401                                .limit_content_width = value;
6402                        },
6403                    }),
6404                    metadata: None,
6405                },
6406                pick_discriminant: |settings_content| {
6407                    let enabled = settings_content
6408                        .agent
6409                        .as_ref()?
6410                        .limit_content_width
6411                        .unwrap_or(true);
6412                    Some(if enabled { 1 } else { 0 })
6413                },
6414                fields: vec![
6415                    vec![],
6416                    vec![SettingItem {
6417                        files: USER,
6418                        title: "Max Content Width",
6419                        description: "Maximum content width in pixels. Content will be centered when the panel is wider than this value.",
6420                        field: Box::new(SettingField {
6421                            organization_override: None,
6422                            json_path: Some("agent.max_content_width"),
6423                            pick: |settings_content| {
6424                                settings_content.agent.as_ref()?.max_content_width.as_ref()
6425                            },
6426                            write: |settings_content, value, _| {
6427                                settings_content
6428                                    .agent
6429                                    .get_or_insert_default()
6430                                    .max_content_width = value;
6431                            },
6432                        }),
6433                        metadata: None,
6434                    }],
6435                ],
6436            }),
6437        ]
6438    }
6439
6440    SettingsPage {
6441        title: "Panels",
6442        items: concat_sections![
6443            project_panel_section(),
6444            terminal_panel_section(),
6445            outline_panel_section(),
6446            git_panel_section(),
6447            debugger_panel_section(),
6448            collaboration_panel_section(),
6449            agent_panel_section(),
6450        ],
6451    }
6452}
6453
6454fn debugger_page() -> SettingsPage {
6455    fn general_section() -> [SettingsPageItem; 6] {
6456        [
6457            SettingsPageItem::SectionHeader("General"),
6458            SettingsPageItem::SettingItem(SettingItem {
6459                title: "Stepping Granularity",
6460                description: "Determines the stepping granularity for debug operations.",
6461                field: Box::new(SettingField {
6462                    organization_override: None,
6463                    json_path: Some("debugger.stepping_granularity"),
6464                    pick: |settings_content| {
6465                        settings_content
6466                            .debugger
6467                            .as_ref()?
6468                            .stepping_granularity
6469                            .as_ref()
6470                    },
6471                    write: |settings_content, value, _| {
6472                        settings_content
6473                            .debugger
6474                            .get_or_insert_default()
6475                            .stepping_granularity = value;
6476                    },
6477                }),
6478                metadata: None,
6479                files: USER,
6480            }),
6481            SettingsPageItem::SettingItem(SettingItem {
6482                title: "Save Breakpoints",
6483                description: "Whether breakpoints should be reused across Omega sessions.",
6484                field: Box::new(SettingField {
6485                    organization_override: None,
6486                    json_path: Some("debugger.save_breakpoints"),
6487                    pick: |settings_content| {
6488                        settings_content
6489                            .debugger
6490                            .as_ref()?
6491                            .save_breakpoints
6492                            .as_ref()
6493                    },
6494                    write: |settings_content, value, _| {
6495                        settings_content
6496                            .debugger
6497                            .get_or_insert_default()
6498                            .save_breakpoints = value;
6499                    },
6500                }),
6501                metadata: None,
6502                files: USER,
6503            }),
6504            SettingsPageItem::SettingItem(SettingItem {
6505                title: "Timeout",
6506                description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
6507                field: Box::new(SettingField {
6508                    organization_override: None,
6509                    json_path: Some("debugger.timeout"),
6510                    pick: |settings_content| settings_content.debugger.as_ref()?.timeout.as_ref(),
6511                    write: |settings_content, value, _| {
6512                        settings_content.debugger.get_or_insert_default().timeout = value;
6513                    },
6514                }),
6515                metadata: None,
6516                files: USER,
6517            }),
6518            SettingsPageItem::SettingItem(SettingItem {
6519                title: "Log DAP Communications",
6520                description: "Whether to log messages between active debug adapters and Omega.",
6521                field: Box::new(SettingField {
6522                    organization_override: None,
6523                    json_path: Some("debugger.log_dap_communications"),
6524                    pick: |settings_content| {
6525                        settings_content
6526                            .debugger
6527                            .as_ref()?
6528                            .log_dap_communications
6529                            .as_ref()
6530                    },
6531                    write: |settings_content, value, _| {
6532                        settings_content
6533                            .debugger
6534                            .get_or_insert_default()
6535                            .log_dap_communications = value;
6536                    },
6537                }),
6538                metadata: None,
6539                files: USER,
6540            }),
6541            SettingsPageItem::SettingItem(SettingItem {
6542                title: "Format DAP Log Messages",
6543                description: "Whether to format DAP messages when adding them to debug adapter logger.",
6544                field: Box::new(SettingField {
6545                    organization_override: None,
6546                    json_path: Some("debugger.format_dap_log_messages"),
6547                    pick: |settings_content| {
6548                        settings_content
6549                            .debugger
6550                            .as_ref()?
6551                            .format_dap_log_messages
6552                            .as_ref()
6553                    },
6554                    write: |settings_content, value, _| {
6555                        settings_content
6556                            .debugger
6557                            .get_or_insert_default()
6558                            .format_dap_log_messages = value;
6559                    },
6560                }),
6561                metadata: None,
6562                files: USER,
6563            }),
6564        ]
6565    }
6566
6567    SettingsPage {
6568        title: "Debugger",
6569        items: concat_sections![general_section()],
6570    }
6571}
6572
6573fn terminal_page() -> SettingsPage {
6574    fn environment_section() -> [SettingsPageItem; 5] {
6575        [
6576                SettingsPageItem::SectionHeader("Environment"),
6577                SettingsPageItem::DynamicItem(DynamicItem {
6578                    discriminant: SettingItem {
6579                        files: USER | PROJECT,
6580                        title: "Shell",
6581                        description: "What shell to use when opening a terminal.",
6582                        field: Box::new(SettingField {
6583                            organization_override: None,
6584                            json_path: Some("terminal.shell$"),
6585                            pick: |settings_content| {
6586                                Some(&dynamic_variants::<settings::Shell>()[
6587                                    settings_content
6588                                        .terminal
6589                                        .as_ref()?
6590                                        .project
6591                                        .shell
6592                                        .as_ref()?
6593                                        .discriminant() as usize
6594                                ])
6595                            },
6596                            write: |settings_content, value, _| {
6597                                let Some(value) = value else {
6598                                    if let Some(terminal) = settings_content.terminal.as_mut() {
6599                                        terminal.project.shell = None;
6600                                    }
6601                                    return;
6602                                };
6603                                let settings_value = settings_content
6604                                    .terminal
6605                                    .get_or_insert_default()
6606                                    .project
6607                                    .shell
6608                                    .get_or_insert_with(|| settings::Shell::default());
6609                                let default_shell = if cfg!(target_os = "windows") {
6610                                    "powershell.exe"
6611                                } else {
6612                                    "sh"
6613                                };
6614                                *settings_value = match value {
6615                                    settings::ShellDiscriminants::System => settings::Shell::System,
6616                                    settings::ShellDiscriminants::Program => {
6617                                        let program = match settings_value {
6618                                            settings::Shell::Program(program) => program.clone(),
6619                                            settings::Shell::WithArguments { program, .. } => program.clone(),
6620                                            _ => String::from(default_shell),
6621                                        };
6622                                        settings::Shell::Program(program)
6623                                    }
6624                                    settings::ShellDiscriminants::WithArguments => {
6625                                        let (program, args, title_override) = match settings_value {
6626                                            settings::Shell::Program(program) => (program.clone(), vec![], None),
6627                                            settings::Shell::WithArguments {
6628                                                program,
6629                                                args,
6630                                                title_override,
6631                                            } => (program.clone(), args.clone(), title_override.clone()),
6632                                            _ => (String::from(default_shell), vec![], None),
6633                                        };
6634                                        settings::Shell::WithArguments {
6635                                            program,
6636                                            args,
6637                                            title_override,
6638                                        }
6639                                    }
6640                                };
6641                            },
6642                        }),
6643                        metadata: None,
6644                    },
6645                    pick_discriminant: |settings_content| {
6646                        Some(
6647                            settings_content
6648                                .terminal
6649                                .as_ref()?
6650                                .project
6651                                .shell
6652                                .as_ref()?
6653                                .discriminant() as usize,
6654                        )
6655                    },
6656                    fields: dynamic_variants::<settings::Shell>()
6657                        .into_iter()
6658                        .map(|variant| match variant {
6659                            settings::ShellDiscriminants::System => vec![],
6660                            settings::ShellDiscriminants::Program => vec![SettingItem {
6661                                files: USER | PROJECT,
6662                                title: "Program",
6663                                description: "The shell program to use.",
6664                                field: Box::new(SettingField {
6665                                    organization_override: None,
6666                                    json_path: Some("terminal.shell"),
6667                                    pick: |settings_content| match settings_content.terminal.as_ref()?.project.shell.as_ref()
6668                                    {
6669                                        Some(settings::Shell::Program(program)) => Some(program),
6670                                        _ => None,
6671                                    },
6672                                    write: |settings_content, value, _| {
6673                                        let Some(value) = value else {
6674                                            return;
6675                                        };
6676                                        match settings_content
6677                                            .terminal
6678                                            .get_or_insert_default()
6679                                            .project
6680                                            .shell
6681                                            .as_mut()
6682                                        {
6683                                            Some(settings::Shell::Program(program)) => *program = value,
6684                                            _ => return,
6685                                        }
6686                                    },
6687                                }),
6688                                metadata: None,
6689                            }],
6690                            settings::ShellDiscriminants::WithArguments => vec![
6691                                SettingItem {
6692                                    files: USER | PROJECT,
6693                                    title: "Program",
6694                                    description: "The shell program to run.",
6695                                    field: Box::new(SettingField {
6696                                        organization_override: None,
6697                                        json_path: Some("terminal.shell.program"),
6698                                        pick: |settings_content| {
6699                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
6700                                                Some(settings::Shell::WithArguments { program, .. }) => Some(program),
6701                                                _ => None,
6702                                            }
6703                                        },
6704                                        write: |settings_content, value, _| {
6705                                            let Some(value) = value else {
6706                                                return;
6707                                            };
6708                                            match settings_content
6709                                                .terminal
6710                                                .get_or_insert_default()
6711                                                .project
6712                                                .shell
6713                                                .as_mut()
6714                                            {
6715                                                Some(settings::Shell::WithArguments { program, .. }) => {
6716                                                    *program = value
6717                                                }
6718                                                _ => return,
6719                                            }
6720                                        },
6721                                    }),
6722                                    metadata: None,
6723                                },
6724                                SettingItem {
6725                                    files: USER | PROJECT,
6726                                    title: "Arguments",
6727                                    description: "The arguments to pass to the shell program.",
6728                                    field: Box::new(
6729                                        SettingField {
6730                                            organization_override: None,
6731                                            json_path: Some("terminal.shell.args"),
6732                                            pick: |settings_content| {
6733                                                match settings_content.terminal.as_ref()?.project.shell.as_ref() {
6734                                                    Some(settings::Shell::WithArguments { args, .. }) => Some(args),
6735                                                    _ => None,
6736                                                }
6737                                            },
6738                                            write: |settings_content, value, _| {
6739                                                let Some(value) = value else {
6740                                                    return;
6741                                                };
6742                                                match settings_content
6743                                                    .terminal
6744                                                    .get_or_insert_default()
6745                                                    .project
6746                                                    .shell
6747                                                    .as_mut()
6748                                                {
6749                                                    Some(settings::Shell::WithArguments { args, .. }) => *args = value,
6750                                                    _ => return,
6751                                                }
6752                                            },
6753                                        }
6754                                        .unimplemented(),
6755                                    ),
6756                                    metadata: None,
6757                                },
6758                                SettingItem {
6759                                    files: USER | PROJECT,
6760                                    title: "Title Override",
6761                                    description: "An optional string to override the title of the terminal tab.",
6762                                    field: Box::new(SettingField {
6763                                        organization_override: None,
6764                                        json_path: Some("terminal.shell.title_override"),
6765                                        pick: |settings_content| {
6766                                            match settings_content.terminal.as_ref()?.project.shell.as_ref() {
6767                                                Some(settings::Shell::WithArguments { title_override, .. }) => {
6768                                                    title_override.as_ref().or(DEFAULT_EMPTY_STRING)
6769                                                }
6770                                                _ => None,
6771                                            }
6772                                        },
6773                                        write: |settings_content, value, _| {
6774                                            match settings_content
6775                                                .terminal
6776                                                .get_or_insert_default()
6777                                                .project
6778                                                .shell
6779                                                .as_mut()
6780                                            {
6781                                                Some(settings::Shell::WithArguments { title_override, .. }) => {
6782                                                    *title_override = value.filter(|s| !s.is_empty())
6783                                                }
6784                                                _ => return,
6785                                            }
6786                                        },
6787                                    }),
6788                                    metadata: None,
6789                                },
6790                            ],
6791                        })
6792                        .collect(),
6793                }),
6794                SettingsPageItem::DynamicItem(DynamicItem {
6795                    discriminant: SettingItem {
6796                        files: USER | PROJECT,
6797                        title: "Working Directory",
6798                        description: "What working directory to use when launching the terminal.",
6799                        field: Box::new(SettingField {
6800                            organization_override: None,
6801                            json_path: Some("terminal.working_directory$"),
6802                            pick: |settings_content| {
6803                                Some(&dynamic_variants::<settings::WorkingDirectory>()[
6804                                    settings_content
6805                                        .terminal
6806                                        .as_ref()?
6807                                        .project
6808                                        .working_directory
6809                                        .as_ref()?
6810                                        .discriminant() as usize
6811                                ])
6812                            },
6813                            write: |settings_content, value, _| {
6814                                let Some(value) = value else {
6815                                    if let Some(terminal) = settings_content.terminal.as_mut() {
6816                                        terminal.project.working_directory = None;
6817                                    }
6818                                    return;
6819                                };
6820                                let settings_value = settings_content
6821                                    .terminal
6822                                    .get_or_insert_default()
6823                                    .project
6824                                    .working_directory
6825                                    .get_or_insert_with(|| settings::WorkingDirectory::CurrentProjectDirectory);
6826                                *settings_value = match value {
6827                                    settings::WorkingDirectoryDiscriminants::CurrentFileDirectory => {
6828                                        settings::WorkingDirectory::CurrentFileDirectory
6829                                    },
6830                                    settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => {
6831                                        settings::WorkingDirectory::CurrentProjectDirectory
6832                                    }
6833                                    settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => {
6834                                        settings::WorkingDirectory::FirstProjectDirectory
6835                                    }
6836                                    settings::WorkingDirectoryDiscriminants::AlwaysHome => {
6837                                        settings::WorkingDirectory::AlwaysHome
6838                                    }
6839                                    settings::WorkingDirectoryDiscriminants::Always => {
6840                                        let directory = match settings_value {
6841                                            settings::WorkingDirectory::Always { .. } => return,
6842                                            _ => String::new(),
6843                                        };
6844                                        settings::WorkingDirectory::Always { directory }
6845                                    }
6846                                };
6847                            },
6848                        }),
6849                        metadata: None,
6850                    },
6851                    pick_discriminant: |settings_content| {
6852                        Some(
6853                            settings_content
6854                                .terminal
6855                                .as_ref()?
6856                                .project
6857                                .working_directory
6858                                .as_ref()?
6859                                .discriminant() as usize,
6860                        )
6861                    },
6862                    fields: dynamic_variants::<settings::WorkingDirectory>()
6863                        .into_iter()
6864                        .map(|variant| match variant {
6865                            settings::WorkingDirectoryDiscriminants::CurrentFileDirectory => vec![],
6866                            settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => vec![],
6867                            settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => vec![],
6868                            settings::WorkingDirectoryDiscriminants::AlwaysHome => vec![],
6869                            settings::WorkingDirectoryDiscriminants::Always => vec![SettingItem {
6870                                files: USER | PROJECT,
6871                                title: "Directory",
6872                                description: "The directory path to use (will be shell expanded).",
6873                                field: Box::new(SettingField {
6874                                    organization_override: None,
6875                                    json_path: Some("terminal.working_directory.always"),
6876                                    pick: |settings_content| {
6877                                        match settings_content.terminal.as_ref()?.project.working_directory.as_ref() {
6878                                            Some(settings::WorkingDirectory::Always { directory }) => Some(directory),
6879                                            _ => None,
6880                                        }
6881                                    },
6882                                    write: |settings_content, value, _| {
6883                                        let value = value.unwrap_or_default();
6884                                        match settings_content
6885                                            .terminal
6886                                            .get_or_insert_default()
6887                                            .project
6888                                            .working_directory
6889                                            .as_mut()
6890                                        {
6891                                            Some(settings::WorkingDirectory::Always { directory }) => *directory = value,
6892                                            _ => return,
6893                                        }
6894                                    },
6895                                }),
6896                                metadata: None,
6897                            }],
6898                        })
6899                        .collect(),
6900                }),
6901                SettingsPageItem::SettingItem(SettingItem {
6902                    title: "Environment Variables",
6903                    description: "Key-value pairs to add to the terminal's environment.",
6904                    field: Box::new(
6905                        SettingField {
6906                            organization_override: None,
6907                            json_path: Some("terminal.env"),
6908                            pick: |settings_content| settings_content.terminal.as_ref()?.project.env.as_ref(),
6909                            write: |settings_content, value, _| {
6910                                settings_content.terminal.get_or_insert_default().project.env = value;
6911                            },
6912                        }
6913                        .unimplemented(),
6914                    ),
6915                    metadata: None,
6916                    files: USER | PROJECT,
6917                }),
6918                SettingsPageItem::SettingItem(SettingItem {
6919                    title: "Detect Virtual Environment",
6920                    description: "Activates the Python virtual environment, if one is found, in the terminal's working directory.",
6921                    field: Box::new(
6922                        SettingField {
6923                            organization_override: None,
6924                            json_path: Some("terminal.detect_venv"),
6925                            pick: |settings_content| settings_content.terminal.as_ref()?.project.detect_venv.as_ref(),
6926                            write: |settings_content, value, _| {
6927                                settings_content
6928                                    .terminal
6929                                    .get_or_insert_default()
6930                                    .project
6931                                    .detect_venv = value;
6932                            },
6933                        }
6934                        .unimplemented(),
6935                    ),
6936                    metadata: None,
6937                    files: USER | PROJECT,
6938                }),
6939            ]
6940    }
6941
6942    fn font_section() -> [SettingsPageItem; 6] {
6943        [
6944            SettingsPageItem::SectionHeader("Font"),
6945            SettingsPageItem::SettingItem(SettingItem {
6946                title: "Font Size",
6947                description: "Font size for terminal text. If not set, defaults to buffer font size.",
6948                field: Box::new(SettingField {
6949                    organization_override: None,
6950                    json_path: Some("terminal.font_size"),
6951                    pick: |settings_content| {
6952                        settings_content
6953                            .terminal
6954                            .as_ref()
6955                            .and_then(|terminal| terminal.font_size.as_ref())
6956                            .or(settings_content.theme.buffer_font_size.as_ref())
6957                    },
6958                    write: |settings_content, value, _| {
6959                        settings_content.terminal.get_or_insert_default().font_size = value;
6960                    },
6961                }),
6962                metadata: None,
6963                files: USER,
6964            }),
6965            SettingsPageItem::SettingItem(SettingItem {
6966                title: "Font Family",
6967                description: "Font family for terminal text. If not set, defaults to buffer font family.",
6968                field: Box::new(SettingField {
6969                    organization_override: None,
6970                    json_path: Some("terminal.font_family"),
6971                    pick: |settings_content| {
6972                        settings_content
6973                            .terminal
6974                            .as_ref()
6975                            .and_then(|terminal| terminal.font_family.as_ref())
6976                            .or(settings_content.theme.buffer_font_family.as_ref())
6977                    },
6978                    write: |settings_content, value, _| {
6979                        settings_content
6980                            .terminal
6981                            .get_or_insert_default()
6982                            .font_family = value;
6983                    },
6984                }),
6985                metadata: None,
6986                files: USER,
6987            }),
6988            SettingsPageItem::SettingItem(SettingItem {
6989                title: "Font Fallbacks",
6990                description: "Font fallbacks for terminal text. If not set, defaults to buffer font fallbacks.",
6991                field: Box::new(
6992                    SettingField {
6993                        organization_override: None,
6994                        json_path: Some("terminal.font_fallbacks"),
6995                        pick: |settings_content| {
6996                            settings_content
6997                                .terminal
6998                                .as_ref()
6999                                .and_then(|terminal| terminal.font_fallbacks.as_ref())
7000                                .or(settings_content.theme.buffer_font_fallbacks.as_ref())
7001                        },
7002                        write: |settings_content, value, _| {
7003                            settings_content
7004                                .terminal
7005                                .get_or_insert_default()
7006                                .font_fallbacks = value;
7007                        },
7008                    }
7009                    .unimplemented(),
7010                ),
7011                metadata: None,
7012                files: USER,
7013            }),
7014            SettingsPageItem::SettingItem(SettingItem {
7015                title: "Font Weight",
7016                description: "Font weight for terminal text in CSS weight units (100-900).",
7017                field: Box::new(SettingField {
7018                    organization_override: None,
7019                    json_path: Some("terminal.font_weight"),
7020                    pick: |settings_content| {
7021                        settings_content.terminal.as_ref()?.font_weight.as_ref()
7022                    },
7023                    write: |settings_content, value, _| {
7024                        settings_content
7025                            .terminal
7026                            .get_or_insert_default()
7027                            .font_weight = value;
7028                    },
7029                }),
7030                metadata: None,
7031                files: USER,
7032            }),
7033            SettingsPageItem::SettingItem(SettingItem {
7034                title: "Font Features",
7035                description: "Font features for terminal text.",
7036                field: Box::new(
7037                    SettingField {
7038                        organization_override: None,
7039                        json_path: Some("terminal.font_features"),
7040                        pick: |settings_content| {
7041                            settings_content
7042                                .terminal
7043                                .as_ref()
7044                                .and_then(|terminal| terminal.font_features.as_ref())
7045                                .or(settings_content.theme.buffer_font_features.as_ref())
7046                        },
7047                        write: |settings_content, value, _| {
7048                            settings_content
7049                                .terminal
7050                                .get_or_insert_default()
7051                                .font_features = value;
7052                        },
7053                    }
7054                    .unimplemented(),
7055                ),
7056                metadata: None,
7057                files: USER,
7058            }),
7059        ]
7060    }
7061
7062    fn display_settings_section() -> [SettingsPageItem; 6] {
7063        [
7064            SettingsPageItem::SectionHeader("Display Settings"),
7065            SettingsPageItem::SettingItem(SettingItem {
7066                title: "Line Height",
7067                description: "Line height for terminal text.",
7068                field: Box::new(
7069                    SettingField {
7070                        organization_override: None,
7071                        json_path: Some("terminal.line_height"),
7072                        pick: |settings_content| {
7073                            settings_content.terminal.as_ref()?.line_height.as_ref()
7074                        },
7075                        write: |settings_content, value, _| {
7076                            settings_content
7077                                .terminal
7078                                .get_or_insert_default()
7079                                .line_height = value;
7080                        },
7081                    }
7082                    .unimplemented(),
7083                ),
7084                metadata: None,
7085                files: USER,
7086            }),
7087            SettingsPageItem::SettingItem(SettingItem {
7088                title: "Cursor Shape",
7089                description: "Default cursor shape for the terminal (bar, block, underline, or hollow).",
7090                field: Box::new(SettingField {
7091                    organization_override: None,
7092                    json_path: Some("terminal.cursor_shape"),
7093                    pick: |settings_content| {
7094                        settings_content.terminal.as_ref()?.cursor_shape.as_ref()
7095                    },
7096                    write: |settings_content, value, _| {
7097                        settings_content
7098                            .terminal
7099                            .get_or_insert_default()
7100                            .cursor_shape = value;
7101                    },
7102                }),
7103                metadata: None,
7104                files: USER,
7105            }),
7106            SettingsPageItem::SettingItem(SettingItem {
7107                title: "Cursor Blinking",
7108                description: "Sets the cursor blinking behavior in the terminal.",
7109                field: Box::new(SettingField {
7110                    organization_override: None,
7111                    json_path: Some("terminal.blinking"),
7112                    pick: |settings_content| settings_content.terminal.as_ref()?.blinking.as_ref(),
7113                    write: |settings_content, value, _| {
7114                        settings_content.terminal.get_or_insert_default().blinking = value;
7115                    },
7116                }),
7117                metadata: None,
7118                files: USER,
7119            }),
7120            SettingsPageItem::SettingItem(SettingItem {
7121                title: "Alternate Scroll",
7122                description: "Whether alternate scroll mode is active by default (converts mouse scroll to arrow keys in apps like Vim).",
7123                field: Box::new(SettingField {
7124                    organization_override: None,
7125                    json_path: Some("terminal.alternate_scroll"),
7126                    pick: |settings_content| {
7127                        settings_content
7128                            .terminal
7129                            .as_ref()?
7130                            .alternate_scroll
7131                            .as_ref()
7132                    },
7133                    write: |settings_content, value, _| {
7134                        settings_content
7135                            .terminal
7136                            .get_or_insert_default()
7137                            .alternate_scroll = value;
7138                    },
7139                }),
7140                metadata: None,
7141                files: USER,
7142            }),
7143            SettingsPageItem::SettingItem(SettingItem {
7144                title: "Minimum Contrast",
7145                description: "The minimum APCA perceptual contrast between foreground and background colors (0-106).",
7146                field: Box::new(SettingField {
7147                    organization_override: None,
7148                    json_path: Some("terminal.minimum_contrast"),
7149                    pick: |settings_content| {
7150                        settings_content
7151                            .terminal
7152                            .as_ref()?
7153                            .minimum_contrast
7154                            .as_ref()
7155                    },
7156                    write: |settings_content, value, _| {
7157                        settings_content
7158                            .terminal
7159                            .get_or_insert_default()
7160                            .minimum_contrast = value;
7161                    },
7162                }),
7163                metadata: None,
7164                files: USER,
7165            }),
7166        ]
7167    }
7168
7169    fn behavior_settings_section() -> [SettingsPageItem; 6] {
7170        [
7171            SettingsPageItem::SectionHeader("Behavior Settings"),
7172            SettingsPageItem::SettingItem(SettingItem {
7173                title: "Option As Meta",
7174                description: "Whether the option key behaves as the meta key.",
7175                field: Box::new(SettingField {
7176                    organization_override: None,
7177                    json_path: Some("terminal.option_as_meta"),
7178                    pick: |settings_content| {
7179                        settings_content.terminal.as_ref()?.option_as_meta.as_ref()
7180                    },
7181                    write: |settings_content, value, _| {
7182                        settings_content
7183                            .terminal
7184                            .get_or_insert_default()
7185                            .option_as_meta = value;
7186                    },
7187                }),
7188                metadata: None,
7189                files: USER,
7190            }),
7191            SettingsPageItem::SettingItem(SettingItem {
7192                title: "Copy On Select",
7193                description: "Whether selecting text in the terminal automatically copies to the system clipboard.",
7194                field: Box::new(SettingField {
7195                    organization_override: None,
7196                    json_path: Some("terminal.copy_on_select"),
7197                    pick: |settings_content| {
7198                        settings_content.terminal.as_ref()?.copy_on_select.as_ref()
7199                    },
7200                    write: |settings_content, value, _| {
7201                        settings_content
7202                            .terminal
7203                            .get_or_insert_default()
7204                            .copy_on_select = value;
7205                    },
7206                }),
7207                metadata: None,
7208                files: USER,
7209            }),
7210            SettingsPageItem::SettingItem(SettingItem {
7211                title: "Keep Selection On Copy",
7212                description: "Whether to keep the text selection after copying it to the clipboard.",
7213                field: Box::new(SettingField {
7214                    organization_override: None,
7215                    json_path: Some("terminal.keep_selection_on_copy"),
7216                    pick: |settings_content| {
7217                        settings_content
7218                            .terminal
7219                            .as_ref()?
7220                            .keep_selection_on_copy
7221                            .as_ref()
7222                    },
7223                    write: |settings_content, value, _| {
7224                        settings_content
7225                            .terminal
7226                            .get_or_insert_default()
7227                            .keep_selection_on_copy = value;
7228                    },
7229                }),
7230                metadata: None,
7231                files: USER,
7232            }),
7233            SettingsPageItem::SettingItem(SettingItem {
7234                title: "Open Links In Mouse Mode",
7235                description: "Whether cmd-click (ctrl-click on Linux and Windows) opens hyperlinks even when the terminal application has enabled mouse reporting. When disabled, these clicks are forwarded to the application; links can still be opened with shift-cmd-click.",
7236                field: Box::new(SettingField {
7237                    organization_override: None,
7238                    json_path: Some("terminal.open_links_in_mouse_mode"),
7239                    pick: |settings_content| {
7240                        settings_content
7241                            .terminal
7242                            .as_ref()?
7243                            .open_links_in_mouse_mode
7244                            .as_ref()
7245                    },
7246                    write: |settings_content, value, _| {
7247                        settings_content
7248                            .terminal
7249                            .get_or_insert_default()
7250                            .open_links_in_mouse_mode = value;
7251                    },
7252                }),
7253                metadata: None,
7254                files: USER,
7255            }),
7256            SettingsPageItem::SettingItem(SettingItem {
7257                title: "Audible Bell",
7258                description: "Whether to play a sound when the BEL character (`\\a`, `0x07`) is printed",
7259                field: Box::new(SettingField {
7260                    organization_override: None,
7261                    json_path: Some("terminal.bell"),
7262                    pick: |settings_content| settings_content.terminal.as_ref()?.bell.as_ref(),
7263                    write: |settings_content, value, _| {
7264                        settings_content.terminal.get_or_insert_default().bell = value;
7265                    },
7266                }),
7267                metadata: None,
7268                files: USER,
7269            }),
7270        ]
7271    }
7272
7273    fn layout_settings_section() -> [SettingsPageItem; 3] {
7274        [
7275            SettingsPageItem::SectionHeader("Layout Settings"),
7276            SettingsPageItem::SettingItem(SettingItem {
7277                title: "Default Width",
7278                description: "Default width when the terminal is docked to the left or right (in pixels).",
7279                field: Box::new(SettingField {
7280                    organization_override: None,
7281                    json_path: Some("terminal.default_width"),
7282                    pick: |settings_content| {
7283                        settings_content.terminal.as_ref()?.default_width.as_ref()
7284                    },
7285                    write: |settings_content, value, _| {
7286                        settings_content
7287                            .terminal
7288                            .get_or_insert_default()
7289                            .default_width = value;
7290                    },
7291                }),
7292                metadata: None,
7293                files: USER,
7294            }),
7295            SettingsPageItem::SettingItem(SettingItem {
7296                title: "Default Height",
7297                description: "Default height when the terminal is docked to the bottom (in pixels).",
7298                field: Box::new(SettingField {
7299                    organization_override: None,
7300                    json_path: Some("terminal.default_height"),
7301                    pick: |settings_content| {
7302                        settings_content.terminal.as_ref()?.default_height.as_ref()
7303                    },
7304                    write: |settings_content, value, _| {
7305                        settings_content
7306                            .terminal
7307                            .get_or_insert_default()
7308                            .default_height = value;
7309                    },
7310                }),
7311                metadata: None,
7312                files: USER,
7313            }),
7314        ]
7315    }
7316
7317    fn advanced_settings_section() -> [SettingsPageItem; 3] {
7318        [
7319            SettingsPageItem::SectionHeader("Advanced Settings"),
7320            SettingsPageItem::SettingItem(SettingItem {
7321                title: "Max Scroll History Lines",
7322                description: "Maximum number of lines to keep in scrollback history (max: 100,000; 0 disables scrolling).",
7323                field: Box::new(SettingField {
7324                    organization_override: None,
7325                    json_path: Some("terminal.max_scroll_history_lines"),
7326                    pick: |settings_content| {
7327                        settings_content
7328                            .terminal
7329                            .as_ref()?
7330                            .max_scroll_history_lines
7331                            .as_ref()
7332                    },
7333                    write: |settings_content, value, _| {
7334                        settings_content
7335                            .terminal
7336                            .get_or_insert_default()
7337                            .max_scroll_history_lines = value;
7338                    },
7339                }),
7340                metadata: None,
7341                files: USER,
7342            }),
7343            SettingsPageItem::SettingItem(SettingItem {
7344                title: "Scroll Multiplier",
7345                description: "The multiplier for scrolling in the terminal with the mouse wheel",
7346                field: Box::new(SettingField {
7347                    organization_override: None,
7348                    json_path: Some("terminal.scroll_multiplier"),
7349                    pick: |settings_content| {
7350                        settings_content
7351                            .terminal
7352                            .as_ref()?
7353                            .scroll_multiplier
7354                            .as_ref()
7355                    },
7356                    write: |settings_content, value, _| {
7357                        settings_content
7358                            .terminal
7359                            .get_or_insert_default()
7360                            .scroll_multiplier = value;
7361                    },
7362                }),
7363                metadata: None,
7364                files: USER,
7365            }),
7366        ]
7367    }
7368
7369    fn toolbar_section() -> [SettingsPageItem; 2] {
7370        [
7371            SettingsPageItem::SectionHeader("Toolbar"),
7372            SettingsPageItem::SettingItem(SettingItem {
7373                title: "Breadcrumbs",
7374                description: "Display the terminal title in breadcrumbs inside the terminal pane.",
7375                field: Box::new(SettingField {
7376                    organization_override: None,
7377                    json_path: Some("terminal.toolbar.breadcrumbs"),
7378                    pick: |settings_content| {
7379                        settings_content
7380                            .terminal
7381                            .as_ref()?
7382                            .toolbar
7383                            .as_ref()?
7384                            .breadcrumbs
7385                            .as_ref()
7386                    },
7387                    write: |settings_content, value, _| {
7388                        settings_content
7389                            .terminal
7390                            .get_or_insert_default()
7391                            .toolbar
7392                            .get_or_insert_default()
7393                            .breadcrumbs = value;
7394                    },
7395                }),
7396                metadata: None,
7397                files: USER,
7398            }),
7399        ]
7400    }
7401
7402    fn scrollbar_section() -> [SettingsPageItem; 2] {
7403        [
7404            SettingsPageItem::SectionHeader("Scrollbar"),
7405            SettingsPageItem::SettingItem(SettingItem {
7406                title: "Show Scrollbar",
7407                description: "When to show the scrollbar in the terminal.",
7408                field: Box::new(SettingField {
7409                    organization_override: None,
7410                    json_path: Some("terminal.scrollbar.show"),
7411                    pick: |settings_content| {
7412                        show_scrollbar_or_editor(settings_content, |settings_content| {
7413                            settings_content
7414                                .terminal
7415                                .as_ref()?
7416                                .scrollbar
7417                                .as_ref()?
7418                                .show
7419                                .as_ref()
7420                        })
7421                    },
7422                    write: |settings_content, value, _| {
7423                        settings_content
7424                            .terminal
7425                            .get_or_insert_default()
7426                            .scrollbar
7427                            .get_or_insert_default()
7428                            .show = value;
7429                    },
7430                }),
7431                metadata: None,
7432                files: USER,
7433            }),
7434        ]
7435    }
7436
7437    SettingsPage {
7438        title: "Terminal",
7439        items: concat_sections![
7440            environment_section(),
7441            font_section(),
7442            display_settings_section(),
7443            behavior_settings_section(),
7444            layout_settings_section(),
7445            advanced_settings_section(),
7446            toolbar_section(),
7447            scrollbar_section(),
7448        ],
7449    }
7450}
7451
7452fn version_control_page() -> SettingsPage {
7453    fn git_integration_section() -> [SettingsPageItem; 2] {
7454        [
7455            SettingsPageItem::SectionHeader("Git Integration"),
7456            SettingsPageItem::DynamicItem(DynamicItem {
7457                discriminant: SettingItem {
7458                    files: USER,
7459                    title: "Disable Git Integration",
7460                    description: "Disable all Git integration features in Omega.",
7461                    field: Box::new(SettingField::<bool> {
7462                        organization_override: None,
7463                        json_path: Some("git.disable_git"),
7464                        pick: |settings_content| {
7465                            settings_content
7466                                .git
7467                                .as_ref()?
7468                                .enabled
7469                                .as_ref()?
7470                                .disable_git
7471                                .as_ref()
7472                        },
7473                        write: |settings_content, value, _| {
7474                            settings_content
7475                                .git
7476                                .get_or_insert_default()
7477                                .enabled
7478                                .get_or_insert_default()
7479                                .disable_git = value;
7480                        },
7481                    }),
7482                    metadata: None,
7483                },
7484                pick_discriminant: |settings_content| {
7485                    let disabled = settings_content
7486                        .git
7487                        .as_ref()?
7488                        .enabled
7489                        .as_ref()?
7490                        .disable_git
7491                        .unwrap_or(false);
7492                    Some(if disabled { 0 } else { 1 })
7493                },
7494                fields: vec![
7495                    vec![],
7496                    vec![
7497                        SettingItem {
7498                            files: USER,
7499                            title: "Enable Git Status",
7500                            description: "Show Git status information in the editor.",
7501                            field: Box::new(SettingField::<bool> {
7502                                organization_override: None,
7503                                json_path: Some("git.enable_status"),
7504                                pick: |settings_content| {
7505                                    settings_content
7506                                        .git
7507                                        .as_ref()?
7508                                        .enabled
7509                                        .as_ref()?
7510                                        .enable_status
7511                                        .as_ref()
7512                                },
7513                                write: |settings_content, value, _| {
7514                                    settings_content
7515                                        .git
7516                                        .get_or_insert_default()
7517                                        .enabled
7518                                        .get_or_insert_default()
7519                                        .enable_status = value;
7520                                },
7521                            }),
7522                            metadata: None,
7523                        },
7524                        SettingItem {
7525                            files: USER,
7526                            title: "Enable Git Diff",
7527                            description: "Show Git diff information in the editor.",
7528                            field: Box::new(SettingField::<bool> {
7529                                organization_override: None,
7530                                json_path: Some("git.enable_diff"),
7531                                pick: |settings_content| {
7532                                    settings_content
7533                                        .git
7534                                        .as_ref()?
7535                                        .enabled
7536                                        .as_ref()?
7537                                        .enable_diff
7538                                        .as_ref()
7539                                },
7540                                write: |settings_content, value, _| {
7541                                    settings_content
7542                                        .git
7543                                        .get_or_insert_default()
7544                                        .enabled
7545                                        .get_or_insert_default()
7546                                        .enable_diff = value;
7547                                },
7548                            }),
7549                            metadata: None,
7550                        },
7551                    ],
7552                ],
7553            }),
7554        ]
7555    }
7556
7557    fn git_gutter_section() -> [SettingsPageItem; 3] {
7558        [
7559            SettingsPageItem::SectionHeader("Git Gutter"),
7560            SettingsPageItem::SettingItem(SettingItem {
7561                title: "Visibility",
7562                description: "Control whether Git status is shown in the editor's gutter.",
7563                field: Box::new(SettingField {
7564                    organization_override: None,
7565                    json_path: Some("git.git_gutter"),
7566                    pick: |settings_content| settings_content.git.as_ref()?.git_gutter.as_ref(),
7567                    write: |settings_content, value, _| {
7568                        settings_content.git.get_or_insert_default().git_gutter = value;
7569                    },
7570                }),
7571                metadata: None,
7572                files: USER,
7573            }),
7574            // todo(settings_ui): Figure out the right default for this value in default.json
7575            SettingsPageItem::SettingItem(SettingItem {
7576                title: "Debounce",
7577                description: "Debounce threshold in milliseconds after which changes are reflected in the Git gutter.",
7578                field: Box::new(SettingField {
7579                    organization_override: None,
7580                    json_path: Some("git.gutter_debounce"),
7581                    pick: |settings_content| {
7582                        settings_content.git.as_ref()?.gutter_debounce.as_ref()
7583                    },
7584                    write: |settings_content, value, _| {
7585                        settings_content.git.get_or_insert_default().gutter_debounce = value;
7586                    },
7587                }),
7588                metadata: None,
7589                files: USER,
7590            }),
7591        ]
7592    }
7593
7594    fn inline_git_blame_section() -> [SettingsPageItem; 6] {
7595        [
7596            SettingsPageItem::SectionHeader("Inline Git Blame"),
7597            SettingsPageItem::DynamicItem(DynamicItem {
7598                discriminant: SettingItem {
7599                    title: "Enabled",
7600                    description: "Whether or not to show Git blame data for the currently focused line.",
7601                    field: Box::new(SettingField {
7602                        organization_override: None,
7603                        json_path: Some("git.inline_blame.enabled"),
7604                        pick: |settings_content| {
7605                            settings_content
7606                                .git
7607                                .as_ref()?
7608                                .inline_blame
7609                                .as_ref()?
7610                                .enabled
7611                                .as_ref()
7612                        },
7613                        write: |settings_content, value, _| {
7614                            settings_content
7615                                .git
7616                                .get_or_insert_default()
7617                                .inline_blame
7618                                .get_or_insert_default()
7619                                .enabled = value;
7620                        },
7621                    }),
7622                    metadata: None,
7623                    files: USER,
7624                },
7625                pick_discriminant: |settings_content| {
7626                    Some(
7627                        *settings_content
7628                            .git
7629                            .as_ref()?
7630                            .inline_blame
7631                            .as_ref()?
7632                            .enabled
7633                            .as_ref()? as usize,
7634                    )
7635                },
7636                fields: vec![
7637                    vec![],
7638                    vec![SettingItem {
7639                        title: "Location",
7640                        description: "Where to render Git blame when it is enabled.",
7641                        field: Box::new(SettingField {
7642                            organization_override: None,
7643                            json_path: Some("git.inline_blame.location"),
7644                            pick: |settings_content| {
7645                                settings_content
7646                                    .git
7647                                    .as_ref()?
7648                                    .inline_blame
7649                                    .as_ref()?
7650                                    .location
7651                                    .as_ref()
7652                            },
7653                            write: |settings_content, value, _| {
7654                                settings_content
7655                                    .git
7656                                    .get_or_insert_default()
7657                                    .inline_blame
7658                                    .get_or_insert_default()
7659                                    .location = value;
7660                            },
7661                        }),
7662                        metadata: None,
7663                        files: USER,
7664                    }],
7665                ],
7666            }),
7667            SettingsPageItem::SettingItem(SettingItem {
7668                title: "Delay",
7669                description: "The delay after which the inline blame information is shown.",
7670                field: Box::new(SettingField {
7671                    organization_override: None,
7672                    json_path: Some("git.inline_blame.delay_ms"),
7673                    pick: |settings_content| {
7674                        settings_content
7675                            .git
7676                            .as_ref()?
7677                            .inline_blame
7678                            .as_ref()?
7679                            .delay_ms
7680                            .as_ref()
7681                    },
7682                    write: |settings_content, value, _| {
7683                        settings_content
7684                            .git
7685                            .get_or_insert_default()
7686                            .inline_blame
7687                            .get_or_insert_default()
7688                            .delay_ms = value;
7689                    },
7690                }),
7691                metadata: None,
7692                files: USER,
7693            }),
7694            SettingsPageItem::SettingItem(SettingItem {
7695                title: "Padding",
7696                description: "Padding between the end of the source line and the start of the inline blame in columns.",
7697                field: Box::new(SettingField {
7698                    organization_override: None,
7699                    json_path: Some("git.inline_blame.padding"),
7700                    pick: |settings_content| {
7701                        settings_content
7702                            .git
7703                            .as_ref()?
7704                            .inline_blame
7705                            .as_ref()?
7706                            .padding
7707                            .as_ref()
7708                    },
7709                    write: |settings_content, value, _| {
7710                        settings_content
7711                            .git
7712                            .get_or_insert_default()
7713                            .inline_blame
7714                            .get_or_insert_default()
7715                            .padding = value;
7716                    },
7717                }),
7718                metadata: None,
7719                files: USER,
7720            }),
7721            SettingsPageItem::SettingItem(SettingItem {
7722                title: "Minimum Column",
7723                description: "The minimum column number at which to show the inline blame information.",
7724                field: Box::new(SettingField {
7725                    organization_override: None,
7726                    json_path: Some("git.inline_blame.min_column"),
7727                    pick: |settings_content| {
7728                        settings_content
7729                            .git
7730                            .as_ref()?
7731                            .inline_blame
7732                            .as_ref()?
7733                            .min_column
7734                            .as_ref()
7735                    },
7736                    write: |settings_content, value, _| {
7737                        settings_content
7738                            .git
7739                            .get_or_insert_default()
7740                            .inline_blame
7741                            .get_or_insert_default()
7742                            .min_column = value;
7743                    },
7744                }),
7745                metadata: None,
7746                files: USER,
7747            }),
7748            SettingsPageItem::SettingItem(SettingItem {
7749                title: "Show Commit Summary",
7750                description: "Show commit summary as part of the inline blame.",
7751                field: Box::new(SettingField {
7752                    organization_override: None,
7753                    json_path: Some("git.inline_blame.show_commit_summary"),
7754                    pick: |settings_content| {
7755                        settings_content
7756                            .git
7757                            .as_ref()?
7758                            .inline_blame
7759                            .as_ref()?
7760                            .show_commit_summary
7761                            .as_ref()
7762                    },
7763                    write: |settings_content, value, _| {
7764                        settings_content
7765                            .git
7766                            .get_or_insert_default()
7767                            .inline_blame
7768                            .get_or_insert_default()
7769                            .show_commit_summary = value;
7770                    },
7771                }),
7772                metadata: None,
7773                files: USER,
7774            }),
7775        ]
7776    }
7777
7778    fn git_blame_view_section() -> [SettingsPageItem; 2] {
7779        [
7780            SettingsPageItem::SectionHeader("Git Blame View"),
7781            SettingsPageItem::SettingItem(SettingItem {
7782                title: "Show Avatar",
7783                description: "Show the avatar of the author of the commit.",
7784                field: Box::new(SettingField {
7785                    organization_override: None,
7786                    json_path: Some("git.blame.show_avatar"),
7787                    pick: |settings_content| {
7788                        settings_content
7789                            .git
7790                            .as_ref()?
7791                            .blame
7792                            .as_ref()?
7793                            .show_avatar
7794                            .as_ref()
7795                    },
7796                    write: |settings_content, value, _| {
7797                        settings_content
7798                            .git
7799                            .get_or_insert_default()
7800                            .blame
7801                            .get_or_insert_default()
7802                            .show_avatar = value;
7803                    },
7804                }),
7805                metadata: None,
7806                files: USER,
7807            }),
7808        ]
7809    }
7810
7811    fn branch_picker_section() -> [SettingsPageItem; 2] {
7812        [
7813            SettingsPageItem::SectionHeader("Branch Picker"),
7814            SettingsPageItem::SettingItem(SettingItem {
7815                title: "Show Author Name",
7816                description: "Show author name as part of the commit information in branch picker.",
7817                field: Box::new(SettingField {
7818                    organization_override: None,
7819                    json_path: Some("git.branch_picker.show_author_name"),
7820                    pick: |settings_content| {
7821                        settings_content
7822                            .git
7823                            .as_ref()?
7824                            .branch_picker
7825                            .as_ref()?
7826                            .show_author_name
7827                            .as_ref()
7828                    },
7829                    write: |settings_content, value, _| {
7830                        settings_content
7831                            .git
7832                            .get_or_insert_default()
7833                            .branch_picker
7834                            .get_or_insert_default()
7835                            .show_author_name = value;
7836                    },
7837                }),
7838                metadata: None,
7839                files: USER,
7840            }),
7841        ]
7842    }
7843
7844    fn git_hunks_section() -> [SettingsPageItem; 4] {
7845        [
7846            SettingsPageItem::SectionHeader("Git Hunks"),
7847            SettingsPageItem::SettingItem(SettingItem {
7848                title: "Hunk Style",
7849                description: "How Git hunks are displayed visually in the editor.",
7850                field: Box::new(SettingField {
7851                    organization_override: None,
7852                    json_path: Some("git.hunk_style"),
7853                    pick: |settings_content| settings_content.git.as_ref()?.hunk_style.as_ref(),
7854                    write: |settings_content, value, _| {
7855                        settings_content.git.get_or_insert_default().hunk_style = value;
7856                    },
7857                }),
7858                metadata: None,
7859                files: USER,
7860            }),
7861            SettingsPageItem::SettingItem(SettingItem {
7862                title: "Path Style",
7863                description: "Should the name or path be displayed first in the git view.",
7864                field: Box::new(SettingField {
7865                    organization_override: None,
7866                    json_path: Some("git.path_style"),
7867                    pick: |settings_content| settings_content.git.as_ref()?.path_style.as_ref(),
7868                    write: |settings_content, value, _| {
7869                        settings_content.git.get_or_insert_default().path_style = value;
7870                    },
7871                }),
7872                metadata: None,
7873                files: USER,
7874            }),
7875            SettingsPageItem::SettingItem(SettingItem {
7876                title: "Show Stage/Restore Buttons",
7877                description: "Whether to show the stage and restore buttons on diff hunks.",
7878                field: Box::new(SettingField {
7879                    organization_override: None,
7880                    json_path: Some("git.show_stage_restore_buttons"),
7881                    pick: |settings_content| {
7882                        settings_content
7883                            .git
7884                            .as_ref()?
7885                            .show_stage_restore_buttons
7886                            .as_ref()
7887                    },
7888                    write: |settings_content, value, _| {
7889                        settings_content
7890                            .git
7891                            .get_or_insert_default()
7892                            .show_stage_restore_buttons = value;
7893                    },
7894                }),
7895                metadata: None,
7896                files: USER,
7897            }),
7898        ]
7899    }
7900
7901    fn file_diff_section() -> [SettingsPageItem; 2] {
7902        [
7903            SettingsPageItem::SectionHeader("File Diff"),
7904            SettingsPageItem::SettingItem(SettingItem {
7905                title: "Show Full File by Default",
7906                description: "Whether newly opened file diffs show the full file instead of changes only.",
7907                field: Box::new(SettingField {
7908                    organization_override: None,
7909                    json_path: Some("git.file_diff.show_full_file"),
7910                    pick: |settings_content| {
7911                        settings_content
7912                            .git
7913                            .as_ref()?
7914                            .file_diff
7915                            .as_ref()?
7916                            .show_full_file
7917                            .as_ref()
7918                    },
7919                    write: |settings_content, value, _| {
7920                        settings_content
7921                            .git
7922                            .get_or_insert_default()
7923                            .file_diff
7924                            .get_or_insert_default()
7925                            .show_full_file = value;
7926                    },
7927                }),
7928                metadata: None,
7929                files: USER,
7930            }),
7931        ]
7932    }
7933
7934    SettingsPage {
7935        title: "Version Control",
7936        items: concat_sections![
7937            git_integration_section(),
7938            git_gutter_section(),
7939            inline_git_blame_section(),
7940            git_blame_view_section(),
7941            branch_picker_section(),
7942            file_diff_section(),
7943            git_hunks_section(),
7944        ],
7945    }
7946}
7947
7948fn collaboration_page() -> SettingsPage {
7949    fn calls_section() -> [SettingsPageItem; 3] {
7950        [
7951            SettingsPageItem::SectionHeader("Calls"),
7952            SettingsPageItem::SettingItem(SettingItem {
7953                title: "Mute On Join",
7954                description: "Whether the microphone should be muted when joining a channel or a call.",
7955                field: Box::new(SettingField {
7956                    organization_override: None,
7957                    json_path: Some("calls.mute_on_join"),
7958                    pick: |settings_content| settings_content.calls.as_ref()?.mute_on_join.as_ref(),
7959                    write: |settings_content, value, _| {
7960                        settings_content.calls.get_or_insert_default().mute_on_join = value;
7961                    },
7962                }),
7963                metadata: None,
7964                files: USER,
7965            }),
7966            SettingsPageItem::SettingItem(SettingItem {
7967                title: "Share On Join",
7968                description: "Whether your current project should be shared when joining an empty channel.",
7969                field: Box::new(SettingField {
7970                    organization_override: None,
7971                    json_path: Some("calls.share_on_join"),
7972                    pick: |settings_content| {
7973                        settings_content.calls.as_ref()?.share_on_join.as_ref()
7974                    },
7975                    write: |settings_content, value, _| {
7976                        settings_content.calls.get_or_insert_default().share_on_join = value;
7977                    },
7978                }),
7979                metadata: None,
7980                files: USER,
7981            }),
7982        ]
7983    }
7984
7985    fn audio_settings() -> [SettingsPageItem; 3] {
7986        [
7987            SettingsPageItem::ActionLink(ActionLink {
7988                title: "Test Audio".into(),
7989                description: Some("Test your microphone and speaker setup".into()),
7990                button_text: "Test Audio".into(),
7991                on_click: Arc::new(|_settings_window, window, cx| {
7992                    open_audio_test_window(window, cx);
7993                }),
7994                files: USER,
7995            }),
7996            SettingsPageItem::SettingItem(SettingItem {
7997                title: "Output Audio Device",
7998                description: "Select output audio device",
7999                field: Box::new(SettingField {
8000                    organization_override: None,
8001                    json_path: Some("audio.experimental.output_audio_device"),
8002                    pick: |settings_content| {
8003                        settings_content
8004                            .audio
8005                            .as_ref()?
8006                            .output_audio_device
8007                            .as_ref()
8008                            .or(DEFAULT_EMPTY_AUDIO_OUTPUT)
8009                    },
8010                    write: |settings_content, value, _| {
8011                        settings_content
8012                            .audio
8013                            .get_or_insert_default()
8014                            .output_audio_device = value;
8015                    },
8016                }),
8017                metadata: None,
8018                files: USER,
8019            }),
8020            SettingsPageItem::SettingItem(SettingItem {
8021                title: "Input Audio Device",
8022                description: "Select input audio device",
8023                field: Box::new(SettingField {
8024                    organization_override: None,
8025                    json_path: Some("audio.experimental.input_audio_device"),
8026                    pick: |settings_content| {
8027                        settings_content
8028                            .audio
8029                            .as_ref()?
8030                            .input_audio_device
8031                            .as_ref()
8032                            .or(DEFAULT_EMPTY_AUDIO_INPUT)
8033                    },
8034                    write: |settings_content, value, _| {
8035                        settings_content
8036                            .audio
8037                            .get_or_insert_default()
8038                            .input_audio_device = value;
8039                    },
8040                }),
8041                metadata: None,
8042                files: USER,
8043            }),
8044        ]
8045    }
8046
8047    SettingsPage {
8048        title: "Collaboration",
8049        items: concat_sections![calls_section(), audio_settings()],
8050    }
8051}
8052
8053fn ai_page(cx: &App) -> SettingsPage {
8054    fn general_section() -> [SettingsPageItem; 6] {
8055        [
8056            SettingsPageItem::SectionHeader("General"),
8057            SettingsPageItem::SettingItem(SettingItem {
8058                title: "Disable AI",
8059                description: "Whether to disable all AI features in Omega.",
8060                field: Box::new(SettingField {
8061                    organization_override: None,
8062                    json_path: Some("disable_ai"),
8063                    pick: |settings_content| settings_content.project.disable_ai.as_ref(),
8064                    write: |settings_content, value, _| {
8065                        settings_content.project.disable_ai = value;
8066                    },
8067                }),
8068                metadata: None,
8069                files: USER | PROJECT,
8070            }),
8071            SettingsPageItem::SettingItem(SettingItem {
8072                title: "Threads Sidebar Side",
8073                description: "Which side of the window the threads sidebar appears on.",
8074                field: Box::new(SettingField {
8075                    organization_override: None,
8076                    json_path: Some("agent.sidebar_side"),
8077                    pick: |settings_content| settings_content.agent.as_ref()?.sidebar_side.as_ref(),
8078                    write: |settings_content, value, _| {
8079                        settings_content.agent.get_or_insert_default().sidebar_side = value;
8080                    },
8081                }),
8082                metadata: None,
8083                files: USER,
8084            }),
8085            SettingsPageItem::SubPageLink(SubPageLink {
8086                title: "LLM Providers".into(),
8087                r#type: Default::default(),
8088                json_path: Some("llm_providers"),
8089                description: Some("Configure natively-included model providers.".into()),
8090                search_aliases: &[
8091                    "ai",
8092                    "amazon",
8093                    "anthropic",
8094                    "api key",
8095                    "azure",
8096                    "bedrock",
8097                    "chat",
8098                    "claude",
8099                    "copilot",
8100                    "gemini",
8101                    "github",
8102                    "google",
8103                    "gpt",
8104                    "grok",
8105                    "llama",
8106                    "llm",
8107                    "lm studio",
8108                    "mistral",
8109                    "ollama",
8110                    "openai",
8111                    "opencode",
8112                    "provider",
8113                    "vercel",
8114                    "xai",
8115                ],
8116                in_json: false,
8117                files: USER,
8118                render: render_llm_providers_page,
8119            }),
8120            SettingsPageItem::SubPageLink(SubPageLink {
8121                title: "External Agents".into(),
8122                r#type: Default::default(),
8123                json_path: Some("agent_servers"),
8124                description: Some(
8125                    "View, add, and remove agents connected through the Agent Client Protocol."
8126                        .into(),
8127                ),
8128                search_aliases: &[
8129                    "acp",
8130                    "agent client protocol",
8131                    "amp",
8132                    "claude agent",
8133                    "claude code",
8134                    "codex",
8135                    "copilot cli",
8136                    "cursor",
8137                    "external agent",
8138                    "factory droid",
8139                    "github copilot",
8140                    "grok build",
8141                    "junie",
8142                    "opencode",
8143                ],
8144                in_json: false,
8145                files: USER,
8146                render: render_external_agents_page,
8147            }),
8148            SettingsPageItem::SubPageLink(SubPageLink {
8149                title: "MCP Servers".into(),
8150                r#type: Default::default(),
8151                json_path: Some("context_servers"),
8152                description: Some(
8153                    "View, add, configure, and remove Model Context Protocol servers.".into(),
8154                ),
8155                search_aliases: &["context server", "mcp", "model context protocol"],
8156                in_json: false,
8157                files: USER,
8158                render: render_mcp_servers_page,
8159            }),
8160        ]
8161    }
8162
8163    fn agent_configuration_section(_cx: &App) -> Box<[SettingsPageItem]> {
8164        let mut items = vec![SettingsPageItem::SectionHeader("Agent Configuration")];
8165
8166        items.extend([
8167            SettingsPageItem::SubPageLink(SubPageLink {
8168                title: "Skills".into(),
8169                r#type: Default::default(),
8170                json_path: Some(zed_actions::AGENT_SKILLS_SETTINGS_PATH),
8171                description: Some("View and manage agent skills installed globally or in project worktrees.".into()),
8172                search_aliases: &["agent skill", "agent skills", "custom instructions", "skill", "skills"],
8173                in_json: false,
8174                files: USER | PROJECT,
8175                render: render_skills_setup_page,
8176            }),
8177            SettingsPageItem::SubPageLink(SubPageLink {
8178                title: "Sandbox".into(),
8179                r#type: Default::default(),
8180                json_path: Some(zed_actions::AGENT_SANDBOX_SETTINGS_PATH),
8181                description: Some(
8182                    "Review and change the elevated terminal sandbox permissions that are always allowed without prompting."
8183                        .into(),
8184                ),
8185                search_aliases: &[
8186                    "allow",
8187                    "domain",
8188                    "filesystem",
8189                    "network",
8190                    "sandbox",
8191                    "unsandboxed",
8192                    "permissions",
8193                ],
8194                in_json: true,
8195                files: USER,
8196                render: render_sandbox_settings_page,
8197            }),
8198            SettingsPageItem::SubPageLink(SubPageLink {
8199                title: "Tool Permissions".into(),
8200                r#type: Default::default(),
8201                json_path: Some("agent.tool_permissions"),
8202                description: Some("Set up regex patterns to auto-allow, auto-deny, or always request confirmation, for specific tool inputs.".into()),
8203                search_aliases: &[],
8204                in_json: true,
8205                files: USER,
8206                render: render_tool_permissions_setup_page,
8207            }),
8208        ]);
8209
8210        items.extend([
8211            SettingsPageItem::SettingItem(SettingItem {
8212                title: "Single File Review",
8213                description: "When enabled, agent edits will also be displayed in single-file buffers for review.",
8214                field: Box::new(SettingField {
8215                    organization_override: None,
8216                    json_path: Some("agent.single_file_review"),
8217                    pick: |settings_content| {
8218                        settings_content.agent.as_ref()?.single_file_review.as_ref()
8219                    },
8220                    write: |settings_content, value, _| {
8221                        settings_content
8222                            .agent
8223                            .get_or_insert_default()
8224                            .single_file_review = value;
8225                    },
8226                }),
8227                metadata: None,
8228                files: USER,
8229            }),
8230            SettingsPageItem::SettingItem(SettingItem {
8231                title: "Enable Feedback",
8232                description: "Show voting thumbs up/down icon buttons for feedback on agent edits.",
8233                field: Box::new(SettingField {
8234                    organization_override: Some(|org_config| if org_config.is_agent_thread_feedback_enabled {
8235                        None
8236                    } else {
8237                        Some(&false)
8238                    }),
8239                    json_path: Some("agent.enable_feedback"),
8240                    pick: |settings_content| {
8241                        settings_content.agent.as_ref()?.enable_feedback.as_ref()
8242                    },
8243                    write: |settings_content, value, _| {
8244                        settings_content
8245                            .agent
8246                            .get_or_insert_default()
8247                            .enable_feedback = value;
8248                    },
8249                }),
8250                metadata: None,
8251                files: USER,
8252            }),
8253            SettingsPageItem::SettingItem(SettingItem {
8254                title: "Notify When Agent Waiting",
8255                description: "Where to show notifications when the agent has completed its response or needs confirmation before running a tool action.",
8256                field: Box::new(SettingField {
8257                    organization_override: None,
8258                    json_path: Some("agent.notify_when_agent_waiting"),
8259                    pick: |settings_content| {
8260                        settings_content
8261                            .agent
8262                            .as_ref()?
8263                            .notify_when_agent_waiting
8264                            .as_ref()
8265                    },
8266                    write: |settings_content, value, _| {
8267                        settings_content
8268                            .agent
8269                            .get_or_insert_default()
8270                            .notify_when_agent_waiting = value;
8271                    },
8272                }),
8273                metadata: None,
8274                files: USER,
8275            }),
8276            SettingsPageItem::SettingItem(SettingItem {
8277                title: "Play Sound When Agent Done",
8278                description: "When to play a sound when the agent has either completed its response, or needs user input.",
8279                field: Box::new(SettingField {
8280                    organization_override: None,
8281                    json_path: Some("agent.play_sound_when_agent_done"),
8282                    pick: |settings_content| {
8283                        settings_content
8284                            .agent
8285                            .as_ref()?
8286                            .play_sound_when_agent_done
8287                            .as_ref()
8288                    },
8289                    write: |settings_content, value, _| {
8290                        settings_content
8291                            .agent
8292                            .get_or_insert_default()
8293                            .play_sound_when_agent_done = value;
8294                    },
8295                }),
8296                metadata: None,
8297                files: USER,
8298            }),
8299            SettingsPageItem::SettingItem(SettingItem {
8300                title: "Expand Edit Card",
8301                description: "Whether to have edit cards in the agent panel expanded, showing a Preview of the diff.",
8302                field: Box::new(SettingField {
8303                    organization_override: None,
8304                    json_path: Some("agent.expand_edit_card"),
8305                    pick: |settings_content| {
8306                        settings_content.agent.as_ref()?.expand_edit_card.as_ref()
8307                    },
8308                    write: |settings_content, value, _| {
8309                        settings_content
8310                            .agent
8311                            .get_or_insert_default()
8312                            .expand_edit_card = value;
8313                    },
8314                }),
8315                metadata: None,
8316                files: USER,
8317            }),
8318            SettingsPageItem::SettingItem(SettingItem {
8319                title: "Expand Terminal Card",
8320                description: "Whether to have terminal cards in the agent panel expanded, showing the whole command output.",
8321                field: Box::new(SettingField {
8322                    organization_override: None,
8323                    json_path: Some("agent.expand_terminal_card"),
8324                    pick: |settings_content| {
8325                        settings_content
8326                            .agent
8327                            .as_ref()?
8328                            .expand_terminal_card
8329                            .as_ref()
8330                    },
8331                    write: |settings_content, value, _| {
8332                        settings_content
8333                            .agent
8334                            .get_or_insert_default()
8335                            .expand_terminal_card = value;
8336                    },
8337                }),
8338                metadata: None,
8339                files: USER,
8340            }),
8341            SettingsPageItem::SettingItem(SettingItem {
8342                title: "Terminal Thread Init Command",
8343                description: "Command to automatically run when Omega creates a Terminal Thread shell in the agent panel. Runs in your configured shell.",
8344                field: Box::new(SettingField {
8345                    organization_override: None,
8346                    json_path: Some("agent.terminal_init_command"),
8347                    pick: |settings_content| {
8348                        settings_content
8349                            .agent
8350                            .as_ref()?
8351                            .terminal_init_command
8352                            .as_ref()
8353                    },
8354                    write: |settings_content, value, _| {
8355                        settings_content
8356                            .agent
8357                            .get_or_insert_default()
8358                            .terminal_init_command = value;
8359                    },
8360                }),
8361                metadata: Some(Box::new(SettingsFieldMetadata {
8362                    placeholder: Some("e.g. claude"),
8363                    display_confirm_button: true,
8364                    display_clear_button: true,
8365                    confirm_on_focus_out: true,
8366                    treat_missing_text_as_empty: true,
8367                    ..Default::default()
8368                })),
8369                files: USER,
8370            }),
8371            SettingsPageItem::SettingItem(SettingItem {
8372                title: "Thinking Display",
8373                description: "How thinking blocks should be displayed by default. 'Auto' fully expands during streaming, then auto-collapses when done. 'Preview' auto-expands with a height constraint during streaming. 'Always Expanded' shows full content. 'Always Collapsed' keeps them collapsed.",
8374                field: Box::new(SettingField {
8375                    organization_override: None,
8376                    json_path: Some("agent.thinking_display"),
8377                    pick: |settings_content| {
8378                        settings_content
8379                            .agent
8380                            .as_ref()?
8381                            .thinking_display
8382                            .as_ref()
8383                    },
8384                    write: |settings_content, value, _| {
8385                        settings_content
8386                            .agent
8387                            .get_or_insert_default()
8388                            .thinking_display = value;
8389                    },
8390                }),
8391                metadata: None,
8392                files: USER,
8393            }),
8394            SettingsPageItem::SettingItem(SettingItem {
8395                title: "Cancel Generation On Terminal Stop",
8396                description: "Whether clicking the stop button on a running terminal tool should also cancel the agent's generation. Note that this only applies to the stop button, not to ctrl+c inside the terminal.",
8397                field: Box::new(SettingField {
8398                    organization_override: None,
8399                    json_path: Some("agent.cancel_generation_on_terminal_stop"),
8400                    pick: |settings_content| {
8401                        settings_content
8402                            .agent
8403                            .as_ref()?
8404                            .cancel_generation_on_terminal_stop
8405                            .as_ref()
8406                    },
8407                    write: |settings_content, value, _| {
8408                        settings_content
8409                            .agent
8410                            .get_or_insert_default()
8411                            .cancel_generation_on_terminal_stop = value;
8412                    },
8413                }),
8414                metadata: None,
8415                files: USER,
8416            }),
8417            SettingsPageItem::SettingItem(SettingItem {
8418                title: "Use Modifier To Send",
8419                description: "Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages.",
8420                field: Box::new(SettingField {
8421                    organization_override: None,
8422                    json_path: Some("agent.use_modifier_to_send"),
8423                    pick: |settings_content| {
8424                        settings_content
8425                            .agent
8426                            .as_ref()?
8427                            .use_modifier_to_send
8428                            .as_ref()
8429                    },
8430                    write: |settings_content, value, _| {
8431                        settings_content
8432                            .agent
8433                            .get_or_insert_default()
8434                            .use_modifier_to_send = value;
8435                    },
8436                }),
8437                metadata: None,
8438                files: USER,
8439            }),
8440            SettingsPageItem::SettingItem(SettingItem {
8441                title: "Message Editor Min Lines",
8442                description: "Minimum number of lines to display in the agent message editor.",
8443                field: Box::new(SettingField {
8444                    organization_override: None,
8445                    json_path: Some("agent.message_editor_min_lines"),
8446                    pick: |settings_content| {
8447                        settings_content
8448                            .agent
8449                            .as_ref()?
8450                            .message_editor_min_lines
8451                            .as_ref()
8452                    },
8453                    write: |settings_content, value, _| {
8454                        settings_content
8455                            .agent
8456                            .get_or_insert_default()
8457                            .message_editor_min_lines = value;
8458                    },
8459                }),
8460                metadata: None,
8461                files: USER,
8462            }),
8463            SettingsPageItem::SettingItem(SettingItem {
8464                title: "Show Turn Stats",
8465                description: "Whether to show turn statistics like elapsed time during generation and final turn duration.",
8466                field: Box::new(SettingField {
8467                    organization_override: None,
8468                    json_path: Some("agent.show_turn_stats"),
8469                    pick: |settings_content| {
8470                        settings_content.agent.as_ref()?.show_turn_stats.as_ref()
8471                    },
8472                    write: |settings_content, value, _| {
8473                        settings_content
8474                            .agent
8475                            .get_or_insert_default()
8476                            .show_turn_stats = value;
8477                    },
8478                }),
8479                metadata: None,
8480                files: USER,
8481            }),
8482            SettingsPageItem::SettingItem(SettingItem {
8483                title: "Show Merge Conflict Indicator",
8484                description: "Whether to show the merge conflict indicator in the status bar that offers to resolve conflicts using the agent.",
8485                field: Box::new(SettingField {
8486                    organization_override: None,
8487                    json_path: Some("agent.show_merge_conflict_indicator"),
8488                    pick: |settings_content| {
8489                        settings_content.agent.as_ref()?.show_merge_conflict_indicator.as_ref()
8490                    },
8491                    write: |settings_content, value, _| {
8492                        settings_content
8493                            .agent
8494                            .get_or_insert_default()
8495                            .show_merge_conflict_indicator = value;
8496                    },
8497                }),
8498                metadata: None,
8499                files: USER,
8500            }),
8501        ]);
8502
8503        items.extend([
8504            SettingsPageItem::SettingItem(SettingItem {
8505                title: "Auto Compact",
8506                description: "Automatically compact the agent's context when it grows too large, summarizing earlier messages to free up room in the model's context window.",
8507                field: Box::new(SettingField {
8508                    organization_override: None,
8509                    json_path: Some("agent.auto_compact.enabled"),
8510                    pick: |settings_content| {
8511                        settings_content
8512                            .agent
8513                            .as_ref()?
8514                            .auto_compact
8515                            .as_ref()?
8516                            .enabled
8517                            .as_ref()
8518                    },
8519                    write: |settings_content, value, _| {
8520                        settings_content
8521                            .agent
8522                            .get_or_insert_default()
8523                            .auto_compact
8524                            .get_or_insert_default()
8525                            .enabled = value;
8526                    },
8527                }),
8528                metadata: None,
8529                files: USER,
8530            }),
8531            SettingsPageItem::SettingItem(SettingItem {
8532                title: "Auto Compact Threshold",
8533                description: "When auto compaction runs. A percentage string like \"90%\" is measured against the context window. A positive integer is the number of used tokens to compact after. A negative integer is the number of tokens remaining in the context window before compacting.",
8534                field: Box::new(SettingField {
8535                    organization_override: None,
8536                    json_path: Some("agent.auto_compact.threshold"),
8537                    pick: |settings_content| {
8538                        settings_content
8539                            .agent
8540                            .as_ref()?
8541                            .auto_compact
8542                            .as_ref()?
8543                            .threshold
8544                            .as_ref()
8545                    },
8546                    write: |settings_content, value, _| {
8547                        settings_content
8548                            .agent
8549                            .get_or_insert_default()
8550                            .auto_compact
8551                            .get_or_insert_default()
8552                            .threshold = value;
8553                    },
8554                }),
8555                metadata: Some(Box::new(SettingsFieldMetadata {
8556                    placeholder: Some("90%"),
8557                    ..Default::default()
8558                })),
8559                files: USER,
8560            }),
8561        ]);
8562
8563        items.into_boxed_slice()
8564    }
8565
8566    fn edit_prediction_display_sub_section() -> [SettingsPageItem; 1] {
8567        [SettingsPageItem::SettingItem(SettingItem {
8568            title: "Display Mode",
8569            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.",
8570            field: Box::new(SettingField {
8571                organization_override: None,
8572                json_path: Some("edit_prediction.display_mode"),
8573                pick: |settings_content| {
8574                    settings_content
8575                        .project
8576                        .all_languages
8577                        .edit_predictions
8578                        .as_ref()?
8579                        .mode
8580                        .as_ref()
8581                },
8582                write: |settings_content, value, _| {
8583                    settings_content
8584                        .project
8585                        .all_languages
8586                        .edit_predictions
8587                        .get_or_insert_default()
8588                        .mode = value;
8589                },
8590            }),
8591            metadata: None,
8592            files: USER,
8593        })]
8594    }
8595
8596    SettingsPage {
8597        title: "AI",
8598        items: concat_sections!(
8599            @vec,
8600            general_section(),
8601            agent_configuration_section(cx),
8602            edit_prediction_language_settings_section(),
8603            edit_prediction_display_sub_section(),
8604        )
8605        .into(),
8606    }
8607}
8608
8609fn network_page() -> SettingsPage {
8610    fn network_section() -> [SettingsPageItem; 3] {
8611        [
8612            SettingsPageItem::SectionHeader("Network"),
8613            SettingsPageItem::SettingItem(SettingItem {
8614                title: "Proxy",
8615                description: "The proxy to use for network requests.",
8616                field: Box::new(SettingField {
8617                    organization_override: None,
8618                    json_path: Some("proxy"),
8619                    pick: |settings_content| settings_content.proxy.as_ref(),
8620                    write: |settings_content, value, _| {
8621                        settings_content.proxy = value;
8622                    },
8623                }),
8624                metadata: Some(Box::new(SettingsFieldMetadata {
8625                    placeholder: Some("socks5h://localhost:10808"),
8626                    ..Default::default()
8627                })),
8628                files: USER,
8629            }),
8630            SettingsPageItem::SettingItem(SettingItem {
8631                title: "Server URL",
8632                description: "The URL of the collaboration server to connect to.",
8633                field: Box::new(SettingField {
8634                    organization_override: None,
8635                    json_path: Some("server_url"),
8636                    pick: |settings_content| settings_content.server_url.as_ref(),
8637                    write: |settings_content, value, _| {
8638                        settings_content.server_url = value;
8639                    },
8640                }),
8641                metadata: Some(Box::new(SettingsFieldMetadata {
8642                    placeholder: Some("https://services.openagents.invalid"),
8643                    ..Default::default()
8644                })),
8645                files: USER,
8646            }),
8647        ]
8648    }
8649
8650    SettingsPage {
8651        title: "Network",
8652        items: concat_sections![network_section()],
8653    }
8654}
8655
8656fn language_settings_field<T>(
8657    settings_content: &SettingsContent,
8658    get_language_setting_field: fn(&LanguageSettingsContent) -> Option<&T>,
8659) -> Option<&T> {
8660    let all_languages = &settings_content.project.all_languages;
8661
8662    active_language()
8663        .and_then(|current_language_name| {
8664            all_languages
8665                .languages
8666                .0
8667                .get(current_language_name.as_ref())
8668        })
8669        .and_then(get_language_setting_field)
8670        .or_else(|| get_language_setting_field(&all_languages.defaults))
8671}
8672
8673fn language_settings_field_mut<T>(
8674    settings_content: &mut SettingsContent,
8675    value: Option<T>,
8676    write: fn(&mut LanguageSettingsContent, Option<T>),
8677) {
8678    let all_languages = &mut settings_content.project.all_languages;
8679    let language_content = if let Some(current_language) = active_language() {
8680        all_languages
8681            .languages
8682            .0
8683            .entry(current_language.to_string())
8684            .or_default()
8685    } else {
8686        &mut all_languages.defaults
8687    };
8688    write(language_content, value);
8689}
8690
8691fn language_settings_data() -> Box<[SettingsPageItem]> {
8692    fn indentation_section() -> [SettingsPageItem; 5] {
8693        [
8694            SettingsPageItem::SectionHeader("Indentation"),
8695            SettingsPageItem::SettingItem(SettingItem {
8696                title: "Tab Size",
8697                description: "How many columns a tab should occupy.",
8698                field: Box::new(SettingField {
8699                    organization_override: None,
8700                    json_path: Some("languages.$(language).tab_size"), // TODO(cameron): not JQ syntax because not URL-safe
8701                    pick: |settings_content| {
8702                        language_settings_field(settings_content, |language| {
8703                            language.tab_size.as_ref()
8704                        })
8705                    },
8706                    write: |settings_content, value, _| {
8707                        language_settings_field_mut(settings_content, value, |language, value| {
8708                            language.tab_size = value;
8709                        })
8710                    },
8711                }),
8712                metadata: None,
8713                files: USER | PROJECT,
8714            }),
8715            SettingsPageItem::SettingItem(SettingItem {
8716                title: "Hard Tabs",
8717                description: "Whether to indent lines using tab characters, as opposed to multiple spaces.",
8718                field: Box::new(SettingField {
8719                    organization_override: None,
8720                    json_path: Some("languages.$(language).hard_tabs"),
8721                    pick: |settings_content| {
8722                        language_settings_field(settings_content, |language| {
8723                            language.hard_tabs.as_ref()
8724                        })
8725                    },
8726                    write: |settings_content, value, _| {
8727                        language_settings_field_mut(settings_content, value, |language, value| {
8728                            language.hard_tabs = value;
8729                        })
8730                    },
8731                }),
8732                metadata: None,
8733                files: USER | PROJECT,
8734            }),
8735            SettingsPageItem::SettingItem(SettingItem {
8736                title: "Auto Indent",
8737                description: "Controls automatic indentation behavior when typing.",
8738                field: Box::new(SettingField {
8739                    organization_override: None,
8740                    json_path: Some("languages.$(language).auto_indent"),
8741                    pick: |settings_content| {
8742                        language_settings_field(settings_content, |language| {
8743                            language.auto_indent.as_ref()
8744                        })
8745                    },
8746                    write: |settings_content, value, _| {
8747                        language_settings_field_mut(settings_content, value, |language, value| {
8748                            language.auto_indent = value;
8749                        })
8750                    },
8751                }),
8752                metadata: None,
8753                files: USER | PROJECT,
8754            }),
8755            SettingsPageItem::SettingItem(SettingItem {
8756                title: "Auto Indent On Paste",
8757                description: "Whether indentation of pasted content should be adjusted based on the context.",
8758                field: Box::new(SettingField {
8759                    organization_override: None,
8760                    json_path: Some("languages.$(language).auto_indent_on_paste"),
8761                    pick: |settings_content| {
8762                        language_settings_field(settings_content, |language| {
8763                            language.auto_indent_on_paste.as_ref()
8764                        })
8765                    },
8766                    write: |settings_content, value, _| {
8767                        language_settings_field_mut(settings_content, value, |language, value| {
8768                            language.auto_indent_on_paste = value;
8769                        })
8770                    },
8771                }),
8772                metadata: None,
8773                files: USER | PROJECT,
8774            }),
8775        ]
8776    }
8777
8778    fn wrapping_section() -> [SettingsPageItem; 6] {
8779        [
8780            SettingsPageItem::SectionHeader("Wrapping"),
8781            SettingsPageItem::SettingItem(SettingItem {
8782                title: "Soft Wrap",
8783                description: "How to soft-wrap long lines of text.",
8784                field: Box::new(SettingField {
8785                    organization_override: None,
8786                    json_path: Some("languages.$(language).soft_wrap"),
8787                    pick: |settings_content| {
8788                        language_settings_field(settings_content, |language| {
8789                            language.soft_wrap.as_ref()
8790                        })
8791                    },
8792                    write: |settings_content, value, _| {
8793                        language_settings_field_mut(settings_content, value, |language, value| {
8794                            language.soft_wrap = value;
8795                        })
8796                    },
8797                }),
8798                metadata: None,
8799                files: USER | PROJECT,
8800            }),
8801            SettingsPageItem::SettingItem(SettingItem {
8802                title: "Show Wrap Guides",
8803                description: "Show wrap guides in the editor.",
8804                field: Box::new(SettingField {
8805                    organization_override: None,
8806                    json_path: Some("languages.$(language).show_wrap_guides"),
8807                    pick: |settings_content| {
8808                        language_settings_field(settings_content, |language| {
8809                            language.show_wrap_guides.as_ref()
8810                        })
8811                    },
8812                    write: |settings_content, value, _| {
8813                        language_settings_field_mut(settings_content, value, |language, value| {
8814                            language.show_wrap_guides = value;
8815                        })
8816                    },
8817                }),
8818                metadata: None,
8819                files: USER | PROJECT,
8820            }),
8821            SettingsPageItem::SettingItem(SettingItem {
8822                title: "Preferred Line Length",
8823                description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled.",
8824                field: Box::new(SettingField {
8825                    organization_override: None,
8826                    json_path: Some("languages.$(language).preferred_line_length"),
8827                    pick: |settings_content| {
8828                        language_settings_field(settings_content, |language| {
8829                            language.preferred_line_length.as_ref()
8830                        })
8831                    },
8832                    write: |settings_content, value, _| {
8833                        language_settings_field_mut(settings_content, value, |language, value| {
8834                            language.preferred_line_length = value;
8835                        })
8836                    },
8837                }),
8838                metadata: None,
8839                files: USER | PROJECT,
8840            }),
8841            SettingsPageItem::SettingItem(SettingItem {
8842                title: "Wrap Guides",
8843                description: "Character counts at which to show wrap guides in the editor.",
8844                field: Box::new(
8845                    SettingField {
8846                        organization_override: None,
8847                        json_path: Some("languages.$(language).wrap_guides"),
8848                        pick: |settings_content| {
8849                            language_settings_field(settings_content, |language| {
8850                                language.wrap_guides.as_ref()
8851                            })
8852                        },
8853                        write: |settings_content, value, _| {
8854                            language_settings_field_mut(
8855                                settings_content,
8856                                value,
8857                                |language, value| {
8858                                    language.wrap_guides = value;
8859                                },
8860                            )
8861                        },
8862                    }
8863                    .unimplemented(),
8864                ),
8865                metadata: None,
8866                files: USER | PROJECT,
8867            }),
8868            SettingsPageItem::SettingItem(SettingItem {
8869                title: "Allow Rewrap",
8870                description: "Controls where the `editor::rewrap` action is allowed for this language.",
8871                field: Box::new(SettingField {
8872                    organization_override: None,
8873                    json_path: Some("languages.$(language).allow_rewrap"),
8874                    pick: |settings_content| {
8875                        language_settings_field(settings_content, |language| {
8876                            language.allow_rewrap.as_ref()
8877                        })
8878                    },
8879                    write: |settings_content, value, _| {
8880                        language_settings_field_mut(settings_content, value, |language, value| {
8881                            language.allow_rewrap = value;
8882                        })
8883                    },
8884                }),
8885                metadata: None,
8886                files: USER | PROJECT,
8887            }),
8888        ]
8889    }
8890
8891    fn indent_guides_section() -> [SettingsPageItem; 6] {
8892        [
8893            SettingsPageItem::SectionHeader("Indent Guides"),
8894            SettingsPageItem::SettingItem(SettingItem {
8895                title: "Enabled",
8896                description: "Display indent guides in the editor.",
8897                field: Box::new(SettingField {
8898                    organization_override: None,
8899                    json_path: Some("languages.$(language).indent_guides.enabled"),
8900                    pick: |settings_content| {
8901                        language_settings_field(settings_content, |language| {
8902                            language
8903                                .indent_guides
8904                                .as_ref()
8905                                .and_then(|indent_guides| indent_guides.enabled.as_ref())
8906                        })
8907                    },
8908                    write: |settings_content, value, _| {
8909                        language_settings_field_mut(settings_content, value, |language, value| {
8910                            language.indent_guides.get_or_insert_default().enabled = value;
8911                        })
8912                    },
8913                }),
8914                metadata: None,
8915                files: USER | PROJECT,
8916            }),
8917            SettingsPageItem::SettingItem(SettingItem {
8918                title: "Line Width",
8919                description: "The width of the indent guides in pixels, between 1 and 10.",
8920                field: Box::new(SettingField {
8921                    organization_override: None,
8922                    json_path: Some("languages.$(language).indent_guides.line_width"),
8923                    pick: |settings_content| {
8924                        language_settings_field(settings_content, |language| {
8925                            language
8926                                .indent_guides
8927                                .as_ref()
8928                                .and_then(|indent_guides| indent_guides.line_width.as_ref())
8929                        })
8930                    },
8931                    write: |settings_content, value, _| {
8932                        language_settings_field_mut(settings_content, value, |language, value| {
8933                            language.indent_guides.get_or_insert_default().line_width = value;
8934                        })
8935                    },
8936                }),
8937                metadata: None,
8938                files: USER | PROJECT,
8939            }),
8940            SettingsPageItem::SettingItem(SettingItem {
8941                title: "Active Line Width",
8942                description: "The width of the active indent guide in pixels, between 1 and 10.",
8943                field: Box::new(SettingField {
8944                    organization_override: None,
8945                    json_path: Some("languages.$(language).indent_guides.active_line_width"),
8946                    pick: |settings_content| {
8947                        language_settings_field(settings_content, |language| {
8948                            language
8949                                .indent_guides
8950                                .as_ref()
8951                                .and_then(|indent_guides| indent_guides.active_line_width.as_ref())
8952                        })
8953                    },
8954                    write: |settings_content, value, _| {
8955                        language_settings_field_mut(settings_content, value, |language, value| {
8956                            language
8957                                .indent_guides
8958                                .get_or_insert_default()
8959                                .active_line_width = value;
8960                        })
8961                    },
8962                }),
8963                metadata: None,
8964                files: USER | PROJECT,
8965            }),
8966            SettingsPageItem::SettingItem(SettingItem {
8967                title: "Coloring",
8968                description: "Determines how indent guides are colored.",
8969                field: Box::new(SettingField {
8970                    organization_override: None,
8971                    json_path: Some("languages.$(language).indent_guides.coloring"),
8972                    pick: |settings_content| {
8973                        language_settings_field(settings_content, |language| {
8974                            language
8975                                .indent_guides
8976                                .as_ref()
8977                                .and_then(|indent_guides| indent_guides.coloring.as_ref())
8978                        })
8979                    },
8980                    write: |settings_content, value, _| {
8981                        language_settings_field_mut(settings_content, value, |language, value| {
8982                            language.indent_guides.get_or_insert_default().coloring = value;
8983                        })
8984                    },
8985                }),
8986                metadata: None,
8987                files: USER | PROJECT,
8988            }),
8989            SettingsPageItem::SettingItem(SettingItem {
8990                title: "Background Coloring",
8991                description: "Determines how indent guide backgrounds are colored.",
8992                field: Box::new(SettingField {
8993                    organization_override: None,
8994                    json_path: Some("languages.$(language).indent_guides.background_coloring"),
8995                    pick: |settings_content| {
8996                        language_settings_field(settings_content, |language| {
8997                            language.indent_guides.as_ref().and_then(|indent_guides| {
8998                                indent_guides.background_coloring.as_ref()
8999                            })
9000                        })
9001                    },
9002                    write: |settings_content, value, _| {
9003                        language_settings_field_mut(settings_content, value, |language, value| {
9004                            language
9005                                .indent_guides
9006                                .get_or_insert_default()
9007                                .background_coloring = value;
9008                        })
9009                    },
9010                }),
9011                metadata: None,
9012                files: USER | PROJECT,
9013            }),
9014        ]
9015    }
9016
9017    fn formatting_section() -> [SettingsPageItem; 8] {
9018        [
9019            SettingsPageItem::SectionHeader("Formatting"),
9020            SettingsPageItem::SettingItem(SettingItem {
9021                title: "Format On Save",
9022                description: "On: format the whole buffer.\nOff: do not format.\nModifications: format only lines with unstaged changes; skips formatting when a git diff or LSP range formatting is unavailable.\nModifications If Available: same, but falls back to formatting the whole buffer.",
9023                field: Box::new(
9024                    // TODO(settings_ui): this setting should just be a bool
9025                    SettingField {
9026                        organization_override: None,
9027                        json_path: Some("languages.$(language).format_on_save"),
9028                        pick: |settings_content| {
9029                            language_settings_field(settings_content, |language| {
9030                                language.format_on_save.as_ref()
9031                            })
9032                        },
9033                        write: |settings_content, value, _| {
9034                            language_settings_field_mut(
9035                                settings_content,
9036                                value,
9037                                |language, value| {
9038                                    language.format_on_save = value;
9039                                },
9040                            )
9041                        },
9042                    },
9043                ),
9044                metadata: None,
9045                files: USER | PROJECT,
9046            }),
9047            SettingsPageItem::SettingItem(SettingItem {
9048                title: "Remove Trailing Whitespace On Save",
9049                description: "Whether or not to remove any trailing whitespace from lines of a buffer before saving it.",
9050                field: Box::new(SettingField {
9051                    organization_override: None,
9052                    json_path: Some("languages.$(language).remove_trailing_whitespace_on_save"),
9053                    pick: |settings_content| {
9054                        language_settings_field(settings_content, |language| {
9055                            language.remove_trailing_whitespace_on_save.as_ref()
9056                        })
9057                    },
9058                    write: |settings_content, value, _| {
9059                        language_settings_field_mut(settings_content, value, |language, value| {
9060                            language.remove_trailing_whitespace_on_save = value;
9061                        })
9062                    },
9063                }),
9064                metadata: None,
9065                files: USER | PROJECT,
9066            }),
9067            SettingsPageItem::SettingItem(SettingItem {
9068                title: "Ensure Final Newline On Save",
9069                description: "Whether or not to ensure there's a single newline at the end of a buffer when saving it.",
9070                field: Box::new(SettingField {
9071                    organization_override: None,
9072                    json_path: Some("languages.$(language).ensure_final_newline_on_save"),
9073                    pick: |settings_content| {
9074                        language_settings_field(settings_content, |language| {
9075                            language.ensure_final_newline_on_save.as_ref()
9076                        })
9077                    },
9078                    write: |settings_content, value, _| {
9079                        language_settings_field_mut(settings_content, value, |language, value| {
9080                            language.ensure_final_newline_on_save = value;
9081                        })
9082                    },
9083                }),
9084                metadata: None,
9085                files: USER | PROJECT,
9086            }),
9087            SettingsPageItem::SettingItem(SettingItem {
9088                title: "Line Ending",
9089                description: "How line endings should be handled for new files and during format and save operations.",
9090                field: Box::new(SettingField {
9091                    organization_override: None,
9092                    json_path: Some("languages.$(language).line_ending"),
9093                    pick: |settings_content| {
9094                        language_settings_field(settings_content, |language| {
9095                            language.line_ending.as_ref()
9096                        })
9097                    },
9098                    write: |settings_content, value, _| {
9099                        language_settings_field_mut(settings_content, value, |language, value| {
9100                            language.line_ending = value;
9101                        })
9102                    },
9103                }),
9104                metadata: Some(Box::new(SettingsFieldMetadata {
9105                    should_do_titlecase: Some(false),
9106                    ..Default::default()
9107                })),
9108                files: USER | PROJECT,
9109            }),
9110            SettingsPageItem::SettingItem(SettingItem {
9111                title: "Formatter",
9112                description: "How to perform a buffer format.",
9113                field: Box::new(
9114                    SettingField {
9115                        organization_override: None,
9116                        json_path: Some("languages.$(language).formatter"),
9117                        pick: |settings_content| {
9118                            language_settings_field(settings_content, |language| {
9119                                language.formatter.as_ref()
9120                            })
9121                        },
9122                        write: |settings_content, value, _| {
9123                            language_settings_field_mut(
9124                                settings_content,
9125                                value,
9126                                |language, value| {
9127                                    language.formatter = value;
9128                                },
9129                            )
9130                        },
9131                    }
9132                    .unimplemented(),
9133                ),
9134                metadata: None,
9135                files: USER | PROJECT,
9136            }),
9137            SettingsPageItem::SettingItem(SettingItem {
9138                title: "Use On Type Format",
9139                description: "Whether to use additional LSP queries to format (and amend) the code after every \"trigger\" symbol input, defined by LSP server capabilities",
9140                field: Box::new(SettingField {
9141                    organization_override: None,
9142                    json_path: Some("languages.$(language).use_on_type_format"),
9143                    pick: |settings_content| {
9144                        language_settings_field(settings_content, |language| {
9145                            language.use_on_type_format.as_ref()
9146                        })
9147                    },
9148                    write: |settings_content, value, _| {
9149                        language_settings_field_mut(settings_content, value, |language, value| {
9150                            language.use_on_type_format = value;
9151                        })
9152                    },
9153                }),
9154                metadata: None,
9155                files: USER | PROJECT,
9156            }),
9157            SettingsPageItem::SettingItem(SettingItem {
9158                title: "Code Actions On Format",
9159                description: "Additional code actions to run when formatting.",
9160                field: Box::new(
9161                    SettingField {
9162                        organization_override: None,
9163                        json_path: Some("languages.$(language).code_actions_on_format"),
9164                        pick: |settings_content| {
9165                            language_settings_field(settings_content, |language| {
9166                                language.code_actions_on_format.as_ref()
9167                            })
9168                        },
9169                        write: |settings_content, value, _| {
9170                            language_settings_field_mut(
9171                                settings_content,
9172                                value,
9173                                |language, value| {
9174                                    language.code_actions_on_format = value;
9175                                },
9176                            )
9177                        },
9178                    }
9179                    .unimplemented(),
9180                ),
9181                metadata: None,
9182                files: USER | PROJECT,
9183            }),
9184        ]
9185    }
9186
9187    fn autoclose_section() -> [SettingsPageItem; 5] {
9188        [
9189            SettingsPageItem::SectionHeader("Autoclose"),
9190            SettingsPageItem::SettingItem(SettingItem {
9191                title: "Use Autoclose",
9192                description: "Whether to automatically type closing characters for you. For example, when you type '(', Omega will automatically add a closing ')' at the correct position.",
9193                field: Box::new(SettingField {
9194                    organization_override: None,
9195                    json_path: Some("languages.$(language).use_autoclose"),
9196                    pick: |settings_content| {
9197                        language_settings_field(settings_content, |language| {
9198                            language.use_autoclose.as_ref()
9199                        })
9200                    },
9201                    write: |settings_content, value, _| {
9202                        language_settings_field_mut(settings_content, value, |language, value| {
9203                            language.use_autoclose = value;
9204                        })
9205                    },
9206                }),
9207                metadata: None,
9208                files: USER | PROJECT,
9209            }),
9210            SettingsPageItem::SettingItem(SettingItem {
9211                title: "Use Auto Surround",
9212                description: "Whether to automatically surround text with characters for you. For example, when you select text and type '(', Omega will automatically surround text with ().",
9213                field: Box::new(SettingField {
9214                    organization_override: None,
9215                    json_path: Some("languages.$(language).use_auto_surround"),
9216                    pick: |settings_content| {
9217                        language_settings_field(settings_content, |language| {
9218                            language.use_auto_surround.as_ref()
9219                        })
9220                    },
9221                    write: |settings_content, value, _| {
9222                        language_settings_field_mut(settings_content, value, |language, value| {
9223                            language.use_auto_surround = value;
9224                        })
9225                    },
9226                }),
9227                metadata: None,
9228                files: USER | PROJECT,
9229            }),
9230            SettingsPageItem::SettingItem(SettingItem {
9231                title: "Always Treat Brackets As Autoclosed",
9232                description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted.",
9233                field: Box::new(SettingField {
9234                    organization_override: None,
9235                    json_path: Some("languages.$(language).always_treat_brackets_as_autoclosed"),
9236                    pick: |settings_content| {
9237                        language_settings_field(settings_content, |language| {
9238                            language.always_treat_brackets_as_autoclosed.as_ref()
9239                        })
9240                    },
9241                    write: |settings_content, value, _| {
9242                        language_settings_field_mut(settings_content, value, |language, value| {
9243                            language.always_treat_brackets_as_autoclosed = value;
9244                        })
9245                    },
9246                }),
9247                metadata: None,
9248                files: USER | PROJECT,
9249            }),
9250            SettingsPageItem::SettingItem(SettingItem {
9251                title: "JSX Tag Auto Close",
9252                description: "Whether to automatically close JSX tags.",
9253                field: Box::new(SettingField {
9254                    organization_override: None,
9255                    json_path: Some("languages.$(language).jsx_tag_auto_close"),
9256                    // TODO(settings_ui): this setting should just be a bool
9257                    pick: |settings_content| {
9258                        language_settings_field(settings_content, |language| {
9259                            language.jsx_tag_auto_close.as_ref()?.enabled.as_ref()
9260                        })
9261                    },
9262                    write: |settings_content, value, _| {
9263                        language_settings_field_mut(settings_content, value, |language, value| {
9264                            language.jsx_tag_auto_close.get_or_insert_default().enabled = value;
9265                        })
9266                    },
9267                }),
9268                metadata: None,
9269                files: USER | PROJECT,
9270            }),
9271        ]
9272    }
9273
9274    fn whitespace_section() -> [SettingsPageItem; 4] {
9275        [
9276            SettingsPageItem::SectionHeader("Whitespace"),
9277            SettingsPageItem::SettingItem(SettingItem {
9278                title: "Show Whitespaces",
9279                description: "Whether to show tabs and spaces in the editor.",
9280                field: Box::new(SettingField {
9281                    organization_override: None,
9282                    json_path: Some("languages.$(language).show_whitespaces"),
9283                    pick: |settings_content| {
9284                        language_settings_field(settings_content, |language| {
9285                            language.show_whitespaces.as_ref()
9286                        })
9287                    },
9288                    write: |settings_content, value, _| {
9289                        language_settings_field_mut(settings_content, value, |language, value| {
9290                            language.show_whitespaces = value;
9291                        })
9292                    },
9293                }),
9294                metadata: None,
9295                files: USER | PROJECT,
9296            }),
9297            SettingsPageItem::SettingItem(SettingItem {
9298                title: "Space Whitespace Indicator",
9299                description: "Visible character used to render space characters when show_whitespaces is enabled (default: \"\")",
9300                field: Box::new(
9301                    SettingField {
9302                        organization_override: None,
9303                        json_path: Some("languages.$(language).whitespace_map.space"),
9304                        pick: |settings_content| {
9305                            language_settings_field(settings_content, |language| {
9306                                language.whitespace_map.as_ref()?.space.as_ref()
9307                            })
9308                        },
9309                        write: |settings_content, value, _| {
9310                            language_settings_field_mut(
9311                                settings_content,
9312                                value,
9313                                |language, value| {
9314                                    language.whitespace_map.get_or_insert_default().space = value;
9315                                },
9316                            )
9317                        },
9318                    }
9319                    .unimplemented(),
9320                ),
9321                metadata: None,
9322                files: USER | PROJECT,
9323            }),
9324            SettingsPageItem::SettingItem(SettingItem {
9325                title: "Tab Whitespace Indicator",
9326                description: "Visible character used to render tab characters when show_whitespaces is enabled (default: \"\")",
9327                field: Box::new(
9328                    SettingField {
9329                        organization_override: None,
9330                        json_path: Some("languages.$(language).whitespace_map.tab"),
9331                        pick: |settings_content| {
9332                            language_settings_field(settings_content, |language| {
9333                                language.whitespace_map.as_ref()?.tab.as_ref()
9334                            })
9335                        },
9336                        write: |settings_content, value, _| {
9337                            language_settings_field_mut(
9338                                settings_content,
9339                                value,
9340                                |language, value| {
9341                                    language.whitespace_map.get_or_insert_default().tab = value;
9342                                },
9343                            )
9344                        },
9345                    }
9346                    .unimplemented(),
9347                ),
9348                metadata: None,
9349                files: USER | PROJECT,
9350            }),
9351        ]
9352    }
9353
9354    fn completions_section() -> [SettingsPageItem; 8] {
9355        [
9356            SettingsPageItem::SectionHeader("Completions"),
9357            SettingsPageItem::SettingItem(SettingItem {
9358                title: "Show Completions On Input",
9359                description: "Whether to pop the completions menu while typing in an editor without explicitly requesting it.",
9360                field: Box::new(SettingField {
9361                    organization_override: None,
9362                    json_path: Some("languages.$(language).show_completions_on_input"),
9363                    pick: |settings_content| {
9364                        language_settings_field(settings_content, |language| {
9365                            language.show_completions_on_input.as_ref()
9366                        })
9367                    },
9368                    write: |settings_content, value, _| {
9369                        language_settings_field_mut(settings_content, value, |language, value| {
9370                            language.show_completions_on_input = value;
9371                        })
9372                    },
9373                }),
9374                metadata: None,
9375                files: USER | PROJECT,
9376            }),
9377            SettingsPageItem::SettingItem(SettingItem {
9378                title: "Show Completion Documentation",
9379                description: "Whether to display inline and alongside documentation for items in the completions menu.",
9380                field: Box::new(SettingField {
9381                    organization_override: None,
9382                    json_path: Some("languages.$(language).show_completion_documentation"),
9383                    pick: |settings_content| {
9384                        language_settings_field(settings_content, |language| {
9385                            language.show_completion_documentation.as_ref()
9386                        })
9387                    },
9388                    write: |settings_content, value, _| {
9389                        language_settings_field_mut(settings_content, value, |language, value| {
9390                            language.show_completion_documentation = value;
9391                        })
9392                    },
9393                }),
9394                metadata: None,
9395                files: USER | PROJECT,
9396            }),
9397            SettingsPageItem::SettingItem(SettingItem {
9398                title: "Words",
9399                description: "Controls how words are completed.",
9400                field: Box::new(SettingField {
9401                    organization_override: None,
9402                    json_path: Some("languages.$(language).completions.words"),
9403                    pick: |settings_content| {
9404                        language_settings_field(settings_content, |language| {
9405                            language.completions.as_ref()?.words.as_ref()
9406                        })
9407                    },
9408                    write: |settings_content, value, _| {
9409                        language_settings_field_mut(settings_content, value, |language, value| {
9410                            language.completions.get_or_insert_default().words = value;
9411                        })
9412                    },
9413                }),
9414                metadata: None,
9415                files: USER | PROJECT,
9416            }),
9417            SettingsPageItem::SettingItem(SettingItem {
9418                title: "Words Min Length",
9419                description: "How many characters has to be in the completions query to automatically show the words-based completions.",
9420                field: Box::new(SettingField {
9421                    organization_override: None,
9422                    json_path: Some("languages.$(language).completions.words_min_length"),
9423                    pick: |settings_content| {
9424                        language_settings_field(settings_content, |language| {
9425                            language.completions.as_ref()?.words_min_length.as_ref()
9426                        })
9427                    },
9428                    write: |settings_content, value, _| {
9429                        language_settings_field_mut(settings_content, value, |language, value| {
9430                            language
9431                                .completions
9432                                .get_or_insert_default()
9433                                .words_min_length = value;
9434                        })
9435                    },
9436                }),
9437                metadata: None,
9438                files: USER | PROJECT,
9439            }),
9440            SettingsPageItem::SettingItem(SettingItem {
9441                title: "Completion Menu Scrollbar",
9442                description: "When to show the scrollbar in the completion menu.",
9443                field: Box::new(SettingField {
9444                    organization_override: None,
9445                    json_path: Some("editor.completion_menu_scrollbar"),
9446                    pick: |settings_content| {
9447                        settings_content.editor.completion_menu_scrollbar.as_ref()
9448                    },
9449                    write: |settings_content, value, _| {
9450                        settings_content.editor.completion_menu_scrollbar = value;
9451                    },
9452                }),
9453                metadata: None,
9454                files: USER,
9455            }),
9456            SettingsPageItem::SettingItem(SettingItem {
9457                title: "Completion Detail Alignment",
9458                description: "Whether to align detail text in code completions context menus left or right.",
9459                field: Box::new(SettingField {
9460                    organization_override: None,
9461                    json_path: Some("editor.completion_detail_alignment"),
9462                    pick: |settings_content| {
9463                        settings_content.editor.completion_detail_alignment.as_ref()
9464                    },
9465                    write: |settings_content, value, _| {
9466                        settings_content.editor.completion_detail_alignment = value;
9467                    },
9468                }),
9469                metadata: None,
9470                files: USER,
9471            }),
9472            SettingsPageItem::SettingItem(SettingItem {
9473                title: "Completion Menu Item Kind",
9474                description: "How to display the LSP item kind (function, method, variable, etc.) of each entry in the completions menu.",
9475                field: Box::new(SettingField {
9476                    organization_override: None,
9477                    json_path: Some("editor.completion_menu_item_kind"),
9478                    pick: |settings_content| {
9479                        settings_content.editor.completion_menu_item_kind.as_ref()
9480                    },
9481                    write: |settings_content, value, _| {
9482                        settings_content.editor.completion_menu_item_kind = value;
9483                    },
9484                }),
9485                metadata: None,
9486                files: USER,
9487            }),
9488        ]
9489    }
9490
9491    fn inlay_hints_section() -> [SettingsPageItem; 10] {
9492        [
9493            SettingsPageItem::SectionHeader("Inlay Hints"),
9494            SettingsPageItem::SettingItem(SettingItem {
9495                title: "Enabled",
9496                description: "Global switch to toggle hints on and off.",
9497                field: Box::new(SettingField {
9498                    organization_override: None,
9499                    json_path: Some("languages.$(language).inlay_hints.enabled"),
9500                    pick: |settings_content| {
9501                        language_settings_field(settings_content, |language| {
9502                            language.inlay_hints.as_ref()?.enabled.as_ref()
9503                        })
9504                    },
9505                    write: |settings_content, value, _| {
9506                        language_settings_field_mut(settings_content, value, |language, value| {
9507                            language.inlay_hints.get_or_insert_default().enabled = value;
9508                        })
9509                    },
9510                }),
9511                metadata: None,
9512                files: USER | PROJECT,
9513            }),
9514            SettingsPageItem::SettingItem(SettingItem {
9515                title: "Show Value Hints",
9516                description: "Global switch to toggle inline values on and off when debugging.",
9517                field: Box::new(SettingField {
9518                    organization_override: None,
9519                    json_path: Some("languages.$(language).inlay_hints.show_value_hints"),
9520                    pick: |settings_content| {
9521                        language_settings_field(settings_content, |language| {
9522                            language.inlay_hints.as_ref()?.show_value_hints.as_ref()
9523                        })
9524                    },
9525                    write: |settings_content, value, _| {
9526                        language_settings_field_mut(settings_content, value, |language, value| {
9527                            language
9528                                .inlay_hints
9529                                .get_or_insert_default()
9530                                .show_value_hints = value;
9531                        })
9532                    },
9533                }),
9534                metadata: None,
9535                files: USER | PROJECT,
9536            }),
9537            SettingsPageItem::SettingItem(SettingItem {
9538                title: "Show Type Hints",
9539                description: "Whether type hints should be shown.",
9540                field: Box::new(SettingField {
9541                    organization_override: None,
9542                    json_path: Some("languages.$(language).inlay_hints.show_type_hints"),
9543                    pick: |settings_content| {
9544                        language_settings_field(settings_content, |language| {
9545                            language.inlay_hints.as_ref()?.show_type_hints.as_ref()
9546                        })
9547                    },
9548                    write: |settings_content, value, _| {
9549                        language_settings_field_mut(settings_content, value, |language, value| {
9550                            language.inlay_hints.get_or_insert_default().show_type_hints = value;
9551                        })
9552                    },
9553                }),
9554                metadata: None,
9555                files: USER | PROJECT,
9556            }),
9557            SettingsPageItem::SettingItem(SettingItem {
9558                title: "Show Parameter Hints",
9559                description: "Whether parameter hints should be shown.",
9560                field: Box::new(SettingField {
9561                    organization_override: None,
9562                    json_path: Some("languages.$(language).inlay_hints.show_parameter_hints"),
9563                    pick: |settings_content| {
9564                        language_settings_field(settings_content, |language| {
9565                            language.inlay_hints.as_ref()?.show_parameter_hints.as_ref()
9566                        })
9567                    },
9568                    write: |settings_content, value, _| {
9569                        language_settings_field_mut(settings_content, value, |language, value| {
9570                            language
9571                                .inlay_hints
9572                                .get_or_insert_default()
9573                                .show_parameter_hints = value;
9574                        })
9575                    },
9576                }),
9577                metadata: None,
9578                files: USER | PROJECT,
9579            }),
9580            SettingsPageItem::SettingItem(SettingItem {
9581                title: "Show Other Hints",
9582                description: "Whether other hints should be shown.",
9583                field: Box::new(SettingField {
9584                    organization_override: None,
9585                    json_path: Some("languages.$(language).inlay_hints.show_other_hints"),
9586                    pick: |settings_content| {
9587                        language_settings_field(settings_content, |language| {
9588                            language.inlay_hints.as_ref()?.show_other_hints.as_ref()
9589                        })
9590                    },
9591                    write: |settings_content, value, _| {
9592                        language_settings_field_mut(settings_content, value, |language, value| {
9593                            language
9594                                .inlay_hints
9595                                .get_or_insert_default()
9596                                .show_other_hints = value;
9597                        })
9598                    },
9599                }),
9600                metadata: None,
9601                files: USER | PROJECT,
9602            }),
9603            SettingsPageItem::SettingItem(SettingItem {
9604                title: "Show Background",
9605                description: "Show a background for inlay hints.",
9606                field: Box::new(SettingField {
9607                    organization_override: None,
9608                    json_path: Some("languages.$(language).inlay_hints.show_background"),
9609                    pick: |settings_content| {
9610                        language_settings_field(settings_content, |language| {
9611                            language.inlay_hints.as_ref()?.show_background.as_ref()
9612                        })
9613                    },
9614                    write: |settings_content, value, _| {
9615                        language_settings_field_mut(settings_content, value, |language, value| {
9616                            language.inlay_hints.get_or_insert_default().show_background = value;
9617                        })
9618                    },
9619                }),
9620                metadata: None,
9621                files: USER | PROJECT,
9622            }),
9623            SettingsPageItem::SettingItem(SettingItem {
9624                title: "Edit Debounce Ms",
9625                description: "Whether or not to debounce inlay hints updates after buffer edits (set to 0 to disable debouncing).",
9626                field: Box::new(SettingField {
9627                    organization_override: None,
9628                    json_path: Some("languages.$(language).inlay_hints.edit_debounce_ms"),
9629                    pick: |settings_content| {
9630                        language_settings_field(settings_content, |language| {
9631                            language.inlay_hints.as_ref()?.edit_debounce_ms.as_ref()
9632                        })
9633                    },
9634                    write: |settings_content, value, _| {
9635                        language_settings_field_mut(settings_content, value, |language, value| {
9636                            language
9637                                .inlay_hints
9638                                .get_or_insert_default()
9639                                .edit_debounce_ms = value;
9640                        })
9641                    },
9642                }),
9643                metadata: None,
9644                files: USER | PROJECT,
9645            }),
9646            SettingsPageItem::SettingItem(SettingItem {
9647                title: "Scroll Debounce Ms",
9648                description: "Whether or not to debounce inlay hints updates after buffer scrolls (set to 0 to disable debouncing).",
9649                field: Box::new(SettingField {
9650                    organization_override: None,
9651                    json_path: Some("languages.$(language).inlay_hints.scroll_debounce_ms"),
9652                    pick: |settings_content| {
9653                        language_settings_field(settings_content, |language| {
9654                            language.inlay_hints.as_ref()?.scroll_debounce_ms.as_ref()
9655                        })
9656                    },
9657                    write: |settings_content, value, _| {
9658                        language_settings_field_mut(settings_content, value, |language, value| {
9659                            language
9660                                .inlay_hints
9661                                .get_or_insert_default()
9662                                .scroll_debounce_ms = value;
9663                        })
9664                    },
9665                }),
9666                metadata: None,
9667                files: USER | PROJECT,
9668            }),
9669            SettingsPageItem::SettingItem(SettingItem {
9670                title: "Toggle On Modifiers Press",
9671                description: "Toggles inlay hints (hides or shows) when the user presses the modifiers specified.",
9672                field: Box::new(
9673                    SettingField {
9674                        organization_override: None,
9675                        json_path: Some(
9676                            "languages.$(language).inlay_hints.toggle_on_modifiers_press",
9677                        ),
9678                        pick: |settings_content| {
9679                            language_settings_field(settings_content, |language| {
9680                                language
9681                                    .inlay_hints
9682                                    .as_ref()?
9683                                    .toggle_on_modifiers_press
9684                                    .as_ref()
9685                            })
9686                        },
9687                        write: |settings_content, value, _| {
9688                            language_settings_field_mut(
9689                                settings_content,
9690                                value,
9691                                |language, value| {
9692                                    language
9693                                        .inlay_hints
9694                                        .get_or_insert_default()
9695                                        .toggle_on_modifiers_press = value;
9696                                },
9697                            )
9698                        },
9699                    }
9700                    .unimplemented(),
9701                ),
9702                metadata: None,
9703                files: USER | PROJECT,
9704            }),
9705        ]
9706    }
9707
9708    fn tasks_section() -> [SettingsPageItem; 4] {
9709        [
9710            SettingsPageItem::SectionHeader("Tasks"),
9711            SettingsPageItem::SettingItem(SettingItem {
9712                title: "Enabled",
9713                description: "Whether tasks are enabled for this language.",
9714                field: Box::new(SettingField {
9715                    organization_override: None,
9716                    json_path: Some("languages.$(language).tasks.enabled"),
9717                    pick: |settings_content| {
9718                        language_settings_field(settings_content, |language| {
9719                            language.tasks.as_ref()?.enabled.as_ref()
9720                        })
9721                    },
9722                    write: |settings_content, value, _| {
9723                        language_settings_field_mut(settings_content, value, |language, value| {
9724                            language.tasks.get_or_insert_default().enabled = value;
9725                        })
9726                    },
9727                }),
9728                metadata: None,
9729                files: USER | PROJECT,
9730            }),
9731            SettingsPageItem::SettingItem(SettingItem {
9732                title: "Variables",
9733                description: "Extra task variables to set for a particular language.",
9734                field: Box::new(
9735                    SettingField {
9736                        organization_override: None,
9737                        json_path: Some("languages.$(language).tasks.variables"),
9738                        pick: |settings_content| {
9739                            language_settings_field(settings_content, |language| {
9740                                language.tasks.as_ref()?.variables.as_ref()
9741                            })
9742                        },
9743                        write: |settings_content, value, _| {
9744                            language_settings_field_mut(
9745                                settings_content,
9746                                value,
9747                                |language, value| {
9748                                    language.tasks.get_or_insert_default().variables = value;
9749                                },
9750                            )
9751                        },
9752                    }
9753                    .unimplemented(),
9754                ),
9755                metadata: None,
9756                files: USER | PROJECT,
9757            }),
9758            SettingsPageItem::SettingItem(SettingItem {
9759                title: "Prefer LSP",
9760                description: "Use LSP tasks over Omega language extension tasks.",
9761                field: Box::new(SettingField {
9762                    organization_override: None,
9763                    json_path: Some("languages.$(language).tasks.prefer_lsp"),
9764                    pick: |settings_content| {
9765                        language_settings_field(settings_content, |language| {
9766                            language.tasks.as_ref()?.prefer_lsp.as_ref()
9767                        })
9768                    },
9769                    write: |settings_content, value, _| {
9770                        language_settings_field_mut(settings_content, value, |language, value| {
9771                            language.tasks.get_or_insert_default().prefer_lsp = value;
9772                        })
9773                    },
9774                }),
9775                metadata: None,
9776                files: USER | PROJECT,
9777            }),
9778        ]
9779    }
9780
9781    fn miscellaneous_section() -> [SettingsPageItem; 7] {
9782        [
9783            SettingsPageItem::SectionHeader("Miscellaneous"),
9784            SettingsPageItem::SettingItem(SettingItem {
9785                title: "Word Diff Enabled",
9786                description: "Whether to enable word diff highlighting in the editor. When enabled, changed words within modified lines are highlighted to show exactly what changed.",
9787                field: Box::new(SettingField {
9788                    organization_override: None,
9789                    json_path: Some("languages.$(language).word_diff_enabled"),
9790                    pick: |settings_content| {
9791                        language_settings_field(settings_content, |language| {
9792                            language.word_diff_enabled.as_ref()
9793                        })
9794                    },
9795                    write: |settings_content, value, _| {
9796                        language_settings_field_mut(settings_content, value, |language, value| {
9797                            language.word_diff_enabled = value;
9798                        })
9799                    },
9800                }),
9801                metadata: None,
9802                files: USER | PROJECT,
9803            }),
9804            SettingsPageItem::SettingItem(SettingItem {
9805                title: "Debuggers",
9806                description: "Preferred debuggers for this language.",
9807                field: Box::new(
9808                    SettingField {
9809                        organization_override: None,
9810                        json_path: Some("languages.$(language).debuggers"),
9811                        pick: |settings_content| {
9812                            language_settings_field(settings_content, |language| {
9813                                language.debuggers.as_ref()
9814                            })
9815                        },
9816                        write: |settings_content, value, _| {
9817                            language_settings_field_mut(
9818                                settings_content,
9819                                value,
9820                                |language, value| {
9821                                    language.debuggers = value;
9822                                },
9823                            )
9824                        },
9825                    }
9826                    .unimplemented(),
9827                ),
9828                metadata: None,
9829                files: USER | PROJECT,
9830            }),
9831            SettingsPageItem::SettingItem(SettingItem {
9832                title: "Middle Click Paste",
9833                description: "Enable middle-click paste on Linux.",
9834                field: Box::new(SettingField {
9835                    organization_override: None,
9836                    json_path: Some("languages.$(language).editor.middle_click_paste"),
9837                    pick: |settings_content| settings_content.editor.middle_click_paste.as_ref(),
9838                    write: |settings_content, value, _| {
9839                        settings_content.editor.middle_click_paste = value;
9840                    },
9841                }),
9842                metadata: None,
9843                files: USER,
9844            }),
9845            SettingsPageItem::SettingItem(SettingItem {
9846                title: "Extend Comment On Newline",
9847                description: "Whether to start a new line with a comment when a previous line is a comment as well.",
9848                field: Box::new(SettingField {
9849                    organization_override: None,
9850                    json_path: Some("languages.$(language).extend_comment_on_newline"),
9851                    pick: |settings_content| {
9852                        language_settings_field(settings_content, |language| {
9853                            language.extend_comment_on_newline.as_ref()
9854                        })
9855                    },
9856                    write: |settings_content, value, _| {
9857                        language_settings_field_mut(settings_content, value, |language, value| {
9858                            language.extend_comment_on_newline = value;
9859                        })
9860                    },
9861                }),
9862                metadata: None,
9863                files: USER | PROJECT,
9864            }),
9865            SettingsPageItem::SettingItem(SettingItem {
9866                title: "Colorize Brackets",
9867                description: "Whether to colorize brackets in the editor.",
9868                field: Box::new(SettingField {
9869                    organization_override: None,
9870                    json_path: Some("languages.$(language).colorize_brackets"),
9871                    pick: |settings_content| {
9872                        language_settings_field(settings_content, |language| {
9873                            language.colorize_brackets.as_ref()
9874                        })
9875                    },
9876                    write: |settings_content, value, _| {
9877                        language_settings_field_mut(settings_content, value, |language, value| {
9878                            language.colorize_brackets = value;
9879                        })
9880                    },
9881                }),
9882                metadata: None,
9883                files: USER | PROJECT,
9884            }),
9885            SettingsPageItem::SettingItem(SettingItem {
9886                title: "Vim/Emacs Modeline Support",
9887                description: "Number of lines to search for modelines (set to 0 to disable).",
9888                field: Box::new(SettingField {
9889                    organization_override: None,
9890                    json_path: Some("modeline_lines"),
9891                    pick: |settings_content| settings_content.modeline_lines.as_ref(),
9892                    write: |settings_content, value, _| {
9893                        settings_content.modeline_lines = value;
9894                    },
9895                }),
9896                metadata: None,
9897                files: USER | PROJECT,
9898            }),
9899        ]
9900    }
9901
9902    fn global_only_miscellaneous_sub_section() -> [SettingsPageItem; 3] {
9903        [
9904            SettingsPageItem::SettingItem(SettingItem {
9905                title: "Image Viewer",
9906                description: "The unit for image file sizes.",
9907                field: Box::new(SettingField {
9908                    organization_override: None,
9909                    json_path: Some("image_viewer.unit"),
9910                    pick: |settings_content| {
9911                        settings_content
9912                            .image_viewer
9913                            .as_ref()
9914                            .and_then(|image_viewer| image_viewer.unit.as_ref())
9915                    },
9916                    write: |settings_content, value, _| {
9917                        settings_content.image_viewer.get_or_insert_default().unit = value;
9918                    },
9919                }),
9920                metadata: None,
9921                files: USER,
9922            }),
9923            SettingsPageItem::DynamicItem(DynamicItem {
9924                discriminant: SettingItem {
9925                    files: USER,
9926                    title: "Limit Markdown Preview Width",
9927                    description: "Whether to constrain the markdown preview content to a maximum width, centering it when the pane is wider, for optimal readability.",
9928                    field: Box::new(SettingField::<bool> {
9929                        organization_override: None,
9930                        json_path: Some("markdown_preview.limit_content_width"),
9931                        pick: |settings_content| {
9932                            settings_content
9933                                .markdown_preview
9934                                .as_ref()?
9935                                .limit_content_width
9936                                .as_ref()
9937                        },
9938                        write: |settings_content, value, _| {
9939                            settings_content
9940                                .markdown_preview
9941                                .get_or_insert_default()
9942                                .limit_content_width = value;
9943                        },
9944                    }),
9945                    metadata: None,
9946                },
9947                pick_discriminant: |settings_content| {
9948                    let enabled = settings_content
9949                        .markdown_preview
9950                        .as_ref()?
9951                        .limit_content_width
9952                        .unwrap_or(true);
9953                    Some(if enabled { 1 } else { 0 })
9954                },
9955                fields: vec![
9956                    vec![],
9957                    vec![SettingItem {
9958                        files: USER,
9959                        title: "Max Width",
9960                        description: "Maximum content width in pixels. Content will be centered when the pane is wider than this value.",
9961                        field: Box::new(SettingField {
9962                            organization_override: None,
9963                            json_path: Some("markdown_preview.max_width"),
9964                            pick: |settings_content| {
9965                                settings_content
9966                                    .markdown_preview
9967                                    .as_ref()?
9968                                    .max_width
9969                                    .as_ref()
9970                            },
9971                            write: |settings_content, value, _| {
9972                                settings_content
9973                                    .markdown_preview
9974                                    .get_or_insert_default()
9975                                    .max_width = value;
9976                            },
9977                        }),
9978                        metadata: None,
9979                    }],
9980                ],
9981            }),
9982            SettingsPageItem::SettingItem(SettingItem {
9983                title: "Drop Size Target",
9984                description: "Relative size of the drop target in the editor that will open dropped file as a split pane.",
9985                field: Box::new(SettingField {
9986                    organization_override: None,
9987                    json_path: Some("drop_target_size"),
9988                    pick: |settings_content| settings_content.workspace.drop_target_size.as_ref(),
9989                    write: |settings_content, value, _| {
9990                        settings_content.workspace.drop_target_size = value;
9991                    },
9992                }),
9993                metadata: None,
9994                files: USER,
9995            }),
9996        ]
9997    }
9998
9999    let is_global = active_language().is_none();
10000
10001    let code_lens_item = [SettingsPageItem::SettingItem(SettingItem {
10002        title: "Code Lens",
10003        description: "Whether and how to display code lenses from language servers.",
10004        field: Box::new(SettingField {
10005            organization_override: None,
10006            json_path: Some("code_lens"),
10007            pick: |settings_content| settings_content.editor.code_lens.as_ref(),
10008            write: |settings_content, value, _| {
10009                settings_content.editor.code_lens = value;
10010            },
10011        }),
10012        metadata: None,
10013        files: USER,
10014    })];
10015
10016    let lsp_document_colors_item = [SettingsPageItem::SettingItem(SettingItem {
10017        title: "LSP Document Colors",
10018        description: "How to render LSP color previews in the editor.",
10019        field: Box::new(SettingField {
10020            organization_override: None,
10021            json_path: Some("lsp_document_colors"),
10022            pick: |settings_content| settings_content.editor.lsp_document_colors.as_ref(),
10023            write: |settings_content, value, _| {
10024                settings_content.editor.lsp_document_colors = value;
10025            },
10026        }),
10027        metadata: None,
10028        files: USER,
10029    })];
10030
10031    if is_global {
10032        concat_sections!(
10033            indentation_section(),
10034            wrapping_section(),
10035            indent_guides_section(),
10036            formatting_section(),
10037            autoclose_section(),
10038            whitespace_section(),
10039            completions_section(),
10040            inlay_hints_section(),
10041            code_lens_item,
10042            lsp_document_colors_item,
10043            tasks_section(),
10044            miscellaneous_section(),
10045            global_only_miscellaneous_sub_section(),
10046        )
10047    } else {
10048        concat_sections!(
10049            indentation_section(),
10050            wrapping_section(),
10051            indent_guides_section(),
10052            formatting_section(),
10053            autoclose_section(),
10054            whitespace_section(),
10055            completions_section(),
10056            inlay_hints_section(),
10057            code_lens_item,
10058            tasks_section(),
10059            miscellaneous_section(),
10060        )
10061    }
10062}
10063
10064/// LanguageSettings items that should be included in the "Languages & Tools" page
10065/// not the "Editor" page
10066fn non_editor_language_settings_data() -> Box<[SettingsPageItem]> {
10067    fn lsp_section() -> [SettingsPageItem; 10] {
10068        [
10069            SettingsPageItem::SectionHeader("LSP"),
10070            SettingsPageItem::SettingItem(SettingItem {
10071                title: "Enable Language Server",
10072                description: "Whether to use language servers to provide code intelligence.",
10073                field: Box::new(SettingField {
10074                    organization_override: None,
10075                    json_path: Some("languages.$(language).enable_language_server"),
10076                    pick: |settings_content| {
10077                        language_settings_field(settings_content, |language| {
10078                            language.enable_language_server.as_ref()
10079                        })
10080                    },
10081                    write: |settings_content, value, _| {
10082                        language_settings_field_mut(settings_content, value, |language, value| {
10083                            language.enable_language_server = value;
10084                        })
10085                    },
10086                }),
10087                metadata: None,
10088                files: USER | PROJECT,
10089            }),
10090            SettingsPageItem::SettingItem(SettingItem {
10091                title: "Language Servers",
10092                description: "The list of language servers to use (or disable) for this language.",
10093                field: Box::new(
10094                    SettingField {
10095                        organization_override: None,
10096                        json_path: Some("languages.$(language).language_servers"),
10097                        pick: |settings_content| {
10098                            language_settings_field(settings_content, |language| {
10099                                language.language_servers.as_ref()
10100                            })
10101                        },
10102                        write: |settings_content, value, _| {
10103                            language_settings_field_mut(
10104                                settings_content,
10105                                value,
10106                                |language, value| {
10107                                    language.language_servers = value;
10108                                },
10109                            )
10110                        },
10111                    }
10112                    .unimplemented(),
10113                ),
10114                metadata: None,
10115                files: USER | PROJECT,
10116            }),
10117            SettingsPageItem::SettingItem(SettingItem {
10118                title: "Linked Edits",
10119                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.",
10120                field: Box::new(SettingField {
10121                    organization_override: None,
10122                    json_path: Some("languages.$(language).linked_edits"),
10123                    pick: |settings_content| {
10124                        language_settings_field(settings_content, |language| {
10125                            language.linked_edits.as_ref()
10126                        })
10127                    },
10128                    write: |settings_content, value, _| {
10129                        language_settings_field_mut(settings_content, value, |language, value| {
10130                            language.linked_edits = value;
10131                        })
10132                    },
10133                }),
10134                metadata: None,
10135                files: USER | PROJECT,
10136            }),
10137            SettingsPageItem::SettingItem(SettingItem {
10138                title: "Go To Definition Fallback",
10139                description: "Whether to follow-up empty Go to definition responses from the language server.",
10140                field: Box::new(SettingField {
10141                    organization_override: None,
10142                    json_path: Some("go_to_definition_fallback"),
10143                    pick: |settings_content| {
10144                        settings_content.editor.go_to_definition_fallback.as_ref()
10145                    },
10146                    write: |settings_content, value, _| {
10147                        settings_content.editor.go_to_definition_fallback = value;
10148                    },
10149                }),
10150                metadata: None,
10151                files: USER,
10152            }),
10153            SettingsPageItem::SettingItem(SettingItem {
10154                title: "Go To Definition Scroll Strategy",
10155                description: "How to scroll the target into view when navigating to a definition or reference.",
10156                field: Box::new(SettingField {
10157                    organization_override: None,
10158                    json_path: Some("go_to_definition_scroll_strategy"),
10159                    pick: |settings_content| {
10160                        settings_content
10161                            .editor
10162                            .go_to_definition_scroll_strategy
10163                            .as_ref()
10164                    },
10165                    write: |settings_content, value, _| {
10166                        settings_content.editor.go_to_definition_scroll_strategy = value;
10167                    },
10168                }),
10169                metadata: None,
10170                files: USER,
10171            }),
10172            SettingsPageItem::SettingItem(SettingItem {
10173                title: "LSP Results Location",
10174                description: "Where to show LSP results that can contain multiple locations (Go to Definition, Go to Implementation, Find All References).",
10175                field: Box::new(SettingField {
10176                    organization_override: None,
10177                    json_path: Some("lsp_results_location"),
10178                    pick: |settings_content| settings_content.editor.lsp_results_location.as_ref(),
10179                    write: |settings_content, value, _| {
10180                        settings_content.editor.lsp_results_location = value;
10181                    },
10182                }),
10183                metadata: None,
10184                files: USER,
10185            }),
10186            SettingsPageItem::SettingItem(SettingItem {
10187                title: "Semantic Tokens",
10188                description: {
10189                    static DESCRIPTION: OnceLock<&'static str> = OnceLock::new();
10190                    DESCRIPTION.get_or_init(|| {
10191                        SemanticTokens::VARIANTS
10192                            .iter()
10193                            .filter_map(|v| {
10194                                v.get_documentation().map(|doc| format!("{v:?}: {doc}"))
10195                            })
10196                            .join("\n")
10197                            .leak()
10198                    })
10199                },
10200                field: Box::new(SettingField {
10201                    organization_override: None,
10202                    json_path: Some("languages.$(language).semantic_tokens"),
10203                    pick: |settings_content| {
10204                        settings_content
10205                            .project
10206                            .all_languages
10207                            .defaults
10208                            .semantic_tokens
10209                            .as_ref()
10210                    },
10211                    write: |settings_content, value, _| {
10212                        settings_content
10213                            .project
10214                            .all_languages
10215                            .defaults
10216                            .semantic_tokens = value;
10217                    },
10218                }),
10219                metadata: None,
10220                files: USER | PROJECT,
10221            }),
10222            SettingsPageItem::SettingItem(SettingItem {
10223                title: "LSP Folding Ranges",
10224                description: "When enabled, use folding ranges from the language server instead of indent-based folding.",
10225                field: Box::new(SettingField {
10226                    organization_override: None,
10227                    json_path: Some("languages.$(language).document_folding_ranges"),
10228                    pick: |settings_content| {
10229                        language_settings_field(settings_content, |language| {
10230                            language.document_folding_ranges.as_ref()
10231                        })
10232                    },
10233                    write: |settings_content, value, _| {
10234                        language_settings_field_mut(settings_content, value, |language, value| {
10235                            language.document_folding_ranges = value;
10236                        })
10237                    },
10238                }),
10239                metadata: None,
10240                files: USER | PROJECT,
10241            }),
10242            SettingsPageItem::SettingItem(SettingItem {
10243                title: "LSP Document Symbols",
10244                description: "When enabled, use the language server's document symbols for outlines and breadcrumbs instead of tree-sitter.",
10245                field: Box::new(SettingField {
10246                    organization_override: None,
10247                    json_path: Some("languages.$(language).document_symbols"),
10248                    pick: |settings_content| {
10249                        language_settings_field(settings_content, |language| {
10250                            language.document_symbols.as_ref()
10251                        })
10252                    },
10253                    write: |settings_content, value, _| {
10254                        language_settings_field_mut(settings_content, value, |language, value| {
10255                            language.document_symbols = value;
10256                        })
10257                    },
10258                }),
10259                metadata: None,
10260                files: USER | PROJECT,
10261            }),
10262        ]
10263    }
10264
10265    fn lsp_completions_section() -> [SettingsPageItem; 4] {
10266        [
10267            SettingsPageItem::SectionHeader("LSP Completions"),
10268            SettingsPageItem::SettingItem(SettingItem {
10269                title: "Enabled",
10270                description: "Whether to fetch LSP completions or not.",
10271                field: Box::new(SettingField {
10272                    organization_override: None,
10273                    json_path: Some("languages.$(language).completions.lsp"),
10274                    pick: |settings_content| {
10275                        language_settings_field(settings_content, |language| {
10276                            language.completions.as_ref()?.lsp.as_ref()
10277                        })
10278                    },
10279                    write: |settings_content, value, _| {
10280                        language_settings_field_mut(settings_content, value, |language, value| {
10281                            language.completions.get_or_insert_default().lsp = value;
10282                        })
10283                    },
10284                }),
10285                metadata: None,
10286                files: USER | PROJECT,
10287            }),
10288            SettingsPageItem::SettingItem(SettingItem {
10289                title: "Fetch Timeout (milliseconds)",
10290                description: "When fetching LSP completions, determines how long to wait for a response of a particular server (set to 0 to wait indefinitely).",
10291                field: Box::new(SettingField {
10292                    organization_override: None,
10293                    json_path: Some("languages.$(language).completions.lsp_fetch_timeout_ms"),
10294                    pick: |settings_content| {
10295                        language_settings_field(settings_content, |language| {
10296                            language.completions.as_ref()?.lsp_fetch_timeout_ms.as_ref()
10297                        })
10298                    },
10299                    write: |settings_content, value, _| {
10300                        language_settings_field_mut(settings_content, value, |language, value| {
10301                            language
10302                                .completions
10303                                .get_or_insert_default()
10304                                .lsp_fetch_timeout_ms = value;
10305                        })
10306                    },
10307                }),
10308                metadata: None,
10309                files: USER | PROJECT,
10310            }),
10311            SettingsPageItem::SettingItem(SettingItem {
10312                title: "Insert Mode",
10313                description: "Controls how LSP completions are inserted.",
10314                field: Box::new(SettingField {
10315                    organization_override: None,
10316                    json_path: Some("languages.$(language).completions.lsp_insert_mode"),
10317                    pick: |settings_content| {
10318                        language_settings_field(settings_content, |language| {
10319                            language.completions.as_ref()?.lsp_insert_mode.as_ref()
10320                        })
10321                    },
10322                    write: |settings_content, value, _| {
10323                        language_settings_field_mut(settings_content, value, |language, value| {
10324                            language.completions.get_or_insert_default().lsp_insert_mode = value;
10325                        })
10326                    },
10327                }),
10328                metadata: None,
10329                files: USER | PROJECT,
10330            }),
10331        ]
10332    }
10333
10334    fn debugger_section() -> [SettingsPageItem; 2] {
10335        [
10336            SettingsPageItem::SectionHeader("Debuggers"),
10337            SettingsPageItem::SettingItem(SettingItem {
10338                title: "Debuggers",
10339                description: "Preferred debuggers for this language.",
10340                field: Box::new(
10341                    SettingField {
10342                        organization_override: None,
10343                        json_path: Some("languages.$(language).debuggers"),
10344                        pick: |settings_content| {
10345                            language_settings_field(settings_content, |language| {
10346                                language.debuggers.as_ref()
10347                            })
10348                        },
10349                        write: |settings_content, value, _| {
10350                            language_settings_field_mut(
10351                                settings_content,
10352                                value,
10353                                |language, value| {
10354                                    language.debuggers = value;
10355                                },
10356                            )
10357                        },
10358                    }
10359                    .unimplemented(),
10360                ),
10361                metadata: None,
10362                files: USER | PROJECT,
10363            }),
10364        ]
10365    }
10366
10367    fn prettier_section() -> [SettingsPageItem; 5] {
10368        [
10369            SettingsPageItem::SectionHeader("Prettier"),
10370            SettingsPageItem::SettingItem(SettingItem {
10371                title: "Allowed",
10372                description: "Enables or disables formatting with Prettier for a given language.",
10373                field: Box::new(SettingField {
10374                    organization_override: None,
10375                    json_path: Some("languages.$(language).prettier.allowed"),
10376                    pick: |settings_content| {
10377                        language_settings_field(settings_content, |language| {
10378                            language.prettier.as_ref()?.allowed.as_ref()
10379                        })
10380                    },
10381                    write: |settings_content, value, _| {
10382                        language_settings_field_mut(settings_content, value, |language, value| {
10383                            language.prettier.get_or_insert_default().allowed = value;
10384                        })
10385                    },
10386                }),
10387                metadata: None,
10388                files: USER | PROJECT,
10389            }),
10390            SettingsPageItem::SettingItem(SettingItem {
10391                title: "Parser",
10392                description: "Forces Prettier integration to use a specific parser name when formatting files with the language.",
10393                field: Box::new(SettingField {
10394                    organization_override: None,
10395                    json_path: Some("languages.$(language).prettier.parser"),
10396                    pick: |settings_content| {
10397                        language_settings_field(settings_content, |language| {
10398                            language.prettier.as_ref()?.parser.as_ref()
10399                        })
10400                    },
10401                    write: |settings_content, value, _| {
10402                        language_settings_field_mut(settings_content, value, |language, value| {
10403                            language.prettier.get_or_insert_default().parser = value;
10404                        })
10405                    },
10406                }),
10407                metadata: None,
10408                files: USER | PROJECT,
10409            }),
10410            SettingsPageItem::SettingItem(SettingItem {
10411                title: "Plugins",
10412                description: "Forces Prettier integration to use specific plugins when formatting files with the language.",
10413                field: Box::new(
10414                    SettingField {
10415                        organization_override: None,
10416                        json_path: Some("languages.$(language).prettier.plugins"),
10417                        pick: |settings_content| {
10418                            language_settings_field(settings_content, |language| {
10419                                language.prettier.as_ref()?.plugins.as_ref()
10420                            })
10421                        },
10422                        write: |settings_content, value, _| {
10423                            language_settings_field_mut(
10424                                settings_content,
10425                                value,
10426                                |language, value| {
10427                                    language.prettier.get_or_insert_default().plugins = value;
10428                                },
10429                            )
10430                        },
10431                    }
10432                    .unimplemented(),
10433                ),
10434                metadata: None,
10435                files: USER | PROJECT,
10436            }),
10437            SettingsPageItem::SettingItem(SettingItem {
10438                title: "Options",
10439                description: "Default Prettier options, in the format as in package.json section for Prettier.",
10440                field: Box::new(
10441                    SettingField {
10442                        organization_override: None,
10443                        json_path: Some("languages.$(language).prettier.options"),
10444                        pick: |settings_content| {
10445                            language_settings_field(settings_content, |language| {
10446                                language.prettier.as_ref()?.options.as_ref()
10447                            })
10448                        },
10449                        write: |settings_content, value, _| {
10450                            language_settings_field_mut(
10451                                settings_content,
10452                                value,
10453                                |language, value| {
10454                                    language.prettier.get_or_insert_default().options = value;
10455                                },
10456                            )
10457                        },
10458                    }
10459                    .unimplemented(),
10460                ),
10461                metadata: None,
10462                files: USER | PROJECT,
10463            }),
10464        ]
10465    }
10466
10467    concat_sections!(
10468        lsp_section(),
10469        lsp_completions_section(),
10470        debugger_section(),
10471        prettier_section(),
10472    )
10473}
10474
10475fn edit_prediction_language_settings_section() -> [SettingsPageItem; 5] {
10476    [
10477        SettingsPageItem::SectionHeader("Edit Predictions"),
10478        SettingsPageItem::SubPageLink(SubPageLink {
10479            title: "Configure Providers".into(),
10480            r#type: Default::default(),
10481            json_path: Some("edit_predictions.providers"),
10482            description: Some("Set up different edit prediction providers in complement to the built-in edit prediction model (unavailable in Omega by default).".into()),
10483            search_aliases: &[],
10484            in_json: false,
10485            files: USER,
10486            render: render_edit_prediction_setup_page
10487        }),
10488        SettingsPageItem::SettingItem(SettingItem {
10489            title: "Data Collection",
10490            description: "Controls whether Omega may collect training data when using built-in edit predictions. Data is only collected for files in projects detected as open source. The default value uses the preference previously set via the status-bar toggle, or false if no preference has been stored.",
10491            field: Box::new(SettingField {
10492                organization_override: Some(|org_settings| {
10493                    const DATA_COLLECTION_DISABLED: EditPredictionDataCollectionChoice = EditPredictionDataCollectionChoice::No;
10494
10495                    if !org_settings.edit_prediction.is_feedback_enabled {
10496                        Some(&DATA_COLLECTION_DISABLED)
10497                    } else {
10498                        None
10499                    }
10500                }),
10501                json_path: Some("edit_predictions.allow_data_collection"),
10502                pick: |settings_content| {
10503                    settings_content
10504                        .project
10505                        .all_languages
10506                        .edit_predictions
10507                        .as_ref()?
10508                        .allow_data_collection
10509                        .as_ref()
10510                },
10511                write: |settings_content, value, _app| {
10512                    settings_content
10513                        .project
10514                        .all_languages
10515                        .edit_predictions
10516                        .get_or_insert_default()
10517                        .allow_data_collection = value;
10518                },
10519            }),
10520            metadata: None,
10521            files: USER,
10522        }),
10523        SettingsPageItem::SettingItem(SettingItem {
10524            title: "Show Edit Predictions",
10525            description: "Controls whether edit predictions are shown immediately or manually.",
10526            field: Box::new(SettingField {
10527                organization_override: None,
10528                json_path: Some("languages.$(language).show_edit_predictions"),
10529                pick: |settings_content| {
10530                    language_settings_field(settings_content, |language| {
10531                        language.show_edit_predictions.as_ref()
10532                    })
10533                },
10534                write: |settings_content, value, _| {
10535                    language_settings_field_mut(settings_content, value, |language, value| {
10536                        language.show_edit_predictions = value;
10537                    })
10538                },
10539            }),
10540            metadata: None,
10541            files: USER | PROJECT,
10542        }),
10543        SettingsPageItem::SettingItem(SettingItem {
10544            title: "Disable in Language Scopes",
10545            description: "Controls whether edit predictions are shown in the given language scopes.",
10546            field: Box::new(
10547                SettingField {
10548                    organization_override: None,
10549                    json_path: Some("languages.$(language).edit_predictions_disabled_in"),
10550                    pick: |settings_content| {
10551                        language_settings_field(settings_content, |language| {
10552                            language.edit_predictions_disabled_in.as_ref()
10553                        })
10554                    },
10555                    write: |settings_content, value, _| {
10556                        language_settings_field_mut(settings_content, value, |language, value| {
10557                            language.edit_predictions_disabled_in = value;
10558                        })
10559                    },
10560                }
10561                .unimplemented(),
10562            ),
10563            metadata: None,
10564            files: USER | PROJECT,
10565        }),
10566    ]
10567}
10568
10569fn show_scrollbar_or_editor(
10570    settings_content: &SettingsContent,
10571    show: fn(&SettingsContent) -> Option<&settings::ShowScrollbar>,
10572) -> Option<&settings::ShowScrollbar> {
10573    show(settings_content).or(settings_content
10574        .editor
10575        .scrollbar
10576        .as_ref()
10577        .and_then(|scrollbar| scrollbar.show.as_ref()))
10578}
10579
10580fn dynamic_variants<T>() -> &'static [T::Discriminant]
10581where
10582    T: strum::IntoDiscriminant,
10583    T::Discriminant: strum::VariantArray,
10584{
10585    <<T as strum::IntoDiscriminant>::Discriminant as strum::VariantArray>::VARIANTS
10586}
10587
10588/// Updates the `vim_mode` setting, disabling `helix_mode` if present and
10589/// `vim_mode` is being enabled.
10590fn write_vim_mode(settings: &mut SettingsContent, value: Option<bool>, _: &App) {
10591    write_vim_mode_inner(settings, value);
10592}
10593
10594fn write_vim_mode_inner(settings: &mut SettingsContent, value: Option<bool>) {
10595    if value == Some(true) && settings.helix_mode == Some(true) {
10596        settings.helix_mode = Some(false);
10597    }
10598    settings.vim_mode = value;
10599}
10600
10601/// Updates the `helix_mode` setting, disabling `vim_mode` if present and
10602/// `helix_mode` is being enabled.
10603fn write_helix_mode(settings: &mut SettingsContent, value: Option<bool>, _: &App) {
10604    write_helix_mode_inner(settings, value);
10605}
10606
10607fn write_helix_mode_inner(settings: &mut SettingsContent, value: Option<bool>) {
10608    if value == Some(true) && settings.vim_mode == Some(true) {
10609        settings.vim_mode = Some(false);
10610    }
10611    settings.helix_mode = value;
10612}
10613
10614#[cfg(test)]
10615mod tests {
10616    use super::*;
10617
10618    #[test]
10619    fn test_write_vim_helix_mode() {
10620        // Enabling vim mode while `vim_mode` and `helix_mode` are not yet set
10621        // should only update the `vim_mode` setting.
10622        let mut settings = SettingsContent::default();
10623        write_vim_mode_inner(&mut settings, Some(true));
10624        assert_eq!(settings.vim_mode, Some(true));
10625        assert_eq!(settings.helix_mode, None);
10626
10627        // Enabling helix mode while `vim_mode` and `helix_mode` are not yet set
10628        // should only update the `helix_mode` setting.
10629        let mut settings = SettingsContent::default();
10630        write_helix_mode_inner(&mut settings, Some(true));
10631        assert_eq!(settings.helix_mode, Some(true));
10632        assert_eq!(settings.vim_mode, None);
10633
10634        // Disabling helix mode should only touch `helix_mode` setting when
10635        // `vim_mode` is not set.
10636        write_helix_mode_inner(&mut settings, Some(false));
10637        assert_eq!(settings.helix_mode, Some(false));
10638        assert_eq!(settings.vim_mode, None);
10639
10640        // Enabling vim mode should update `vim_mode` but leave `helix_mode`
10641        // untouched.
10642        write_vim_mode_inner(&mut settings, Some(true));
10643        assert_eq!(settings.vim_mode, Some(true));
10644        assert_eq!(settings.helix_mode, Some(false));
10645
10646        // Enabling helix mode should update `helix_mode` and disable
10647        // `vim_mode`.
10648        write_helix_mode_inner(&mut settings, Some(true));
10649        assert_eq!(settings.helix_mode, Some(true));
10650        assert_eq!(settings.vim_mode, Some(false));
10651
10652        // Enabling vim mode should update `vim_mode` and disable
10653        // `helix_mode`.
10654        write_vim_mode_inner(&mut settings, Some(true));
10655        assert_eq!(settings.vim_mode, Some(true));
10656        assert_eq!(settings.helix_mode, Some(false));
10657    }
10658}
10659
Served at tenant.openagents/omega Member data and write actions are omitted.