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