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