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