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