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