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