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