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