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