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