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