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; 11] {
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: "Highlight on Yank Duration",
2489 description: "Duration in milliseconds to highlight yanked text in Vim mode.",
2490 field: Box::new(SettingField {
2491 json_path: Some("vim.highlight_on_yank_duration"),
2492 pick: |settings_content| {
2493 settings_content
2494 .vim
2495 .as_ref()?
2496 .highlight_on_yank_duration
2497 .as_ref()
2498 },
2499 write: |settings_content, value| {
2500 settings_content
2501 .vim
2502 .get_or_insert_default()
2503 .highlight_on_yank_duration = value;
2504 },
2505 }),
2506 metadata: None,
2507 files: USER,
2508 }),
2509 SettingsPageItem::SettingItem(SettingItem {
2510 title: "Cursor Shape - Normal Mode",
2511 description: "Cursor shape for normal mode.",
2512 field: Box::new(SettingField {
2513 json_path: Some("vim.cursor_shape.normal"),
2514 pick: |settings_content| {
2515 settings_content
2516 .vim
2517 .as_ref()?
2518 .cursor_shape
2519 .as_ref()?
2520 .normal
2521 .as_ref()
2522 },
2523 write: |settings_content, value| {
2524 settings_content
2525 .vim
2526 .get_or_insert_default()
2527 .cursor_shape
2528 .get_or_insert_default()
2529 .normal = value;
2530 },
2531 }),
2532 metadata: None,
2533 files: USER,
2534 }),
2535 SettingsPageItem::SettingItem(SettingItem {
2536 title: "Cursor Shape - Insert Mode",
2537 description: "Cursor shape for insert mode. Inherit uses the editor's cursor shape.",
2538 field: Box::new(SettingField {
2539 json_path: Some("vim.cursor_shape.insert"),
2540 pick: |settings_content| {
2541 settings_content
2542 .vim
2543 .as_ref()?
2544 .cursor_shape
2545 .as_ref()?
2546 .insert
2547 .as_ref()
2548 },
2549 write: |settings_content, value| {
2550 settings_content
2551 .vim
2552 .get_or_insert_default()
2553 .cursor_shape
2554 .get_or_insert_default()
2555 .insert = value;
2556 },
2557 }),
2558 metadata: None,
2559 files: USER,
2560 }),
2561 SettingsPageItem::SettingItem(SettingItem {
2562 title: "Cursor Shape - Replace Mode",
2563 description: "Cursor shape for replace mode.",
2564 field: Box::new(SettingField {
2565 json_path: Some("vim.cursor_shape.replace"),
2566 pick: |settings_content| {
2567 settings_content
2568 .vim
2569 .as_ref()?
2570 .cursor_shape
2571 .as_ref()?
2572 .replace
2573 .as_ref()
2574 },
2575 write: |settings_content, value| {
2576 settings_content
2577 .vim
2578 .get_or_insert_default()
2579 .cursor_shape
2580 .get_or_insert_default()
2581 .replace = value;
2582 },
2583 }),
2584 metadata: None,
2585 files: USER,
2586 }),
2587 SettingsPageItem::SettingItem(SettingItem {
2588 title: "Cursor Shape - Visual Mode",
2589 description: "Cursor shape for visual mode.",
2590 field: Box::new(SettingField {
2591 json_path: Some("vim.cursor_shape.visual"),
2592 pick: |settings_content| {
2593 settings_content
2594 .vim
2595 .as_ref()?
2596 .cursor_shape
2597 .as_ref()?
2598 .visual
2599 .as_ref()
2600 },
2601 write: |settings_content, value| {
2602 settings_content
2603 .vim
2604 .get_or_insert_default()
2605 .cursor_shape
2606 .get_or_insert_default()
2607 .visual = value;
2608 },
2609 }),
2610 metadata: None,
2611 files: USER,
2612 }),
2613 SettingsPageItem::SettingItem(SettingItem {
2614 title: "Custom Digraphs",
2615 description: "Custom digraph mappings for Vim mode.",
2616 field: Box::new(
2617 SettingField {
2618 json_path: Some("vim.custom_digraphs"),
2619 pick: |settings_content| {
2620 settings_content.vim.as_ref()?.custom_digraphs.as_ref()
2621 },
2622 write: |settings_content, value| {
2623 settings_content.vim.get_or_insert_default().custom_digraphs = value;
2624 },
2625 }
2626 .unimplemented(),
2627 ),
2628 metadata: None,
2629 files: USER,
2630 }),
2631 ]
2632 }
2633
2634 let items = concat_sections!(
2635 auto_save_section(),
2636 which_key_section(),
2637 multibuffer_section(),
2638 scrolling_section(),
2639 signature_help_section(),
2640 hover_popover_section(),
2641 drag_and_drop_selection_section(),
2642 gutter_section(),
2643 scrollbar_section(),
2644 minimap_section(),
2645 toolbar_section(),
2646 vim_settings_section(),
2647 language_settings_data(),
2648 );
2649
2650 SettingsPage {
2651 title: "Editor",
2652 items: items,
2653 }
2654}
2655
2656fn languages_and_tools_page(cx: &App) -> SettingsPage {
2657 fn file_types_section() -> [SettingsPageItem; 2] {
2658 [
2659 SettingsPageItem::SectionHeader("File Types"),
2660 SettingsPageItem::SettingItem(SettingItem {
2661 title: "File Type Associations",
2662 description: "A mapping from languages to files and file extensions that should be treated as that language.",
2663 field: Box::new(
2664 SettingField {
2665 json_path: Some("file_type_associations"),
2666 pick: |settings_content| {
2667 settings_content.project.all_languages.file_types.as_ref()
2668 },
2669 write: |settings_content, value| {
2670 settings_content.project.all_languages.file_types = value;
2671 },
2672 }
2673 .unimplemented(),
2674 ),
2675 metadata: None,
2676 files: USER | PROJECT,
2677 }),
2678 ]
2679 }
2680
2681 fn diagnostics_section() -> [SettingsPageItem; 3] {
2682 [
2683 SettingsPageItem::SectionHeader("Diagnostics"),
2684 SettingsPageItem::SettingItem(SettingItem {
2685 title: "Max Severity",
2686 description: "Which level to use to filter out diagnostics displayed in the editor.",
2687 field: Box::new(SettingField {
2688 json_path: Some("diagnostics_max_severity"),
2689 pick: |settings_content| {
2690 settings_content.editor.diagnostics_max_severity.as_ref()
2691 },
2692 write: |settings_content, value| {
2693 settings_content.editor.diagnostics_max_severity = value;
2694 },
2695 }),
2696 metadata: None,
2697 files: USER,
2698 }),
2699 SettingsPageItem::SettingItem(SettingItem {
2700 title: "Include Warnings",
2701 description: "Whether to show warnings or not by default.",
2702 field: Box::new(SettingField {
2703 json_path: Some("diagnostics.include_warnings"),
2704 pick: |settings_content| {
2705 settings_content
2706 .diagnostics
2707 .as_ref()?
2708 .include_warnings
2709 .as_ref()
2710 },
2711 write: |settings_content, value| {
2712 settings_content
2713 .diagnostics
2714 .get_or_insert_default()
2715 .include_warnings = value;
2716 },
2717 }),
2718 metadata: None,
2719 files: USER,
2720 }),
2721 ]
2722 }
2723
2724 fn inline_diagnostics_section() -> [SettingsPageItem; 5] {
2725 [
2726 SettingsPageItem::SectionHeader("Inline Diagnostics"),
2727 SettingsPageItem::SettingItem(SettingItem {
2728 title: "Enabled",
2729 description: "Whether to show diagnostics inline or not.",
2730 field: Box::new(SettingField {
2731 json_path: Some("diagnostics.inline.enabled"),
2732 pick: |settings_content| {
2733 settings_content
2734 .diagnostics
2735 .as_ref()?
2736 .inline
2737 .as_ref()?
2738 .enabled
2739 .as_ref()
2740 },
2741 write: |settings_content, value| {
2742 settings_content
2743 .diagnostics
2744 .get_or_insert_default()
2745 .inline
2746 .get_or_insert_default()
2747 .enabled = value;
2748 },
2749 }),
2750 metadata: None,
2751 files: USER,
2752 }),
2753 SettingsPageItem::SettingItem(SettingItem {
2754 title: "Update Debounce",
2755 description: "The delay in milliseconds to show inline diagnostics after the last diagnostic update.",
2756 field: Box::new(SettingField {
2757 json_path: Some("diagnostics.inline.update_debounce_ms"),
2758 pick: |settings_content| {
2759 settings_content
2760 .diagnostics
2761 .as_ref()?
2762 .inline
2763 .as_ref()?
2764 .update_debounce_ms
2765 .as_ref()
2766 },
2767 write: |settings_content, value| {
2768 settings_content
2769 .diagnostics
2770 .get_or_insert_default()
2771 .inline
2772 .get_or_insert_default()
2773 .update_debounce_ms = value;
2774 },
2775 }),
2776 metadata: None,
2777 files: USER,
2778 }),
2779 SettingsPageItem::SettingItem(SettingItem {
2780 title: "Padding",
2781 description: "The amount of padding between the end of the source line and the start of the inline diagnostic.",
2782 field: Box::new(SettingField {
2783 json_path: Some("diagnostics.inline.padding"),
2784 pick: |settings_content| {
2785 settings_content
2786 .diagnostics
2787 .as_ref()?
2788 .inline
2789 .as_ref()?
2790 .padding
2791 .as_ref()
2792 },
2793 write: |settings_content, value| {
2794 settings_content
2795 .diagnostics
2796 .get_or_insert_default()
2797 .inline
2798 .get_or_insert_default()
2799 .padding = value;
2800 },
2801 }),
2802 metadata: None,
2803 files: USER,
2804 }),
2805 SettingsPageItem::SettingItem(SettingItem {
2806 title: "Minimum Column",
2807 description: "The minimum column at which to display inline diagnostics.",
2808 field: Box::new(SettingField {
2809 json_path: Some("diagnostics.inline.min_column"),
2810 pick: |settings_content| {
2811 settings_content
2812 .diagnostics
2813 .as_ref()?
2814 .inline
2815 .as_ref()?
2816 .min_column
2817 .as_ref()
2818 },
2819 write: |settings_content, value| {
2820 settings_content
2821 .diagnostics
2822 .get_or_insert_default()
2823 .inline
2824 .get_or_insert_default()
2825 .min_column = value;
2826 },
2827 }),
2828 metadata: None,
2829 files: USER,
2830 }),
2831 ]
2832 }
2833
2834 fn lsp_pull_diagnostics_section() -> [SettingsPageItem; 3] {
2835 [
2836 SettingsPageItem::SectionHeader("LSP Pull Diagnostics"),
2837 SettingsPageItem::SettingItem(SettingItem {
2838 title: "Enabled",
2839 description: "Whether to pull for language server-powered diagnostics or not.",
2840 field: Box::new(SettingField {
2841 json_path: Some("diagnostics.lsp_pull_diagnostics.enabled"),
2842 pick: |settings_content| {
2843 settings_content
2844 .diagnostics
2845 .as_ref()?
2846 .lsp_pull_diagnostics
2847 .as_ref()?
2848 .enabled
2849 .as_ref()
2850 },
2851 write: |settings_content, value| {
2852 settings_content
2853 .diagnostics
2854 .get_or_insert_default()
2855 .lsp_pull_diagnostics
2856 .get_or_insert_default()
2857 .enabled = value;
2858 },
2859 }),
2860 metadata: None,
2861 files: USER,
2862 }),
2863 // todo(settings_ui): Needs unit
2864 SettingsPageItem::SettingItem(SettingItem {
2865 title: "Debounce",
2866 description: "Minimum time to wait before pulling diagnostics from the language server(s).",
2867 field: Box::new(SettingField {
2868 json_path: Some("diagnostics.lsp_pull_diagnostics.debounce_ms"),
2869 pick: |settings_content| {
2870 settings_content
2871 .diagnostics
2872 .as_ref()?
2873 .lsp_pull_diagnostics
2874 .as_ref()?
2875 .debounce_ms
2876 .as_ref()
2877 },
2878 write: |settings_content, value| {
2879 settings_content
2880 .diagnostics
2881 .get_or_insert_default()
2882 .lsp_pull_diagnostics
2883 .get_or_insert_default()
2884 .debounce_ms = value;
2885 },
2886 }),
2887 metadata: None,
2888 files: USER,
2889 }),
2890 ]
2891 }
2892
2893 fn lsp_highlights_section() -> [SettingsPageItem; 2] {
2894 [
2895 SettingsPageItem::SectionHeader("LSP Highlights"),
2896 SettingsPageItem::SettingItem(SettingItem {
2897 title: "Debounce",
2898 description: "The debounce delay before querying highlights from the language.",
2899 field: Box::new(SettingField {
2900 json_path: Some("lsp_highlight_debounce"),
2901 pick: |settings_content| {
2902 settings_content.editor.lsp_highlight_debounce.as_ref()
2903 },
2904 write: |settings_content, value| {
2905 settings_content.editor.lsp_highlight_debounce = value;
2906 },
2907 }),
2908 metadata: None,
2909 files: USER,
2910 }),
2911 ]
2912 }
2913
2914 fn languages_list_section(cx: &App) -> Box<[SettingsPageItem]> {
2915 // todo(settings_ui): Refresh on extension (un)/installed
2916 // Note that `crates/json_schema_store` solves the same problem, there is probably a way to unify the two
2917 std::iter::once(SettingsPageItem::SectionHeader("Languages"))
2918 .chain(all_language_names(cx).into_iter().map(|language_name| {
2919 let link = format!("languages.{language_name}");
2920 SettingsPageItem::SubPageLink(SubPageLink {
2921 title: language_name,
2922 r#type: crate::SubPageType::Language,
2923 description: None,
2924 json_path: Some(link.leak()),
2925 in_json: true,
2926 files: USER | PROJECT,
2927 render: |this, scroll_handle, window, cx| {
2928 let items: Box<[SettingsPageItem]> = concat_sections!(
2929 language_settings_data(),
2930 non_editor_language_settings_data(),
2931 edit_prediction_language_settings_section()
2932 );
2933 this.render_sub_page_items(
2934 items.iter().enumerate(),
2935 scroll_handle,
2936 window,
2937 cx,
2938 )
2939 .into_any_element()
2940 },
2941 })
2942 }))
2943 .collect()
2944 }
2945
2946 SettingsPage {
2947 title: "Languages & Tools",
2948 items: {
2949 concat_sections!(
2950 non_editor_language_settings_data(),
2951 file_types_section(),
2952 diagnostics_section(),
2953 inline_diagnostics_section(),
2954 lsp_pull_diagnostics_section(),
2955 lsp_highlights_section(),
2956 languages_list_section(cx),
2957 )
2958 },
2959 }
2960}
2961
2962fn search_and_files_page() -> SettingsPage {
2963 fn search_section() -> [SettingsPageItem; 9] {
2964 [
2965 SettingsPageItem::SectionHeader("Search"),
2966 SettingsPageItem::SettingItem(SettingItem {
2967 title: "Whole Word",
2968 description: "Search for whole words by default.",
2969 field: Box::new(SettingField {
2970 json_path: Some("search.whole_word"),
2971 pick: |settings_content| {
2972 settings_content.editor.search.as_ref()?.whole_word.as_ref()
2973 },
2974 write: |settings_content, value| {
2975 settings_content
2976 .editor
2977 .search
2978 .get_or_insert_default()
2979 .whole_word = value;
2980 },
2981 }),
2982 metadata: None,
2983 files: USER,
2984 }),
2985 SettingsPageItem::SettingItem(SettingItem {
2986 title: "Case Sensitive",
2987 description: "Search case-sensitively by default.",
2988 field: Box::new(SettingField {
2989 json_path: Some("search.case_sensitive"),
2990 pick: |settings_content| {
2991 settings_content
2992 .editor
2993 .search
2994 .as_ref()?
2995 .case_sensitive
2996 .as_ref()
2997 },
2998 write: |settings_content, value| {
2999 settings_content
3000 .editor
3001 .search
3002 .get_or_insert_default()
3003 .case_sensitive = value;
3004 },
3005 }),
3006 metadata: None,
3007 files: USER,
3008 }),
3009 SettingsPageItem::SettingItem(SettingItem {
3010 title: "Use Smartcase Search",
3011 description: "Whether to automatically enable case-sensitive search based on the search query.",
3012 field: Box::new(SettingField {
3013 json_path: Some("use_smartcase_search"),
3014 pick: |settings_content| settings_content.editor.use_smartcase_search.as_ref(),
3015 write: |settings_content, value| {
3016 settings_content.editor.use_smartcase_search = value;
3017 },
3018 }),
3019 metadata: None,
3020 files: USER,
3021 }),
3022 SettingsPageItem::SettingItem(SettingItem {
3023 title: "Include Ignored",
3024 description: "Include ignored files in search results by default.",
3025 field: Box::new(SettingField {
3026 json_path: Some("search.include_ignored"),
3027 pick: |settings_content| {
3028 settings_content
3029 .editor
3030 .search
3031 .as_ref()?
3032 .include_ignored
3033 .as_ref()
3034 },
3035 write: |settings_content, value| {
3036 settings_content
3037 .editor
3038 .search
3039 .get_or_insert_default()
3040 .include_ignored = value;
3041 },
3042 }),
3043 metadata: None,
3044 files: USER,
3045 }),
3046 SettingsPageItem::SettingItem(SettingItem {
3047 title: "Regex",
3048 description: "Use regex search by default.",
3049 field: Box::new(SettingField {
3050 json_path: Some("search.regex"),
3051 pick: |settings_content| {
3052 settings_content.editor.search.as_ref()?.regex.as_ref()
3053 },
3054 write: |settings_content, value| {
3055 settings_content.editor.search.get_or_insert_default().regex = value;
3056 },
3057 }),
3058 metadata: None,
3059 files: USER,
3060 }),
3061 SettingsPageItem::SettingItem(SettingItem {
3062 title: "Search Wrap",
3063 description: "Whether the editor search results will loop.",
3064 field: Box::new(SettingField {
3065 json_path: Some("search_wrap"),
3066 pick: |settings_content| settings_content.editor.search_wrap.as_ref(),
3067 write: |settings_content, value| {
3068 settings_content.editor.search_wrap = value;
3069 },
3070 }),
3071 metadata: None,
3072 files: USER,
3073 }),
3074 SettingsPageItem::SettingItem(SettingItem {
3075 title: "Center on Match",
3076 description: "Whether to center the current match in the editor",
3077 field: Box::new(SettingField {
3078 json_path: Some("editor.search.center_on_match"),
3079 pick: |settings_content| {
3080 settings_content
3081 .editor
3082 .search
3083 .as_ref()
3084 .and_then(|search| search.center_on_match.as_ref())
3085 },
3086 write: |settings_content, value| {
3087 settings_content
3088 .editor
3089 .search
3090 .get_or_insert_default()
3091 .center_on_match = value;
3092 },
3093 }),
3094 metadata: None,
3095 files: USER,
3096 }),
3097 SettingsPageItem::SettingItem(SettingItem {
3098 title: "Seed Search Query From Cursor",
3099 description: "When to populate a new search's query based on the text under the cursor.",
3100 field: Box::new(SettingField {
3101 json_path: Some("seed_search_query_from_cursor"),
3102 pick: |settings_content| {
3103 settings_content
3104 .editor
3105 .seed_search_query_from_cursor
3106 .as_ref()
3107 },
3108 write: |settings_content, value| {
3109 settings_content.editor.seed_search_query_from_cursor = value;
3110 },
3111 }),
3112 metadata: None,
3113 files: USER,
3114 }),
3115 ]
3116 }
3117
3118 fn file_finder_section() -> [SettingsPageItem; 6] {
3119 [
3120 SettingsPageItem::SectionHeader("File Finder"),
3121 // todo: null by default
3122 SettingsPageItem::SettingItem(SettingItem {
3123 title: "Include Ignored in Search",
3124 description: "Use gitignored files when searching.",
3125 field: Box::new(SettingField {
3126 json_path: Some("file_finder.include_ignored"),
3127 pick: |settings_content| {
3128 settings_content
3129 .file_finder
3130 .as_ref()?
3131 .include_ignored
3132 .as_ref()
3133 },
3134 write: |settings_content, value| {
3135 settings_content
3136 .file_finder
3137 .get_or_insert_default()
3138 .include_ignored = value;
3139 },
3140 }),
3141 metadata: None,
3142 files: USER,
3143 }),
3144 SettingsPageItem::SettingItem(SettingItem {
3145 title: "File Icons",
3146 description: "Show file icons in the file finder.",
3147 field: Box::new(SettingField {
3148 json_path: Some("file_finder.file_icons"),
3149 pick: |settings_content| {
3150 settings_content.file_finder.as_ref()?.file_icons.as_ref()
3151 },
3152 write: |settings_content, value| {
3153 settings_content
3154 .file_finder
3155 .get_or_insert_default()
3156 .file_icons = value;
3157 },
3158 }),
3159 metadata: None,
3160 files: USER,
3161 }),
3162 SettingsPageItem::SettingItem(SettingItem {
3163 title: "Modal Max Width",
3164 description: "Determines how much space the file finder can take up in relation to the available window width.",
3165 field: Box::new(SettingField {
3166 json_path: Some("file_finder.modal_max_width"),
3167 pick: |settings_content| {
3168 settings_content
3169 .file_finder
3170 .as_ref()?
3171 .modal_max_width
3172 .as_ref()
3173 },
3174 write: |settings_content, value| {
3175 settings_content
3176 .file_finder
3177 .get_or_insert_default()
3178 .modal_max_width = value;
3179 },
3180 }),
3181 metadata: None,
3182 files: USER,
3183 }),
3184 SettingsPageItem::SettingItem(SettingItem {
3185 title: "Skip Focus For Active In Search",
3186 description: "Whether the file finder should skip focus for the active file in search results.",
3187 field: Box::new(SettingField {
3188 json_path: Some("file_finder.skip_focus_for_active_in_search"),
3189 pick: |settings_content| {
3190 settings_content
3191 .file_finder
3192 .as_ref()?
3193 .skip_focus_for_active_in_search
3194 .as_ref()
3195 },
3196 write: |settings_content, value| {
3197 settings_content
3198 .file_finder
3199 .get_or_insert_default()
3200 .skip_focus_for_active_in_search = value;
3201 },
3202 }),
3203 metadata: None,
3204 files: USER,
3205 }),
3206 SettingsPageItem::SettingItem(SettingItem {
3207 title: "Git Status",
3208 description: "Show the Git status in the file finder.",
3209 field: Box::new(SettingField {
3210 json_path: Some("file_finder.git_status"),
3211 pick: |settings_content| {
3212 settings_content.file_finder.as_ref()?.git_status.as_ref()
3213 },
3214 write: |settings_content, value| {
3215 settings_content
3216 .file_finder
3217 .get_or_insert_default()
3218 .git_status = value;
3219 },
3220 }),
3221 metadata: None,
3222 files: USER,
3223 }),
3224 ]
3225 }
3226
3227 fn file_scan_section() -> [SettingsPageItem; 5] {
3228 [
3229 SettingsPageItem::SectionHeader("File Scan"),
3230 SettingsPageItem::SettingItem(SettingItem {
3231 title: "File Scan Exclusions",
3232 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\"",
3233 field: Box::new(
3234 SettingField {
3235 json_path: Some("file_scan_exclusions"),
3236 pick: |settings_content| {
3237 settings_content
3238 .project
3239 .worktree
3240 .file_scan_exclusions
3241 .as_ref()
3242 },
3243 write: |settings_content, value| {
3244 settings_content.project.worktree.file_scan_exclusions = value;
3245 },
3246 }
3247 .unimplemented(),
3248 ),
3249 metadata: None,
3250 files: USER,
3251 }),
3252 SettingsPageItem::SettingItem(SettingItem {
3253 title: "File Scan Inclusions",
3254 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",
3255 field: Box::new(
3256 SettingField {
3257 json_path: Some("file_scan_inclusions"),
3258 pick: |settings_content| {
3259 settings_content
3260 .project
3261 .worktree
3262 .file_scan_inclusions
3263 .as_ref()
3264 },
3265 write: |settings_content, value| {
3266 settings_content.project.worktree.file_scan_inclusions = value;
3267 },
3268 }
3269 .unimplemented(),
3270 ),
3271 metadata: None,
3272 files: USER,
3273 }),
3274 SettingsPageItem::SettingItem(SettingItem {
3275 title: "Restore File State",
3276 description: "Restore previous file state when reopening.",
3277 field: Box::new(SettingField {
3278 json_path: Some("restore_on_file_reopen"),
3279 pick: |settings_content| {
3280 settings_content.workspace.restore_on_file_reopen.as_ref()
3281 },
3282 write: |settings_content, value| {
3283 settings_content.workspace.restore_on_file_reopen = value;
3284 },
3285 }),
3286 metadata: None,
3287 files: USER,
3288 }),
3289 SettingsPageItem::SettingItem(SettingItem {
3290 title: "Close on File Delete",
3291 description: "Automatically close files that have been deleted.",
3292 field: Box::new(SettingField {
3293 json_path: Some("close_on_file_delete"),
3294 pick: |settings_content| {
3295 settings_content.workspace.close_on_file_delete.as_ref()
3296 },
3297 write: |settings_content, value| {
3298 settings_content.workspace.close_on_file_delete = value;
3299 },
3300 }),
3301 metadata: None,
3302 files: USER,
3303 }),
3304 ]
3305 }
3306
3307 SettingsPage {
3308 title: "Search & Files",
3309 items: concat_sections![search_section(), file_finder_section(), file_scan_section()],
3310 }
3311}
3312
3313fn window_and_layout_page() -> SettingsPage {
3314 fn status_bar_section() -> [SettingsPageItem; 9] {
3315 [
3316 SettingsPageItem::SectionHeader("Status Bar"),
3317 SettingsPageItem::SettingItem(SettingItem {
3318 title: "Project Panel Button",
3319 description: "Show the project panel button in the status bar.",
3320 field: Box::new(SettingField {
3321 json_path: Some("project_panel.button"),
3322 pick: |settings_content| {
3323 settings_content.project_panel.as_ref()?.button.as_ref()
3324 },
3325 write: |settings_content, value| {
3326 settings_content
3327 .project_panel
3328 .get_or_insert_default()
3329 .button = value;
3330 },
3331 }),
3332 metadata: None,
3333 files: USER,
3334 }),
3335 SettingsPageItem::SettingItem(SettingItem {
3336 title: "Active Language Button",
3337 description: "Show the active language button in the status bar.",
3338 field: Box::new(SettingField {
3339 json_path: Some("status_bar.active_language_button"),
3340 pick: |settings_content| {
3341 settings_content
3342 .status_bar
3343 .as_ref()?
3344 .active_language_button
3345 .as_ref()
3346 },
3347 write: |settings_content, value| {
3348 settings_content
3349 .status_bar
3350 .get_or_insert_default()
3351 .active_language_button = value;
3352 },
3353 }),
3354 metadata: None,
3355 files: USER,
3356 }),
3357 SettingsPageItem::SettingItem(SettingItem {
3358 title: "Active Encoding Button",
3359 description: "Control when to show the active encoding in the status bar.",
3360 field: Box::new(SettingField {
3361 json_path: Some("status_bar.active_encoding_button"),
3362 pick: |settings_content| {
3363 settings_content
3364 .status_bar
3365 .as_ref()?
3366 .active_encoding_button
3367 .as_ref()
3368 },
3369 write: |settings_content, value| {
3370 settings_content
3371 .status_bar
3372 .get_or_insert_default()
3373 .active_encoding_button = value;
3374 },
3375 }),
3376 metadata: None,
3377 files: USER,
3378 }),
3379 SettingsPageItem::SettingItem(SettingItem {
3380 title: "Cursor Position Button",
3381 description: "Show the cursor position button in the status bar.",
3382 field: Box::new(SettingField {
3383 json_path: Some("status_bar.cursor_position_button"),
3384 pick: |settings_content| {
3385 settings_content
3386 .status_bar
3387 .as_ref()?
3388 .cursor_position_button
3389 .as_ref()
3390 },
3391 write: |settings_content, value| {
3392 settings_content
3393 .status_bar
3394 .get_or_insert_default()
3395 .cursor_position_button = value;
3396 },
3397 }),
3398 metadata: None,
3399 files: USER,
3400 }),
3401 SettingsPageItem::SettingItem(SettingItem {
3402 title: "Terminal Button",
3403 description: "Show the terminal button in the status bar.",
3404 field: Box::new(SettingField {
3405 json_path: Some("terminal.button"),
3406 pick: |settings_content| settings_content.terminal.as_ref()?.button.as_ref(),
3407 write: |settings_content, value| {
3408 settings_content.terminal.get_or_insert_default().button = value;
3409 },
3410 }),
3411 metadata: None,
3412 files: USER,
3413 }),
3414 SettingsPageItem::SettingItem(SettingItem {
3415 title: "Diagnostics Button",
3416 description: "Show the project diagnostics button in the status bar.",
3417 field: Box::new(SettingField {
3418 json_path: Some("diagnostics.button"),
3419 pick: |settings_content| settings_content.diagnostics.as_ref()?.button.as_ref(),
3420 write: |settings_content, value| {
3421 settings_content.diagnostics.get_or_insert_default().button = value;
3422 },
3423 }),
3424 metadata: None,
3425 files: USER,
3426 }),
3427 SettingsPageItem::SettingItem(SettingItem {
3428 title: "Project Search Button",
3429 description: "Show the project search button in the status bar.",
3430 field: Box::new(SettingField {
3431 json_path: Some("search.button"),
3432 pick: |settings_content| {
3433 settings_content.editor.search.as_ref()?.button.as_ref()
3434 },
3435 write: |settings_content, value| {
3436 settings_content
3437 .editor
3438 .search
3439 .get_or_insert_default()
3440 .button = value;
3441 },
3442 }),
3443 metadata: None,
3444 files: USER,
3445 }),
3446 SettingsPageItem::SettingItem(SettingItem {
3447 title: "Debugger Button",
3448 description: "Show the debugger button in the status bar.",
3449 field: Box::new(SettingField {
3450 json_path: Some("debugger.button"),
3451 pick: |settings_content| settings_content.debugger.as_ref()?.button.as_ref(),
3452 write: |settings_content, value| {
3453 settings_content.debugger.get_or_insert_default().button = value;
3454 },
3455 }),
3456 metadata: None,
3457 files: USER,
3458 }),
3459 ]
3460 }
3461
3462 fn title_bar_section() -> [SettingsPageItem; 9] {
3463 [
3464 SettingsPageItem::SectionHeader("Title Bar"),
3465 SettingsPageItem::SettingItem(SettingItem {
3466 title: "Show Branch Icon",
3467 description: "Show the branch icon beside branch switcher in the titlebar.",
3468 field: Box::new(SettingField {
3469 json_path: Some("title_bar.show_branch_icon"),
3470 pick: |settings_content| {
3471 settings_content
3472 .title_bar
3473 .as_ref()?
3474 .show_branch_icon
3475 .as_ref()
3476 },
3477 write: |settings_content, value| {
3478 settings_content
3479 .title_bar
3480 .get_or_insert_default()
3481 .show_branch_icon = value;
3482 },
3483 }),
3484 metadata: None,
3485 files: USER,
3486 }),
3487 SettingsPageItem::SettingItem(SettingItem {
3488 title: "Show Branch Name",
3489 description: "Show the branch name button in the titlebar.",
3490 field: Box::new(SettingField {
3491 json_path: Some("title_bar.show_branch_name"),
3492 pick: |settings_content| {
3493 settings_content
3494 .title_bar
3495 .as_ref()?
3496 .show_branch_name
3497 .as_ref()
3498 },
3499 write: |settings_content, value| {
3500 settings_content
3501 .title_bar
3502 .get_or_insert_default()
3503 .show_branch_name = value;
3504 },
3505 }),
3506 metadata: None,
3507 files: USER,
3508 }),
3509 SettingsPageItem::SettingItem(SettingItem {
3510 title: "Show Project Items",
3511 description: "Show the project host and name in the titlebar.",
3512 field: Box::new(SettingField {
3513 json_path: Some("title_bar.show_project_items"),
3514 pick: |settings_content| {
3515 settings_content
3516 .title_bar
3517 .as_ref()?
3518 .show_project_items
3519 .as_ref()
3520 },
3521 write: |settings_content, value| {
3522 settings_content
3523 .title_bar
3524 .get_or_insert_default()
3525 .show_project_items = value;
3526 },
3527 }),
3528 metadata: None,
3529 files: USER,
3530 }),
3531 SettingsPageItem::SettingItem(SettingItem {
3532 title: "Show Onboarding Banner",
3533 description: "Show banners announcing new features in the titlebar.",
3534 field: Box::new(SettingField {
3535 json_path: Some("title_bar.show_onboarding_banner"),
3536 pick: |settings_content| {
3537 settings_content
3538 .title_bar
3539 .as_ref()?
3540 .show_onboarding_banner
3541 .as_ref()
3542 },
3543 write: |settings_content, value| {
3544 settings_content
3545 .title_bar
3546 .get_or_insert_default()
3547 .show_onboarding_banner = value;
3548 },
3549 }),
3550 metadata: None,
3551 files: USER,
3552 }),
3553 SettingsPageItem::SettingItem(SettingItem {
3554 title: "Show Sign In",
3555 description: "Show the sign in button in the titlebar.",
3556 field: Box::new(SettingField {
3557 json_path: Some("title_bar.show_sign_in"),
3558 pick: |settings_content| {
3559 settings_content.title_bar.as_ref()?.show_sign_in.as_ref()
3560 },
3561 write: |settings_content, value| {
3562 settings_content
3563 .title_bar
3564 .get_or_insert_default()
3565 .show_sign_in = value;
3566 },
3567 }),
3568 metadata: None,
3569 files: USER,
3570 }),
3571 SettingsPageItem::SettingItem(SettingItem {
3572 title: "Show User Menu",
3573 description: "Show the user menu button in the titlebar.",
3574 field: Box::new(SettingField {
3575 json_path: Some("title_bar.show_user_menu"),
3576 pick: |settings_content| {
3577 settings_content.title_bar.as_ref()?.show_user_menu.as_ref()
3578 },
3579 write: |settings_content, value| {
3580 settings_content
3581 .title_bar
3582 .get_or_insert_default()
3583 .show_user_menu = value;
3584 },
3585 }),
3586 metadata: None,
3587 files: USER,
3588 }),
3589 SettingsPageItem::SettingItem(SettingItem {
3590 title: "Show User Picture",
3591 description: "Show user picture in the titlebar.",
3592 field: Box::new(SettingField {
3593 json_path: Some("title_bar.show_user_picture"),
3594 pick: |settings_content| {
3595 settings_content
3596 .title_bar
3597 .as_ref()?
3598 .show_user_picture
3599 .as_ref()
3600 },
3601 write: |settings_content, value| {
3602 settings_content
3603 .title_bar
3604 .get_or_insert_default()
3605 .show_user_picture = value;
3606 },
3607 }),
3608 metadata: None,
3609 files: USER,
3610 }),
3611 SettingsPageItem::SettingItem(SettingItem {
3612 title: "Show Menus",
3613 description: "Show the menus in the titlebar.",
3614 field: Box::new(SettingField {
3615 json_path: Some("title_bar.show_menus"),
3616 pick: |settings_content| {
3617 settings_content.title_bar.as_ref()?.show_menus.as_ref()
3618 },
3619 write: |settings_content, value| {
3620 settings_content
3621 .title_bar
3622 .get_or_insert_default()
3623 .show_menus = value;
3624 },
3625 }),
3626 metadata: None,
3627 files: USER,
3628 }),
3629 ]
3630 }
3631
3632 fn tab_bar_section() -> [SettingsPageItem; 9] {
3633 [
3634 SettingsPageItem::SectionHeader("Tab Bar"),
3635 SettingsPageItem::SettingItem(SettingItem {
3636 title: "Show Tab Bar",
3637 description: "Show the tab bar in the editor.",
3638 field: Box::new(SettingField {
3639 json_path: Some("tab_bar.show"),
3640 pick: |settings_content| settings_content.tab_bar.as_ref()?.show.as_ref(),
3641 write: |settings_content, value| {
3642 settings_content.tab_bar.get_or_insert_default().show = value;
3643 },
3644 }),
3645 metadata: None,
3646 files: USER,
3647 }),
3648 SettingsPageItem::SettingItem(SettingItem {
3649 title: "Show Git Status In Tabs",
3650 description: "Show the Git file status on a tab item.",
3651 field: Box::new(SettingField {
3652 json_path: Some("tabs.git_status"),
3653 pick: |settings_content| settings_content.tabs.as_ref()?.git_status.as_ref(),
3654 write: |settings_content, value| {
3655 settings_content.tabs.get_or_insert_default().git_status = value;
3656 },
3657 }),
3658 metadata: None,
3659 files: USER,
3660 }),
3661 SettingsPageItem::SettingItem(SettingItem {
3662 title: "Show File Icons In Tabs",
3663 description: "Show the file icon for a tab.",
3664 field: Box::new(SettingField {
3665 json_path: Some("tabs.file_icons"),
3666 pick: |settings_content| settings_content.tabs.as_ref()?.file_icons.as_ref(),
3667 write: |settings_content, value| {
3668 settings_content.tabs.get_or_insert_default().file_icons = value;
3669 },
3670 }),
3671 metadata: None,
3672 files: USER,
3673 }),
3674 SettingsPageItem::SettingItem(SettingItem {
3675 title: "Tab Close Position",
3676 description: "Position of the close button in a tab.",
3677 field: Box::new(SettingField {
3678 json_path: Some("tabs.close_position"),
3679 pick: |settings_content| {
3680 settings_content.tabs.as_ref()?.close_position.as_ref()
3681 },
3682 write: |settings_content, value| {
3683 settings_content.tabs.get_or_insert_default().close_position = value;
3684 },
3685 }),
3686 metadata: None,
3687 files: USER,
3688 }),
3689 SettingsPageItem::SettingItem(SettingItem {
3690 files: USER,
3691 title: "Maximum Tabs",
3692 description: "Maximum open tabs in a pane. Will not close an unsaved tab.",
3693 // todo(settings_ui): The default for this value is null and it's use in code
3694 // is complex, so I'm going to come back to this later
3695 field: Box::new(
3696 SettingField {
3697 json_path: Some("max_tabs"),
3698 pick: |settings_content| settings_content.workspace.max_tabs.as_ref(),
3699 write: |settings_content, value| {
3700 settings_content.workspace.max_tabs = value;
3701 },
3702 }
3703 .unimplemented(),
3704 ),
3705 metadata: None,
3706 }),
3707 SettingsPageItem::SettingItem(SettingItem {
3708 title: "Show Navigation History Buttons",
3709 description: "Show the navigation history buttons in the tab bar.",
3710 field: Box::new(SettingField {
3711 json_path: Some("tab_bar.show_nav_history_buttons"),
3712 pick: |settings_content| {
3713 settings_content
3714 .tab_bar
3715 .as_ref()?
3716 .show_nav_history_buttons
3717 .as_ref()
3718 },
3719 write: |settings_content, value| {
3720 settings_content
3721 .tab_bar
3722 .get_or_insert_default()
3723 .show_nav_history_buttons = value;
3724 },
3725 }),
3726 metadata: None,
3727 files: USER,
3728 }),
3729 SettingsPageItem::SettingItem(SettingItem {
3730 title: "Show Tab Bar Buttons",
3731 description: "Show the tab bar buttons (New, Split Pane, Zoom).",
3732 field: Box::new(SettingField {
3733 json_path: Some("tab_bar.show_tab_bar_buttons"),
3734 pick: |settings_content| {
3735 settings_content
3736 .tab_bar
3737 .as_ref()?
3738 .show_tab_bar_buttons
3739 .as_ref()
3740 },
3741 write: |settings_content, value| {
3742 settings_content
3743 .tab_bar
3744 .get_or_insert_default()
3745 .show_tab_bar_buttons = value;
3746 },
3747 }),
3748 metadata: None,
3749 files: USER,
3750 }),
3751 SettingsPageItem::SettingItem(SettingItem {
3752 title: "Pinned Tabs Layout",
3753 description: "Show pinned tabs in a separate row above unpinned tabs.",
3754 field: Box::new(SettingField {
3755 json_path: Some("tab_bar.show_pinned_tabs_in_separate_row"),
3756 pick: |settings_content| {
3757 settings_content
3758 .tab_bar
3759 .as_ref()?
3760 .show_pinned_tabs_in_separate_row
3761 .as_ref()
3762 },
3763 write: |settings_content, value| {
3764 settings_content
3765 .tab_bar
3766 .get_or_insert_default()
3767 .show_pinned_tabs_in_separate_row = value;
3768 },
3769 }),
3770 metadata: None,
3771 files: USER,
3772 }),
3773 ]
3774 }
3775
3776 fn tab_settings_section() -> [SettingsPageItem; 4] {
3777 [
3778 SettingsPageItem::SectionHeader("Tab Settings"),
3779 SettingsPageItem::SettingItem(SettingItem {
3780 title: "Activate On Close",
3781 description: "What to do after closing the current tab.",
3782 field: Box::new(SettingField {
3783 json_path: Some("tabs.activate_on_close"),
3784 pick: |settings_content| {
3785 settings_content.tabs.as_ref()?.activate_on_close.as_ref()
3786 },
3787 write: |settings_content, value| {
3788 settings_content
3789 .tabs
3790 .get_or_insert_default()
3791 .activate_on_close = value;
3792 },
3793 }),
3794 metadata: None,
3795 files: USER,
3796 }),
3797 SettingsPageItem::SettingItem(SettingItem {
3798 title: "Tab Show Diagnostics",
3799 description: "Which files containing diagnostic errors/warnings to mark in the tabs.",
3800 field: Box::new(SettingField {
3801 json_path: Some("tabs.show_diagnostics"),
3802 pick: |settings_content| {
3803 settings_content.tabs.as_ref()?.show_diagnostics.as_ref()
3804 },
3805 write: |settings_content, value| {
3806 settings_content
3807 .tabs
3808 .get_or_insert_default()
3809 .show_diagnostics = value;
3810 },
3811 }),
3812 metadata: None,
3813 files: USER,
3814 }),
3815 SettingsPageItem::SettingItem(SettingItem {
3816 title: "Show Close Button",
3817 description: "Controls the appearance behavior of the tab's close button.",
3818 field: Box::new(SettingField {
3819 json_path: Some("tabs.show_close_button"),
3820 pick: |settings_content| {
3821 settings_content.tabs.as_ref()?.show_close_button.as_ref()
3822 },
3823 write: |settings_content, value| {
3824 settings_content
3825 .tabs
3826 .get_or_insert_default()
3827 .show_close_button = value;
3828 },
3829 }),
3830 metadata: None,
3831 files: USER,
3832 }),
3833 ]
3834 }
3835
3836 fn preview_tabs_section() -> [SettingsPageItem; 8] {
3837 [
3838 SettingsPageItem::SectionHeader("Preview Tabs"),
3839 SettingsPageItem::SettingItem(SettingItem {
3840 title: "Preview Tabs Enabled",
3841 description: "Show opened editors as preview tabs.",
3842 field: Box::new(SettingField {
3843 json_path: Some("preview_tabs.enabled"),
3844 pick: |settings_content| {
3845 settings_content.preview_tabs.as_ref()?.enabled.as_ref()
3846 },
3847 write: |settings_content, value| {
3848 settings_content
3849 .preview_tabs
3850 .get_or_insert_default()
3851 .enabled = value;
3852 },
3853 }),
3854 metadata: None,
3855 files: USER,
3856 }),
3857 SettingsPageItem::SettingItem(SettingItem {
3858 title: "Enable Preview From Project Panel",
3859 description: "Whether to open tabs in preview mode when opened from the project panel with a single click.",
3860 field: Box::new(SettingField {
3861 json_path: Some("preview_tabs.enable_preview_from_project_panel"),
3862 pick: |settings_content| {
3863 settings_content
3864 .preview_tabs
3865 .as_ref()?
3866 .enable_preview_from_project_panel
3867 .as_ref()
3868 },
3869 write: |settings_content, value| {
3870 settings_content
3871 .preview_tabs
3872 .get_or_insert_default()
3873 .enable_preview_from_project_panel = value;
3874 },
3875 }),
3876 metadata: None,
3877 files: USER,
3878 }),
3879 SettingsPageItem::SettingItem(SettingItem {
3880 title: "Enable Preview From File Finder",
3881 description: "Whether to open tabs in preview mode when selected from the file finder.",
3882 field: Box::new(SettingField {
3883 json_path: Some("preview_tabs.enable_preview_from_file_finder"),
3884 pick: |settings_content| {
3885 settings_content
3886 .preview_tabs
3887 .as_ref()?
3888 .enable_preview_from_file_finder
3889 .as_ref()
3890 },
3891 write: |settings_content, value| {
3892 settings_content
3893 .preview_tabs
3894 .get_or_insert_default()
3895 .enable_preview_from_file_finder = value;
3896 },
3897 }),
3898 metadata: None,
3899 files: USER,
3900 }),
3901 SettingsPageItem::SettingItem(SettingItem {
3902 title: "Enable Preview From Multibuffer",
3903 description: "Whether to open tabs in preview mode when opened from a multibuffer.",
3904 field: Box::new(SettingField {
3905 json_path: Some("preview_tabs.enable_preview_from_multibuffer"),
3906 pick: |settings_content| {
3907 settings_content
3908 .preview_tabs
3909 .as_ref()?
3910 .enable_preview_from_multibuffer
3911 .as_ref()
3912 },
3913 write: |settings_content, value| {
3914 settings_content
3915 .preview_tabs
3916 .get_or_insert_default()
3917 .enable_preview_from_multibuffer = value;
3918 },
3919 }),
3920 metadata: None,
3921 files: USER,
3922 }),
3923 SettingsPageItem::SettingItem(SettingItem {
3924 title: "Enable Preview Multibuffer From Code Navigation",
3925 description: "Whether to open tabs in preview mode when code navigation is used to open a multibuffer.",
3926 field: Box::new(SettingField {
3927 json_path: Some("preview_tabs.enable_preview_multibuffer_from_code_navigation"),
3928 pick: |settings_content| {
3929 settings_content
3930 .preview_tabs
3931 .as_ref()?
3932 .enable_preview_multibuffer_from_code_navigation
3933 .as_ref()
3934 },
3935 write: |settings_content, value| {
3936 settings_content
3937 .preview_tabs
3938 .get_or_insert_default()
3939 .enable_preview_multibuffer_from_code_navigation = value;
3940 },
3941 }),
3942 metadata: None,
3943 files: USER,
3944 }),
3945 SettingsPageItem::SettingItem(SettingItem {
3946 title: "Enable Preview File From Code Navigation",
3947 description: "Whether to open tabs in preview mode when code navigation is used to open a single file.",
3948 field: Box::new(SettingField {
3949 json_path: Some("preview_tabs.enable_preview_file_from_code_navigation"),
3950 pick: |settings_content| {
3951 settings_content
3952 .preview_tabs
3953 .as_ref()?
3954 .enable_preview_file_from_code_navigation
3955 .as_ref()
3956 },
3957 write: |settings_content, value| {
3958 settings_content
3959 .preview_tabs
3960 .get_or_insert_default()
3961 .enable_preview_file_from_code_navigation = value;
3962 },
3963 }),
3964 metadata: None,
3965 files: USER,
3966 }),
3967 SettingsPageItem::SettingItem(SettingItem {
3968 title: "Enable Keep Preview On Code Navigation",
3969 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.",
3970 field: Box::new(SettingField {
3971 json_path: Some("preview_tabs.enable_keep_preview_on_code_navigation"),
3972 pick: |settings_content| {
3973 settings_content
3974 .preview_tabs
3975 .as_ref()?
3976 .enable_keep_preview_on_code_navigation
3977 .as_ref()
3978 },
3979 write: |settings_content, value| {
3980 settings_content
3981 .preview_tabs
3982 .get_or_insert_default()
3983 .enable_keep_preview_on_code_navigation = value;
3984 },
3985 }),
3986 metadata: None,
3987 files: USER,
3988 }),
3989 ]
3990 }
3991
3992 fn layout_section() -> [SettingsPageItem; 4] {
3993 [
3994 SettingsPageItem::SectionHeader("Layout"),
3995 SettingsPageItem::SettingItem(SettingItem {
3996 title: "Bottom Dock Layout",
3997 description: "Layout mode for the bottom dock.",
3998 field: Box::new(SettingField {
3999 json_path: Some("bottom_dock_layout"),
4000 pick: |settings_content| settings_content.workspace.bottom_dock_layout.as_ref(),
4001 write: |settings_content, value| {
4002 settings_content.workspace.bottom_dock_layout = value;
4003 },
4004 }),
4005 metadata: None,
4006 files: USER,
4007 }),
4008 SettingsPageItem::SettingItem(SettingItem {
4009 files: USER,
4010 title: "Centered Layout Left Padding",
4011 description: "Left padding for centered layout.",
4012 field: Box::new(SettingField {
4013 json_path: Some("centered_layout.left_padding"),
4014 pick: |settings_content| {
4015 settings_content
4016 .workspace
4017 .centered_layout
4018 .as_ref()?
4019 .left_padding
4020 .as_ref()
4021 },
4022 write: |settings_content, value| {
4023 settings_content
4024 .workspace
4025 .centered_layout
4026 .get_or_insert_default()
4027 .left_padding = value;
4028 },
4029 }),
4030 metadata: None,
4031 }),
4032 SettingsPageItem::SettingItem(SettingItem {
4033 files: USER,
4034 title: "Centered Layout Right Padding",
4035 description: "Right padding for centered layout.",
4036 field: Box::new(SettingField {
4037 json_path: Some("centered_layout.right_padding"),
4038 pick: |settings_content| {
4039 settings_content
4040 .workspace
4041 .centered_layout
4042 .as_ref()?
4043 .right_padding
4044 .as_ref()
4045 },
4046 write: |settings_content, value| {
4047 settings_content
4048 .workspace
4049 .centered_layout
4050 .get_or_insert_default()
4051 .right_padding = value;
4052 },
4053 }),
4054 metadata: None,
4055 }),
4056 ]
4057 }
4058
4059 fn window_section() -> [SettingsPageItem; 3] {
4060 [
4061 SettingsPageItem::SectionHeader("Window"),
4062 // todo(settings_ui): Should we filter by platform.as_ref()?
4063 SettingsPageItem::SettingItem(SettingItem {
4064 title: "Use System Window Tabs",
4065 description: "(macOS only) whether to allow Windows to tab together.",
4066 field: Box::new(SettingField {
4067 json_path: Some("use_system_window_tabs"),
4068 pick: |settings_content| {
4069 settings_content.workspace.use_system_window_tabs.as_ref()
4070 },
4071 write: |settings_content, value| {
4072 settings_content.workspace.use_system_window_tabs = value;
4073 },
4074 }),
4075 metadata: None,
4076 files: USER,
4077 }),
4078 SettingsPageItem::SettingItem(SettingItem {
4079 title: "Window Decorations",
4080 description: "(Linux only) whether Zed or your compositor should draw window decorations.",
4081 field: Box::new(SettingField {
4082 json_path: Some("window_decorations"),
4083 pick: |settings_content| settings_content.workspace.window_decorations.as_ref(),
4084 write: |settings_content, value| {
4085 settings_content.workspace.window_decorations = value;
4086 },
4087 }),
4088 metadata: None,
4089 files: USER,
4090 }),
4091 ]
4092 }
4093
4094 fn pane_modifiers_section() -> [SettingsPageItem; 4] {
4095 [
4096 SettingsPageItem::SectionHeader("Pane Modifiers"),
4097 SettingsPageItem::SettingItem(SettingItem {
4098 title: "Inactive Opacity",
4099 description: "Opacity of inactive panels (0.0 - 1.0).",
4100 field: Box::new(SettingField {
4101 json_path: Some("active_pane_modifiers.inactive_opacity"),
4102 pick: |settings_content| {
4103 settings_content
4104 .workspace
4105 .active_pane_modifiers
4106 .as_ref()?
4107 .inactive_opacity
4108 .as_ref()
4109 },
4110 write: |settings_content, value| {
4111 settings_content
4112 .workspace
4113 .active_pane_modifiers
4114 .get_or_insert_default()
4115 .inactive_opacity = value;
4116 },
4117 }),
4118 metadata: None,
4119 files: USER,
4120 }),
4121 SettingsPageItem::SettingItem(SettingItem {
4122 title: "Border Size",
4123 description: "Size of the border surrounding the active pane.",
4124 field: Box::new(SettingField {
4125 json_path: Some("active_pane_modifiers.border_size"),
4126 pick: |settings_content| {
4127 settings_content
4128 .workspace
4129 .active_pane_modifiers
4130 .as_ref()?
4131 .border_size
4132 .as_ref()
4133 },
4134 write: |settings_content, value| {
4135 settings_content
4136 .workspace
4137 .active_pane_modifiers
4138 .get_or_insert_default()
4139 .border_size = value;
4140 },
4141 }),
4142 metadata: None,
4143 files: USER,
4144 }),
4145 SettingsPageItem::SettingItem(SettingItem {
4146 title: "Zoomed Padding",
4147 description: "Show padding for zoomed panes.",
4148 field: Box::new(SettingField {
4149 json_path: Some("zoomed_padding"),
4150 pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
4151 write: |settings_content, value| {
4152 settings_content.workspace.zoomed_padding = value;
4153 },
4154 }),
4155 metadata: None,
4156 files: USER,
4157 }),
4158 ]
4159 }
4160
4161 fn pane_split_direction_section() -> [SettingsPageItem; 3] {
4162 [
4163 SettingsPageItem::SectionHeader("Pane Split Direction"),
4164 SettingsPageItem::SettingItem(SettingItem {
4165 title: "Vertical Split Direction",
4166 description: "Direction to split vertically.",
4167 field: Box::new(SettingField {
4168 json_path: Some("pane_split_direction_vertical"),
4169 pick: |settings_content| {
4170 settings_content
4171 .workspace
4172 .pane_split_direction_vertical
4173 .as_ref()
4174 },
4175 write: |settings_content, value| {
4176 settings_content.workspace.pane_split_direction_vertical = value;
4177 },
4178 }),
4179 metadata: None,
4180 files: USER,
4181 }),
4182 SettingsPageItem::SettingItem(SettingItem {
4183 title: "Horizontal Split Direction",
4184 description: "Direction to split horizontally.",
4185 field: Box::new(SettingField {
4186 json_path: Some("pane_split_direction_horizontal"),
4187 pick: |settings_content| {
4188 settings_content
4189 .workspace
4190 .pane_split_direction_horizontal
4191 .as_ref()
4192 },
4193 write: |settings_content, value| {
4194 settings_content.workspace.pane_split_direction_horizontal = value;
4195 },
4196 }),
4197 metadata: None,
4198 files: USER,
4199 }),
4200 ]
4201 }
4202
4203 SettingsPage {
4204 title: "Window & Layout",
4205 items: concat_sections![
4206 status_bar_section(),
4207 title_bar_section(),
4208 tab_bar_section(),
4209 tab_settings_section(),
4210 preview_tabs_section(),
4211 layout_section(),
4212 window_section(),
4213 pane_modifiers_section(),
4214 pane_split_direction_section(),
4215 ],
4216 }
4217}
4218
4219fn panels_page() -> SettingsPage {
4220 fn project_panel_section() -> [SettingsPageItem; 20] {
4221 [
4222 SettingsPageItem::SectionHeader("Project Panel"),
4223 SettingsPageItem::SettingItem(SettingItem {
4224 title: "Project Panel Dock",
4225 description: "Where to dock the project panel.",
4226 field: Box::new(SettingField {
4227 json_path: Some("project_panel.dock"),
4228 pick: |settings_content| settings_content.project_panel.as_ref()?.dock.as_ref(),
4229 write: |settings_content, value| {
4230 settings_content.project_panel.get_or_insert_default().dock = value;
4231 },
4232 }),
4233 metadata: None,
4234 files: USER,
4235 }),
4236 SettingsPageItem::SettingItem(SettingItem {
4237 title: "Project Panel Default Width",
4238 description: "Default width of the project panel in pixels.",
4239 field: Box::new(SettingField {
4240 json_path: Some("project_panel.default_width"),
4241 pick: |settings_content| {
4242 settings_content
4243 .project_panel
4244 .as_ref()?
4245 .default_width
4246 .as_ref()
4247 },
4248 write: |settings_content, value| {
4249 settings_content
4250 .project_panel
4251 .get_or_insert_default()
4252 .default_width = value;
4253 },
4254 }),
4255 metadata: None,
4256 files: USER,
4257 }),
4258 SettingsPageItem::SettingItem(SettingItem {
4259 title: "Hide .gitignore",
4260 description: "Whether to hide the gitignore entries in the project panel.",
4261 field: Box::new(SettingField {
4262 json_path: Some("project_panel.hide_gitignore"),
4263 pick: |settings_content| {
4264 settings_content
4265 .project_panel
4266 .as_ref()?
4267 .hide_gitignore
4268 .as_ref()
4269 },
4270 write: |settings_content, value| {
4271 settings_content
4272 .project_panel
4273 .get_or_insert_default()
4274 .hide_gitignore = value;
4275 },
4276 }),
4277 metadata: None,
4278 files: USER,
4279 }),
4280 SettingsPageItem::SettingItem(SettingItem {
4281 title: "Entry Spacing",
4282 description: "Spacing between worktree entries in the project panel.",
4283 field: Box::new(SettingField {
4284 json_path: Some("project_panel.entry_spacing"),
4285 pick: |settings_content| {
4286 settings_content
4287 .project_panel
4288 .as_ref()?
4289 .entry_spacing
4290 .as_ref()
4291 },
4292 write: |settings_content, value| {
4293 settings_content
4294 .project_panel
4295 .get_or_insert_default()
4296 .entry_spacing = value;
4297 },
4298 }),
4299 metadata: None,
4300 files: USER,
4301 }),
4302 SettingsPageItem::SettingItem(SettingItem {
4303 title: "File Icons",
4304 description: "Show file icons in the project panel.",
4305 field: Box::new(SettingField {
4306 json_path: Some("project_panel.file_icons"),
4307 pick: |settings_content| {
4308 settings_content.project_panel.as_ref()?.file_icons.as_ref()
4309 },
4310 write: |settings_content, value| {
4311 settings_content
4312 .project_panel
4313 .get_or_insert_default()
4314 .file_icons = value;
4315 },
4316 }),
4317 metadata: None,
4318 files: USER,
4319 }),
4320 SettingsPageItem::SettingItem(SettingItem {
4321 title: "Folder Icons",
4322 description: "Whether to show folder icons or chevrons for directories in the project panel.",
4323 field: Box::new(SettingField {
4324 json_path: Some("project_panel.folder_icons"),
4325 pick: |settings_content| {
4326 settings_content
4327 .project_panel
4328 .as_ref()?
4329 .folder_icons
4330 .as_ref()
4331 },
4332 write: |settings_content, value| {
4333 settings_content
4334 .project_panel
4335 .get_or_insert_default()
4336 .folder_icons = value;
4337 },
4338 }),
4339 metadata: None,
4340 files: USER,
4341 }),
4342 SettingsPageItem::SettingItem(SettingItem {
4343 title: "Git Status",
4344 description: "Show the Git status in the project panel.",
4345 field: Box::new(SettingField {
4346 json_path: Some("project_panel.git_status"),
4347 pick: |settings_content| {
4348 settings_content.project_panel.as_ref()?.git_status.as_ref()
4349 },
4350 write: |settings_content, value| {
4351 settings_content
4352 .project_panel
4353 .get_or_insert_default()
4354 .git_status = value;
4355 },
4356 }),
4357 metadata: None,
4358 files: USER,
4359 }),
4360 SettingsPageItem::SettingItem(SettingItem {
4361 title: "Indent Size",
4362 description: "Amount of indentation for nested items.",
4363 field: Box::new(SettingField {
4364 json_path: Some("project_panel.indent_size"),
4365 pick: |settings_content| {
4366 settings_content
4367 .project_panel
4368 .as_ref()?
4369 .indent_size
4370 .as_ref()
4371 },
4372 write: |settings_content, value| {
4373 settings_content
4374 .project_panel
4375 .get_or_insert_default()
4376 .indent_size = value;
4377 },
4378 }),
4379 metadata: None,
4380 files: USER,
4381 }),
4382 SettingsPageItem::SettingItem(SettingItem {
4383 title: "Auto Reveal Entries",
4384 description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
4385 field: Box::new(SettingField {
4386 json_path: Some("project_panel.auto_reveal_entries"),
4387 pick: |settings_content| {
4388 settings_content
4389 .project_panel
4390 .as_ref()?
4391 .auto_reveal_entries
4392 .as_ref()
4393 },
4394 write: |settings_content, value| {
4395 settings_content
4396 .project_panel
4397 .get_or_insert_default()
4398 .auto_reveal_entries = value;
4399 },
4400 }),
4401 metadata: None,
4402 files: USER,
4403 }),
4404 SettingsPageItem::SettingItem(SettingItem {
4405 title: "Starts Open",
4406 description: "Whether the project panel should open on startup.",
4407 field: Box::new(SettingField {
4408 json_path: Some("project_panel.starts_open"),
4409 pick: |settings_content| {
4410 settings_content
4411 .project_panel
4412 .as_ref()?
4413 .starts_open
4414 .as_ref()
4415 },
4416 write: |settings_content, value| {
4417 settings_content
4418 .project_panel
4419 .get_or_insert_default()
4420 .starts_open = value;
4421 },
4422 }),
4423 metadata: None,
4424 files: USER,
4425 }),
4426 SettingsPageItem::SettingItem(SettingItem {
4427 title: "Auto Fold Directories",
4428 description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
4429 field: Box::new(SettingField {
4430 json_path: Some("project_panel.auto_fold_dirs"),
4431 pick: |settings_content| {
4432 settings_content
4433 .project_panel
4434 .as_ref()?
4435 .auto_fold_dirs
4436 .as_ref()
4437 },
4438 write: |settings_content, value| {
4439 settings_content
4440 .project_panel
4441 .get_or_insert_default()
4442 .auto_fold_dirs = value;
4443 },
4444 }),
4445 metadata: None,
4446 files: USER,
4447 }),
4448 SettingsPageItem::SettingItem(SettingItem {
4449 title: "Show Scrollbar",
4450 description: "Show the scrollbar in the project panel.",
4451 field: Box::new(SettingField {
4452 json_path: Some("project_panel.scrollbar.show"),
4453 pick: |settings_content| {
4454 show_scrollbar_or_editor(settings_content, |settings_content| {
4455 settings_content
4456 .project_panel
4457 .as_ref()?
4458 .scrollbar
4459 .as_ref()?
4460 .show
4461 .as_ref()
4462 })
4463 },
4464 write: |settings_content, value| {
4465 settings_content
4466 .project_panel
4467 .get_or_insert_default()
4468 .scrollbar
4469 .get_or_insert_default()
4470 .show = value;
4471 },
4472 }),
4473 metadata: None,
4474 files: USER,
4475 }),
4476 SettingsPageItem::SettingItem(SettingItem {
4477 title: "Show Diagnostics",
4478 description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
4479 field: Box::new(SettingField {
4480 json_path: Some("project_panel.show_diagnostics"),
4481 pick: |settings_content| {
4482 settings_content
4483 .project_panel
4484 .as_ref()?
4485 .show_diagnostics
4486 .as_ref()
4487 },
4488 write: |settings_content, value| {
4489 settings_content
4490 .project_panel
4491 .get_or_insert_default()
4492 .show_diagnostics = value;
4493 },
4494 }),
4495 metadata: None,
4496 files: USER,
4497 }),
4498 SettingsPageItem::SettingItem(SettingItem {
4499 title: "Sticky Scroll",
4500 description: "Whether to stick parent directories at top of the project panel.",
4501 field: Box::new(SettingField {
4502 json_path: Some("project_panel.sticky_scroll"),
4503 pick: |settings_content| {
4504 settings_content
4505 .project_panel
4506 .as_ref()?
4507 .sticky_scroll
4508 .as_ref()
4509 },
4510 write: |settings_content, value| {
4511 settings_content
4512 .project_panel
4513 .get_or_insert_default()
4514 .sticky_scroll = value;
4515 },
4516 }),
4517 metadata: None,
4518 files: USER,
4519 }),
4520 SettingsPageItem::SettingItem(SettingItem {
4521 files: USER,
4522 title: "Show Indent Guides",
4523 description: "Show indent guides in the project panel.",
4524 field: Box::new(SettingField {
4525 json_path: Some("project_panel.indent_guides.show"),
4526 pick: |settings_content| {
4527 settings_content
4528 .project_panel
4529 .as_ref()?
4530 .indent_guides
4531 .as_ref()?
4532 .show
4533 .as_ref()
4534 },
4535 write: |settings_content, value| {
4536 settings_content
4537 .project_panel
4538 .get_or_insert_default()
4539 .indent_guides
4540 .get_or_insert_default()
4541 .show = value;
4542 },
4543 }),
4544 metadata: None,
4545 }),
4546 SettingsPageItem::SettingItem(SettingItem {
4547 title: "Drag and Drop",
4548 description: "Whether to enable drag-and-drop operations in the project panel.",
4549 field: Box::new(SettingField {
4550 json_path: Some("project_panel.drag_and_drop"),
4551 pick: |settings_content| {
4552 settings_content
4553 .project_panel
4554 .as_ref()?
4555 .drag_and_drop
4556 .as_ref()
4557 },
4558 write: |settings_content, value| {
4559 settings_content
4560 .project_panel
4561 .get_or_insert_default()
4562 .drag_and_drop = value;
4563 },
4564 }),
4565 metadata: None,
4566 files: USER,
4567 }),
4568 SettingsPageItem::SettingItem(SettingItem {
4569 title: "Hide Root",
4570 description: "Whether to hide the root entry when only one folder is open in the window.",
4571 field: Box::new(SettingField {
4572 json_path: Some("project_panel.drag_and_drop"),
4573 pick: |settings_content| {
4574 settings_content.project_panel.as_ref()?.hide_root.as_ref()
4575 },
4576 write: |settings_content, value| {
4577 settings_content
4578 .project_panel
4579 .get_or_insert_default()
4580 .hide_root = value;
4581 },
4582 }),
4583 metadata: None,
4584 files: USER,
4585 }),
4586 SettingsPageItem::SettingItem(SettingItem {
4587 title: "Hide Hidden",
4588 description: "Whether to hide the hidden entries in the project panel.",
4589 field: Box::new(SettingField {
4590 json_path: Some("project_panel.hide_hidden"),
4591 pick: |settings_content| {
4592 settings_content
4593 .project_panel
4594 .as_ref()?
4595 .hide_hidden
4596 .as_ref()
4597 },
4598 write: |settings_content, value| {
4599 settings_content
4600 .project_panel
4601 .get_or_insert_default()
4602 .hide_hidden = value;
4603 },
4604 }),
4605 metadata: None,
4606 files: USER,
4607 }),
4608 SettingsPageItem::SettingItem(SettingItem {
4609 title: "Hidden Files",
4610 description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
4611 field: Box::new(
4612 SettingField {
4613 json_path: Some("worktree.hidden_files"),
4614 pick: |settings_content| {
4615 settings_content.project.worktree.hidden_files.as_ref()
4616 },
4617 write: |settings_content, value| {
4618 settings_content.project.worktree.hidden_files = value;
4619 },
4620 }
4621 .unimplemented(),
4622 ),
4623 metadata: None,
4624 files: USER,
4625 }),
4626 ]
4627 }
4628
4629 fn auto_open_files_section() -> [SettingsPageItem; 5] {
4630 [
4631 SettingsPageItem::SectionHeader("Auto Open Files"),
4632 SettingsPageItem::SettingItem(SettingItem {
4633 title: "On Create",
4634 description: "Whether to automatically open newly created files in the editor.",
4635 field: Box::new(SettingField {
4636 json_path: Some("project_panel.auto_open.on_create"),
4637 pick: |settings_content| {
4638 settings_content
4639 .project_panel
4640 .as_ref()?
4641 .auto_open
4642 .as_ref()?
4643 .on_create
4644 .as_ref()
4645 },
4646 write: |settings_content, value| {
4647 settings_content
4648 .project_panel
4649 .get_or_insert_default()
4650 .auto_open
4651 .get_or_insert_default()
4652 .on_create = value;
4653 },
4654 }),
4655 metadata: None,
4656 files: USER,
4657 }),
4658 SettingsPageItem::SettingItem(SettingItem {
4659 title: "On Paste",
4660 description: "Whether to automatically open files after pasting or duplicating them.",
4661 field: Box::new(SettingField {
4662 json_path: Some("project_panel.auto_open.on_paste"),
4663 pick: |settings_content| {
4664 settings_content
4665 .project_panel
4666 .as_ref()?
4667 .auto_open
4668 .as_ref()?
4669 .on_paste
4670 .as_ref()
4671 },
4672 write: |settings_content, value| {
4673 settings_content
4674 .project_panel
4675 .get_or_insert_default()
4676 .auto_open
4677 .get_or_insert_default()
4678 .on_paste = value;
4679 },
4680 }),
4681 metadata: None,
4682 files: USER,
4683 }),
4684 SettingsPageItem::SettingItem(SettingItem {
4685 title: "On Drop",
4686 description: "Whether to automatically open files dropped from external sources.",
4687 field: Box::new(SettingField {
4688 json_path: Some("project_panel.auto_open.on_drop"),
4689 pick: |settings_content| {
4690 settings_content
4691 .project_panel
4692 .as_ref()?
4693 .auto_open
4694 .as_ref()?
4695 .on_drop
4696 .as_ref()
4697 },
4698 write: |settings_content, value| {
4699 settings_content
4700 .project_panel
4701 .get_or_insert_default()
4702 .auto_open
4703 .get_or_insert_default()
4704 .on_drop = value;
4705 },
4706 }),
4707 metadata: None,
4708 files: USER,
4709 }),
4710 SettingsPageItem::SettingItem(SettingItem {
4711 title: "Sort Mode",
4712 description: "Sort order for entries in the project panel.",
4713 field: Box::new(SettingField {
4714 pick: |settings_content| {
4715 settings_content.project_panel.as_ref()?.sort_mode.as_ref()
4716 },
4717 write: |settings_content, value| {
4718 settings_content
4719 .project_panel
4720 .get_or_insert_default()
4721 .sort_mode = value;
4722 },
4723 json_path: Some("project_panel.sort_mode"),
4724 }),
4725 metadata: None,
4726 files: USER,
4727 }),
4728 ]
4729 }
4730
4731 fn terminal_panel_section() -> [SettingsPageItem; 2] {
4732 [
4733 SettingsPageItem::SectionHeader("Terminal Panel"),
4734 SettingsPageItem::SettingItem(SettingItem {
4735 title: "Terminal Dock",
4736 description: "Where to dock the terminal panel.",
4737 field: Box::new(SettingField {
4738 json_path: Some("terminal.dock"),
4739 pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
4740 write: |settings_content, value| {
4741 settings_content.terminal.get_or_insert_default().dock = value;
4742 },
4743 }),
4744 metadata: None,
4745 files: USER,
4746 }),
4747 ]
4748 }
4749
4750 fn outline_panel_section() -> [SettingsPageItem; 11] {
4751 [
4752 SettingsPageItem::SectionHeader("Outline Panel"),
4753 SettingsPageItem::SettingItem(SettingItem {
4754 title: "Outline Panel Button",
4755 description: "Show the outline panel button in the status bar.",
4756 field: Box::new(SettingField {
4757 json_path: Some("outline_panel.button"),
4758 pick: |settings_content| {
4759 settings_content.outline_panel.as_ref()?.button.as_ref()
4760 },
4761 write: |settings_content, value| {
4762 settings_content
4763 .outline_panel
4764 .get_or_insert_default()
4765 .button = value;
4766 },
4767 }),
4768 metadata: None,
4769 files: USER,
4770 }),
4771 SettingsPageItem::SettingItem(SettingItem {
4772 title: "Outline Panel Dock",
4773 description: "Where to dock the outline panel.",
4774 field: Box::new(SettingField {
4775 json_path: Some("outline_panel.dock"),
4776 pick: |settings_content| settings_content.outline_panel.as_ref()?.dock.as_ref(),
4777 write: |settings_content, value| {
4778 settings_content.outline_panel.get_or_insert_default().dock = value;
4779 },
4780 }),
4781 metadata: None,
4782 files: USER,
4783 }),
4784 SettingsPageItem::SettingItem(SettingItem {
4785 title: "Outline Panel Default Width",
4786 description: "Default width of the outline panel in pixels.",
4787 field: Box::new(SettingField {
4788 json_path: Some("outline_panel.default_width"),
4789 pick: |settings_content| {
4790 settings_content
4791 .outline_panel
4792 .as_ref()?
4793 .default_width
4794 .as_ref()
4795 },
4796 write: |settings_content, value| {
4797 settings_content
4798 .outline_panel
4799 .get_or_insert_default()
4800 .default_width = value;
4801 },
4802 }),
4803 metadata: None,
4804 files: USER,
4805 }),
4806 SettingsPageItem::SettingItem(SettingItem {
4807 title: "File Icons",
4808 description: "Show file icons in the outline panel.",
4809 field: Box::new(SettingField {
4810 json_path: Some("outline_panel.file_icons"),
4811 pick: |settings_content| {
4812 settings_content.outline_panel.as_ref()?.file_icons.as_ref()
4813 },
4814 write: |settings_content, value| {
4815 settings_content
4816 .outline_panel
4817 .get_or_insert_default()
4818 .file_icons = value;
4819 },
4820 }),
4821 metadata: None,
4822 files: USER,
4823 }),
4824 SettingsPageItem::SettingItem(SettingItem {
4825 title: "Folder Icons",
4826 description: "Whether to show folder icons or chevrons for directories in the outline panel.",
4827 field: Box::new(SettingField {
4828 json_path: Some("outline_panel.folder_icons"),
4829 pick: |settings_content| {
4830 settings_content
4831 .outline_panel
4832 .as_ref()?
4833 .folder_icons
4834 .as_ref()
4835 },
4836 write: |settings_content, value| {
4837 settings_content
4838 .outline_panel
4839 .get_or_insert_default()
4840 .folder_icons = value;
4841 },
4842 }),
4843 metadata: None,
4844 files: USER,
4845 }),
4846 SettingsPageItem::SettingItem(SettingItem {
4847 title: "Git Status",
4848 description: "Show the Git status in the outline panel.",
4849 field: Box::new(SettingField {
4850 json_path: Some("outline_panel.git_status"),
4851 pick: |settings_content| {
4852 settings_content.outline_panel.as_ref()?.git_status.as_ref()
4853 },
4854 write: |settings_content, value| {
4855 settings_content
4856 .outline_panel
4857 .get_or_insert_default()
4858 .git_status = value;
4859 },
4860 }),
4861 metadata: None,
4862 files: USER,
4863 }),
4864 SettingsPageItem::SettingItem(SettingItem {
4865 title: "Indent Size",
4866 description: "Amount of indentation for nested items.",
4867 field: Box::new(SettingField {
4868 json_path: Some("outline_panel.indent_size"),
4869 pick: |settings_content| {
4870 settings_content
4871 .outline_panel
4872 .as_ref()?
4873 .indent_size
4874 .as_ref()
4875 },
4876 write: |settings_content, value| {
4877 settings_content
4878 .outline_panel
4879 .get_or_insert_default()
4880 .indent_size = value;
4881 },
4882 }),
4883 metadata: None,
4884 files: USER,
4885 }),
4886 SettingsPageItem::SettingItem(SettingItem {
4887 title: "Auto Reveal Entries",
4888 description: "Whether to reveal when a corresponding outline entry becomes active.",
4889 field: Box::new(SettingField {
4890 json_path: Some("outline_panel.auto_reveal_entries"),
4891 pick: |settings_content| {
4892 settings_content
4893 .outline_panel
4894 .as_ref()?
4895 .auto_reveal_entries
4896 .as_ref()
4897 },
4898 write: |settings_content, value| {
4899 settings_content
4900 .outline_panel
4901 .get_or_insert_default()
4902 .auto_reveal_entries = value;
4903 },
4904 }),
4905 metadata: None,
4906 files: USER,
4907 }),
4908 SettingsPageItem::SettingItem(SettingItem {
4909 title: "Auto Fold Directories",
4910 description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
4911 field: Box::new(SettingField {
4912 json_path: Some("outline_panel.auto_fold_dirs"),
4913 pick: |settings_content| {
4914 settings_content
4915 .outline_panel
4916 .as_ref()?
4917 .auto_fold_dirs
4918 .as_ref()
4919 },
4920 write: |settings_content, value| {
4921 settings_content
4922 .outline_panel
4923 .get_or_insert_default()
4924 .auto_fold_dirs = value;
4925 },
4926 }),
4927 metadata: None,
4928 files: USER,
4929 }),
4930 SettingsPageItem::SettingItem(SettingItem {
4931 files: USER,
4932 title: "Show Indent Guides",
4933 description: "When to show indent guides in the outline panel.",
4934 field: Box::new(SettingField {
4935 json_path: Some("outline_panel.indent_guides.show"),
4936 pick: |settings_content| {
4937 settings_content
4938 .outline_panel
4939 .as_ref()?
4940 .indent_guides
4941 .as_ref()?
4942 .show
4943 .as_ref()
4944 },
4945 write: |settings_content, value| {
4946 settings_content
4947 .outline_panel
4948 .get_or_insert_default()
4949 .indent_guides
4950 .get_or_insert_default()
4951 .show = value;
4952 },
4953 }),
4954 metadata: None,
4955 }),
4956 ]
4957 }
4958
4959 fn git_panel_section() -> [SettingsPageItem; 10] {
4960 [
4961 SettingsPageItem::SectionHeader("Git Panel"),
4962 SettingsPageItem::SettingItem(SettingItem {
4963 title: "Git Panel Button",
4964 description: "Show the Git panel button in the status bar.",
4965 field: Box::new(SettingField {
4966 json_path: Some("git_panel.button"),
4967 pick: |settings_content| settings_content.git_panel.as_ref()?.button.as_ref(),
4968 write: |settings_content, value| {
4969 settings_content.git_panel.get_or_insert_default().button = value;
4970 },
4971 }),
4972 metadata: None,
4973 files: USER,
4974 }),
4975 SettingsPageItem::SettingItem(SettingItem {
4976 title: "Git Panel Dock",
4977 description: "Where to dock the Git panel.",
4978 field: Box::new(SettingField {
4979 json_path: Some("git_panel.dock"),
4980 pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
4981 write: |settings_content, value| {
4982 settings_content.git_panel.get_or_insert_default().dock = value;
4983 },
4984 }),
4985 metadata: None,
4986 files: USER,
4987 }),
4988 SettingsPageItem::SettingItem(SettingItem {
4989 title: "Git Panel Default Width",
4990 description: "Default width of the Git panel in pixels.",
4991 field: Box::new(SettingField {
4992 json_path: Some("git_panel.default_width"),
4993 pick: |settings_content| {
4994 settings_content.git_panel.as_ref()?.default_width.as_ref()
4995 },
4996 write: |settings_content, value| {
4997 settings_content
4998 .git_panel
4999 .get_or_insert_default()
5000 .default_width = value;
5001 },
5002 }),
5003 metadata: None,
5004 files: USER,
5005 }),
5006 SettingsPageItem::SettingItem(SettingItem {
5007 title: "Git Panel Status Style",
5008 description: "How entry statuses are displayed.",
5009 field: Box::new(SettingField {
5010 json_path: Some("git_panel.status_style"),
5011 pick: |settings_content| {
5012 settings_content.git_panel.as_ref()?.status_style.as_ref()
5013 },
5014 write: |settings_content, value| {
5015 settings_content
5016 .git_panel
5017 .get_or_insert_default()
5018 .status_style = value;
5019 },
5020 }),
5021 metadata: None,
5022 files: USER,
5023 }),
5024 SettingsPageItem::SettingItem(SettingItem {
5025 title: "Fallback Branch Name",
5026 description: "Default branch name will be when init.defaultbranch is not set in Git.",
5027 field: Box::new(SettingField {
5028 json_path: Some("git_panel.fallback_branch_name"),
5029 pick: |settings_content| {
5030 settings_content
5031 .git_panel
5032 .as_ref()?
5033 .fallback_branch_name
5034 .as_ref()
5035 },
5036 write: |settings_content, value| {
5037 settings_content
5038 .git_panel
5039 .get_or_insert_default()
5040 .fallback_branch_name = value;
5041 },
5042 }),
5043 metadata: None,
5044 files: USER,
5045 }),
5046 SettingsPageItem::SettingItem(SettingItem {
5047 title: "Sort By Path",
5048 description: "Enable to sort entries in the panel by path, disable to sort by status.",
5049 field: Box::new(SettingField {
5050 json_path: Some("git_panel.sort_by_path"),
5051 pick: |settings_content| {
5052 settings_content.git_panel.as_ref()?.sort_by_path.as_ref()
5053 },
5054 write: |settings_content, value| {
5055 settings_content
5056 .git_panel
5057 .get_or_insert_default()
5058 .sort_by_path = value;
5059 },
5060 }),
5061 metadata: None,
5062 files: USER,
5063 }),
5064 SettingsPageItem::SettingItem(SettingItem {
5065 title: "Collapse Untracked Diff",
5066 description: "Whether to collapse untracked files in the diff panel.",
5067 field: Box::new(SettingField {
5068 json_path: Some("git_panel.collapse_untracked_diff"),
5069 pick: |settings_content| {
5070 settings_content
5071 .git_panel
5072 .as_ref()?
5073 .collapse_untracked_diff
5074 .as_ref()
5075 },
5076 write: |settings_content, value| {
5077 settings_content
5078 .git_panel
5079 .get_or_insert_default()
5080 .collapse_untracked_diff = value;
5081 },
5082 }),
5083 metadata: None,
5084 files: USER,
5085 }),
5086 SettingsPageItem::SettingItem(SettingItem {
5087 title: "Tree View",
5088 description: "Enable to show entries in tree view list, disable to show in flat view list.",
5089 field: Box::new(SettingField {
5090 json_path: Some("git_panel.tree_view"),
5091 pick: |settings_content| {
5092 settings_content.git_panel.as_ref()?.tree_view.as_ref()
5093 },
5094 write: |settings_content, value| {
5095 settings_content.git_panel.get_or_insert_default().tree_view = value;
5096 },
5097 }),
5098 metadata: None,
5099 files: USER,
5100 }),
5101 SettingsPageItem::SettingItem(SettingItem {
5102 title: "Scroll Bar",
5103 description: "How and when the scrollbar should be displayed.",
5104 field: Box::new(SettingField {
5105 json_path: Some("git_panel.scrollbar.show"),
5106 pick: |settings_content| {
5107 show_scrollbar_or_editor(settings_content, |settings_content| {
5108 settings_content
5109 .git_panel
5110 .as_ref()?
5111 .scrollbar
5112 .as_ref()?
5113 .show
5114 .as_ref()
5115 })
5116 },
5117 write: |settings_content, value| {
5118 settings_content
5119 .git_panel
5120 .get_or_insert_default()
5121 .scrollbar
5122 .get_or_insert_default()
5123 .show = value;
5124 },
5125 }),
5126 metadata: None,
5127 files: USER,
5128 }),
5129 ]
5130 }
5131
5132 fn debugger_panel_section() -> [SettingsPageItem; 2] {
5133 [
5134 SettingsPageItem::SectionHeader("Debugger Panel"),
5135 SettingsPageItem::SettingItem(SettingItem {
5136 title: "Debugger Panel Dock",
5137 description: "The dock position of the debug panel.",
5138 field: Box::new(SettingField {
5139 json_path: Some("debugger.dock"),
5140 pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
5141 write: |settings_content, value| {
5142 settings_content.debugger.get_or_insert_default().dock = value;
5143 },
5144 }),
5145 metadata: None,
5146 files: USER,
5147 }),
5148 ]
5149 }
5150
5151 fn notification_panel_section() -> [SettingsPageItem; 4] {
5152 [
5153 SettingsPageItem::SectionHeader("Notification Panel"),
5154 SettingsPageItem::SettingItem(SettingItem {
5155 title: "Notification Panel Button",
5156 description: "Show the notification panel button in the status bar.",
5157 field: Box::new(SettingField {
5158 json_path: Some("notification_panel.button"),
5159 pick: |settings_content| {
5160 settings_content
5161 .notification_panel
5162 .as_ref()?
5163 .button
5164 .as_ref()
5165 },
5166 write: |settings_content, value| {
5167 settings_content
5168 .notification_panel
5169 .get_or_insert_default()
5170 .button = value;
5171 },
5172 }),
5173 metadata: None,
5174 files: USER,
5175 }),
5176 SettingsPageItem::SettingItem(SettingItem {
5177 title: "Notification Panel Dock",
5178 description: "Where to dock the notification panel.",
5179 field: Box::new(SettingField {
5180 json_path: Some("notification_panel.dock"),
5181 pick: |settings_content| {
5182 settings_content.notification_panel.as_ref()?.dock.as_ref()
5183 },
5184 write: |settings_content, value| {
5185 settings_content
5186 .notification_panel
5187 .get_or_insert_default()
5188 .dock = value;
5189 },
5190 }),
5191 metadata: None,
5192 files: USER,
5193 }),
5194 SettingsPageItem::SettingItem(SettingItem {
5195 title: "Notification Panel Default Width",
5196 description: "Default width of the notification panel in pixels.",
5197 field: Box::new(SettingField {
5198 json_path: Some("notification_panel.default_width"),
5199 pick: |settings_content| {
5200 settings_content
5201 .notification_panel
5202 .as_ref()?
5203 .default_width
5204 .as_ref()
5205 },
5206 write: |settings_content, value| {
5207 settings_content
5208 .notification_panel
5209 .get_or_insert_default()
5210 .default_width = value;
5211 },
5212 }),
5213 metadata: None,
5214 files: USER,
5215 }),
5216 ]
5217 }
5218
5219 fn collaboration_panel_section() -> [SettingsPageItem; 4] {
5220 [
5221 SettingsPageItem::SectionHeader("Collaboration Panel"),
5222 SettingsPageItem::SettingItem(SettingItem {
5223 title: "Collaboration Panel Button",
5224 description: "Show the collaboration panel button in the status bar.",
5225 field: Box::new(SettingField {
5226 json_path: Some("collaboration_panel.button"),
5227 pick: |settings_content| {
5228 settings_content
5229 .collaboration_panel
5230 .as_ref()?
5231 .button
5232 .as_ref()
5233 },
5234 write: |settings_content, value| {
5235 settings_content
5236 .collaboration_panel
5237 .get_or_insert_default()
5238 .button = value;
5239 },
5240 }),
5241 metadata: None,
5242 files: USER,
5243 }),
5244 SettingsPageItem::SettingItem(SettingItem {
5245 title: "Collaboration Panel Dock",
5246 description: "Where to dock the collaboration panel.",
5247 field: Box::new(SettingField {
5248 json_path: Some("collaboration_panel.dock"),
5249 pick: |settings_content| {
5250 settings_content.collaboration_panel.as_ref()?.dock.as_ref()
5251 },
5252 write: |settings_content, value| {
5253 settings_content
5254 .collaboration_panel
5255 .get_or_insert_default()
5256 .dock = value;
5257 },
5258 }),
5259 metadata: None,
5260 files: USER,
5261 }),
5262 SettingsPageItem::SettingItem(SettingItem {
5263 title: "Collaboration Panel Default Width",
5264 description: "Default width of the collaboration panel in pixels.",
5265 field: Box::new(SettingField {
5266 json_path: Some("collaboration_panel.dock"),
5267 pick: |settings_content| {
5268 settings_content
5269 .collaboration_panel
5270 .as_ref()?
5271 .default_width
5272 .as_ref()
5273 },
5274 write: |settings_content, value| {
5275 settings_content
5276 .collaboration_panel
5277 .get_or_insert_default()
5278 .default_width = value;
5279 },
5280 }),
5281 metadata: None,
5282 files: USER,
5283 }),
5284 ]
5285 }
5286
5287 fn agent_panel_section() -> [SettingsPageItem; 5] {
5288 [
5289 SettingsPageItem::SectionHeader("Agent Panel"),
5290 SettingsPageItem::SettingItem(SettingItem {
5291 title: "Agent Panel Button",
5292 description: "Whether to show the agent panel button in the status bar.",
5293 field: Box::new(SettingField {
5294 json_path: Some("agent.button"),
5295 pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
5296 write: |settings_content, value| {
5297 settings_content.agent.get_or_insert_default().button = value;
5298 },
5299 }),
5300 metadata: None,
5301 files: USER,
5302 }),
5303 SettingsPageItem::SettingItem(SettingItem {
5304 title: "Agent Panel Dock",
5305 description: "Where to dock the agent panel.",
5306 field: Box::new(SettingField {
5307 json_path: Some("agent.dock"),
5308 pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
5309 write: |settings_content, value| {
5310 settings_content.agent.get_or_insert_default().dock = value;
5311 },
5312 }),
5313 metadata: None,
5314 files: USER,
5315 }),
5316 SettingsPageItem::SettingItem(SettingItem {
5317 title: "Agent Panel Default Width",
5318 description: "Default width when the agent panel is docked to the left or right.",
5319 field: Box::new(SettingField {
5320 json_path: Some("agent.default_width"),
5321 pick: |settings_content| {
5322 settings_content.agent.as_ref()?.default_width.as_ref()
5323 },
5324 write: |settings_content, value| {
5325 settings_content.agent.get_or_insert_default().default_width = value;
5326 },
5327 }),
5328 metadata: None,
5329 files: USER,
5330 }),
5331 SettingsPageItem::SettingItem(SettingItem {
5332 title: "Agent Panel Default Height",
5333 description: "Default height when the agent panel is docked to the bottom.",
5334 field: Box::new(SettingField {
5335 json_path: Some("agent.default_height"),
5336 pick: |settings_content| {
5337 settings_content.agent.as_ref()?.default_height.as_ref()
5338 },
5339 write: |settings_content, value| {
5340 settings_content
5341 .agent
5342 .get_or_insert_default()
5343 .default_height = value;
5344 },
5345 }),
5346 metadata: None,
5347 files: USER,
5348 }),
5349 ]
5350 }
5351
5352 SettingsPage {
5353 title: "Panels",
5354 items: concat_sections![
5355 project_panel_section(),
5356 auto_open_files_section(),
5357 terminal_panel_section(),
5358 outline_panel_section(),
5359 git_panel_section(),
5360 debugger_panel_section(),
5361 notification_panel_section(),
5362 collaboration_panel_section(),
5363 agent_panel_section(),
5364 ],
5365 }
5366}
5367
5368fn debugger_page() -> SettingsPage {
5369 fn general_section() -> [SettingsPageItem; 6] {
5370 [
5371 SettingsPageItem::SectionHeader("General"),
5372 SettingsPageItem::SettingItem(SettingItem {
5373 title: "Stepping Granularity",
5374 description: "Determines the stepping granularity for debug operations.",
5375 field: Box::new(SettingField {
5376 json_path: Some("debugger.stepping_granularity"),
5377 pick: |settings_content| {
5378 settings_content
5379 .debugger
5380 .as_ref()?
5381 .stepping_granularity
5382 .as_ref()
5383 },
5384 write: |settings_content, value| {
5385 settings_content
5386 .debugger
5387 .get_or_insert_default()
5388 .stepping_granularity = value;
5389 },
5390 }),
5391 metadata: None,
5392 files: USER,
5393 }),
5394 SettingsPageItem::SettingItem(SettingItem {
5395 title: "Save Breakpoints",
5396 description: "Whether breakpoints should be reused across Zed sessions.",
5397 field: Box::new(SettingField {
5398 json_path: Some("debugger.save_breakpoints"),
5399 pick: |settings_content| {
5400 settings_content
5401 .debugger
5402 .as_ref()?
5403 .save_breakpoints
5404 .as_ref()
5405 },
5406 write: |settings_content, value| {
5407 settings_content
5408 .debugger
5409 .get_or_insert_default()
5410 .save_breakpoints = value;
5411 },
5412 }),
5413 metadata: None,
5414 files: USER,
5415 }),
5416 SettingsPageItem::SettingItem(SettingItem {
5417 title: "Timeout",
5418 description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
5419 field: Box::new(SettingField {
5420 json_path: Some("debugger.timeout"),
5421 pick: |settings_content| settings_content.debugger.as_ref()?.timeout.as_ref(),
5422 write: |settings_content, value| {
5423 settings_content.debugger.get_or_insert_default().timeout = value;
5424 },
5425 }),
5426 metadata: None,
5427 files: USER,
5428 }),
5429 SettingsPageItem::SettingItem(SettingItem {
5430 title: "Log DAP Communications",
5431 description: "Whether to log messages between active debug adapters and Zed.",
5432 field: Box::new(SettingField {
5433 json_path: Some("debugger.log_dap_communications"),
5434 pick: |settings_content| {
5435 settings_content
5436 .debugger
5437 .as_ref()?
5438 .log_dap_communications
5439 .as_ref()
5440 },
5441 write: |settings_content, value| {
5442 settings_content
5443 .debugger
5444 .get_or_insert_default()
5445 .log_dap_communications = value;
5446 },
5447 }),
5448 metadata: None,
5449 files: USER,
5450 }),
5451 SettingsPageItem::SettingItem(SettingItem {
5452 title: "Format DAP Log Messages",
5453 description: "Whether to format DAP messages when adding them to debug adapter logger.",
5454 field: Box::new(SettingField {
5455 json_path: Some("debugger.format_dap_log_messages"),
5456 pick: |settings_content| {
5457 settings_content
5458 .debugger
5459 .as_ref()?
5460 .format_dap_log_messages
5461 .as_ref()
5462 },
5463 write: |settings_content, value| {
5464 settings_content
5465 .debugger
5466 .get_or_insert_default()
5467 .format_dap_log_messages = value;
5468 },
5469 }),
5470 metadata: None,
5471 files: USER,
5472 }),
5473 ]
5474 }
5475
5476 SettingsPage {
5477 title: "Debugger",
5478 items: concat_sections![general_section()],
5479 }
5480}
5481
5482fn terminal_page() -> SettingsPage {
5483 fn environment_section() -> [SettingsPageItem; 5] {
5484 [
5485 SettingsPageItem::SectionHeader("Environment"),
5486 SettingsPageItem::DynamicItem(DynamicItem {
5487 discriminant: SettingItem {
5488 files: USER | PROJECT,
5489 title: "Shell",
5490 description: "What shell to use when opening a terminal.",
5491 field: Box::new(SettingField {
5492 json_path: Some("terminal.shell$"),
5493 pick: |settings_content| {
5494 Some(&dynamic_variants::<settings::Shell>()[
5495 settings_content
5496 .terminal
5497 .as_ref()?
5498 .project
5499 .shell
5500 .as_ref()?
5501 .discriminant() as usize
5502 ])
5503 },
5504 write: |settings_content, value| {
5505 let Some(value) = value else {
5506 if let Some(terminal) = settings_content.terminal.as_mut() {
5507 terminal.project.shell = None;
5508 }
5509 return;
5510 };
5511 let settings_value = settings_content
5512 .terminal
5513 .get_or_insert_default()
5514 .project
5515 .shell
5516 .get_or_insert_with(|| settings::Shell::default());
5517 let default_shell = if cfg!(target_os = "windows") {
5518 "powershell.exe"
5519 } else {
5520 "sh"
5521 };
5522 *settings_value = match value {
5523 settings::ShellDiscriminants::System => settings::Shell::System,
5524 settings::ShellDiscriminants::Program => {
5525 let program = match settings_value {
5526 settings::Shell::Program(program) => program.clone(),
5527 settings::Shell::WithArguments { program, .. } => program.clone(),
5528 _ => String::from(default_shell),
5529 };
5530 settings::Shell::Program(program)
5531 }
5532 settings::ShellDiscriminants::WithArguments => {
5533 let (program, args, title_override) = match settings_value {
5534 settings::Shell::Program(program) => (program.clone(), vec![], None),
5535 settings::Shell::WithArguments {
5536 program,
5537 args,
5538 title_override,
5539 } => (program.clone(), args.clone(), title_override.clone()),
5540 _ => (String::from(default_shell), vec![], None),
5541 };
5542 settings::Shell::WithArguments {
5543 program,
5544 args,
5545 title_override,
5546 }
5547 }
5548 };
5549 },
5550 }),
5551 metadata: None,
5552 },
5553 pick_discriminant: |settings_content| {
5554 Some(
5555 settings_content
5556 .terminal
5557 .as_ref()?
5558 .project
5559 .shell
5560 .as_ref()?
5561 .discriminant() as usize,
5562 )
5563 },
5564 fields: dynamic_variants::<settings::Shell>()
5565 .into_iter()
5566 .map(|variant| match variant {
5567 settings::ShellDiscriminants::System => vec![],
5568 settings::ShellDiscriminants::Program => vec![SettingItem {
5569 files: USER | PROJECT,
5570 title: "Program",
5571 description: "The shell program to use.",
5572 field: Box::new(SettingField {
5573 json_path: Some("terminal.shell"),
5574 pick: |settings_content| match settings_content.terminal.as_ref()?.project.shell.as_ref()
5575 {
5576 Some(settings::Shell::Program(program)) => Some(program),
5577 _ => None,
5578 },
5579 write: |settings_content, value| {
5580 let Some(value) = value else {
5581 return;
5582 };
5583 match settings_content
5584 .terminal
5585 .get_or_insert_default()
5586 .project
5587 .shell
5588 .as_mut()
5589 {
5590 Some(settings::Shell::Program(program)) => *program = value,
5591 _ => return,
5592 }
5593 },
5594 }),
5595 metadata: None,
5596 }],
5597 settings::ShellDiscriminants::WithArguments => vec![
5598 SettingItem {
5599 files: USER | PROJECT,
5600 title: "Program",
5601 description: "The shell program to run.",
5602 field: Box::new(SettingField {
5603 json_path: Some("terminal.shell.program"),
5604 pick: |settings_content| {
5605 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
5606 Some(settings::Shell::WithArguments { program, .. }) => Some(program),
5607 _ => None,
5608 }
5609 },
5610 write: |settings_content, value| {
5611 let Some(value) = value else {
5612 return;
5613 };
5614 match settings_content
5615 .terminal
5616 .get_or_insert_default()
5617 .project
5618 .shell
5619 .as_mut()
5620 {
5621 Some(settings::Shell::WithArguments { program, .. }) => {
5622 *program = value
5623 }
5624 _ => return,
5625 }
5626 },
5627 }),
5628 metadata: None,
5629 },
5630 SettingItem {
5631 files: USER | PROJECT,
5632 title: "Arguments",
5633 description: "The arguments to pass to the shell program.",
5634 field: Box::new(
5635 SettingField {
5636 json_path: Some("terminal.shell.args"),
5637 pick: |settings_content| {
5638 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
5639 Some(settings::Shell::WithArguments { args, .. }) => Some(args),
5640 _ => None,
5641 }
5642 },
5643 write: |settings_content, value| {
5644 let Some(value) = value else {
5645 return;
5646 };
5647 match settings_content
5648 .terminal
5649 .get_or_insert_default()
5650 .project
5651 .shell
5652 .as_mut()
5653 {
5654 Some(settings::Shell::WithArguments { args, .. }) => *args = value,
5655 _ => return,
5656 }
5657 },
5658 }
5659 .unimplemented(),
5660 ),
5661 metadata: None,
5662 },
5663 SettingItem {
5664 files: USER | PROJECT,
5665 title: "Title Override",
5666 description: "An optional string to override the title of the terminal tab.",
5667 field: Box::new(SettingField {
5668 json_path: Some("terminal.shell.title_override"),
5669 pick: |settings_content| {
5670 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
5671 Some(settings::Shell::WithArguments { title_override, .. }) => {
5672 title_override.as_ref().or(DEFAULT_EMPTY_STRING)
5673 }
5674 _ => None,
5675 }
5676 },
5677 write: |settings_content, value| {
5678 match settings_content
5679 .terminal
5680 .get_or_insert_default()
5681 .project
5682 .shell
5683 .as_mut()
5684 {
5685 Some(settings::Shell::WithArguments { title_override, .. }) => {
5686 *title_override = value.filter(|s| !s.is_empty())
5687 }
5688 _ => return,
5689 }
5690 },
5691 }),
5692 metadata: None,
5693 },
5694 ],
5695 })
5696 .collect(),
5697 }),
5698 SettingsPageItem::DynamicItem(DynamicItem {
5699 discriminant: SettingItem {
5700 files: USER | PROJECT,
5701 title: "Working Directory",
5702 description: "What working directory to use when launching the terminal.",
5703 field: Box::new(SettingField {
5704 json_path: Some("terminal.working_directory$"),
5705 pick: |settings_content| {
5706 Some(&dynamic_variants::<settings::WorkingDirectory>()[
5707 settings_content
5708 .terminal
5709 .as_ref()?
5710 .project
5711 .working_directory
5712 .as_ref()?
5713 .discriminant() as usize
5714 ])
5715 },
5716 write: |settings_content, value| {
5717 let Some(value) = value else {
5718 if let Some(terminal) = settings_content.terminal.as_mut() {
5719 terminal.project.working_directory = None;
5720 }
5721 return;
5722 };
5723 let settings_value = settings_content
5724 .terminal
5725 .get_or_insert_default()
5726 .project
5727 .working_directory
5728 .get_or_insert_with(|| settings::WorkingDirectory::CurrentProjectDirectory);
5729 *settings_value = match value {
5730 settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => {
5731 settings::WorkingDirectory::CurrentProjectDirectory
5732 }
5733 settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => {
5734 settings::WorkingDirectory::FirstProjectDirectory
5735 }
5736 settings::WorkingDirectoryDiscriminants::AlwaysHome => {
5737 settings::WorkingDirectory::AlwaysHome
5738 }
5739 settings::WorkingDirectoryDiscriminants::Always => {
5740 let directory = match settings_value {
5741 settings::WorkingDirectory::Always { .. } => return,
5742 _ => String::new(),
5743 };
5744 settings::WorkingDirectory::Always { directory }
5745 }
5746 };
5747 },
5748 }),
5749 metadata: None,
5750 },
5751 pick_discriminant: |settings_content| {
5752 Some(
5753 settings_content
5754 .terminal
5755 .as_ref()?
5756 .project
5757 .working_directory
5758 .as_ref()?
5759 .discriminant() as usize,
5760 )
5761 },
5762 fields: dynamic_variants::<settings::WorkingDirectory>()
5763 .into_iter()
5764 .map(|variant| match variant {
5765 settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => vec![],
5766 settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => vec![],
5767 settings::WorkingDirectoryDiscriminants::AlwaysHome => vec![],
5768 settings::WorkingDirectoryDiscriminants::Always => vec![SettingItem {
5769 files: USER | PROJECT,
5770 title: "Directory",
5771 description: "The directory path to use (will be shell expanded).",
5772 field: Box::new(SettingField {
5773 json_path: Some("terminal.working_directory.always"),
5774 pick: |settings_content| {
5775 match settings_content.terminal.as_ref()?.project.working_directory.as_ref() {
5776 Some(settings::WorkingDirectory::Always { directory }) => Some(directory),
5777 _ => None,
5778 }
5779 },
5780 write: |settings_content, value| {
5781 let value = value.unwrap_or_default();
5782 match settings_content
5783 .terminal
5784 .get_or_insert_default()
5785 .project
5786 .working_directory
5787 .as_mut()
5788 {
5789 Some(settings::WorkingDirectory::Always { directory }) => *directory = value,
5790 _ => return,
5791 }
5792 },
5793 }),
5794 metadata: None,
5795 }],
5796 })
5797 .collect(),
5798 }),
5799 SettingsPageItem::SettingItem(SettingItem {
5800 title: "Environment Variables",
5801 description: "Key-value pairs to add to the terminal's environment.",
5802 field: Box::new(
5803 SettingField {
5804 json_path: Some("terminal.env"),
5805 pick: |settings_content| settings_content.terminal.as_ref()?.project.env.as_ref(),
5806 write: |settings_content, value| {
5807 settings_content.terminal.get_or_insert_default().project.env = value;
5808 },
5809 }
5810 .unimplemented(),
5811 ),
5812 metadata: None,
5813 files: USER | PROJECT,
5814 }),
5815 SettingsPageItem::SettingItem(SettingItem {
5816 title: "Detect Virtual Environment",
5817 description: "Activates the Python virtual environment, if one is found, in the terminal's working directory.",
5818 field: Box::new(
5819 SettingField {
5820 json_path: Some("terminal.detect_venv"),
5821 pick: |settings_content| settings_content.terminal.as_ref()?.project.detect_venv.as_ref(),
5822 write: |settings_content, value| {
5823 settings_content
5824 .terminal
5825 .get_or_insert_default()
5826 .project
5827 .detect_venv = value;
5828 },
5829 }
5830 .unimplemented(),
5831 ),
5832 metadata: None,
5833 files: USER | PROJECT,
5834 }),
5835 ]
5836 }
5837
5838 fn font_section() -> [SettingsPageItem; 6] {
5839 [
5840 SettingsPageItem::SectionHeader("Font"),
5841 SettingsPageItem::SettingItem(SettingItem {
5842 title: "Font Size",
5843 description: "Font size for terminal text. If not set, defaults to buffer font size.",
5844 field: Box::new(SettingField {
5845 json_path: Some("terminal.font_size"),
5846 pick: |settings_content| {
5847 settings_content
5848 .terminal
5849 .as_ref()
5850 .and_then(|terminal| terminal.font_size.as_ref())
5851 .or(settings_content.theme.buffer_font_size.as_ref())
5852 },
5853 write: |settings_content, value| {
5854 settings_content.terminal.get_or_insert_default().font_size = value;
5855 },
5856 }),
5857 metadata: None,
5858 files: USER,
5859 }),
5860 SettingsPageItem::SettingItem(SettingItem {
5861 title: "Font Family",
5862 description: "Font family for terminal text. If not set, defaults to buffer font family.",
5863 field: Box::new(SettingField {
5864 json_path: Some("terminal.font_family"),
5865 pick: |settings_content| {
5866 settings_content
5867 .terminal
5868 .as_ref()
5869 .and_then(|terminal| terminal.font_family.as_ref())
5870 .or(settings_content.theme.buffer_font_family.as_ref())
5871 },
5872 write: |settings_content, value| {
5873 settings_content
5874 .terminal
5875 .get_or_insert_default()
5876 .font_family = value;
5877 },
5878 }),
5879 metadata: None,
5880 files: USER,
5881 }),
5882 SettingsPageItem::SettingItem(SettingItem {
5883 title: "Font Fallbacks",
5884 description: "Font fallbacks for terminal text. If not set, defaults to buffer font fallbacks.",
5885 field: Box::new(
5886 SettingField {
5887 json_path: Some("terminal.font_fallbacks"),
5888 pick: |settings_content| {
5889 settings_content
5890 .terminal
5891 .as_ref()
5892 .and_then(|terminal| terminal.font_fallbacks.as_ref())
5893 .or(settings_content.theme.buffer_font_fallbacks.as_ref())
5894 },
5895 write: |settings_content, value| {
5896 settings_content
5897 .terminal
5898 .get_or_insert_default()
5899 .font_fallbacks = value;
5900 },
5901 }
5902 .unimplemented(),
5903 ),
5904 metadata: None,
5905 files: USER,
5906 }),
5907 SettingsPageItem::SettingItem(SettingItem {
5908 title: "Font Weight",
5909 description: "Font weight for terminal text in CSS weight units (100-900).",
5910 field: Box::new(SettingField {
5911 json_path: Some("terminal.font_weight"),
5912 pick: |settings_content| {
5913 settings_content.terminal.as_ref()?.font_weight.as_ref()
5914 },
5915 write: |settings_content, value| {
5916 settings_content
5917 .terminal
5918 .get_or_insert_default()
5919 .font_weight = value;
5920 },
5921 }),
5922 metadata: None,
5923 files: USER,
5924 }),
5925 SettingsPageItem::SettingItem(SettingItem {
5926 title: "Font Features",
5927 description: "Font features for terminal text.",
5928 field: Box::new(
5929 SettingField {
5930 json_path: Some("terminal.font_features"),
5931 pick: |settings_content| {
5932 settings_content
5933 .terminal
5934 .as_ref()
5935 .and_then(|terminal| terminal.font_features.as_ref())
5936 .or(settings_content.theme.buffer_font_features.as_ref())
5937 },
5938 write: |settings_content, value| {
5939 settings_content
5940 .terminal
5941 .get_or_insert_default()
5942 .font_features = value;
5943 },
5944 }
5945 .unimplemented(),
5946 ),
5947 metadata: None,
5948 files: USER,
5949 }),
5950 ]
5951 }
5952
5953 fn display_settings_section() -> [SettingsPageItem; 6] {
5954 [
5955 SettingsPageItem::SectionHeader("Display Settings"),
5956 SettingsPageItem::SettingItem(SettingItem {
5957 title: "Line Height",
5958 description: "Line height for terminal text.",
5959 field: Box::new(
5960 SettingField {
5961 json_path: Some("terminal.line_height"),
5962 pick: |settings_content| {
5963 settings_content.terminal.as_ref()?.line_height.as_ref()
5964 },
5965 write: |settings_content, value| {
5966 settings_content
5967 .terminal
5968 .get_or_insert_default()
5969 .line_height = value;
5970 },
5971 }
5972 .unimplemented(),
5973 ),
5974 metadata: None,
5975 files: USER,
5976 }),
5977 SettingsPageItem::SettingItem(SettingItem {
5978 title: "Cursor Shape",
5979 description: "Default cursor shape for the terminal (bar, block, underline, or hollow).",
5980 field: Box::new(SettingField {
5981 json_path: Some("terminal.cursor_shape"),
5982 pick: |settings_content| {
5983 settings_content.terminal.as_ref()?.cursor_shape.as_ref()
5984 },
5985 write: |settings_content, value| {
5986 settings_content
5987 .terminal
5988 .get_or_insert_default()
5989 .cursor_shape = value;
5990 },
5991 }),
5992 metadata: None,
5993 files: USER,
5994 }),
5995 SettingsPageItem::SettingItem(SettingItem {
5996 title: "Cursor Blinking",
5997 description: "Sets the cursor blinking behavior in the terminal.",
5998 field: Box::new(SettingField {
5999 json_path: Some("terminal.blinking"),
6000 pick: |settings_content| settings_content.terminal.as_ref()?.blinking.as_ref(),
6001 write: |settings_content, value| {
6002 settings_content.terminal.get_or_insert_default().blinking = value;
6003 },
6004 }),
6005 metadata: None,
6006 files: USER,
6007 }),
6008 SettingsPageItem::SettingItem(SettingItem {
6009 title: "Alternate Scroll",
6010 description: "Whether alternate scroll mode is active by default (converts mouse scroll to arrow keys in apps like Vim).",
6011 field: Box::new(SettingField {
6012 json_path: Some("terminal.alternate_scroll"),
6013 pick: |settings_content| {
6014 settings_content
6015 .terminal
6016 .as_ref()?
6017 .alternate_scroll
6018 .as_ref()
6019 },
6020 write: |settings_content, value| {
6021 settings_content
6022 .terminal
6023 .get_or_insert_default()
6024 .alternate_scroll = value;
6025 },
6026 }),
6027 metadata: None,
6028 files: USER,
6029 }),
6030 SettingsPageItem::SettingItem(SettingItem {
6031 title: "Minimum Contrast",
6032 description: "The minimum APCA perceptual contrast between foreground and background colors (0-106).",
6033 field: Box::new(SettingField {
6034 json_path: Some("terminal.minimum_contrast"),
6035 pick: |settings_content| {
6036 settings_content
6037 .terminal
6038 .as_ref()?
6039 .minimum_contrast
6040 .as_ref()
6041 },
6042 write: |settings_content, value| {
6043 settings_content
6044 .terminal
6045 .get_or_insert_default()
6046 .minimum_contrast = value;
6047 },
6048 }),
6049 metadata: None,
6050 files: USER,
6051 }),
6052 ]
6053 }
6054
6055 fn behavior_settings_section() -> [SettingsPageItem; 4] {
6056 [
6057 SettingsPageItem::SectionHeader("Behavior Settings"),
6058 SettingsPageItem::SettingItem(SettingItem {
6059 title: "Option As Meta",
6060 description: "Whether the option key behaves as the meta key.",
6061 field: Box::new(SettingField {
6062 json_path: Some("terminal.option_as_meta"),
6063 pick: |settings_content| {
6064 settings_content.terminal.as_ref()?.option_as_meta.as_ref()
6065 },
6066 write: |settings_content, value| {
6067 settings_content
6068 .terminal
6069 .get_or_insert_default()
6070 .option_as_meta = value;
6071 },
6072 }),
6073 metadata: None,
6074 files: USER,
6075 }),
6076 SettingsPageItem::SettingItem(SettingItem {
6077 title: "Copy On Select",
6078 description: "Whether selecting text in the terminal automatically copies to the system clipboard.",
6079 field: Box::new(SettingField {
6080 json_path: Some("terminal.copy_on_select"),
6081 pick: |settings_content| {
6082 settings_content.terminal.as_ref()?.copy_on_select.as_ref()
6083 },
6084 write: |settings_content, value| {
6085 settings_content
6086 .terminal
6087 .get_or_insert_default()
6088 .copy_on_select = value;
6089 },
6090 }),
6091 metadata: None,
6092 files: USER,
6093 }),
6094 SettingsPageItem::SettingItem(SettingItem {
6095 title: "Keep Selection On Copy",
6096 description: "Whether to keep the text selection after copying it to the clipboard.",
6097 field: Box::new(SettingField {
6098 json_path: Some("terminal.keep_selection_on_copy"),
6099 pick: |settings_content| {
6100 settings_content
6101 .terminal
6102 .as_ref()?
6103 .keep_selection_on_copy
6104 .as_ref()
6105 },
6106 write: |settings_content, value| {
6107 settings_content
6108 .terminal
6109 .get_or_insert_default()
6110 .keep_selection_on_copy = value;
6111 },
6112 }),
6113 metadata: None,
6114 files: USER,
6115 }),
6116 ]
6117 }
6118
6119 fn layout_settings_section() -> [SettingsPageItem; 3] {
6120 [
6121 SettingsPageItem::SectionHeader("Layout Settings"),
6122 SettingsPageItem::SettingItem(SettingItem {
6123 title: "Default Width",
6124 description: "Default width when the terminal is docked to the left or right (in pixels).",
6125 field: Box::new(SettingField {
6126 json_path: Some("terminal.default_width"),
6127 pick: |settings_content| {
6128 settings_content.terminal.as_ref()?.default_width.as_ref()
6129 },
6130 write: |settings_content, value| {
6131 settings_content
6132 .terminal
6133 .get_or_insert_default()
6134 .default_width = value;
6135 },
6136 }),
6137 metadata: None,
6138 files: USER,
6139 }),
6140 SettingsPageItem::SettingItem(SettingItem {
6141 title: "Default Height",
6142 description: "Default height when the terminal is docked to the bottom (in pixels).",
6143 field: Box::new(SettingField {
6144 json_path: Some("terminal.default_height"),
6145 pick: |settings_content| {
6146 settings_content.terminal.as_ref()?.default_height.as_ref()
6147 },
6148 write: |settings_content, value| {
6149 settings_content
6150 .terminal
6151 .get_or_insert_default()
6152 .default_height = value;
6153 },
6154 }),
6155 metadata: None,
6156 files: USER,
6157 }),
6158 ]
6159 }
6160
6161 fn advanced_settings_section() -> [SettingsPageItem; 3] {
6162 [
6163 SettingsPageItem::SectionHeader("Advanced Settings"),
6164 SettingsPageItem::SettingItem(SettingItem {
6165 title: "Max Scroll History Lines",
6166 description: "Maximum number of lines to keep in scrollback history (max: 100,000; 0 disables scrolling).",
6167 field: Box::new(SettingField {
6168 json_path: Some("terminal.max_scroll_history_lines"),
6169 pick: |settings_content| {
6170 settings_content
6171 .terminal
6172 .as_ref()?
6173 .max_scroll_history_lines
6174 .as_ref()
6175 },
6176 write: |settings_content, value| {
6177 settings_content
6178 .terminal
6179 .get_or_insert_default()
6180 .max_scroll_history_lines = value;
6181 },
6182 }),
6183 metadata: None,
6184 files: USER,
6185 }),
6186 SettingsPageItem::SettingItem(SettingItem {
6187 title: "Scroll Multiplier",
6188 description: "The multiplier for scrolling in the terminal with the mouse wheel",
6189 field: Box::new(SettingField {
6190 json_path: Some("terminal.scroll_multiplier"),
6191 pick: |settings_content| {
6192 settings_content
6193 .terminal
6194 .as_ref()?
6195 .scroll_multiplier
6196 .as_ref()
6197 },
6198 write: |settings_content, value| {
6199 settings_content
6200 .terminal
6201 .get_or_insert_default()
6202 .scroll_multiplier = value;
6203 },
6204 }),
6205 metadata: None,
6206 files: USER,
6207 }),
6208 ]
6209 }
6210
6211 fn toolbar_section() -> [SettingsPageItem; 2] {
6212 [
6213 SettingsPageItem::SectionHeader("Toolbar"),
6214 SettingsPageItem::SettingItem(SettingItem {
6215 title: "Breadcrumbs",
6216 description: "Display the terminal title in breadcrumbs inside the terminal pane.",
6217 field: Box::new(SettingField {
6218 json_path: Some("terminal.toolbar.breadcrumbs"),
6219 pick: |settings_content| {
6220 settings_content
6221 .terminal
6222 .as_ref()?
6223 .toolbar
6224 .as_ref()?
6225 .breadcrumbs
6226 .as_ref()
6227 },
6228 write: |settings_content, value| {
6229 settings_content
6230 .terminal
6231 .get_or_insert_default()
6232 .toolbar
6233 .get_or_insert_default()
6234 .breadcrumbs = value;
6235 },
6236 }),
6237 metadata: None,
6238 files: USER,
6239 }),
6240 ]
6241 }
6242
6243 fn scrollbar_section() -> [SettingsPageItem; 2] {
6244 [
6245 SettingsPageItem::SectionHeader("Scrollbar"),
6246 SettingsPageItem::SettingItem(SettingItem {
6247 title: "Show Scrollbar",
6248 description: "When to show the scrollbar in the terminal.",
6249 field: Box::new(SettingField {
6250 json_path: Some("terminal.scrollbar.show"),
6251 pick: |settings_content| {
6252 show_scrollbar_or_editor(settings_content, |settings_content| {
6253 settings_content
6254 .terminal
6255 .as_ref()?
6256 .scrollbar
6257 .as_ref()?
6258 .show
6259 .as_ref()
6260 })
6261 },
6262 write: |settings_content, value| {
6263 settings_content
6264 .terminal
6265 .get_or_insert_default()
6266 .scrollbar
6267 .get_or_insert_default()
6268 .show = value;
6269 },
6270 }),
6271 metadata: None,
6272 files: USER,
6273 }),
6274 ]
6275 }
6276
6277 SettingsPage {
6278 title: "Terminal",
6279 items: concat_sections![
6280 environment_section(),
6281 font_section(),
6282 display_settings_section(),
6283 behavior_settings_section(),
6284 layout_settings_section(),
6285 advanced_settings_section(),
6286 toolbar_section(),
6287 scrollbar_section(),
6288 ],
6289 }
6290}
6291
6292fn version_control_page() -> SettingsPage {
6293 fn git_integration_section() -> [SettingsPageItem; 2] {
6294 [
6295 SettingsPageItem::SectionHeader("Git Integration"),
6296 SettingsPageItem::DynamicItem(DynamicItem {
6297 discriminant: SettingItem {
6298 files: USER,
6299 title: "Disable Git Integration",
6300 description: "Disable all Git integration features in Zed.",
6301 field: Box::new(SettingField::<bool> {
6302 json_path: Some("git.disable_git"),
6303 pick: |settings_content| {
6304 settings_content
6305 .git
6306 .as_ref()?
6307 .enabled
6308 .as_ref()?
6309 .disable_git
6310 .as_ref()
6311 },
6312 write: |settings_content, value| {
6313 settings_content
6314 .git
6315 .get_or_insert_default()
6316 .enabled
6317 .get_or_insert_default()
6318 .disable_git = value;
6319 },
6320 }),
6321 metadata: None,
6322 },
6323 pick_discriminant: |settings_content| {
6324 let disabled = settings_content
6325 .git
6326 .as_ref()?
6327 .enabled
6328 .as_ref()?
6329 .disable_git
6330 .unwrap_or(false);
6331 Some(if disabled { 0 } else { 1 })
6332 },
6333 fields: vec![
6334 vec![],
6335 vec![
6336 SettingItem {
6337 files: USER,
6338 title: "Enable Git Status",
6339 description: "Show Git status information in the editor.",
6340 field: Box::new(SettingField::<bool> {
6341 json_path: Some("git.enable_status"),
6342 pick: |settings_content| {
6343 settings_content
6344 .git
6345 .as_ref()?
6346 .enabled
6347 .as_ref()?
6348 .enable_status
6349 .as_ref()
6350 },
6351 write: |settings_content, value| {
6352 settings_content
6353 .git
6354 .get_or_insert_default()
6355 .enabled
6356 .get_or_insert_default()
6357 .enable_status = value;
6358 },
6359 }),
6360 metadata: None,
6361 },
6362 SettingItem {
6363 files: USER,
6364 title: "Enable Git Diff",
6365 description: "Show Git diff information in the editor.",
6366 field: Box::new(SettingField::<bool> {
6367 json_path: Some("git.enable_diff"),
6368 pick: |settings_content| {
6369 settings_content
6370 .git
6371 .as_ref()?
6372 .enabled
6373 .as_ref()?
6374 .enable_diff
6375 .as_ref()
6376 },
6377 write: |settings_content, value| {
6378 settings_content
6379 .git
6380 .get_or_insert_default()
6381 .enabled
6382 .get_or_insert_default()
6383 .enable_diff = value;
6384 },
6385 }),
6386 metadata: None,
6387 },
6388 ],
6389 ],
6390 }),
6391 ]
6392 }
6393
6394 fn git_gutter_section() -> [SettingsPageItem; 3] {
6395 [
6396 SettingsPageItem::SectionHeader("Git Gutter"),
6397 SettingsPageItem::SettingItem(SettingItem {
6398 title: "Visibility",
6399 description: "Control whether Git status is shown in the editor's gutter.",
6400 field: Box::new(SettingField {
6401 json_path: Some("git.git_gutter"),
6402 pick: |settings_content| settings_content.git.as_ref()?.git_gutter.as_ref(),
6403 write: |settings_content, value| {
6404 settings_content.git.get_or_insert_default().git_gutter = value;
6405 },
6406 }),
6407 metadata: None,
6408 files: USER,
6409 }),
6410 // todo(settings_ui): Figure out the right default for this value in default.json
6411 SettingsPageItem::SettingItem(SettingItem {
6412 title: "Debounce",
6413 description: "Debounce threshold in milliseconds after which changes are reflected in the Git gutter.",
6414 field: Box::new(SettingField {
6415 json_path: Some("git.gutter_debounce"),
6416 pick: |settings_content| {
6417 settings_content.git.as_ref()?.gutter_debounce.as_ref()
6418 },
6419 write: |settings_content, value| {
6420 settings_content.git.get_or_insert_default().gutter_debounce = value;
6421 },
6422 }),
6423 metadata: None,
6424 files: USER,
6425 }),
6426 ]
6427 }
6428
6429 fn inline_git_blame_section() -> [SettingsPageItem; 6] {
6430 [
6431 SettingsPageItem::SectionHeader("Inline Git Blame"),
6432 SettingsPageItem::SettingItem(SettingItem {
6433 title: "Enabled",
6434 description: "Whether or not to show Git blame data inline in the currently focused line.",
6435 field: Box::new(SettingField {
6436 json_path: Some("git.inline_blame.enabled"),
6437 pick: |settings_content| {
6438 settings_content
6439 .git
6440 .as_ref()?
6441 .inline_blame
6442 .as_ref()?
6443 .enabled
6444 .as_ref()
6445 },
6446 write: |settings_content, value| {
6447 settings_content
6448 .git
6449 .get_or_insert_default()
6450 .inline_blame
6451 .get_or_insert_default()
6452 .enabled = value;
6453 },
6454 }),
6455 metadata: None,
6456 files: USER,
6457 }),
6458 SettingsPageItem::SettingItem(SettingItem {
6459 title: "Delay",
6460 description: "The delay after which the inline blame information is shown.",
6461 field: Box::new(SettingField {
6462 json_path: Some("git.inline_blame.delay_ms"),
6463 pick: |settings_content| {
6464 settings_content
6465 .git
6466 .as_ref()?
6467 .inline_blame
6468 .as_ref()?
6469 .delay_ms
6470 .as_ref()
6471 },
6472 write: |settings_content, value| {
6473 settings_content
6474 .git
6475 .get_or_insert_default()
6476 .inline_blame
6477 .get_or_insert_default()
6478 .delay_ms = value;
6479 },
6480 }),
6481 metadata: None,
6482 files: USER,
6483 }),
6484 SettingsPageItem::SettingItem(SettingItem {
6485 title: "Padding",
6486 description: "Padding between the end of the source line and the start of the inline blame in columns.",
6487 field: Box::new(SettingField {
6488 json_path: Some("git.inline_blame.padding"),
6489 pick: |settings_content| {
6490 settings_content
6491 .git
6492 .as_ref()?
6493 .inline_blame
6494 .as_ref()?
6495 .padding
6496 .as_ref()
6497 },
6498 write: |settings_content, value| {
6499 settings_content
6500 .git
6501 .get_or_insert_default()
6502 .inline_blame
6503 .get_or_insert_default()
6504 .padding = value;
6505 },
6506 }),
6507 metadata: None,
6508 files: USER,
6509 }),
6510 SettingsPageItem::SettingItem(SettingItem {
6511 title: "Minimum Column",
6512 description: "The minimum column number at which to show the inline blame information.",
6513 field: Box::new(SettingField {
6514 json_path: Some("git.inline_blame.min_column"),
6515 pick: |settings_content| {
6516 settings_content
6517 .git
6518 .as_ref()?
6519 .inline_blame
6520 .as_ref()?
6521 .min_column
6522 .as_ref()
6523 },
6524 write: |settings_content, value| {
6525 settings_content
6526 .git
6527 .get_or_insert_default()
6528 .inline_blame
6529 .get_or_insert_default()
6530 .min_column = value;
6531 },
6532 }),
6533 metadata: None,
6534 files: USER,
6535 }),
6536 SettingsPageItem::SettingItem(SettingItem {
6537 title: "Show Commit Summary",
6538 description: "Show commit summary as part of the inline blame.",
6539 field: Box::new(SettingField {
6540 json_path: Some("git.inline_blame.show_commit_summary"),
6541 pick: |settings_content| {
6542 settings_content
6543 .git
6544 .as_ref()?
6545 .inline_blame
6546 .as_ref()?
6547 .show_commit_summary
6548 .as_ref()
6549 },
6550 write: |settings_content, value| {
6551 settings_content
6552 .git
6553 .get_or_insert_default()
6554 .inline_blame
6555 .get_or_insert_default()
6556 .show_commit_summary = value;
6557 },
6558 }),
6559 metadata: None,
6560 files: USER,
6561 }),
6562 ]
6563 }
6564
6565 fn git_blame_view_section() -> [SettingsPageItem; 2] {
6566 [
6567 SettingsPageItem::SectionHeader("Git Blame View"),
6568 SettingsPageItem::SettingItem(SettingItem {
6569 title: "Show Avatar",
6570 description: "Show the avatar of the author of the commit.",
6571 field: Box::new(SettingField {
6572 json_path: Some("git.blame.show_avatar"),
6573 pick: |settings_content| {
6574 settings_content
6575 .git
6576 .as_ref()?
6577 .blame
6578 .as_ref()?
6579 .show_avatar
6580 .as_ref()
6581 },
6582 write: |settings_content, value| {
6583 settings_content
6584 .git
6585 .get_or_insert_default()
6586 .blame
6587 .get_or_insert_default()
6588 .show_avatar = value;
6589 },
6590 }),
6591 metadata: None,
6592 files: USER,
6593 }),
6594 ]
6595 }
6596
6597 fn branch_picker_section() -> [SettingsPageItem; 2] {
6598 [
6599 SettingsPageItem::SectionHeader("Branch Picker"),
6600 SettingsPageItem::SettingItem(SettingItem {
6601 title: "Show Author Name",
6602 description: "Show author name as part of the commit information in branch picker.",
6603 field: Box::new(SettingField {
6604 json_path: Some("git.branch_picker.show_author_name"),
6605 pick: |settings_content| {
6606 settings_content
6607 .git
6608 .as_ref()?
6609 .branch_picker
6610 .as_ref()?
6611 .show_author_name
6612 .as_ref()
6613 },
6614 write: |settings_content, value| {
6615 settings_content
6616 .git
6617 .get_or_insert_default()
6618 .branch_picker
6619 .get_or_insert_default()
6620 .show_author_name = value;
6621 },
6622 }),
6623 metadata: None,
6624 files: USER,
6625 }),
6626 ]
6627 }
6628
6629 fn git_hunks_section() -> [SettingsPageItem; 3] {
6630 [
6631 SettingsPageItem::SectionHeader("Git Hunks"),
6632 SettingsPageItem::SettingItem(SettingItem {
6633 title: "Hunk Style",
6634 description: "How Git hunks are displayed visually in the editor.",
6635 field: Box::new(SettingField {
6636 json_path: Some("git.hunk_style"),
6637 pick: |settings_content| settings_content.git.as_ref()?.hunk_style.as_ref(),
6638 write: |settings_content, value| {
6639 settings_content.git.get_or_insert_default().hunk_style = value;
6640 },
6641 }),
6642 metadata: None,
6643 files: USER,
6644 }),
6645 SettingsPageItem::SettingItem(SettingItem {
6646 title: "Path Style",
6647 description: "Should the name or path be displayed first in the git view.",
6648 field: Box::new(SettingField {
6649 json_path: Some("git.path_style"),
6650 pick: |settings_content| settings_content.git.as_ref()?.path_style.as_ref(),
6651 write: |settings_content, value| {
6652 settings_content.git.get_or_insert_default().path_style = value;
6653 },
6654 }),
6655 metadata: None,
6656 files: USER,
6657 }),
6658 ]
6659 }
6660
6661 SettingsPage {
6662 title: "Version Control",
6663 items: concat_sections![
6664 git_integration_section(),
6665 git_gutter_section(),
6666 inline_git_blame_section(),
6667 git_blame_view_section(),
6668 branch_picker_section(),
6669 git_hunks_section(),
6670 ],
6671 }
6672}
6673
6674fn collaboration_page() -> SettingsPage {
6675 fn calls_section() -> [SettingsPageItem; 3] {
6676 [
6677 SettingsPageItem::SectionHeader("Calls"),
6678 SettingsPageItem::SettingItem(SettingItem {
6679 title: "Mute On Join",
6680 description: "Whether the microphone should be muted when joining a channel or a call.",
6681 field: Box::new(SettingField {
6682 json_path: Some("calls.mute_on_join"),
6683 pick: |settings_content| settings_content.calls.as_ref()?.mute_on_join.as_ref(),
6684 write: |settings_content, value| {
6685 settings_content.calls.get_or_insert_default().mute_on_join = value;
6686 },
6687 }),
6688 metadata: None,
6689 files: USER,
6690 }),
6691 SettingsPageItem::SettingItem(SettingItem {
6692 title: "Share On Join",
6693 description: "Whether your current project should be shared when joining an empty channel.",
6694 field: Box::new(SettingField {
6695 json_path: Some("calls.share_on_join"),
6696 pick: |settings_content| {
6697 settings_content.calls.as_ref()?.share_on_join.as_ref()
6698 },
6699 write: |settings_content, value| {
6700 settings_content.calls.get_or_insert_default().share_on_join = value;
6701 },
6702 }),
6703 metadata: None,
6704 files: USER,
6705 }),
6706 ]
6707 }
6708
6709 fn experimental_section() -> [SettingsPageItem; 6] {
6710 [
6711 SettingsPageItem::SectionHeader("Experimental"),
6712 SettingsPageItem::SettingItem(SettingItem {
6713 title: "Rodio Audio",
6714 description: "Opt into the new audio system.",
6715 field: Box::new(SettingField {
6716 json_path: Some("audio.experimental.rodio_audio"),
6717 pick: |settings_content| settings_content.audio.as_ref()?.rodio_audio.as_ref(),
6718 write: |settings_content, value| {
6719 settings_content.audio.get_or_insert_default().rodio_audio = value;
6720 },
6721 }),
6722 metadata: None,
6723 files: USER,
6724 }),
6725 SettingsPageItem::SettingItem(SettingItem {
6726 title: "Auto Microphone Volume",
6727 description: "Automatically adjust microphone volume (requires rodio audio).",
6728 field: Box::new(SettingField {
6729 json_path: Some("audio.experimental.auto_microphone_volume"),
6730 pick: |settings_content| {
6731 settings_content
6732 .audio
6733 .as_ref()?
6734 .auto_microphone_volume
6735 .as_ref()
6736 },
6737 write: |settings_content, value| {
6738 settings_content
6739 .audio
6740 .get_or_insert_default()
6741 .auto_microphone_volume = value;
6742 },
6743 }),
6744 metadata: None,
6745 files: USER,
6746 }),
6747 SettingsPageItem::SettingItem(SettingItem {
6748 title: "Auto Speaker Volume",
6749 description: "Automatically adjust volume of other call members (requires rodio audio).",
6750 field: Box::new(SettingField {
6751 json_path: Some("audio.experimental.auto_speaker_volume"),
6752 pick: |settings_content| {
6753 settings_content
6754 .audio
6755 .as_ref()?
6756 .auto_speaker_volume
6757 .as_ref()
6758 },
6759 write: |settings_content, value| {
6760 settings_content
6761 .audio
6762 .get_or_insert_default()
6763 .auto_speaker_volume = value;
6764 },
6765 }),
6766 metadata: None,
6767 files: USER,
6768 }),
6769 SettingsPageItem::SettingItem(SettingItem {
6770 title: "Denoise",
6771 description: "Remove background noises (requires rodio audio).",
6772 field: Box::new(SettingField {
6773 json_path: Some("audio.experimental.denoise"),
6774 pick: |settings_content| settings_content.audio.as_ref()?.denoise.as_ref(),
6775 write: |settings_content, value| {
6776 settings_content.audio.get_or_insert_default().denoise = value;
6777 },
6778 }),
6779 metadata: None,
6780 files: USER,
6781 }),
6782 SettingsPageItem::SettingItem(SettingItem {
6783 title: "Legacy Audio Compatible",
6784 description: "Use audio parameters compatible with previous versions (requires rodio audio).",
6785 field: Box::new(SettingField {
6786 json_path: Some("audio.experimental.legacy_audio_compatible"),
6787 pick: |settings_content| {
6788 settings_content
6789 .audio
6790 .as_ref()?
6791 .legacy_audio_compatible
6792 .as_ref()
6793 },
6794 write: |settings_content, value| {
6795 settings_content
6796 .audio
6797 .get_or_insert_default()
6798 .legacy_audio_compatible = value;
6799 },
6800 }),
6801 metadata: None,
6802 files: USER,
6803 }),
6804 ]
6805 }
6806
6807 SettingsPage {
6808 title: "Collaboration",
6809 items: concat_sections![calls_section(), experimental_section()],
6810 }
6811}
6812
6813fn ai_page() -> SettingsPage {
6814 fn general_section() -> [SettingsPageItem; 2] {
6815 [
6816 SettingsPageItem::SectionHeader("General"),
6817 SettingsPageItem::SettingItem(SettingItem {
6818 title: "Disable AI",
6819 description: "Whether to disable all AI features in Zed.",
6820 field: Box::new(SettingField {
6821 json_path: Some("disable_ai"),
6822 pick: |settings_content| settings_content.disable_ai.as_ref(),
6823 write: |settings_content, value| {
6824 settings_content.disable_ai = value;
6825 },
6826 }),
6827 metadata: None,
6828 files: USER,
6829 }),
6830 ]
6831 }
6832
6833 fn agent_configuration_section() -> [SettingsPageItem; 11] {
6834 [
6835 SettingsPageItem::SectionHeader("Agent Configuration"),
6836 SettingsPageItem::SettingItem(SettingItem {
6837 title: "Always Allow Tool Actions",
6838 description: "When enabled, the agent can run potentially destructive actions without asking for your confirmation. This setting has no effect on external agents.",
6839 field: Box::new(SettingField {
6840 json_path: Some("agent.always_allow_tool_actions"),
6841 pick: |settings_content| {
6842 settings_content
6843 .agent
6844 .as_ref()?
6845 .always_allow_tool_actions
6846 .as_ref()
6847 },
6848 write: |settings_content, value| {
6849 settings_content
6850 .agent
6851 .get_or_insert_default()
6852 .always_allow_tool_actions = value;
6853 },
6854 }),
6855 metadata: None,
6856 files: USER,
6857 }),
6858 SettingsPageItem::SettingItem(SettingItem {
6859 title: "Single File Review",
6860 description: "When enabled, agent edits will also be displayed in single-file buffers for review.",
6861 field: Box::new(SettingField {
6862 json_path: Some("agent.single_file_review"),
6863 pick: |settings_content| {
6864 settings_content.agent.as_ref()?.single_file_review.as_ref()
6865 },
6866 write: |settings_content, value| {
6867 settings_content
6868 .agent
6869 .get_or_insert_default()
6870 .single_file_review = value;
6871 },
6872 }),
6873 metadata: None,
6874 files: USER,
6875 }),
6876 SettingsPageItem::SettingItem(SettingItem {
6877 title: "Enable Feedback",
6878 description: "Show voting thumbs up/down icon buttons for feedback on agent edits.",
6879 field: Box::new(SettingField {
6880 json_path: Some("agent.enable_feedback"),
6881 pick: |settings_content| {
6882 settings_content.agent.as_ref()?.enable_feedback.as_ref()
6883 },
6884 write: |settings_content, value| {
6885 settings_content
6886 .agent
6887 .get_or_insert_default()
6888 .enable_feedback = value;
6889 },
6890 }),
6891 metadata: None,
6892 files: USER,
6893 }),
6894 SettingsPageItem::SettingItem(SettingItem {
6895 title: "Notify When Agent Waiting",
6896 description: "Where to show notifications when the agent has completed its response or needs confirmation before running a tool action.",
6897 field: Box::new(SettingField {
6898 json_path: Some("agent.notify_when_agent_waiting"),
6899 pick: |settings_content| {
6900 settings_content
6901 .agent
6902 .as_ref()?
6903 .notify_when_agent_waiting
6904 .as_ref()
6905 },
6906 write: |settings_content, value| {
6907 settings_content
6908 .agent
6909 .get_or_insert_default()
6910 .notify_when_agent_waiting = value;
6911 },
6912 }),
6913 metadata: None,
6914 files: USER,
6915 }),
6916 SettingsPageItem::SettingItem(SettingItem {
6917 title: "Play Sound When Agent Done",
6918 description: "Whether to play a sound when the agent has either completed its response, or needs user input.",
6919 field: Box::new(SettingField {
6920 json_path: Some("agent.play_sound_when_agent_done"),
6921 pick: |settings_content| {
6922 settings_content
6923 .agent
6924 .as_ref()?
6925 .play_sound_when_agent_done
6926 .as_ref()
6927 },
6928 write: |settings_content, value| {
6929 settings_content
6930 .agent
6931 .get_or_insert_default()
6932 .play_sound_when_agent_done = value;
6933 },
6934 }),
6935 metadata: None,
6936 files: USER,
6937 }),
6938 SettingsPageItem::SettingItem(SettingItem {
6939 title: "Expand Edit Card",
6940 description: "Whether to have edit cards in the agent panel expanded, showing a Preview of the diff.",
6941 field: Box::new(SettingField {
6942 json_path: Some("agent.expand_edit_card"),
6943 pick: |settings_content| {
6944 settings_content.agent.as_ref()?.expand_edit_card.as_ref()
6945 },
6946 write: |settings_content, value| {
6947 settings_content
6948 .agent
6949 .get_or_insert_default()
6950 .expand_edit_card = value;
6951 },
6952 }),
6953 metadata: None,
6954 files: USER,
6955 }),
6956 SettingsPageItem::SettingItem(SettingItem {
6957 title: "Expand Terminal Card",
6958 description: "Whether to have terminal cards in the agent panel expanded, showing the whole command output.",
6959 field: Box::new(SettingField {
6960 json_path: Some("agent.expand_terminal_card"),
6961 pick: |settings_content| {
6962 settings_content
6963 .agent
6964 .as_ref()?
6965 .expand_terminal_card
6966 .as_ref()
6967 },
6968 write: |settings_content, value| {
6969 settings_content
6970 .agent
6971 .get_or_insert_default()
6972 .expand_terminal_card = value;
6973 },
6974 }),
6975 metadata: None,
6976 files: USER,
6977 }),
6978 SettingsPageItem::SettingItem(SettingItem {
6979 title: "Use Modifier To Send",
6980 description: "Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages.",
6981 field: Box::new(SettingField {
6982 json_path: Some("agent.use_modifier_to_send"),
6983 pick: |settings_content| {
6984 settings_content
6985 .agent
6986 .as_ref()?
6987 .use_modifier_to_send
6988 .as_ref()
6989 },
6990 write: |settings_content, value| {
6991 settings_content
6992 .agent
6993 .get_or_insert_default()
6994 .use_modifier_to_send = value;
6995 },
6996 }),
6997 metadata: None,
6998 files: USER,
6999 }),
7000 SettingsPageItem::SettingItem(SettingItem {
7001 title: "Message Editor Min Lines",
7002 description: "Minimum number of lines to display in the agent message editor.",
7003 field: Box::new(SettingField {
7004 json_path: Some("agent.message_editor_min_lines"),
7005 pick: |settings_content| {
7006 settings_content
7007 .agent
7008 .as_ref()?
7009 .message_editor_min_lines
7010 .as_ref()
7011 },
7012 write: |settings_content, value| {
7013 settings_content
7014 .agent
7015 .get_or_insert_default()
7016 .message_editor_min_lines = value;
7017 },
7018 }),
7019 metadata: None,
7020 files: USER,
7021 }),
7022 SettingsPageItem::SettingItem(SettingItem {
7023 title: "Show Turn Stats",
7024 description: "Whether to show turn statistics like elapsed time during generation and final turn duration.",
7025 field: Box::new(SettingField {
7026 json_path: Some("agent.show_turn_stats"),
7027 pick: |settings_content| {
7028 settings_content.agent.as_ref()?.show_turn_stats.as_ref()
7029 },
7030 write: |settings_content, value| {
7031 settings_content
7032 .agent
7033 .get_or_insert_default()
7034 .show_turn_stats = value;
7035 },
7036 }),
7037 metadata: None,
7038 files: USER,
7039 }),
7040 ]
7041 }
7042
7043 fn context_servers_section() -> [SettingsPageItem; 2] {
7044 [
7045 SettingsPageItem::SectionHeader("Context Servers"),
7046 SettingsPageItem::SettingItem(SettingItem {
7047 title: "Context Server Timeout",
7048 description: "Default timeout in seconds for context server tool calls. Can be overridden per-server in context_servers configuration.",
7049 field: Box::new(SettingField {
7050 json_path: Some("context_server_timeout"),
7051 pick: |settings_content| {
7052 settings_content.project.context_server_timeout.as_ref()
7053 },
7054 write: |settings_content, value| {
7055 settings_content.project.context_server_timeout = value;
7056 },
7057 }),
7058 metadata: None,
7059 files: USER | PROJECT,
7060 }),
7061 ]
7062 }
7063
7064 fn edit_prediction_display_sub_section() -> [SettingsPageItem; 2] {
7065 [
7066 SettingsPageItem::SettingItem(SettingItem {
7067 title: "Display Mode",
7068 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.",
7069 field: Box::new(SettingField {
7070 json_path: Some("edit_prediction.display_mode"),
7071 pick: |settings_content| {
7072 settings_content
7073 .project
7074 .all_languages
7075 .edit_predictions
7076 .as_ref()?
7077 .mode
7078 .as_ref()
7079 },
7080 write: |settings_content, value| {
7081 settings_content
7082 .project
7083 .all_languages
7084 .edit_predictions
7085 .get_or_insert_default()
7086 .mode = value;
7087 },
7088 }),
7089 metadata: None,
7090 files: USER,
7091 }),
7092 SettingsPageItem::SettingItem(SettingItem {
7093 title: "Display In Text Threads",
7094 description: "Whether edit predictions are enabled when editing text threads in the agent panel.",
7095 field: Box::new(SettingField {
7096 json_path: Some("edit_prediction.in_text_threads"),
7097 pick: |settings_content| {
7098 settings_content
7099 .project
7100 .all_languages
7101 .edit_predictions
7102 .as_ref()?
7103 .enabled_in_text_threads
7104 .as_ref()
7105 },
7106 write: |settings_content, value| {
7107 settings_content
7108 .project
7109 .all_languages
7110 .edit_predictions
7111 .get_or_insert_default()
7112 .enabled_in_text_threads = value;
7113 },
7114 }),
7115 metadata: None,
7116 files: USER,
7117 }),
7118 ]
7119 }
7120
7121 SettingsPage {
7122 title: "AI",
7123 items: concat_sections![
7124 general_section(),
7125 agent_configuration_section(),
7126 context_servers_section(),
7127 edit_prediction_language_settings_section(),
7128 edit_prediction_display_sub_section()
7129 ],
7130 }
7131}
7132
7133fn network_page() -> SettingsPage {
7134 fn network_section() -> [SettingsPageItem; 3] {
7135 [
7136 SettingsPageItem::SectionHeader("Network"),
7137 SettingsPageItem::SettingItem(SettingItem {
7138 title: "Proxy",
7139 description: "The proxy to use for network requests.",
7140 field: Box::new(SettingField {
7141 json_path: Some("proxy"),
7142 pick: |settings_content| settings_content.proxy.as_ref(),
7143 write: |settings_content, value| {
7144 settings_content.proxy = value;
7145 },
7146 }),
7147 metadata: Some(Box::new(SettingsFieldMetadata {
7148 placeholder: Some("socks5h://localhost:10808"),
7149 ..Default::default()
7150 })),
7151 files: USER,
7152 }),
7153 SettingsPageItem::SettingItem(SettingItem {
7154 title: "Server URL",
7155 description: "The URL of the Zed server to connect to.",
7156 field: Box::new(SettingField {
7157 json_path: Some("server_url"),
7158 pick: |settings_content| settings_content.server_url.as_ref(),
7159 write: |settings_content, value| {
7160 settings_content.server_url = value;
7161 },
7162 }),
7163 metadata: Some(Box::new(SettingsFieldMetadata {
7164 placeholder: Some("https://zed.dev"),
7165 ..Default::default()
7166 })),
7167 files: USER,
7168 }),
7169 ]
7170 }
7171
7172 SettingsPage {
7173 title: "Network",
7174 items: concat_sections![network_section()],
7175 }
7176}
7177
7178fn language_settings_field<T>(
7179 settings_content: &SettingsContent,
7180 get_language_setting_field: fn(&LanguageSettingsContent) -> Option<&T>,
7181) -> Option<&T> {
7182 let all_languages = &settings_content.project.all_languages;
7183
7184 active_language()
7185 .and_then(|current_language_name| {
7186 all_languages
7187 .languages
7188 .0
7189 .get(current_language_name.as_ref())
7190 })
7191 .and_then(get_language_setting_field)
7192 .or_else(|| get_language_setting_field(&all_languages.defaults))
7193}
7194
7195fn language_settings_field_mut<T>(
7196 settings_content: &mut SettingsContent,
7197 value: Option<T>,
7198 write: fn(&mut LanguageSettingsContent, Option<T>),
7199) {
7200 let all_languages = &mut settings_content.project.all_languages;
7201 let language_content = if let Some(current_language) = active_language() {
7202 all_languages
7203 .languages
7204 .0
7205 .entry(current_language.to_string())
7206 .or_default()
7207 } else {
7208 &mut all_languages.defaults
7209 };
7210 write(language_content, value);
7211}
7212
7213fn language_settings_data() -> Box<[SettingsPageItem]> {
7214 fn indentation_section() -> [SettingsPageItem; 5] {
7215 [
7216 SettingsPageItem::SectionHeader("Indentation"),
7217 SettingsPageItem::SettingItem(SettingItem {
7218 title: "Tab Size",
7219 description: "How many columns a tab should occupy.",
7220 field: Box::new(SettingField {
7221 json_path: Some("languages.$(language).tab_size"), // TODO(cameron): not JQ syntax because not URL-safe
7222 pick: |settings_content| {
7223 language_settings_field(settings_content, |language| {
7224 language.tab_size.as_ref()
7225 })
7226 },
7227 write: |settings_content, value| {
7228 language_settings_field_mut(settings_content, value, |language, value| {
7229 language.tab_size = value;
7230 })
7231 },
7232 }),
7233 metadata: None,
7234 files: USER | PROJECT,
7235 }),
7236 SettingsPageItem::SettingItem(SettingItem {
7237 title: "Hard Tabs",
7238 description: "Whether to indent lines using tab characters, as opposed to multiple spaces.",
7239 field: Box::new(SettingField {
7240 json_path: Some("languages.$(language).hard_tabs"),
7241 pick: |settings_content| {
7242 language_settings_field(settings_content, |language| {
7243 language.hard_tabs.as_ref()
7244 })
7245 },
7246 write: |settings_content, value| {
7247 language_settings_field_mut(settings_content, value, |language, value| {
7248 language.hard_tabs = value;
7249 })
7250 },
7251 }),
7252 metadata: None,
7253 files: USER | PROJECT,
7254 }),
7255 SettingsPageItem::SettingItem(SettingItem {
7256 title: "Auto Indent",
7257 description: "Whether indentation should be adjusted based on the context whilst typing.",
7258 field: Box::new(SettingField {
7259 json_path: Some("languages.$(language).auto_indent"),
7260 pick: |settings_content| {
7261 language_settings_field(settings_content, |language| {
7262 language.auto_indent.as_ref()
7263 })
7264 },
7265 write: |settings_content, value| {
7266 language_settings_field_mut(settings_content, value, |language, value| {
7267 language.auto_indent = value;
7268 })
7269 },
7270 }),
7271 metadata: None,
7272 files: USER | PROJECT,
7273 }),
7274 SettingsPageItem::SettingItem(SettingItem {
7275 title: "Auto Indent On Paste",
7276 description: "Whether indentation of pasted content should be adjusted based on the context.",
7277 field: Box::new(SettingField {
7278 json_path: Some("languages.$(language).auto_indent_on_paste"),
7279 pick: |settings_content| {
7280 language_settings_field(settings_content, |language| {
7281 language.auto_indent_on_paste.as_ref()
7282 })
7283 },
7284 write: |settings_content, value| {
7285 language_settings_field_mut(settings_content, value, |language, value| {
7286 language.auto_indent_on_paste = value;
7287 })
7288 },
7289 }),
7290 metadata: None,
7291 files: USER | PROJECT,
7292 }),
7293 ]
7294 }
7295
7296 fn wrapping_section() -> [SettingsPageItem; 6] {
7297 [
7298 SettingsPageItem::SectionHeader("Wrapping"),
7299 SettingsPageItem::SettingItem(SettingItem {
7300 title: "Soft Wrap",
7301 description: "How to soft-wrap long lines of text.",
7302 field: Box::new(SettingField {
7303 json_path: Some("languages.$(language).soft_wrap"),
7304 pick: |settings_content| {
7305 language_settings_field(settings_content, |language| {
7306 language.soft_wrap.as_ref()
7307 })
7308 },
7309 write: |settings_content, value| {
7310 language_settings_field_mut(settings_content, value, |language, value| {
7311 language.soft_wrap = value;
7312 })
7313 },
7314 }),
7315 metadata: None,
7316 files: USER | PROJECT,
7317 }),
7318 SettingsPageItem::SettingItem(SettingItem {
7319 title: "Show Wrap Guides",
7320 description: "Show wrap guides in the editor.",
7321 field: Box::new(SettingField {
7322 json_path: Some("languages.$(language).show_wrap_guides"),
7323 pick: |settings_content| {
7324 language_settings_field(settings_content, |language| {
7325 language.show_wrap_guides.as_ref()
7326 })
7327 },
7328 write: |settings_content, value| {
7329 language_settings_field_mut(settings_content, value, |language, value| {
7330 language.show_wrap_guides = value;
7331 })
7332 },
7333 }),
7334 metadata: None,
7335 files: USER | PROJECT,
7336 }),
7337 SettingsPageItem::SettingItem(SettingItem {
7338 title: "Preferred Line Length",
7339 description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled.",
7340 field: Box::new(SettingField {
7341 json_path: Some("languages.$(language).preferred_line_length"),
7342 pick: |settings_content| {
7343 language_settings_field(settings_content, |language| {
7344 language.preferred_line_length.as_ref()
7345 })
7346 },
7347 write: |settings_content, value| {
7348 language_settings_field_mut(settings_content, value, |language, value| {
7349 language.preferred_line_length = value;
7350 })
7351 },
7352 }),
7353 metadata: None,
7354 files: USER | PROJECT,
7355 }),
7356 SettingsPageItem::SettingItem(SettingItem {
7357 title: "Wrap Guides",
7358 description: "Character counts at which to show wrap guides in the editor.",
7359 field: Box::new(
7360 SettingField {
7361 json_path: Some("languages.$(language).wrap_guides"),
7362 pick: |settings_content| {
7363 language_settings_field(settings_content, |language| {
7364 language.wrap_guides.as_ref()
7365 })
7366 },
7367 write: |settings_content, value| {
7368 language_settings_field_mut(
7369 settings_content,
7370 value,
7371 |language, value| {
7372 language.wrap_guides = value;
7373 },
7374 )
7375 },
7376 }
7377 .unimplemented(),
7378 ),
7379 metadata: None,
7380 files: USER | PROJECT,
7381 }),
7382 SettingsPageItem::SettingItem(SettingItem {
7383 title: "Allow Rewrap",
7384 description: "Controls where the `editor::rewrap` action is allowed for this language.",
7385 field: Box::new(SettingField {
7386 json_path: Some("languages.$(language).allow_rewrap"),
7387 pick: |settings_content| {
7388 language_settings_field(settings_content, |language| {
7389 language.allow_rewrap.as_ref()
7390 })
7391 },
7392 write: |settings_content, value| {
7393 language_settings_field_mut(settings_content, value, |language, value| {
7394 language.allow_rewrap = value;
7395 })
7396 },
7397 }),
7398 metadata: None,
7399 files: USER | PROJECT,
7400 }),
7401 ]
7402 }
7403
7404 fn indent_guides_section() -> [SettingsPageItem; 6] {
7405 [
7406 SettingsPageItem::SectionHeader("Indent Guides"),
7407 SettingsPageItem::SettingItem(SettingItem {
7408 title: "Enabled",
7409 description: "Display indent guides in the editor.",
7410 field: Box::new(SettingField {
7411 json_path: Some("languages.$(language).indent_guides.enabled"),
7412 pick: |settings_content| {
7413 language_settings_field(settings_content, |language| {
7414 language
7415 .indent_guides
7416 .as_ref()
7417 .and_then(|indent_guides| indent_guides.enabled.as_ref())
7418 })
7419 },
7420 write: |settings_content, value| {
7421 language_settings_field_mut(settings_content, value, |language, value| {
7422 language.indent_guides.get_or_insert_default().enabled = value;
7423 })
7424 },
7425 }),
7426 metadata: None,
7427 files: USER | PROJECT,
7428 }),
7429 SettingsPageItem::SettingItem(SettingItem {
7430 title: "Line Width",
7431 description: "The width of the indent guides in pixels, between 1 and 10.",
7432 field: Box::new(SettingField {
7433 json_path: Some("languages.$(language).indent_guides.line_width"),
7434 pick: |settings_content| {
7435 language_settings_field(settings_content, |language| {
7436 language
7437 .indent_guides
7438 .as_ref()
7439 .and_then(|indent_guides| indent_guides.line_width.as_ref())
7440 })
7441 },
7442 write: |settings_content, value| {
7443 language_settings_field_mut(settings_content, value, |language, value| {
7444 language.indent_guides.get_or_insert_default().line_width = value;
7445 })
7446 },
7447 }),
7448 metadata: None,
7449 files: USER | PROJECT,
7450 }),
7451 SettingsPageItem::SettingItem(SettingItem {
7452 title: "Active Line Width",
7453 description: "The width of the active indent guide in pixels, between 1 and 10.",
7454 field: Box::new(SettingField {
7455 json_path: Some("languages.$(language).indent_guides.active_line_width"),
7456 pick: |settings_content| {
7457 language_settings_field(settings_content, |language| {
7458 language
7459 .indent_guides
7460 .as_ref()
7461 .and_then(|indent_guides| indent_guides.active_line_width.as_ref())
7462 })
7463 },
7464 write: |settings_content, value| {
7465 language_settings_field_mut(settings_content, value, |language, value| {
7466 language
7467 .indent_guides
7468 .get_or_insert_default()
7469 .active_line_width = value;
7470 })
7471 },
7472 }),
7473 metadata: None,
7474 files: USER | PROJECT,
7475 }),
7476 SettingsPageItem::SettingItem(SettingItem {
7477 title: "Coloring",
7478 description: "Determines how indent guides are colored.",
7479 field: Box::new(SettingField {
7480 json_path: Some("languages.$(language).indent_guides.coloring"),
7481 pick: |settings_content| {
7482 language_settings_field(settings_content, |language| {
7483 language
7484 .indent_guides
7485 .as_ref()
7486 .and_then(|indent_guides| indent_guides.coloring.as_ref())
7487 })
7488 },
7489 write: |settings_content, value| {
7490 language_settings_field_mut(settings_content, value, |language, value| {
7491 language.indent_guides.get_or_insert_default().coloring = value;
7492 })
7493 },
7494 }),
7495 metadata: None,
7496 files: USER | PROJECT,
7497 }),
7498 SettingsPageItem::SettingItem(SettingItem {
7499 title: "Background Coloring",
7500 description: "Determines how indent guide backgrounds are colored.",
7501 field: Box::new(SettingField {
7502 json_path: Some("languages.$(language).indent_guides.background_coloring"),
7503 pick: |settings_content| {
7504 language_settings_field(settings_content, |language| {
7505 language.indent_guides.as_ref().and_then(|indent_guides| {
7506 indent_guides.background_coloring.as_ref()
7507 })
7508 })
7509 },
7510 write: |settings_content, value| {
7511 language_settings_field_mut(settings_content, value, |language, value| {
7512 language
7513 .indent_guides
7514 .get_or_insert_default()
7515 .background_coloring = value;
7516 })
7517 },
7518 }),
7519 metadata: None,
7520 files: USER | PROJECT,
7521 }),
7522 ]
7523 }
7524
7525 fn formatting_section() -> [SettingsPageItem; 7] {
7526 [
7527 SettingsPageItem::SectionHeader("Formatting"),
7528 SettingsPageItem::SettingItem(SettingItem {
7529 title: "Format On Save",
7530 description: "Whether or not to perform a buffer format before saving.",
7531 field: Box::new(
7532 // TODO(settings_ui): this setting should just be a bool
7533 SettingField {
7534 json_path: Some("languages.$(language).format_on_save"),
7535 pick: |settings_content| {
7536 language_settings_field(settings_content, |language| {
7537 language.format_on_save.as_ref()
7538 })
7539 },
7540 write: |settings_content, value| {
7541 language_settings_field_mut(
7542 settings_content,
7543 value,
7544 |language, value| {
7545 language.format_on_save = value;
7546 },
7547 )
7548 },
7549 },
7550 ),
7551 metadata: None,
7552 files: USER | PROJECT,
7553 }),
7554 SettingsPageItem::SettingItem(SettingItem {
7555 title: "Remove Trailing Whitespace On Save",
7556 description: "Whether or not to remove any trailing whitespace from lines of a buffer before saving it.",
7557 field: Box::new(SettingField {
7558 json_path: Some("languages.$(language).remove_trailing_whitespace_on_save"),
7559 pick: |settings_content| {
7560 language_settings_field(settings_content, |language| {
7561 language.remove_trailing_whitespace_on_save.as_ref()
7562 })
7563 },
7564 write: |settings_content, value| {
7565 language_settings_field_mut(settings_content, value, |language, value| {
7566 language.remove_trailing_whitespace_on_save = value;
7567 })
7568 },
7569 }),
7570 metadata: None,
7571 files: USER | PROJECT,
7572 }),
7573 SettingsPageItem::SettingItem(SettingItem {
7574 title: "Ensure Final Newline On Save",
7575 description: "Whether or not to ensure there's a single newline at the end of a buffer when saving it.",
7576 field: Box::new(SettingField {
7577 json_path: Some("languages.$(language).ensure_final_newline_on_save"),
7578 pick: |settings_content| {
7579 language_settings_field(settings_content, |language| {
7580 language.ensure_final_newline_on_save.as_ref()
7581 })
7582 },
7583 write: |settings_content, value| {
7584 language_settings_field_mut(settings_content, value, |language, value| {
7585 language.ensure_final_newline_on_save = value;
7586 })
7587 },
7588 }),
7589 metadata: None,
7590 files: USER | PROJECT,
7591 }),
7592 SettingsPageItem::SettingItem(SettingItem {
7593 title: "Formatter",
7594 description: "How to perform a buffer format.",
7595 field: Box::new(
7596 SettingField {
7597 json_path: Some("languages.$(language).formatter"),
7598 pick: |settings_content| {
7599 language_settings_field(settings_content, |language| {
7600 language.formatter.as_ref()
7601 })
7602 },
7603 write: |settings_content, value| {
7604 language_settings_field_mut(
7605 settings_content,
7606 value,
7607 |language, value| {
7608 language.formatter = value;
7609 },
7610 )
7611 },
7612 }
7613 .unimplemented(),
7614 ),
7615 metadata: None,
7616 files: USER | PROJECT,
7617 }),
7618 SettingsPageItem::SettingItem(SettingItem {
7619 title: "Use On Type Format",
7620 description: "Whether to use additional LSP queries to format (and amend) the code after every \"trigger\" symbol input, defined by LSP server capabilities",
7621 field: Box::new(SettingField {
7622 json_path: Some("languages.$(language).use_on_type_format"),
7623 pick: |settings_content| {
7624 language_settings_field(settings_content, |language| {
7625 language.use_on_type_format.as_ref()
7626 })
7627 },
7628 write: |settings_content, value| {
7629 language_settings_field_mut(settings_content, value, |language, value| {
7630 language.use_on_type_format = value;
7631 })
7632 },
7633 }),
7634 metadata: None,
7635 files: USER | PROJECT,
7636 }),
7637 SettingsPageItem::SettingItem(SettingItem {
7638 title: "Code Actions On Format",
7639 description: "Additional code actions to run when formatting.",
7640 field: Box::new(
7641 SettingField {
7642 json_path: Some("languages.$(language).code_actions_on_format"),
7643 pick: |settings_content| {
7644 language_settings_field(settings_content, |language| {
7645 language.code_actions_on_format.as_ref()
7646 })
7647 },
7648 write: |settings_content, value| {
7649 language_settings_field_mut(
7650 settings_content,
7651 value,
7652 |language, value| {
7653 language.code_actions_on_format = value;
7654 },
7655 )
7656 },
7657 }
7658 .unimplemented(),
7659 ),
7660 metadata: None,
7661 files: USER | PROJECT,
7662 }),
7663 ]
7664 }
7665
7666 fn autoclose_section() -> [SettingsPageItem; 5] {
7667 [
7668 SettingsPageItem::SectionHeader("Autoclose"),
7669 SettingsPageItem::SettingItem(SettingItem {
7670 title: "Use Autoclose",
7671 description: "Whether to automatically type closing characters for you. For example, when you type '(', Zed will automatically add a closing ')' at the correct position.",
7672 field: Box::new(SettingField {
7673 json_path: Some("languages.$(language).use_autoclose"),
7674 pick: |settings_content| {
7675 language_settings_field(settings_content, |language| {
7676 language.use_autoclose.as_ref()
7677 })
7678 },
7679 write: |settings_content, value| {
7680 language_settings_field_mut(settings_content, value, |language, value| {
7681 language.use_autoclose = value;
7682 })
7683 },
7684 }),
7685 metadata: None,
7686 files: USER | PROJECT,
7687 }),
7688 SettingsPageItem::SettingItem(SettingItem {
7689 title: "Use Auto Surround",
7690 description: "Whether to automatically surround text with characters for you. For example, when you select text and type '(', Zed will automatically surround text with ().",
7691 field: Box::new(SettingField {
7692 json_path: Some("languages.$(language).use_auto_surround"),
7693 pick: |settings_content| {
7694 language_settings_field(settings_content, |language| {
7695 language.use_auto_surround.as_ref()
7696 })
7697 },
7698 write: |settings_content, value| {
7699 language_settings_field_mut(settings_content, value, |language, value| {
7700 language.use_auto_surround = value;
7701 })
7702 },
7703 }),
7704 metadata: None,
7705 files: USER | PROJECT,
7706 }),
7707 SettingsPageItem::SettingItem(SettingItem {
7708 title: "Always Treat Brackets As Autoclosed",
7709 description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted.",
7710 field: Box::new(SettingField {
7711 json_path: Some("languages.$(language).always_treat_brackets_as_autoclosed"),
7712 pick: |settings_content| {
7713 language_settings_field(settings_content, |language| {
7714 language.always_treat_brackets_as_autoclosed.as_ref()
7715 })
7716 },
7717 write: |settings_content, value| {
7718 language_settings_field_mut(settings_content, value, |language, value| {
7719 language.always_treat_brackets_as_autoclosed = value;
7720 })
7721 },
7722 }),
7723 metadata: None,
7724 files: USER | PROJECT,
7725 }),
7726 SettingsPageItem::SettingItem(SettingItem {
7727 title: "JSX Tag Auto Close",
7728 description: "Whether to automatically close JSX tags.",
7729 field: Box::new(SettingField {
7730 json_path: Some("languages.$(language).jsx_tag_auto_close"),
7731 // TODO(settings_ui): this setting should just be a bool
7732 pick: |settings_content| {
7733 language_settings_field(settings_content, |language| {
7734 language.jsx_tag_auto_close.as_ref()?.enabled.as_ref()
7735 })
7736 },
7737 write: |settings_content, value| {
7738 language_settings_field_mut(settings_content, value, |language, value| {
7739 language.jsx_tag_auto_close.get_or_insert_default().enabled = value;
7740 })
7741 },
7742 }),
7743 metadata: None,
7744 files: USER | PROJECT,
7745 }),
7746 ]
7747 }
7748
7749 fn whitespace_section() -> [SettingsPageItem; 4] {
7750 [
7751 SettingsPageItem::SectionHeader("Whitespace"),
7752 SettingsPageItem::SettingItem(SettingItem {
7753 title: "Show Whitespaces",
7754 description: "Whether to show tabs and spaces in the editor.",
7755 field: Box::new(SettingField {
7756 json_path: Some("languages.$(language).show_whitespaces"),
7757 pick: |settings_content| {
7758 language_settings_field(settings_content, |language| {
7759 language.show_whitespaces.as_ref()
7760 })
7761 },
7762 write: |settings_content, value| {
7763 language_settings_field_mut(settings_content, value, |language, value| {
7764 language.show_whitespaces = value;
7765 })
7766 },
7767 }),
7768 metadata: None,
7769 files: USER | PROJECT,
7770 }),
7771 SettingsPageItem::SettingItem(SettingItem {
7772 title: "Space Whitespace Indicator",
7773 description: "Visible character used to render space characters when show_whitespaces is enabled (default: \"•\")",
7774 field: Box::new(
7775 SettingField {
7776 json_path: Some("languages.$(language).whitespace_map.space"),
7777 pick: |settings_content| {
7778 language_settings_field(settings_content, |language| {
7779 language.whitespace_map.as_ref()?.space.as_ref()
7780 })
7781 },
7782 write: |settings_content, value| {
7783 language_settings_field_mut(
7784 settings_content,
7785 value,
7786 |language, value| {
7787 language.whitespace_map.get_or_insert_default().space = value;
7788 },
7789 )
7790 },
7791 }
7792 .unimplemented(),
7793 ),
7794 metadata: None,
7795 files: USER | PROJECT,
7796 }),
7797 SettingsPageItem::SettingItem(SettingItem {
7798 title: "Tab Whitespace Indicator",
7799 description: "Visible character used to render tab characters when show_whitespaces is enabled (default: \"→\")",
7800 field: Box::new(
7801 SettingField {
7802 json_path: Some("languages.$(language).whitespace_map.tab"),
7803 pick: |settings_content| {
7804 language_settings_field(settings_content, |language| {
7805 language.whitespace_map.as_ref()?.tab.as_ref()
7806 })
7807 },
7808 write: |settings_content, value| {
7809 language_settings_field_mut(
7810 settings_content,
7811 value,
7812 |language, value| {
7813 language.whitespace_map.get_or_insert_default().tab = value;
7814 },
7815 )
7816 },
7817 }
7818 .unimplemented(),
7819 ),
7820 metadata: None,
7821 files: USER | PROJECT,
7822 }),
7823 ]
7824 }
7825
7826 fn completions_section() -> [SettingsPageItem; 7] {
7827 [
7828 SettingsPageItem::SectionHeader("Completions"),
7829 SettingsPageItem::SettingItem(SettingItem {
7830 title: "Show Completions On Input",
7831 description: "Whether to pop the completions menu while typing in an editor without explicitly requesting it.",
7832 field: Box::new(SettingField {
7833 json_path: Some("languages.$(language).show_completions_on_input"),
7834 pick: |settings_content| {
7835 language_settings_field(settings_content, |language| {
7836 language.show_completions_on_input.as_ref()
7837 })
7838 },
7839 write: |settings_content, value| {
7840 language_settings_field_mut(settings_content, value, |language, value| {
7841 language.show_completions_on_input = value;
7842 })
7843 },
7844 }),
7845 metadata: None,
7846 files: USER | PROJECT,
7847 }),
7848 SettingsPageItem::SettingItem(SettingItem {
7849 title: "Show Completion Documentation",
7850 description: "Whether to display inline and alongside documentation for items in the completions menu.",
7851 field: Box::new(SettingField {
7852 json_path: Some("languages.$(language).show_completion_documentation"),
7853 pick: |settings_content| {
7854 language_settings_field(settings_content, |language| {
7855 language.show_completion_documentation.as_ref()
7856 })
7857 },
7858 write: |settings_content, value| {
7859 language_settings_field_mut(settings_content, value, |language, value| {
7860 language.show_completion_documentation = value;
7861 })
7862 },
7863 }),
7864 metadata: None,
7865 files: USER | PROJECT,
7866 }),
7867 SettingsPageItem::SettingItem(SettingItem {
7868 title: "Words",
7869 description: "Controls how words are completed.",
7870 field: Box::new(SettingField {
7871 json_path: Some("languages.$(language).completions.words"),
7872 pick: |settings_content| {
7873 language_settings_field(settings_content, |language| {
7874 language.completions.as_ref()?.words.as_ref()
7875 })
7876 },
7877 write: |settings_content, value| {
7878 language_settings_field_mut(settings_content, value, |language, value| {
7879 language.completions.get_or_insert_default().words = value;
7880 })
7881 },
7882 }),
7883 metadata: None,
7884 files: USER | PROJECT,
7885 }),
7886 SettingsPageItem::SettingItem(SettingItem {
7887 title: "Words Min Length",
7888 description: "How many characters has to be in the completions query to automatically show the words-based completions.",
7889 field: Box::new(SettingField {
7890 json_path: Some("languages.$(language).completions.words_min_length"),
7891 pick: |settings_content| {
7892 language_settings_field(settings_content, |language| {
7893 language.completions.as_ref()?.words_min_length.as_ref()
7894 })
7895 },
7896 write: |settings_content, value| {
7897 language_settings_field_mut(settings_content, value, |language, value| {
7898 language
7899 .completions
7900 .get_or_insert_default()
7901 .words_min_length = value;
7902 })
7903 },
7904 }),
7905 metadata: None,
7906 files: USER | PROJECT,
7907 }),
7908 SettingsPageItem::SettingItem(SettingItem {
7909 title: "Completion Menu Scrollbar",
7910 description: "When to show the scrollbar in the completion menu.",
7911 field: Box::new(SettingField {
7912 json_path: Some("editor.completion_menu_scrollbar"),
7913 pick: |settings_content| {
7914 settings_content.editor.completion_menu_scrollbar.as_ref()
7915 },
7916 write: |settings_content, value| {
7917 settings_content.editor.completion_menu_scrollbar = value;
7918 },
7919 }),
7920 metadata: None,
7921 files: USER,
7922 }),
7923 SettingsPageItem::SettingItem(SettingItem {
7924 title: "Completion Detail Alignment",
7925 description: "Whether to align detail text in code completions context menus left or right.",
7926 field: Box::new(SettingField {
7927 json_path: Some("editor.completion_detail_alignment"),
7928 pick: |settings_content| {
7929 settings_content.editor.completion_detail_alignment.as_ref()
7930 },
7931 write: |settings_content, value| {
7932 settings_content.editor.completion_detail_alignment = value;
7933 },
7934 }),
7935 metadata: None,
7936 files: USER,
7937 }),
7938 ]
7939 }
7940
7941 fn inlay_hints_section() -> [SettingsPageItem; 10] {
7942 [
7943 SettingsPageItem::SectionHeader("Inlay Hints"),
7944 SettingsPageItem::SettingItem(SettingItem {
7945 title: "Enabled",
7946 description: "Global switch to toggle hints on and off.",
7947 field: Box::new(SettingField {
7948 json_path: Some("languages.$(language).inlay_hints.enabled"),
7949 pick: |settings_content| {
7950 language_settings_field(settings_content, |language| {
7951 language.inlay_hints.as_ref()?.enabled.as_ref()
7952 })
7953 },
7954 write: |settings_content, value| {
7955 language_settings_field_mut(settings_content, value, |language, value| {
7956 language.inlay_hints.get_or_insert_default().enabled = value;
7957 })
7958 },
7959 }),
7960 metadata: None,
7961 files: USER | PROJECT,
7962 }),
7963 SettingsPageItem::SettingItem(SettingItem {
7964 title: "Show Value Hints",
7965 description: "Global switch to toggle inline values on and off when debugging.",
7966 field: Box::new(SettingField {
7967 json_path: Some("languages.$(language).inlay_hints.show_value_hints"),
7968 pick: |settings_content| {
7969 language_settings_field(settings_content, |language| {
7970 language.inlay_hints.as_ref()?.show_value_hints.as_ref()
7971 })
7972 },
7973 write: |settings_content, value| {
7974 language_settings_field_mut(settings_content, value, |language, value| {
7975 language
7976 .inlay_hints
7977 .get_or_insert_default()
7978 .show_value_hints = value;
7979 })
7980 },
7981 }),
7982 metadata: None,
7983 files: USER | PROJECT,
7984 }),
7985 SettingsPageItem::SettingItem(SettingItem {
7986 title: "Show Type Hints",
7987 description: "Whether type hints should be shown.",
7988 field: Box::new(SettingField {
7989 json_path: Some("languages.$(language).inlay_hints.show_type_hints"),
7990 pick: |settings_content| {
7991 language_settings_field(settings_content, |language| {
7992 language.inlay_hints.as_ref()?.show_type_hints.as_ref()
7993 })
7994 },
7995 write: |settings_content, value| {
7996 language_settings_field_mut(settings_content, value, |language, value| {
7997 language.inlay_hints.get_or_insert_default().show_type_hints = value;
7998 })
7999 },
8000 }),
8001 metadata: None,
8002 files: USER | PROJECT,
8003 }),
8004 SettingsPageItem::SettingItem(SettingItem {
8005 title: "Show Parameter Hints",
8006 description: "Whether parameter hints should be shown.",
8007 field: Box::new(SettingField {
8008 json_path: Some("languages.$(language).inlay_hints.show_parameter_hints"),
8009 pick: |settings_content| {
8010 language_settings_field(settings_content, |language| {
8011 language.inlay_hints.as_ref()?.show_parameter_hints.as_ref()
8012 })
8013 },
8014 write: |settings_content, value| {
8015 language_settings_field_mut(settings_content, value, |language, value| {
8016 language
8017 .inlay_hints
8018 .get_or_insert_default()
8019 .show_parameter_hints = value;
8020 })
8021 },
8022 }),
8023 metadata: None,
8024 files: USER | PROJECT,
8025 }),
8026 SettingsPageItem::SettingItem(SettingItem {
8027 title: "Show Other Hints",
8028 description: "Whether other hints should be shown.",
8029 field: Box::new(SettingField {
8030 json_path: Some("languages.$(language).inlay_hints.show_other_hints"),
8031 pick: |settings_content| {
8032 language_settings_field(settings_content, |language| {
8033 language.inlay_hints.as_ref()?.show_other_hints.as_ref()
8034 })
8035 },
8036 write: |settings_content, value| {
8037 language_settings_field_mut(settings_content, value, |language, value| {
8038 language
8039 .inlay_hints
8040 .get_or_insert_default()
8041 .show_other_hints = value;
8042 })
8043 },
8044 }),
8045 metadata: None,
8046 files: USER | PROJECT,
8047 }),
8048 SettingsPageItem::SettingItem(SettingItem {
8049 title: "Show Background",
8050 description: "Show a background for inlay hints.",
8051 field: Box::new(SettingField {
8052 json_path: Some("languages.$(language).inlay_hints.show_background"),
8053 pick: |settings_content| {
8054 language_settings_field(settings_content, |language| {
8055 language.inlay_hints.as_ref()?.show_background.as_ref()
8056 })
8057 },
8058 write: |settings_content, value| {
8059 language_settings_field_mut(settings_content, value, |language, value| {
8060 language.inlay_hints.get_or_insert_default().show_background = value;
8061 })
8062 },
8063 }),
8064 metadata: None,
8065 files: USER | PROJECT,
8066 }),
8067 SettingsPageItem::SettingItem(SettingItem {
8068 title: "Edit Debounce Ms",
8069 description: "Whether or not to debounce inlay hints updates after buffer edits (set to 0 to disable debouncing).",
8070 field: Box::new(SettingField {
8071 json_path: Some("languages.$(language).inlay_hints.edit_debounce_ms"),
8072 pick: |settings_content| {
8073 language_settings_field(settings_content, |language| {
8074 language.inlay_hints.as_ref()?.edit_debounce_ms.as_ref()
8075 })
8076 },
8077 write: |settings_content, value| {
8078 language_settings_field_mut(settings_content, value, |language, value| {
8079 language
8080 .inlay_hints
8081 .get_or_insert_default()
8082 .edit_debounce_ms = value;
8083 })
8084 },
8085 }),
8086 metadata: None,
8087 files: USER | PROJECT,
8088 }),
8089 SettingsPageItem::SettingItem(SettingItem {
8090 title: "Scroll Debounce Ms",
8091 description: "Whether or not to debounce inlay hints updates after buffer scrolls (set to 0 to disable debouncing).",
8092 field: Box::new(SettingField {
8093 json_path: Some("languages.$(language).inlay_hints.scroll_debounce_ms"),
8094 pick: |settings_content| {
8095 language_settings_field(settings_content, |language| {
8096 language.inlay_hints.as_ref()?.scroll_debounce_ms.as_ref()
8097 })
8098 },
8099 write: |settings_content, value| {
8100 language_settings_field_mut(settings_content, value, |language, value| {
8101 language
8102 .inlay_hints
8103 .get_or_insert_default()
8104 .scroll_debounce_ms = value;
8105 })
8106 },
8107 }),
8108 metadata: None,
8109 files: USER | PROJECT,
8110 }),
8111 SettingsPageItem::SettingItem(SettingItem {
8112 title: "Toggle On Modifiers Press",
8113 description: "Toggles inlay hints (hides or shows) when the user presses the modifiers specified.",
8114 field: Box::new(
8115 SettingField {
8116 json_path: Some(
8117 "languages.$(language).inlay_hints.toggle_on_modifiers_press",
8118 ),
8119 pick: |settings_content| {
8120 language_settings_field(settings_content, |language| {
8121 language
8122 .inlay_hints
8123 .as_ref()?
8124 .toggle_on_modifiers_press
8125 .as_ref()
8126 })
8127 },
8128 write: |settings_content, value| {
8129 language_settings_field_mut(
8130 settings_content,
8131 value,
8132 |language, value| {
8133 language
8134 .inlay_hints
8135 .get_or_insert_default()
8136 .toggle_on_modifiers_press = value;
8137 },
8138 )
8139 },
8140 }
8141 .unimplemented(),
8142 ),
8143 metadata: None,
8144 files: USER | PROJECT,
8145 }),
8146 ]
8147 }
8148
8149 fn tasks_section() -> [SettingsPageItem; 4] {
8150 [
8151 SettingsPageItem::SectionHeader("Tasks"),
8152 SettingsPageItem::SettingItem(SettingItem {
8153 title: "Enabled",
8154 description: "Whether tasks are enabled for this language.",
8155 field: Box::new(SettingField {
8156 json_path: Some("languages.$(language).tasks.enabled"),
8157 pick: |settings_content| {
8158 language_settings_field(settings_content, |language| {
8159 language.tasks.as_ref()?.enabled.as_ref()
8160 })
8161 },
8162 write: |settings_content, value| {
8163 language_settings_field_mut(settings_content, value, |language, value| {
8164 language.tasks.get_or_insert_default().enabled = value;
8165 })
8166 },
8167 }),
8168 metadata: None,
8169 files: USER | PROJECT,
8170 }),
8171 SettingsPageItem::SettingItem(SettingItem {
8172 title: "Variables",
8173 description: "Extra task variables to set for a particular language.",
8174 field: Box::new(
8175 SettingField {
8176 json_path: Some("languages.$(language).tasks.variables"),
8177 pick: |settings_content| {
8178 language_settings_field(settings_content, |language| {
8179 language.tasks.as_ref()?.variables.as_ref()
8180 })
8181 },
8182 write: |settings_content, value| {
8183 language_settings_field_mut(
8184 settings_content,
8185 value,
8186 |language, value| {
8187 language.tasks.get_or_insert_default().variables = value;
8188 },
8189 )
8190 },
8191 }
8192 .unimplemented(),
8193 ),
8194 metadata: None,
8195 files: USER | PROJECT,
8196 }),
8197 SettingsPageItem::SettingItem(SettingItem {
8198 title: "Prefer LSP",
8199 description: "Use LSP tasks over Zed language extension tasks.",
8200 field: Box::new(SettingField {
8201 json_path: Some("languages.$(language).tasks.prefer_lsp"),
8202 pick: |settings_content| {
8203 language_settings_field(settings_content, |language| {
8204 language.tasks.as_ref()?.prefer_lsp.as_ref()
8205 })
8206 },
8207 write: |settings_content, value| {
8208 language_settings_field_mut(settings_content, value, |language, value| {
8209 language.tasks.get_or_insert_default().prefer_lsp = value;
8210 })
8211 },
8212 }),
8213 metadata: None,
8214 files: USER | PROJECT,
8215 }),
8216 ]
8217 }
8218
8219 fn miscellaneous_section() -> [SettingsPageItem; 6] {
8220 [
8221 SettingsPageItem::SectionHeader("Miscellaneous"),
8222 SettingsPageItem::SettingItem(SettingItem {
8223 title: "Word Diff Enabled",
8224 description: "Whether to enable word diff highlighting in the editor. When enabled, changed words within modified lines are highlighted to show exactly what changed.",
8225 field: Box::new(SettingField {
8226 json_path: Some("languages.$(language).word_diff_enabled"),
8227 pick: |settings_content| {
8228 language_settings_field(settings_content, |language| {
8229 language.word_diff_enabled.as_ref()
8230 })
8231 },
8232 write: |settings_content, value| {
8233 language_settings_field_mut(settings_content, value, |language, value| {
8234 language.word_diff_enabled = value;
8235 })
8236 },
8237 }),
8238 metadata: None,
8239 files: USER | PROJECT,
8240 }),
8241 SettingsPageItem::SettingItem(SettingItem {
8242 title: "Debuggers",
8243 description: "Preferred debuggers for this language.",
8244 field: Box::new(
8245 SettingField {
8246 json_path: Some("languages.$(language).debuggers"),
8247 pick: |settings_content| {
8248 language_settings_field(settings_content, |language| {
8249 language.debuggers.as_ref()
8250 })
8251 },
8252 write: |settings_content, value| {
8253 language_settings_field_mut(
8254 settings_content,
8255 value,
8256 |language, value| {
8257 language.debuggers = value;
8258 },
8259 )
8260 },
8261 }
8262 .unimplemented(),
8263 ),
8264 metadata: None,
8265 files: USER | PROJECT,
8266 }),
8267 SettingsPageItem::SettingItem(SettingItem {
8268 title: "Middle Click Paste",
8269 description: "Enable middle-click paste on Linux.",
8270 field: Box::new(SettingField {
8271 json_path: Some("languages.$(language).editor.middle_click_paste"),
8272 pick: |settings_content| settings_content.editor.middle_click_paste.as_ref(),
8273 write: |settings_content, value| {
8274 settings_content.editor.middle_click_paste = value;
8275 },
8276 }),
8277 metadata: None,
8278 files: USER,
8279 }),
8280 SettingsPageItem::SettingItem(SettingItem {
8281 title: "Extend Comment On Newline",
8282 description: "Whether to start a new line with a comment when a previous line is a comment as well.",
8283 field: Box::new(SettingField {
8284 json_path: Some("languages.$(language).extend_comment_on_newline"),
8285 pick: |settings_content| {
8286 language_settings_field(settings_content, |language| {
8287 language.extend_comment_on_newline.as_ref()
8288 })
8289 },
8290 write: |settings_content, value| {
8291 language_settings_field_mut(settings_content, value, |language, value| {
8292 language.extend_comment_on_newline = value;
8293 })
8294 },
8295 }),
8296 metadata: None,
8297 files: USER | PROJECT,
8298 }),
8299 SettingsPageItem::SettingItem(SettingItem {
8300 title: "Colorize Brackets",
8301 description: "Whether to colorize brackets in the editor.",
8302 field: Box::new(SettingField {
8303 json_path: Some("languages.$(language).colorize_brackets"),
8304 pick: |settings_content| {
8305 language_settings_field(settings_content, |language| {
8306 language.colorize_brackets.as_ref()
8307 })
8308 },
8309 write: |settings_content, value| {
8310 language_settings_field_mut(settings_content, value, |language, value| {
8311 language.colorize_brackets = value;
8312 })
8313 },
8314 }),
8315 metadata: None,
8316 files: USER | PROJECT,
8317 }),
8318 ]
8319 }
8320
8321 fn global_only_miscellaneous_sub_section() -> [SettingsPageItem; 3] {
8322 [
8323 SettingsPageItem::SettingItem(SettingItem {
8324 title: "Image Viewer",
8325 description: "The unit for image file sizes.",
8326 field: Box::new(SettingField {
8327 json_path: Some("image_viewer.unit"),
8328 pick: |settings_content| {
8329 settings_content
8330 .image_viewer
8331 .as_ref()
8332 .and_then(|image_viewer| image_viewer.unit.as_ref())
8333 },
8334 write: |settings_content, value| {
8335 settings_content.image_viewer.get_or_insert_default().unit = value;
8336 },
8337 }),
8338 metadata: None,
8339 files: USER,
8340 }),
8341 SettingsPageItem::SettingItem(SettingItem {
8342 title: "Auto Replace Emoji Shortcode",
8343 description: "Whether to automatically replace emoji shortcodes with emoji characters.",
8344 field: Box::new(SettingField {
8345 json_path: Some("message_editor.auto_replace_emoji_shortcode"),
8346 pick: |settings_content| {
8347 settings_content
8348 .message_editor
8349 .as_ref()
8350 .and_then(|message_editor| {
8351 message_editor.auto_replace_emoji_shortcode.as_ref()
8352 })
8353 },
8354 write: |settings_content, value| {
8355 settings_content
8356 .message_editor
8357 .get_or_insert_default()
8358 .auto_replace_emoji_shortcode = value;
8359 },
8360 }),
8361 metadata: None,
8362 files: USER,
8363 }),
8364 SettingsPageItem::SettingItem(SettingItem {
8365 title: "Drop Size Target",
8366 description: "Relative size of the drop target in the editor that will open dropped file as a split pane.",
8367 field: Box::new(SettingField {
8368 json_path: Some("drop_target_size"),
8369 pick: |settings_content| settings_content.workspace.drop_target_size.as_ref(),
8370 write: |settings_content, value| {
8371 settings_content.workspace.drop_target_size = value;
8372 },
8373 }),
8374 metadata: None,
8375 files: USER,
8376 }),
8377 ]
8378 }
8379
8380 let is_global = active_language().is_none();
8381
8382 let lsp_document_colors_item = [SettingsPageItem::SettingItem(SettingItem {
8383 title: "LSP Document Colors",
8384 description: "How to render LSP color previews in the editor.",
8385 field: Box::new(SettingField {
8386 json_path: Some("lsp_document_colors"),
8387 pick: |settings_content| settings_content.editor.lsp_document_colors.as_ref(),
8388 write: |settings_content, value| {
8389 settings_content.editor.lsp_document_colors = value;
8390 },
8391 }),
8392 metadata: None,
8393 files: USER,
8394 })];
8395
8396 if is_global {
8397 concat_sections!(
8398 indentation_section(),
8399 wrapping_section(),
8400 indent_guides_section(),
8401 formatting_section(),
8402 autoclose_section(),
8403 whitespace_section(),
8404 completions_section(),
8405 inlay_hints_section(),
8406 lsp_document_colors_item,
8407 tasks_section(),
8408 miscellaneous_section(),
8409 global_only_miscellaneous_sub_section(),
8410 )
8411 } else {
8412 concat_sections!(
8413 indentation_section(),
8414 wrapping_section(),
8415 indent_guides_section(),
8416 formatting_section(),
8417 autoclose_section(),
8418 whitespace_section(),
8419 completions_section(),
8420 inlay_hints_section(),
8421 tasks_section(),
8422 miscellaneous_section(),
8423 )
8424 }
8425}
8426
8427/// LanguageSettings items that should be included in the "Languages & Tools" page
8428/// not the "Editor" page
8429fn non_editor_language_settings_data() -> Box<[SettingsPageItem]> {
8430 fn lsp_section() -> [SettingsPageItem; 5] {
8431 [
8432 SettingsPageItem::SectionHeader("LSP"),
8433 SettingsPageItem::SettingItem(SettingItem {
8434 title: "Enable Language Server",
8435 description: "Whether to use language servers to provide code intelligence.",
8436 field: Box::new(SettingField {
8437 json_path: Some("languages.$(language).enable_language_server"),
8438 pick: |settings_content| {
8439 language_settings_field(settings_content, |language| {
8440 language.enable_language_server.as_ref()
8441 })
8442 },
8443 write: |settings_content, value| {
8444 language_settings_field_mut(settings_content, value, |language, value| {
8445 language.enable_language_server = value;
8446 })
8447 },
8448 }),
8449 metadata: None,
8450 files: USER | PROJECT,
8451 }),
8452 SettingsPageItem::SettingItem(SettingItem {
8453 title: "Language Servers",
8454 description: "The list of language servers to use (or disable) for this language.",
8455 field: Box::new(
8456 SettingField {
8457 json_path: Some("languages.$(language).language_servers"),
8458 pick: |settings_content| {
8459 language_settings_field(settings_content, |language| {
8460 language.language_servers.as_ref()
8461 })
8462 },
8463 write: |settings_content, value| {
8464 language_settings_field_mut(
8465 settings_content,
8466 value,
8467 |language, value| {
8468 language.language_servers = value;
8469 },
8470 )
8471 },
8472 }
8473 .unimplemented(),
8474 ),
8475 metadata: None,
8476 files: USER | PROJECT,
8477 }),
8478 SettingsPageItem::SettingItem(SettingItem {
8479 title: "Linked Edits",
8480 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.",
8481 field: Box::new(SettingField {
8482 json_path: Some("languages.$(language).linked_edits"),
8483 pick: |settings_content| {
8484 language_settings_field(settings_content, |language| {
8485 language.linked_edits.as_ref()
8486 })
8487 },
8488 write: |settings_content, value| {
8489 language_settings_field_mut(settings_content, value, |language, value| {
8490 language.linked_edits = value;
8491 })
8492 },
8493 }),
8494 metadata: None,
8495 files: USER | PROJECT,
8496 }),
8497 SettingsPageItem::SettingItem(SettingItem {
8498 title: "Go To Definition Fallback",
8499 description: "Whether to follow-up empty Go to definition responses from the language server.",
8500 field: Box::new(SettingField {
8501 json_path: Some("go_to_definition_fallback"),
8502 pick: |settings_content| {
8503 settings_content.editor.go_to_definition_fallback.as_ref()
8504 },
8505 write: |settings_content, value| {
8506 settings_content.editor.go_to_definition_fallback = value;
8507 },
8508 }),
8509 metadata: None,
8510 files: USER,
8511 }),
8512 ]
8513 }
8514
8515 fn lsp_completions_section() -> [SettingsPageItem; 4] {
8516 [
8517 SettingsPageItem::SectionHeader("LSP Completions"),
8518 SettingsPageItem::SettingItem(SettingItem {
8519 title: "Enabled",
8520 description: "Whether to fetch LSP completions or not.",
8521 field: Box::new(SettingField {
8522 json_path: Some("languages.$(language).completions.lsp"),
8523 pick: |settings_content| {
8524 language_settings_field(settings_content, |language| {
8525 language.completions.as_ref()?.lsp.as_ref()
8526 })
8527 },
8528 write: |settings_content, value| {
8529 language_settings_field_mut(settings_content, value, |language, value| {
8530 language.completions.get_or_insert_default().lsp = value;
8531 })
8532 },
8533 }),
8534 metadata: None,
8535 files: USER | PROJECT,
8536 }),
8537 SettingsPageItem::SettingItem(SettingItem {
8538 title: "Fetch Timeout (milliseconds)",
8539 description: "When fetching LSP completions, determines how long to wait for a response of a particular server (set to 0 to wait indefinitely).",
8540 field: Box::new(SettingField {
8541 json_path: Some("languages.$(language).completions.lsp_fetch_timeout_ms"),
8542 pick: |settings_content| {
8543 language_settings_field(settings_content, |language| {
8544 language.completions.as_ref()?.lsp_fetch_timeout_ms.as_ref()
8545 })
8546 },
8547 write: |settings_content, value| {
8548 language_settings_field_mut(settings_content, value, |language, value| {
8549 language
8550 .completions
8551 .get_or_insert_default()
8552 .lsp_fetch_timeout_ms = value;
8553 })
8554 },
8555 }),
8556 metadata: None,
8557 files: USER | PROJECT,
8558 }),
8559 SettingsPageItem::SettingItem(SettingItem {
8560 title: "Insert Mode",
8561 description: "Controls how LSP completions are inserted.",
8562 field: Box::new(SettingField {
8563 json_path: Some("languages.$(language).completions.lsp_insert_mode"),
8564 pick: |settings_content| {
8565 language_settings_field(settings_content, |language| {
8566 language.completions.as_ref()?.lsp_insert_mode.as_ref()
8567 })
8568 },
8569 write: |settings_content, value| {
8570 language_settings_field_mut(settings_content, value, |language, value| {
8571 language.completions.get_or_insert_default().lsp_insert_mode = value;
8572 })
8573 },
8574 }),
8575 metadata: None,
8576 files: USER | PROJECT,
8577 }),
8578 ]
8579 }
8580
8581 fn debugger_section() -> [SettingsPageItem; 2] {
8582 [
8583 SettingsPageItem::SectionHeader("Debuggers"),
8584 SettingsPageItem::SettingItem(SettingItem {
8585 title: "Debuggers",
8586 description: "Preferred debuggers for this language.",
8587 field: Box::new(
8588 SettingField {
8589 json_path: Some("languages.$(language).debuggers"),
8590 pick: |settings_content| {
8591 language_settings_field(settings_content, |language| {
8592 language.debuggers.as_ref()
8593 })
8594 },
8595 write: |settings_content, value| {
8596 language_settings_field_mut(
8597 settings_content,
8598 value,
8599 |language, value| {
8600 language.debuggers = value;
8601 },
8602 )
8603 },
8604 }
8605 .unimplemented(),
8606 ),
8607 metadata: None,
8608 files: USER | PROJECT,
8609 }),
8610 ]
8611 }
8612
8613 fn prettier_section() -> [SettingsPageItem; 5] {
8614 [
8615 SettingsPageItem::SectionHeader("Prettier"),
8616 SettingsPageItem::SettingItem(SettingItem {
8617 title: "Allowed",
8618 description: "Enables or disables formatting with Prettier for a given language.",
8619 field: Box::new(SettingField {
8620 json_path: Some("languages.$(language).prettier.allowed"),
8621 pick: |settings_content| {
8622 language_settings_field(settings_content, |language| {
8623 language.prettier.as_ref()?.allowed.as_ref()
8624 })
8625 },
8626 write: |settings_content, value| {
8627 language_settings_field_mut(settings_content, value, |language, value| {
8628 language.prettier.get_or_insert_default().allowed = value;
8629 })
8630 },
8631 }),
8632 metadata: None,
8633 files: USER | PROJECT,
8634 }),
8635 SettingsPageItem::SettingItem(SettingItem {
8636 title: "Parser",
8637 description: "Forces Prettier integration to use a specific parser name when formatting files with the language.",
8638 field: Box::new(SettingField {
8639 json_path: Some("languages.$(language).prettier.parser"),
8640 pick: |settings_content| {
8641 language_settings_field(settings_content, |language| {
8642 language.prettier.as_ref()?.parser.as_ref()
8643 })
8644 },
8645 write: |settings_content, value| {
8646 language_settings_field_mut(settings_content, value, |language, value| {
8647 language.prettier.get_or_insert_default().parser = value;
8648 })
8649 },
8650 }),
8651 metadata: None,
8652 files: USER | PROJECT,
8653 }),
8654 SettingsPageItem::SettingItem(SettingItem {
8655 title: "Plugins",
8656 description: "Forces Prettier integration to use specific plugins when formatting files with the language.",
8657 field: Box::new(
8658 SettingField {
8659 json_path: Some("languages.$(language).prettier.plugins"),
8660 pick: |settings_content| {
8661 language_settings_field(settings_content, |language| {
8662 language.prettier.as_ref()?.plugins.as_ref()
8663 })
8664 },
8665 write: |settings_content, value| {
8666 language_settings_field_mut(
8667 settings_content,
8668 value,
8669 |language, value| {
8670 language.prettier.get_or_insert_default().plugins = value;
8671 },
8672 )
8673 },
8674 }
8675 .unimplemented(),
8676 ),
8677 metadata: None,
8678 files: USER | PROJECT,
8679 }),
8680 SettingsPageItem::SettingItem(SettingItem {
8681 title: "Options",
8682 description: "Default Prettier options, in the format as in package.json section for Prettier.",
8683 field: Box::new(
8684 SettingField {
8685 json_path: Some("languages.$(language).prettier.options"),
8686 pick: |settings_content| {
8687 language_settings_field(settings_content, |language| {
8688 language.prettier.as_ref()?.options.as_ref()
8689 })
8690 },
8691 write: |settings_content, value| {
8692 language_settings_field_mut(
8693 settings_content,
8694 value,
8695 |language, value| {
8696 language.prettier.get_or_insert_default().options = value;
8697 },
8698 )
8699 },
8700 }
8701 .unimplemented(),
8702 ),
8703 metadata: None,
8704 files: USER | PROJECT,
8705 }),
8706 ]
8707 }
8708
8709 concat_sections!(
8710 lsp_section(),
8711 lsp_completions_section(),
8712 debugger_section(),
8713 prettier_section(),
8714 )
8715}
8716
8717fn edit_prediction_language_settings_section() -> [SettingsPageItem; 4] {
8718 [
8719 SettingsPageItem::SectionHeader("Edit Predictions"),
8720 SettingsPageItem::SubPageLink(SubPageLink {
8721 title: "Configure Providers".into(),
8722 r#type: Default::default(),
8723 json_path: Some("edit_predictions.providers"),
8724 description: Some("Set up different edit prediction providers in complement to Zed's built-in Zeta model.".into()),
8725 in_json: false,
8726 files: USER,
8727 render: render_edit_prediction_setup_page
8728 }),
8729 SettingsPageItem::SettingItem(SettingItem {
8730 title: "Show Edit Predictions",
8731 description: "Controls whether edit predictions are shown immediately or manually.",
8732 field: Box::new(SettingField {
8733 json_path: Some("languages.$(language).show_edit_predictions"),
8734 pick: |settings_content| {
8735 language_settings_field(settings_content, |language| {
8736 language.show_edit_predictions.as_ref()
8737 })
8738 },
8739 write: |settings_content, value| {
8740 language_settings_field_mut(settings_content, value, |language, value| {
8741 language.show_edit_predictions = value;
8742 })
8743 },
8744 }),
8745 metadata: None,
8746 files: USER | PROJECT,
8747 }),
8748 SettingsPageItem::SettingItem(SettingItem {
8749 title: "Disable in Language Scopes",
8750 description: "Controls whether edit predictions are shown in the given language scopes.",
8751 field: Box::new(
8752 SettingField {
8753 json_path: Some("languages.$(language).edit_predictions_disabled_in"),
8754 pick: |settings_content| {
8755 language_settings_field(settings_content, |language| {
8756 language.edit_predictions_disabled_in.as_ref()
8757 })
8758 },
8759 write: |settings_content, value| {
8760 language_settings_field_mut(settings_content, value, |language, value| {
8761 language.edit_predictions_disabled_in = value;
8762 })
8763 },
8764 }
8765 .unimplemented(),
8766 ),
8767 metadata: None,
8768 files: USER | PROJECT,
8769 }),
8770 ]
8771}
8772
8773fn show_scrollbar_or_editor(
8774 settings_content: &SettingsContent,
8775 show: fn(&SettingsContent) -> Option<&settings::ShowScrollbar>,
8776) -> Option<&settings::ShowScrollbar> {
8777 show(settings_content).or(settings_content
8778 .editor
8779 .scrollbar
8780 .as_ref()
8781 .and_then(|scrollbar| scrollbar.show.as_ref()))
8782}
8783
8784fn dynamic_variants<T>() -> &'static [T::Discriminant]
8785where
8786 T: strum::IntoDiscriminant,
8787 T::Discriminant: strum::VariantArray,
8788{
8789 <<T as strum::IntoDiscriminant>::Discriminant as strum::VariantArray>::VARIANTS
8790}