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: "Controls line number display in the editor's gutter. \"disabled\" shows absolute line numbers, \"enabled\" shows relative line numbers for each absolute line, and \"wrapped\" shows relative line numbers for every line, absolute or wrapped.",
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: "Center on Match",
2455 description: "Whether to center the current match in the editor",
2456 field: Box::new(SettingField {
2457 json_path: Some("editor.search.center_on_match"),
2458 pick: |settings_content| {
2459 settings_content
2460 .editor
2461 .search
2462 .as_ref()
2463 .and_then(|search| search.center_on_match.as_ref())
2464 },
2465 write: |settings_content, value| {
2466 settings_content
2467 .editor
2468 .search
2469 .get_or_insert_default()
2470 .center_on_match = value;
2471 },
2472 }),
2473 metadata: None,
2474 files: USER,
2475 }),
2476 SettingsPageItem::SettingItem(SettingItem {
2477 title: "Seed Search Query From Cursor",
2478 description: "When to populate a new search's query based on the text under the cursor.",
2479 field: Box::new(SettingField {
2480 json_path: Some("seed_search_query_from_cursor"),
2481 pick: |settings_content| {
2482 settings_content
2483 .editor
2484 .seed_search_query_from_cursor
2485 .as_ref()
2486 },
2487 write: |settings_content, value| {
2488 settings_content.editor.seed_search_query_from_cursor = value;
2489 },
2490 }),
2491 metadata: None,
2492 files: USER,
2493 }),
2494 SettingsPageItem::SectionHeader("File Finder"),
2495 // todo: null by default
2496 SettingsPageItem::SettingItem(SettingItem {
2497 title: "Include Ignored in Search",
2498 description: "Use gitignored files when searching.",
2499 field: Box::new(
2500 SettingField {
2501 json_path: Some("file_finder.include_ignored"),
2502 pick: |settings_content| {
2503 settings_content
2504 .file_finder
2505 .as_ref()?
2506 .include_ignored
2507 .as_ref()
2508 },
2509 write: |settings_content, value| {
2510 settings_content
2511 .file_finder
2512 .get_or_insert_default()
2513 .include_ignored = value;
2514 },
2515 }
2516 ),
2517 metadata: None,
2518 files: USER,
2519 }),
2520 SettingsPageItem::SettingItem(SettingItem {
2521 title: "File Icons",
2522 description: "Show file icons in the file finder.",
2523 field: Box::new(SettingField {
2524 json_path: Some("file_finder.file_icons"),
2525 pick: |settings_content| {
2526 settings_content.file_finder.as_ref()?.file_icons.as_ref()
2527 },
2528 write: |settings_content, value| {
2529 settings_content
2530 .file_finder
2531 .get_or_insert_default()
2532 .file_icons = value;
2533 },
2534 }),
2535 metadata: None,
2536 files: USER,
2537 }),
2538 SettingsPageItem::SettingItem(SettingItem {
2539 title: "Modal Max Width",
2540 description: "Determines how much space the file finder can take up in relation to the available window width.",
2541 field: Box::new(SettingField {
2542 json_path: Some("file_finder.modal_max_width"),
2543 pick: |settings_content| {
2544 settings_content
2545 .file_finder
2546 .as_ref()?
2547 .modal_max_width
2548 .as_ref()
2549 },
2550 write: |settings_content, value| {
2551 settings_content
2552 .file_finder
2553 .get_or_insert_default()
2554 .modal_max_width = value;
2555 },
2556 }),
2557 metadata: None,
2558 files: USER,
2559 }),
2560 SettingsPageItem::SettingItem(SettingItem {
2561 title: "Skip Focus For Active In Search",
2562 description: "Whether the file finder should skip focus for the active file in search results.",
2563 field: Box::new(SettingField {
2564 json_path: Some("file_finder.skip_focus_for_active_in_search"),
2565 pick: |settings_content| {
2566 settings_content
2567 .file_finder
2568 .as_ref()?
2569 .skip_focus_for_active_in_search
2570 .as_ref()
2571 },
2572 write: |settings_content, value| {
2573 settings_content
2574 .file_finder
2575 .get_or_insert_default()
2576 .skip_focus_for_active_in_search = value;
2577 },
2578 }),
2579 metadata: None,
2580 files: USER,
2581 }),
2582 SettingsPageItem::SettingItem(SettingItem {
2583 title: "Git Status",
2584 description: "Show the Git status in the file finder.",
2585 field: Box::new(SettingField {
2586 json_path: Some("file_finder.git_status"),
2587 pick: |settings_content| {
2588 settings_content.file_finder.as_ref()?.git_status.as_ref()
2589 },
2590 write: |settings_content, value| {
2591 settings_content
2592 .file_finder
2593 .get_or_insert_default()
2594 .git_status = value;
2595 },
2596 }),
2597 metadata: None,
2598 files: USER,
2599 }),
2600 SettingsPageItem::SectionHeader("File Scan"),
2601 SettingsPageItem::SettingItem(SettingItem {
2602 title: "File Scan Exclusions",
2603 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\"",
2604 field: Box::new(
2605 SettingField {
2606 json_path: Some("file_scan_exclusions"),
2607 pick: |settings_content| {
2608 settings_content
2609 .project
2610 .worktree
2611 .file_scan_exclusions
2612 .as_ref()
2613 },
2614 write: |settings_content, value| {
2615 settings_content.project.worktree.file_scan_exclusions = value;
2616 },
2617 }
2618 .unimplemented(),
2619 ),
2620 metadata: None,
2621 files: USER,
2622 }),
2623 SettingsPageItem::SettingItem(SettingItem {
2624 title: "File Scan Inclusions",
2625 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",
2626 field: Box::new(
2627 SettingField {
2628 json_path: Some("file_scan_inclusions"),
2629 pick: |settings_content| {
2630 settings_content
2631 .project
2632 .worktree
2633 .file_scan_inclusions
2634 .as_ref()
2635 },
2636 write: |settings_content, value| {
2637 settings_content.project.worktree.file_scan_inclusions = value;
2638 },
2639 }
2640 .unimplemented(),
2641 ),
2642 metadata: None,
2643 files: USER,
2644 }),
2645 SettingsPageItem::SettingItem(SettingItem {
2646 title: "Restore File State",
2647 description: "Restore previous file state when reopening.",
2648 field: Box::new(SettingField {
2649 json_path: Some("restore_on_file_reopen"),
2650 pick: |settings_content| {
2651 settings_content.workspace.restore_on_file_reopen.as_ref()
2652 },
2653 write: |settings_content, value| {
2654 settings_content.workspace.restore_on_file_reopen = value;
2655 },
2656 }),
2657 metadata: None,
2658 files: USER,
2659 }),
2660 SettingsPageItem::SettingItem(SettingItem {
2661 title: "Close on File Delete",
2662 description: "Automatically close files that have been deleted.",
2663 field: Box::new(SettingField {
2664 json_path: Some("close_on_file_delete"),
2665 pick: |settings_content| {
2666 settings_content.workspace.close_on_file_delete.as_ref()
2667 },
2668 write: |settings_content, value| {
2669 settings_content.workspace.close_on_file_delete = value;
2670 },
2671 }),
2672 metadata: None,
2673 files: USER,
2674 }),
2675 ],
2676 },
2677 SettingsPage {
2678 title: "Window & Layout",
2679 items: vec![
2680 SettingsPageItem::SectionHeader("Status Bar"),
2681 SettingsPageItem::SettingItem(SettingItem {
2682 title: "Project Panel Button",
2683 description: "Show the project panel button in the status bar.",
2684 field: Box::new(SettingField {
2685 json_path: Some("project_panel.button"),
2686 pick: |settings_content| {
2687 settings_content.project_panel.as_ref()?.button.as_ref()
2688 },
2689 write: |settings_content, value| {
2690 settings_content
2691 .project_panel
2692 .get_or_insert_default()
2693 .button = value;
2694 },
2695 }),
2696 metadata: None,
2697 files: USER,
2698 }),
2699 SettingsPageItem::SettingItem(SettingItem {
2700 title: "Active Language Button",
2701 description: "Show the active language button in the status bar.",
2702 field: Box::new(SettingField {
2703 json_path: Some("status_bar.active_language_button"),
2704 pick: |settings_content| {
2705 settings_content
2706 .status_bar
2707 .as_ref()?
2708 .active_language_button
2709 .as_ref()
2710 },
2711 write: |settings_content, value| {
2712 settings_content
2713 .status_bar
2714 .get_or_insert_default()
2715 .active_language_button = value;
2716 },
2717 }),
2718 metadata: None,
2719 files: USER,
2720 }),
2721 SettingsPageItem::SettingItem(SettingItem {
2722 title: "Cursor Position Button",
2723 description: "Show the cursor position button in the status bar.",
2724 field: Box::new(SettingField {
2725 json_path: Some("status_bar.cursor_position_button"),
2726 pick: |settings_content| {
2727 settings_content
2728 .status_bar
2729 .as_ref()?
2730 .cursor_position_button
2731 .as_ref()
2732 },
2733 write: |settings_content, value| {
2734 settings_content
2735 .status_bar
2736 .get_or_insert_default()
2737 .cursor_position_button = value;
2738 },
2739 }),
2740 metadata: None,
2741 files: USER,
2742 }),
2743 SettingsPageItem::SettingItem(SettingItem {
2744 title: "Terminal Button",
2745 description: "Show the terminal button in the status bar.",
2746 field: Box::new(SettingField {
2747 json_path: Some("terminal.button"),
2748 pick: |settings_content| {
2749 settings_content.terminal.as_ref()?.button.as_ref()
2750 },
2751 write: |settings_content, value| {
2752 settings_content.terminal.get_or_insert_default().button = value;
2753 },
2754 }),
2755 metadata: None,
2756 files: USER,
2757 }),
2758 SettingsPageItem::SettingItem(SettingItem {
2759 title: "Diagnostics Button",
2760 description: "Show the project diagnostics button in the status bar.",
2761 field: Box::new(SettingField {
2762 json_path: Some("diagnostics.button"),
2763 pick: |settings_content| {
2764 settings_content.diagnostics.as_ref()?.button.as_ref()
2765 },
2766 write: |settings_content, value| {
2767 settings_content.diagnostics.get_or_insert_default().button = value;
2768 },
2769 }),
2770 metadata: None,
2771 files: USER,
2772 }),
2773 SettingsPageItem::SettingItem(SettingItem {
2774 title: "Project Search Button",
2775 description: "Show the project search button in the status bar.",
2776 field: Box::new(SettingField {
2777 json_path: Some("search.button"),
2778 pick: |settings_content| {
2779 settings_content.editor.search.as_ref()?.button.as_ref()
2780 },
2781 write: |settings_content, value| {
2782 settings_content
2783 .editor
2784 .search
2785 .get_or_insert_default()
2786 .button = value;
2787 },
2788 }),
2789 metadata: None,
2790 files: USER,
2791 }),
2792 SettingsPageItem::SettingItem(SettingItem {
2793 title: "Debugger Button",
2794 description: "Show the debugger button in the status bar.",
2795 field: Box::new(SettingField {
2796 json_path: Some("debugger.button"),
2797 pick: |settings_content| {
2798 settings_content.debugger.as_ref()?.button.as_ref()
2799 },
2800 write: |settings_content, value| {
2801 settings_content.debugger.get_or_insert_default().button = value;
2802 },
2803 }),
2804 metadata: None,
2805 files: USER,
2806 }),
2807 SettingsPageItem::SectionHeader("Title Bar"),
2808 SettingsPageItem::SettingItem(SettingItem {
2809 title: "Show Branch Icon",
2810 description: "Show the branch icon beside branch switcher in the titlebar.",
2811 field: Box::new(SettingField {
2812 json_path: Some("title_bar.show_branch_icon"),
2813 pick: |settings_content| {
2814 settings_content
2815 .title_bar
2816 .as_ref()?
2817 .show_branch_icon
2818 .as_ref()
2819 },
2820 write: |settings_content, value| {
2821 settings_content
2822 .title_bar
2823 .get_or_insert_default()
2824 .show_branch_icon = value;
2825 },
2826 }),
2827 metadata: None,
2828 files: USER,
2829 }),
2830 SettingsPageItem::SettingItem(SettingItem {
2831 title: "Show Branch Name",
2832 description: "Show the branch name button in the titlebar.",
2833 field: Box::new(SettingField {
2834 json_path: Some("title_bar.show_branch_name"),
2835 pick: |settings_content| {
2836 settings_content
2837 .title_bar
2838 .as_ref()?
2839 .show_branch_name
2840 .as_ref()
2841 },
2842 write: |settings_content, value| {
2843 settings_content
2844 .title_bar
2845 .get_or_insert_default()
2846 .show_branch_name = value;
2847 },
2848 }),
2849 metadata: None,
2850 files: USER,
2851 }),
2852 SettingsPageItem::SettingItem(SettingItem {
2853 title: "Show Project Items",
2854 description: "Show the project host and name in the titlebar.",
2855 field: Box::new(SettingField {
2856 json_path: Some("title_bar.show_project_items"),
2857 pick: |settings_content| {
2858 settings_content
2859 .title_bar
2860 .as_ref()?
2861 .show_project_items
2862 .as_ref()
2863 },
2864 write: |settings_content, value| {
2865 settings_content
2866 .title_bar
2867 .get_or_insert_default()
2868 .show_project_items = value;
2869 },
2870 }),
2871 metadata: None,
2872 files: USER,
2873 }),
2874 SettingsPageItem::SettingItem(SettingItem {
2875 title: "Show Onboarding Banner",
2876 description: "Show banners announcing new features in the titlebar.",
2877 field: Box::new(SettingField {
2878 json_path: Some("title_bar.show_onboarding_banner"),
2879 pick: |settings_content| {
2880 settings_content
2881 .title_bar
2882 .as_ref()?
2883 .show_onboarding_banner
2884 .as_ref()
2885 },
2886 write: |settings_content, value| {
2887 settings_content
2888 .title_bar
2889 .get_or_insert_default()
2890 .show_onboarding_banner = value;
2891 },
2892 }),
2893 metadata: None,
2894 files: USER,
2895 }),
2896 SettingsPageItem::SettingItem(SettingItem {
2897 title: "Show User Picture",
2898 description: "Show user picture in the titlebar.",
2899 field: Box::new(SettingField {
2900 json_path: Some("title_bar.show_user_picture"),
2901 pick: |settings_content| {
2902 settings_content
2903 .title_bar
2904 .as_ref()?
2905 .show_user_picture
2906 .as_ref()
2907 },
2908 write: |settings_content, value| {
2909 settings_content
2910 .title_bar
2911 .get_or_insert_default()
2912 .show_user_picture = value;
2913 },
2914 }),
2915 metadata: None,
2916 files: USER,
2917 }),
2918 SettingsPageItem::SettingItem(SettingItem {
2919 title: "Show Sign In",
2920 description: "Show the sign in button in the titlebar.",
2921 field: Box::new(SettingField {
2922 json_path: Some("title_bar.show_sign_in"),
2923 pick: |settings_content| {
2924 settings_content.title_bar.as_ref()?.show_sign_in.as_ref()
2925 },
2926 write: |settings_content, value| {
2927 settings_content
2928 .title_bar
2929 .get_or_insert_default()
2930 .show_sign_in = value;
2931 },
2932 }),
2933 metadata: None,
2934 files: USER,
2935 }),
2936 SettingsPageItem::SettingItem(SettingItem {
2937 title: "Show Menus",
2938 description: "Show the menus in the titlebar.",
2939 field: Box::new(SettingField {
2940 json_path: Some("title_bar.show_menus"),
2941 pick: |settings_content| {
2942 settings_content.title_bar.as_ref()?.show_menus.as_ref()
2943 },
2944 write: |settings_content, value| {
2945 settings_content
2946 .title_bar
2947 .get_or_insert_default()
2948 .show_menus = value;
2949 },
2950 }),
2951 metadata: None,
2952 files: USER,
2953 }),
2954 SettingsPageItem::SectionHeader("Tab Bar"),
2955 SettingsPageItem::SettingItem(SettingItem {
2956 title: "Show Tab Bar",
2957 description: "Show the tab bar in the editor.",
2958 field: Box::new(SettingField {
2959 json_path: Some("tab_bar.show"),
2960 pick: |settings_content| settings_content.tab_bar.as_ref()?.show.as_ref(),
2961 write: |settings_content, value| {
2962 settings_content.tab_bar.get_or_insert_default().show = value;
2963 },
2964 }),
2965 metadata: None,
2966 files: USER,
2967 }),
2968 SettingsPageItem::SettingItem(SettingItem {
2969 title: "Show Git Status In Tabs",
2970 description: "Show the Git file status on a tab item.",
2971 field: Box::new(SettingField {
2972 json_path: Some("tabs.git_status"),
2973 pick: |settings_content| {
2974 settings_content.tabs.as_ref()?.git_status.as_ref()
2975 },
2976 write: |settings_content, value| {
2977 settings_content.tabs.get_or_insert_default().git_status = value;
2978 },
2979 }),
2980 metadata: None,
2981 files: USER,
2982 }),
2983 SettingsPageItem::SettingItem(SettingItem {
2984 title: "Show File Icons In Tabs",
2985 description: "Show the file icon for a tab.",
2986 field: Box::new(SettingField {
2987 json_path: Some("tabs.file_icons"),
2988 pick: |settings_content| {
2989 settings_content.tabs.as_ref()?.file_icons.as_ref()
2990 },
2991 write: |settings_content, value| {
2992 settings_content.tabs.get_or_insert_default().file_icons = value;
2993 },
2994 }),
2995 metadata: None,
2996 files: USER,
2997 }),
2998 SettingsPageItem::SettingItem(SettingItem {
2999 title: "Tab Close Position",
3000 description: "Position of the close button in a tab.",
3001 field: Box::new(SettingField {
3002 json_path: Some("tabs.close_position"),
3003 pick: |settings_content| {
3004 settings_content.tabs.as_ref()?.close_position.as_ref()
3005 },
3006 write: |settings_content, value| {
3007 settings_content.tabs.get_or_insert_default().close_position = value;
3008 },
3009 }),
3010 metadata: None,
3011 files: USER,
3012 }),
3013 SettingsPageItem::SettingItem(SettingItem {
3014 files: USER,
3015 title: "Maximum Tabs",
3016 description: "Maximum open tabs in a pane. Will not close an unsaved tab.",
3017 // todo(settings_ui): The default for this value is null and it's use in code
3018 // is complex, so I'm going to come back to this later
3019 field: Box::new(
3020 SettingField {
3021 json_path: Some("max_tabs"),
3022 pick: |settings_content| settings_content.workspace.max_tabs.as_ref(),
3023 write: |settings_content, value| {
3024 settings_content.workspace.max_tabs = value;
3025 },
3026 }
3027 .unimplemented(),
3028 ),
3029 metadata: None,
3030 }),
3031 SettingsPageItem::SettingItem(SettingItem {
3032 title: "Show Navigation History Buttons",
3033 description: "Show the navigation history buttons in the tab bar.",
3034 field: Box::new(SettingField {
3035 json_path: Some("tab_bar.show_nav_history_buttons"),
3036 pick: |settings_content| {
3037 settings_content
3038 .tab_bar
3039 .as_ref()?
3040 .show_nav_history_buttons
3041 .as_ref()
3042 },
3043 write: |settings_content, value| {
3044 settings_content
3045 .tab_bar
3046 .get_or_insert_default()
3047 .show_nav_history_buttons = value;
3048 },
3049 }),
3050 metadata: None,
3051 files: USER,
3052 }),
3053 SettingsPageItem::SectionHeader("Tab Settings"),
3054 SettingsPageItem::SettingItem(SettingItem {
3055 title: "Activate On Close",
3056 description: "What to do after closing the current tab.",
3057 field: Box::new(SettingField {
3058 json_path: Some("tabs.activate_on_close"),
3059 pick: |settings_content| {
3060 settings_content.tabs.as_ref()?.activate_on_close.as_ref()
3061 },
3062 write: |settings_content, value| {
3063 settings_content
3064 .tabs
3065 .get_or_insert_default()
3066 .activate_on_close = value;
3067 },
3068 }),
3069 metadata: None,
3070 files: USER,
3071 }),
3072 SettingsPageItem::SettingItem(SettingItem {
3073 title: "Tab Show Diagnostics",
3074 description: "Which files containing diagnostic errors/warnings to mark in the tabs.",
3075 field: Box::new(SettingField {
3076 json_path: Some("tabs.show_diagnostics"),
3077 pick: |settings_content| {
3078 settings_content.tabs.as_ref()?.show_diagnostics.as_ref()
3079 },
3080 write: |settings_content, value| {
3081 settings_content
3082 .tabs
3083 .get_or_insert_default()
3084 .show_diagnostics = value;
3085 },
3086 }),
3087 metadata: None,
3088 files: USER,
3089 }),
3090 SettingsPageItem::SettingItem(SettingItem {
3091 title: "Show Close Button",
3092 description: "Controls the appearance behavior of the tab's close button.",
3093 field: Box::new(SettingField {
3094 json_path: Some("tabs.show_close_button"),
3095 pick: |settings_content| {
3096 settings_content.tabs.as_ref()?.show_close_button.as_ref()
3097 },
3098 write: |settings_content, value| {
3099 settings_content
3100 .tabs
3101 .get_or_insert_default()
3102 .show_close_button = value;
3103 },
3104 }),
3105 metadata: None,
3106 files: USER,
3107 }),
3108 SettingsPageItem::SectionHeader("Preview Tabs"),
3109 SettingsPageItem::SettingItem(SettingItem {
3110 title: "Preview Tabs Enabled",
3111 description: "Show opened editors as Preview tabs.",
3112 field: Box::new(SettingField {
3113 json_path: Some("preview_tabs.enabled"),
3114 pick: |settings_content| {
3115 settings_content.preview_tabs.as_ref()?.enabled.as_ref()
3116 },
3117 write: |settings_content, value| {
3118 settings_content
3119 .preview_tabs
3120 .get_or_insert_default()
3121 .enabled = value;
3122 },
3123 }),
3124 metadata: None,
3125 files: USER,
3126 }),
3127 SettingsPageItem::SettingItem(SettingItem {
3128 title: "Enable Preview From File Finder",
3129 description: "Whether to open tabs in Preview mode when selected from the file finder.",
3130 field: Box::new(SettingField {
3131 json_path: Some("preview_tabs.enable_preview_from_file_finder"),
3132 pick: |settings_content| {
3133 settings_content
3134 .preview_tabs
3135 .as_ref()?
3136 .enable_preview_from_file_finder
3137 .as_ref()
3138 },
3139 write: |settings_content, value| {
3140 settings_content
3141 .preview_tabs
3142 .get_or_insert_default()
3143 .enable_preview_from_file_finder = value;
3144 },
3145 }),
3146 metadata: None,
3147 files: USER,
3148 }),
3149 SettingsPageItem::SettingItem(SettingItem {
3150 title: "Enable Preview From Code Navigation",
3151 description: "Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.",
3152 field: Box::new(SettingField {
3153 json_path: Some("preview_tabs.enable_preview_from_code_navigation"),
3154 pick: |settings_content| {
3155 settings_content
3156 .preview_tabs
3157 .as_ref()?
3158 .enable_preview_from_code_navigation
3159 .as_ref()
3160 },
3161 write: |settings_content, value| {
3162 settings_content
3163 .preview_tabs
3164 .get_or_insert_default()
3165 .enable_preview_from_code_navigation = value;
3166 },
3167 }),
3168 metadata: None,
3169 files: USER,
3170 }),
3171 SettingsPageItem::SectionHeader("Layout"),
3172 SettingsPageItem::SettingItem(SettingItem {
3173 title: "Bottom Dock Layout",
3174 description: "Layout mode for the bottom dock.",
3175 field: Box::new(SettingField {
3176 json_path: Some("bottom_dock_layout"),
3177 pick: |settings_content| {
3178 settings_content.workspace.bottom_dock_layout.as_ref()
3179 },
3180 write: |settings_content, value| {
3181 settings_content.workspace.bottom_dock_layout = value;
3182 },
3183 }),
3184 metadata: None,
3185 files: USER,
3186 }),
3187 SettingsPageItem::SettingItem(SettingItem {
3188 files: USER,
3189 title: "Centered Layout Left Padding",
3190 description: "Left padding for centered layout.",
3191 field: Box::new(SettingField {
3192 json_path: Some("centered_layout.left_padding"),
3193 pick: |settings_content| {
3194 settings_content
3195 .workspace
3196 .centered_layout
3197 .as_ref()?
3198 .left_padding
3199 .as_ref()
3200 },
3201 write: |settings_content, value| {
3202 settings_content
3203 .workspace
3204 .centered_layout
3205 .get_or_insert_default()
3206 .left_padding = value;
3207 },
3208 }),
3209 metadata: None,
3210 }),
3211 SettingsPageItem::SettingItem(SettingItem {
3212 files: USER,
3213 title: "Centered Layout Right Padding",
3214 description: "Right padding for centered layout.",
3215 field: Box::new(SettingField {
3216 json_path: Some("centered_layout.right_padding"),
3217 pick: |settings_content| {
3218 settings_content
3219 .workspace
3220 .centered_layout
3221 .as_ref()?
3222 .right_padding
3223 .as_ref()
3224 },
3225 write: |settings_content, value| {
3226 settings_content
3227 .workspace
3228 .centered_layout
3229 .get_or_insert_default()
3230 .right_padding = value;
3231 },
3232 }),
3233 metadata: None,
3234 }),
3235 SettingsPageItem::SectionHeader("Window"),
3236 // todo(settings_ui): Should we filter by platform.as_ref()?
3237 SettingsPageItem::SettingItem(SettingItem {
3238 title: "Use System Window Tabs",
3239 description: "(macOS only) whether to allow Windows to tab together.",
3240 field: Box::new(SettingField {
3241 json_path: Some("use_system_window_tabs"),
3242 pick: |settings_content| {
3243 settings_content.workspace.use_system_window_tabs.as_ref()
3244 },
3245 write: |settings_content, value| {
3246 settings_content.workspace.use_system_window_tabs = value;
3247 },
3248 }),
3249 metadata: None,
3250 files: USER,
3251 }),
3252 SettingsPageItem::SectionHeader("Pane Modifiers"),
3253 SettingsPageItem::SettingItem(SettingItem {
3254 title: "Inactive Opacity",
3255 description: "Opacity of inactive panels (0.0 - 1.0).",
3256 field: Box::new(SettingField {
3257 json_path: Some("active_pane_modifiers.inactive_opacity"),
3258 pick: |settings_content| {
3259 settings_content
3260 .workspace
3261 .active_pane_modifiers
3262 .as_ref()?
3263 .inactive_opacity
3264 .as_ref()
3265 },
3266 write: |settings_content, value| {
3267 settings_content
3268 .workspace
3269 .active_pane_modifiers
3270 .get_or_insert_default()
3271 .inactive_opacity = value;
3272 },
3273 }),
3274 metadata: None,
3275 files: USER,
3276 }),
3277 SettingsPageItem::SettingItem(SettingItem {
3278 title: "Border Size",
3279 description: "Size of the border surrounding the active pane.",
3280 field: Box::new(SettingField {
3281 json_path: Some("active_pane_modifiers.border_size"),
3282 pick: |settings_content| {
3283 settings_content
3284 .workspace
3285 .active_pane_modifiers
3286 .as_ref()?
3287 .border_size
3288 .as_ref()
3289 },
3290 write: |settings_content, value| {
3291 settings_content
3292 .workspace
3293 .active_pane_modifiers
3294 .get_or_insert_default()
3295 .border_size = value;
3296 },
3297 }),
3298 metadata: None,
3299 files: USER,
3300 }),
3301 SettingsPageItem::SettingItem(SettingItem {
3302 title: "Zoomed Padding",
3303 description: "Show padding for zoomed panes.",
3304 field: Box::new(SettingField {
3305 json_path: Some("zoomed_padding"),
3306 pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
3307 write: |settings_content, value| {
3308 settings_content.workspace.zoomed_padding = value;
3309 },
3310 }),
3311 metadata: None,
3312 files: USER,
3313 }),
3314 SettingsPageItem::SectionHeader("Pane Split Direction"),
3315 SettingsPageItem::SettingItem(SettingItem {
3316 title: "Vertical Split Direction",
3317 description: "Direction to split vertically.",
3318 field: Box::new(SettingField {
3319 json_path: Some("pane_split_direction_vertical"),
3320 pick: |settings_content| {
3321 settings_content
3322 .workspace
3323 .pane_split_direction_vertical
3324 .as_ref()
3325 },
3326 write: |settings_content, value| {
3327 settings_content.workspace.pane_split_direction_vertical = value;
3328 },
3329 }),
3330 metadata: None,
3331 files: USER,
3332 }),
3333 SettingsPageItem::SettingItem(SettingItem {
3334 title: "Horizontal Split Direction",
3335 description: "Direction to split horizontally.",
3336 field: Box::new(SettingField {
3337 json_path: Some("pane_split_direction_horizontal"),
3338 pick: |settings_content| {
3339 settings_content
3340 .workspace
3341 .pane_split_direction_horizontal
3342 .as_ref()
3343 },
3344 write: |settings_content, value| {
3345 settings_content.workspace.pane_split_direction_horizontal = value;
3346 },
3347 }),
3348 metadata: None,
3349 files: USER,
3350 }),
3351 ],
3352 },
3353 SettingsPage {
3354 title: "Panels",
3355 items: vec![
3356 SettingsPageItem::SectionHeader("Project Panel"),
3357 SettingsPageItem::SettingItem(SettingItem {
3358 title: "Project Panel Dock",
3359 description: "Where to dock the project panel.",
3360 field: Box::new(SettingField {
3361 json_path: Some("project_panel.dock"),
3362 pick: |settings_content| {
3363 settings_content.project_panel.as_ref()?.dock.as_ref()
3364 },
3365 write: |settings_content, value| {
3366 settings_content.project_panel.get_or_insert_default().dock = value;
3367 },
3368 }),
3369 metadata: None,
3370 files: USER,
3371 }),
3372 SettingsPageItem::SettingItem(SettingItem {
3373 title: "Project Panel Default Width",
3374 description: "Default width of the project panel in pixels.",
3375 field: Box::new(SettingField {
3376 json_path: Some("project_panel.default_width"),
3377 pick: |settings_content| {
3378 settings_content
3379 .project_panel
3380 .as_ref()?
3381 .default_width
3382 .as_ref()
3383 },
3384 write: |settings_content, value| {
3385 settings_content
3386 .project_panel
3387 .get_or_insert_default()
3388 .default_width = value;
3389 },
3390 }),
3391 metadata: None,
3392 files: USER,
3393 }),
3394 SettingsPageItem::SettingItem(SettingItem {
3395 title: "Hide .gitignore",
3396 description: "Whether to hide the gitignore entries in the project panel.",
3397 field: Box::new(SettingField {
3398 json_path: Some("project_panel.hide_gitignore"),
3399 pick: |settings_content| {
3400 settings_content
3401 .project_panel
3402 .as_ref()?
3403 .hide_gitignore
3404 .as_ref()
3405 },
3406 write: |settings_content, value| {
3407 settings_content
3408 .project_panel
3409 .get_or_insert_default()
3410 .hide_gitignore = value;
3411 },
3412 }),
3413 metadata: None,
3414 files: USER,
3415 }),
3416 SettingsPageItem::SettingItem(SettingItem {
3417 title: "Entry Spacing",
3418 description: "Spacing between worktree entries in the project panel.",
3419 field: Box::new(SettingField {
3420 json_path: Some("project_panel.entry_spacing"),
3421 pick: |settings_content| {
3422 settings_content
3423 .project_panel
3424 .as_ref()?
3425 .entry_spacing
3426 .as_ref()
3427 },
3428 write: |settings_content, value| {
3429 settings_content
3430 .project_panel
3431 .get_or_insert_default()
3432 .entry_spacing = value;
3433 },
3434 }),
3435 metadata: None,
3436 files: USER,
3437 }),
3438 SettingsPageItem::SettingItem(SettingItem {
3439 title: "File Icons",
3440 description: "Show file icons in the project panel.",
3441 field: Box::new(SettingField {
3442 json_path: Some("project_panel.file_icons"),
3443 pick: |settings_content| {
3444 settings_content.project_panel.as_ref()?.file_icons.as_ref()
3445 },
3446 write: |settings_content, value| {
3447 settings_content
3448 .project_panel
3449 .get_or_insert_default()
3450 .file_icons = value;
3451 },
3452 }),
3453 metadata: None,
3454 files: USER,
3455 }),
3456 SettingsPageItem::SettingItem(SettingItem {
3457 title: "Folder Icons",
3458 description: "Whether to show folder icons or chevrons for directories in the project panel.",
3459 field: Box::new(SettingField {
3460 json_path: Some("project_panel.folder_icons"),
3461 pick: |settings_content| {
3462 settings_content
3463 .project_panel
3464 .as_ref()?
3465 .folder_icons
3466 .as_ref()
3467 },
3468 write: |settings_content, value| {
3469 settings_content
3470 .project_panel
3471 .get_or_insert_default()
3472 .folder_icons = value;
3473 },
3474 }),
3475 metadata: None,
3476 files: USER,
3477 }),
3478 SettingsPageItem::SettingItem(SettingItem {
3479 title: "Git Status",
3480 description: "Show the Git status in the project panel.",
3481 field: Box::new(SettingField {
3482 json_path: Some("project_panel.git_status"),
3483 pick: |settings_content| {
3484 settings_content.project_panel.as_ref()?.git_status.as_ref()
3485 },
3486 write: |settings_content, value| {
3487 settings_content
3488 .project_panel
3489 .get_or_insert_default()
3490 .git_status = value;
3491 },
3492 }),
3493 metadata: None,
3494 files: USER,
3495 }),
3496 SettingsPageItem::SettingItem(SettingItem {
3497 title: "Indent Size",
3498 description: "Amount of indentation for nested items.",
3499 field: Box::new(SettingField {
3500 json_path: Some("project_panel.indent_size"),
3501 pick: |settings_content| {
3502 settings_content
3503 .project_panel
3504 .as_ref()?
3505 .indent_size
3506 .as_ref()
3507 },
3508 write: |settings_content, value| {
3509 settings_content
3510 .project_panel
3511 .get_or_insert_default()
3512 .indent_size = value;
3513 },
3514 }),
3515 metadata: None,
3516 files: USER,
3517 }),
3518 SettingsPageItem::SettingItem(SettingItem {
3519 title: "Auto Reveal Entries",
3520 description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
3521 field: Box::new(SettingField {
3522 json_path: Some("project_panel.auto_reveal_entries"),
3523 pick: |settings_content| {
3524 settings_content
3525 .project_panel
3526 .as_ref()?
3527 .auto_reveal_entries
3528 .as_ref()
3529 },
3530 write: |settings_content, value| {
3531 settings_content
3532 .project_panel
3533 .get_or_insert_default()
3534 .auto_reveal_entries = value;
3535 },
3536 }),
3537 metadata: None,
3538 files: USER,
3539 }),
3540 SettingsPageItem::SettingItem(SettingItem {
3541 title: "Starts Open",
3542 description: "Whether the project panel should open on startup.",
3543 field: Box::new(SettingField {
3544 json_path: Some("project_panel.starts_open"),
3545 pick: |settings_content| {
3546 settings_content
3547 .project_panel
3548 .as_ref()?
3549 .starts_open
3550 .as_ref()
3551 },
3552 write: |settings_content, value| {
3553 settings_content
3554 .project_panel
3555 .get_or_insert_default()
3556 .starts_open = value;
3557 },
3558 }),
3559 metadata: None,
3560 files: USER,
3561 }),
3562 SettingsPageItem::SettingItem(SettingItem {
3563 title: "Auto Fold Directories",
3564 description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
3565 field: Box::new(SettingField {
3566 json_path: Some("project_panel.auto_fold_dirs"),
3567 pick: |settings_content| {
3568 settings_content
3569 .project_panel
3570 .as_ref()?
3571 .auto_fold_dirs
3572 .as_ref()
3573 },
3574 write: |settings_content, value| {
3575 settings_content
3576 .project_panel
3577 .get_or_insert_default()
3578 .auto_fold_dirs = value;
3579 },
3580 }),
3581 metadata: None,
3582 files: USER,
3583 }),
3584 SettingsPageItem::SettingItem(SettingItem {
3585 title: "Show Scrollbar",
3586 description: "Show the scrollbar in the project panel.",
3587 field: Box::new(SettingField {
3588 json_path: Some("project_panel.scrollbar.show"),
3589 pick: |settings_content| {
3590 show_scrollbar_or_editor(settings_content, |settings_content| {
3591 settings_content
3592 .project_panel
3593 .as_ref()?
3594 .scrollbar
3595 .as_ref()?
3596 .show
3597 .as_ref()
3598 })
3599 },
3600 write: |settings_content, value| {
3601 settings_content
3602 .project_panel
3603 .get_or_insert_default()
3604 .scrollbar
3605 .get_or_insert_default()
3606 .show = value;
3607 },
3608 }),
3609 metadata: None,
3610 files: USER,
3611 }),
3612 SettingsPageItem::SettingItem(SettingItem {
3613 title: "Show Diagnostics",
3614 description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
3615 field: Box::new(SettingField {
3616 json_path: Some("project_panel.show_diagnostics"),
3617 pick: |settings_content| {
3618 settings_content
3619 .project_panel
3620 .as_ref()?
3621 .show_diagnostics
3622 .as_ref()
3623 },
3624 write: |settings_content, value| {
3625 settings_content
3626 .project_panel
3627 .get_or_insert_default()
3628 .show_diagnostics = value;
3629 },
3630 }),
3631 metadata: None,
3632 files: USER,
3633 }),
3634 SettingsPageItem::SettingItem(SettingItem {
3635 title: "Sticky Scroll",
3636 description: "Whether to stick parent directories at top of the project panel.",
3637 field: Box::new(SettingField {
3638 json_path: Some("project_panel.sticky_scroll"),
3639 pick: |settings_content| {
3640 settings_content
3641 .project_panel
3642 .as_ref()?
3643 .sticky_scroll
3644 .as_ref()
3645 },
3646 write: |settings_content, value| {
3647 settings_content
3648 .project_panel
3649 .get_or_insert_default()
3650 .sticky_scroll = value;
3651 },
3652 }),
3653 metadata: None,
3654 files: USER,
3655 }),
3656 SettingsPageItem::SettingItem(SettingItem {
3657 files: USER,
3658 title: "Show Indent Guides",
3659 description: "Show indent guides in the project panel.",
3660 field: Box::new(
3661 SettingField {
3662 json_path: Some("project_panel.indent_guides.show"),
3663 pick: |settings_content| {
3664 settings_content
3665 .project_panel
3666 .as_ref()?
3667 .indent_guides
3668 .as_ref()?
3669 .show
3670 .as_ref()
3671 },
3672 write: |settings_content, value| {
3673 settings_content
3674 .project_panel
3675 .get_or_insert_default()
3676 .indent_guides
3677 .get_or_insert_default()
3678 .show = value;
3679 },
3680 }
3681 ),
3682 metadata: None,
3683 }),
3684 SettingsPageItem::SettingItem(SettingItem {
3685 title: "Drag and Drop",
3686 description: "Whether to enable drag-and-drop operations in the project panel.",
3687 field: Box::new(SettingField {
3688 json_path: Some("project_panel.drag_and_drop"),
3689 pick: |settings_content| {
3690 settings_content
3691 .project_panel
3692 .as_ref()?
3693 .drag_and_drop
3694 .as_ref()
3695 },
3696 write: |settings_content, value| {
3697 settings_content
3698 .project_panel
3699 .get_or_insert_default()
3700 .drag_and_drop = value;
3701 },
3702 }),
3703 metadata: None,
3704 files: USER,
3705 }),
3706 SettingsPageItem::SettingItem(SettingItem {
3707 title: "Hide Root",
3708 description: "Whether to hide the root entry when only one folder is open in the window.",
3709 field: Box::new(SettingField {
3710 json_path: Some("project_panel.drag_and_drop"),
3711 pick: |settings_content| {
3712 settings_content.project_panel.as_ref()?.hide_root.as_ref()
3713 },
3714 write: |settings_content, value| {
3715 settings_content
3716 .project_panel
3717 .get_or_insert_default()
3718 .hide_root = value;
3719 },
3720 }),
3721 metadata: None,
3722 files: USER,
3723 }),
3724 SettingsPageItem::SettingItem(SettingItem {
3725 title: "Hide Hidden",
3726 description: "Whether to hide the hidden entries in the project panel.",
3727 field: Box::new(SettingField {
3728 json_path: Some("project_panel.hide_hidden"),
3729 pick: |settings_content| {
3730 settings_content
3731 .project_panel
3732 .as_ref()?
3733 .hide_hidden
3734 .as_ref()
3735 },
3736 write: |settings_content, value| {
3737 settings_content
3738 .project_panel
3739 .get_or_insert_default()
3740 .hide_hidden = value;
3741 },
3742 }),
3743 metadata: None,
3744 files: USER,
3745 }),
3746 SettingsPageItem::SettingItem(SettingItem {
3747 title: "Hidden Files",
3748 description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
3749 field: Box::new(
3750 SettingField {
3751 json_path: Some("worktree.hidden_files"),
3752 pick: |settings_content| {
3753 settings_content.project.worktree.hidden_files.as_ref()
3754 },
3755 write: |settings_content, value| {
3756 settings_content.project.worktree.hidden_files = value;
3757 },
3758 }
3759 .unimplemented(),
3760 ),
3761 metadata: None,
3762 files: USER,
3763 }),
3764 SettingsPageItem::SettingItem(SettingItem {
3765 title: "Open File on Paste",
3766 description: "Whether to automatically open files when pasting them in the project panel.",
3767 field: Box::new(SettingField {
3768 json_path: Some("project_panel.open_file_on_paste"),
3769 pick: |settings_content| {
3770 settings_content
3771 .project_panel
3772 .as_ref()?
3773 .open_file_on_paste
3774 .as_ref()
3775 },
3776 write: |settings_content, value| {
3777 settings_content
3778 .project_panel
3779 .get_or_insert_default()
3780 .open_file_on_paste = value;
3781 },
3782 }),
3783 metadata: None,
3784 files: USER,
3785 }),
3786 SettingsPageItem::SectionHeader("Terminal Panel"),
3787 SettingsPageItem::SettingItem(SettingItem {
3788 title: "Terminal Dock",
3789 description: "Where to dock the terminal panel.",
3790 field: Box::new(SettingField {
3791 json_path: Some("terminal.dock"),
3792 pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
3793 write: |settings_content, value| {
3794 settings_content.terminal.get_or_insert_default().dock = value;
3795 },
3796 }),
3797 metadata: None,
3798 files: USER,
3799 }),
3800 SettingsPageItem::SectionHeader("Outline Panel"),
3801 SettingsPageItem::SettingItem(SettingItem {
3802 title: "Outline Panel Button",
3803 description: "Show the outline panel button in the status bar.",
3804 field: Box::new(SettingField {
3805 json_path: Some("outline_panel.button"),
3806 pick: |settings_content| {
3807 settings_content.outline_panel.as_ref()?.button.as_ref()
3808 },
3809 write: |settings_content, value| {
3810 settings_content
3811 .outline_panel
3812 .get_or_insert_default()
3813 .button = value;
3814 },
3815 }),
3816 metadata: None,
3817 files: USER,
3818 }),
3819 SettingsPageItem::SettingItem(SettingItem {
3820 title: "Outline Panel Dock",
3821 description: "Where to dock the outline panel.",
3822 field: Box::new(SettingField {
3823 json_path: Some("outline_panel.dock"),
3824 pick: |settings_content| {
3825 settings_content.outline_panel.as_ref()?.dock.as_ref()
3826 },
3827 write: |settings_content, value| {
3828 settings_content.outline_panel.get_or_insert_default().dock = value;
3829 },
3830 }),
3831 metadata: None,
3832 files: USER,
3833 }),
3834 SettingsPageItem::SettingItem(SettingItem {
3835 title: "Outline Panel Default Width",
3836 description: "Default width of the outline panel in pixels.",
3837 field: Box::new(SettingField {
3838 json_path: Some("outline_panel.default_width"),
3839 pick: |settings_content| {
3840 settings_content
3841 .outline_panel
3842 .as_ref()?
3843 .default_width
3844 .as_ref()
3845 },
3846 write: |settings_content, value| {
3847 settings_content
3848 .outline_panel
3849 .get_or_insert_default()
3850 .default_width = value;
3851 },
3852 }),
3853 metadata: None,
3854 files: USER,
3855 }),
3856 SettingsPageItem::SettingItem(SettingItem {
3857 title: "File Icons",
3858 description: "Show file icons in the outline panel.",
3859 field: Box::new(SettingField {
3860 json_path: Some("outline_panel.file_icons"),
3861 pick: |settings_content| {
3862 settings_content.outline_panel.as_ref()?.file_icons.as_ref()
3863 },
3864 write: |settings_content, value| {
3865 settings_content
3866 .outline_panel
3867 .get_or_insert_default()
3868 .file_icons = value;
3869 },
3870 }),
3871 metadata: None,
3872 files: USER,
3873 }),
3874 SettingsPageItem::SettingItem(SettingItem {
3875 title: "Folder Icons",
3876 description: "Whether to show folder icons or chevrons for directories in the outline panel.",
3877 field: Box::new(SettingField {
3878 json_path: Some("outline_panel.folder_icons"),
3879 pick: |settings_content| {
3880 settings_content
3881 .outline_panel
3882 .as_ref()?
3883 .folder_icons
3884 .as_ref()
3885 },
3886 write: |settings_content, value| {
3887 settings_content
3888 .outline_panel
3889 .get_or_insert_default()
3890 .folder_icons = value;
3891 },
3892 }),
3893 metadata: None,
3894 files: USER,
3895 }),
3896 SettingsPageItem::SettingItem(SettingItem {
3897 title: "Git Status",
3898 description: "Show the Git status in the outline panel.",
3899 field: Box::new(SettingField {
3900 json_path: Some("outline_panel.git_status"),
3901 pick: |settings_content| {
3902 settings_content.outline_panel.as_ref()?.git_status.as_ref()
3903 },
3904 write: |settings_content, value| {
3905 settings_content
3906 .outline_panel
3907 .get_or_insert_default()
3908 .git_status = value;
3909 },
3910 }),
3911 metadata: None,
3912 files: USER,
3913 }),
3914 SettingsPageItem::SettingItem(SettingItem {
3915 title: "Indent Size",
3916 description: "Amount of indentation for nested items.",
3917 field: Box::new(SettingField {
3918 json_path: Some("outline_panel.indent_size"),
3919 pick: |settings_content| {
3920 settings_content
3921 .outline_panel
3922 .as_ref()?
3923 .indent_size
3924 .as_ref()
3925 },
3926 write: |settings_content, value| {
3927 settings_content
3928 .outline_panel
3929 .get_or_insert_default()
3930 .indent_size = value;
3931 },
3932 }),
3933 metadata: None,
3934 files: USER,
3935 }),
3936 SettingsPageItem::SettingItem(SettingItem {
3937 title: "Auto Reveal Entries",
3938 description: "Whether to reveal when a corresponding outline entry becomes active.",
3939 field: Box::new(SettingField {
3940 json_path: Some("outline_panel.auto_reveal_entries"),
3941 pick: |settings_content| {
3942 settings_content
3943 .outline_panel
3944 .as_ref()?
3945 .auto_reveal_entries
3946 .as_ref()
3947 },
3948 write: |settings_content, value| {
3949 settings_content
3950 .outline_panel
3951 .get_or_insert_default()
3952 .auto_reveal_entries = value;
3953 },
3954 }),
3955 metadata: None,
3956 files: USER,
3957 }),
3958 SettingsPageItem::SettingItem(SettingItem {
3959 title: "Auto Fold Directories",
3960 description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
3961 field: Box::new(SettingField {
3962 json_path: Some("outline_panel.auto_fold_dirs"),
3963 pick: |settings_content| {
3964 settings_content
3965 .outline_panel
3966 .as_ref()?
3967 .auto_fold_dirs
3968 .as_ref()
3969 },
3970 write: |settings_content, value| {
3971 settings_content
3972 .outline_panel
3973 .get_or_insert_default()
3974 .auto_fold_dirs = value;
3975 },
3976 }),
3977 metadata: None,
3978 files: USER,
3979 }),
3980 SettingsPageItem::SettingItem(SettingItem {
3981 files: USER,
3982 title: "Show Indent Guides",
3983 description: "When to show indent guides in the outline panel.",
3984 field: Box::new(
3985 SettingField {
3986 json_path: Some("outline_panel.indent_guides.show"),
3987 pick: |settings_content| {
3988 settings_content
3989 .outline_panel
3990 .as_ref()?
3991 .indent_guides
3992 .as_ref()?
3993 .show
3994 .as_ref()
3995 },
3996 write: |settings_content, value| {
3997 settings_content
3998 .outline_panel
3999 .get_or_insert_default()
4000 .indent_guides
4001 .get_or_insert_default()
4002 .show = value;
4003 },
4004 }
4005 ),
4006 metadata: None,
4007 }),
4008 SettingsPageItem::SectionHeader("Git Panel"),
4009 SettingsPageItem::SettingItem(SettingItem {
4010 title: "Git Panel Button",
4011 description: "Show the Git panel button in the status bar.",
4012 field: Box::new(SettingField {
4013 json_path: Some("git_panel.button"),
4014 pick: |settings_content| {
4015 settings_content.git_panel.as_ref()?.button.as_ref()
4016 },
4017 write: |settings_content, value| {
4018 settings_content.git_panel.get_or_insert_default().button = value;
4019 },
4020 }),
4021 metadata: None,
4022 files: USER,
4023 }),
4024 SettingsPageItem::SettingItem(SettingItem {
4025 title: "Git Panel Dock",
4026 description: "Where to dock the Git panel.",
4027 field: Box::new(SettingField {
4028 json_path: Some("git_panel.dock"),
4029 pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
4030 write: |settings_content, value| {
4031 settings_content.git_panel.get_or_insert_default().dock = value;
4032 },
4033 }),
4034 metadata: None,
4035 files: USER,
4036 }),
4037 SettingsPageItem::SettingItem(SettingItem {
4038 title: "Git Panel Default Width",
4039 description: "Default width of the Git panel in pixels.",
4040 field: Box::new(SettingField {
4041 json_path: Some("git_panel.default_width"),
4042 pick: |settings_content| {
4043 settings_content.git_panel.as_ref()?.default_width.as_ref()
4044 },
4045 write: |settings_content, value| {
4046 settings_content
4047 .git_panel
4048 .get_or_insert_default()
4049 .default_width = value;
4050 },
4051 }),
4052 metadata: None,
4053 files: USER,
4054 }),
4055 SettingsPageItem::SettingItem(SettingItem {
4056 title: "Git Panel Status Style",
4057 description: "How entry statuses are displayed.",
4058 field: Box::new(SettingField {
4059 json_path: Some("git_panel.status_style"),
4060 pick: |settings_content| {
4061 settings_content.git_panel.as_ref()?.status_style.as_ref()
4062 },
4063 write: |settings_content, value| {
4064 settings_content
4065 .git_panel
4066 .get_or_insert_default()
4067 .status_style = value;
4068 },
4069 }),
4070 metadata: None,
4071 files: USER,
4072 }),
4073 SettingsPageItem::SettingItem(SettingItem {
4074 title: "Fallback Branch Name",
4075 description: "Default branch name will be when init.defaultbranch is not set in Git.",
4076 field: Box::new(SettingField {
4077 json_path: Some("git_panel.fallback_branch_name"),
4078 pick: |settings_content| {
4079 settings_content
4080 .git_panel
4081 .as_ref()?
4082 .fallback_branch_name
4083 .as_ref()
4084 },
4085 write: |settings_content, value| {
4086 settings_content
4087 .git_panel
4088 .get_or_insert_default()
4089 .fallback_branch_name = value;
4090 },
4091 }),
4092 metadata: None,
4093 files: USER,
4094 }),
4095 SettingsPageItem::SettingItem(SettingItem {
4096 title: "Sort By Path",
4097 description: "Enable to sort entries in the panel by path, disable to sort by status.",
4098 field: Box::new(SettingField {
4099 json_path: Some("git_panel.sort_by_path"),
4100 pick: |settings_content| {
4101 settings_content.git_panel.as_ref()?.sort_by_path.as_ref()
4102 },
4103 write: |settings_content, value| {
4104 settings_content
4105 .git_panel
4106 .get_or_insert_default()
4107 .sort_by_path = value;
4108 },
4109 }),
4110 metadata: None,
4111 files: USER,
4112 }),
4113 SettingsPageItem::SettingItem(SettingItem {
4114 title: "Collapse Untracked Diff",
4115 description: "Whether to collapse untracked files in the diff panel.",
4116 field: Box::new(SettingField {
4117 json_path: Some("git_panel.collapse_untracked_diff"),
4118 pick: |settings_content| {
4119 settings_content
4120 .git_panel
4121 .as_ref()?
4122 .collapse_untracked_diff
4123 .as_ref()
4124 },
4125 write: |settings_content, value| {
4126 settings_content
4127 .git_panel
4128 .get_or_insert_default()
4129 .collapse_untracked_diff = value;
4130 },
4131 }),
4132 metadata: None,
4133 files: USER,
4134 }),
4135 SettingsPageItem::SettingItem(SettingItem {
4136 title: "Scroll Bar",
4137 description: "How and when the scrollbar should be displayed.",
4138 field: Box::new(SettingField {
4139 json_path: Some("git_panel.scrollbar.show"),
4140 pick: |settings_content| {
4141 show_scrollbar_or_editor(settings_content, |settings_content| {
4142 settings_content
4143 .git_panel
4144 .as_ref()?
4145 .scrollbar
4146 .as_ref()?
4147 .show
4148 .as_ref()
4149 })
4150 },
4151 write: |settings_content, value| {
4152 settings_content
4153 .git_panel
4154 .get_or_insert_default()
4155 .scrollbar
4156 .get_or_insert_default()
4157 .show = value;
4158 },
4159 }),
4160 metadata: None,
4161 files: USER,
4162 }),
4163 SettingsPageItem::SectionHeader("Debugger Panel"),
4164 SettingsPageItem::SettingItem(SettingItem {
4165 title: "Debugger Panel Dock",
4166 description: "The dock position of the debug panel.",
4167 field: Box::new(SettingField {
4168 json_path: Some("debugger.dock"),
4169 pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
4170 write: |settings_content, value| {
4171 settings_content.debugger.get_or_insert_default().dock = value;
4172 },
4173 }),
4174 metadata: None,
4175 files: USER,
4176 }),
4177 SettingsPageItem::SectionHeader("Notification Panel"),
4178 SettingsPageItem::SettingItem(SettingItem {
4179 title: "Notification Panel Button",
4180 description: "Show the notification panel button in the status bar.",
4181 field: Box::new(SettingField {
4182 json_path: Some("notification_panel.button"),
4183 pick: |settings_content| {
4184 settings_content
4185 .notification_panel
4186 .as_ref()?
4187 .button
4188 .as_ref()
4189 },
4190 write: |settings_content, value| {
4191 settings_content
4192 .notification_panel
4193 .get_or_insert_default()
4194 .button = value;
4195 },
4196 }),
4197 metadata: None,
4198 files: USER,
4199 }),
4200 SettingsPageItem::SettingItem(SettingItem {
4201 title: "Notification Panel Dock",
4202 description: "Where to dock the notification panel.",
4203 field: Box::new(SettingField {
4204 json_path: Some("notification_panel.dock"),
4205 pick: |settings_content| {
4206 settings_content.notification_panel.as_ref()?.dock.as_ref()
4207 },
4208 write: |settings_content, value| {
4209 settings_content
4210 .notification_panel
4211 .get_or_insert_default()
4212 .dock = value;
4213 },
4214 }),
4215 metadata: None,
4216 files: USER,
4217 }),
4218 SettingsPageItem::SettingItem(SettingItem {
4219 title: "Notification Panel Default Width",
4220 description: "Default width of the notification panel in pixels.",
4221 field: Box::new(SettingField {
4222 json_path: Some("notification_panel.default_width"),
4223 pick: |settings_content| {
4224 settings_content
4225 .notification_panel
4226 .as_ref()?
4227 .default_width
4228 .as_ref()
4229 },
4230 write: |settings_content, value| {
4231 settings_content
4232 .notification_panel
4233 .get_or_insert_default()
4234 .default_width = value;
4235 },
4236 }),
4237 metadata: None,
4238 files: USER,
4239 }),
4240 SettingsPageItem::SectionHeader("Collaboration Panel"),
4241 SettingsPageItem::SettingItem(SettingItem {
4242 title: "Collaboration Panel Button",
4243 description: "Show the collaboration panel button in the status bar.",
4244 field: Box::new(SettingField {
4245 json_path: Some("collaboration_panel.button"),
4246 pick: |settings_content| {
4247 settings_content
4248 .collaboration_panel
4249 .as_ref()?
4250 .button
4251 .as_ref()
4252 },
4253 write: |settings_content, value| {
4254 settings_content
4255 .collaboration_panel
4256 .get_or_insert_default()
4257 .button = value;
4258 },
4259 }),
4260 metadata: None,
4261 files: USER,
4262 }),
4263 SettingsPageItem::SettingItem(SettingItem {
4264 title: "Collaboration Panel Dock",
4265 description: "Where to dock the collaboration panel.",
4266 field: Box::new(SettingField {
4267 json_path: Some("collaboration_panel.dock"),
4268 pick: |settings_content| {
4269 settings_content.collaboration_panel.as_ref()?.dock.as_ref()
4270 },
4271 write: |settings_content, value| {
4272 settings_content
4273 .collaboration_panel
4274 .get_or_insert_default()
4275 .dock = value;
4276 },
4277 }),
4278 metadata: None,
4279 files: USER,
4280 }),
4281 SettingsPageItem::SettingItem(SettingItem {
4282 title: "Collaboration Panel Default Width",
4283 description: "Default width of the collaboration panel in pixels.",
4284 field: Box::new(SettingField {
4285 json_path: Some("collaboration_panel.dock"),
4286 pick: |settings_content| {
4287 settings_content
4288 .collaboration_panel
4289 .as_ref()?
4290 .default_width
4291 .as_ref()
4292 },
4293 write: |settings_content, value| {
4294 settings_content
4295 .collaboration_panel
4296 .get_or_insert_default()
4297 .default_width = value;
4298 },
4299 }),
4300 metadata: None,
4301 files: USER,
4302 }),
4303 SettingsPageItem::SectionHeader("Agent Panel"),
4304 SettingsPageItem::SettingItem(SettingItem {
4305 title: "Agent Panel Button",
4306 description: "Whether to show the agent panel button in the status bar.",
4307 field: Box::new(SettingField {
4308 json_path: Some("agent.button"),
4309 pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
4310 write: |settings_content, value| {
4311 settings_content.agent.get_or_insert_default().button = value;
4312 },
4313 }),
4314 metadata: None,
4315 files: USER,
4316 }),
4317 SettingsPageItem::SettingItem(SettingItem {
4318 title: "Agent Panel Dock",
4319 description: "Where to dock the agent panel.",
4320 field: Box::new(SettingField {
4321 json_path: Some("agent.dock"),
4322 pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
4323 write: |settings_content, value| {
4324 settings_content.agent.get_or_insert_default().dock = value;
4325 },
4326 }),
4327 metadata: None,
4328 files: USER,
4329 }),
4330 SettingsPageItem::SettingItem(SettingItem {
4331 title: "Agent Panel Default Width",
4332 description: "Default width when the agent panel is docked to the left or right.",
4333 field: Box::new(SettingField {
4334 json_path: Some("agent.default_width"),
4335 pick: |settings_content| {
4336 settings_content.agent.as_ref()?.default_width.as_ref()
4337 },
4338 write: |settings_content, value| {
4339 settings_content.agent.get_or_insert_default().default_width = value;
4340 },
4341 }),
4342 metadata: None,
4343 files: USER,
4344 }),
4345 SettingsPageItem::SettingItem(SettingItem {
4346 title: "Agent Panel Default Height",
4347 description: "Default height when the agent panel is docked to the bottom.",
4348 field: Box::new(SettingField {
4349 json_path: Some("agent.default_height"),
4350 pick: |settings_content| {
4351 settings_content.agent.as_ref()?.default_height.as_ref()
4352 },
4353 write: |settings_content, value| {
4354 settings_content
4355 .agent
4356 .get_or_insert_default()
4357 .default_height = value;
4358 },
4359 }),
4360 metadata: None,
4361 files: USER,
4362 }),
4363 ],
4364 },
4365 SettingsPage {
4366 title: "Debugger",
4367 items: vec![
4368 SettingsPageItem::SectionHeader("General"),
4369 SettingsPageItem::SettingItem(SettingItem {
4370 title: "Stepping Granularity",
4371 description: "Determines the stepping granularity for debug operations.",
4372 field: Box::new(SettingField {
4373 json_path: Some("agent.default_height"),
4374 pick: |settings_content| {
4375 settings_content
4376 .debugger
4377 .as_ref()?
4378 .stepping_granularity
4379 .as_ref()
4380 },
4381 write: |settings_content, value| {
4382 settings_content
4383 .debugger
4384 .get_or_insert_default()
4385 .stepping_granularity = value;
4386 },
4387 }),
4388 metadata: None,
4389 files: USER,
4390 }),
4391 SettingsPageItem::SettingItem(SettingItem {
4392 title: "Save Breakpoints",
4393 description: "Whether breakpoints should be reused across Zed sessions.",
4394 field: Box::new(SettingField {
4395 json_path: Some("debugger.save_breakpoints"),
4396 pick: |settings_content| {
4397 settings_content
4398 .debugger
4399 .as_ref()?
4400 .save_breakpoints
4401 .as_ref()
4402 },
4403 write: |settings_content, value| {
4404 settings_content
4405 .debugger
4406 .get_or_insert_default()
4407 .save_breakpoints = value;
4408 },
4409 }),
4410 metadata: None,
4411 files: USER,
4412 }),
4413 SettingsPageItem::SettingItem(SettingItem {
4414 title: "Timeout",
4415 description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
4416 field: Box::new(SettingField {
4417 json_path: Some("debugger.timeout"),
4418 pick: |settings_content| {
4419 settings_content.debugger.as_ref()?.timeout.as_ref()
4420 },
4421 write: |settings_content, value| {
4422 settings_content.debugger.get_or_insert_default().timeout = value;
4423 },
4424 }),
4425 metadata: None,
4426 files: USER,
4427 }),
4428 SettingsPageItem::SettingItem(SettingItem {
4429 title: "Log DAP Communications",
4430 description: "Whether to log messages between active debug adapters and Zed.",
4431 field: Box::new(SettingField {
4432 json_path: Some("debugger.log_dap_communications"),
4433 pick: |settings_content| {
4434 settings_content
4435 .debugger
4436 .as_ref()?
4437 .log_dap_communications
4438 .as_ref()
4439 },
4440 write: |settings_content, value| {
4441 settings_content
4442 .debugger
4443 .get_or_insert_default()
4444 .log_dap_communications = value;
4445 },
4446 }),
4447 metadata: None,
4448 files: USER,
4449 }),
4450 SettingsPageItem::SettingItem(SettingItem {
4451 title: "Format DAP Log Messages",
4452 description: "Whether to format DAP messages when adding them to debug adapter logger.",
4453 field: Box::new(SettingField {
4454 json_path: Some("debugger.format_dap_log_messages"),
4455 pick: |settings_content| {
4456 settings_content
4457 .debugger
4458 .as_ref()?
4459 .format_dap_log_messages
4460 .as_ref()
4461 },
4462 write: |settings_content, value| {
4463 settings_content
4464 .debugger
4465 .get_or_insert_default()
4466 .format_dap_log_messages = value;
4467 },
4468 }),
4469 metadata: None,
4470 files: USER,
4471 }),
4472 ],
4473 },
4474 SettingsPage {
4475 title: "Terminal",
4476 items: vec![
4477 SettingsPageItem::SectionHeader("Environment"),
4478 SettingsPageItem::DynamicItem(DynamicItem {
4479 discriminant: SettingItem {
4480 files: USER | PROJECT,
4481 title: "Shell",
4482 description: "What shell to use when opening a terminal.",
4483 field: Box::new(SettingField {
4484 json_path: Some("terminal.shell$"),
4485 pick: |settings_content| {
4486 Some(&dynamic_variants::<settings::Shell>()[
4487 settings_content
4488 .terminal
4489 .as_ref()?
4490 .project
4491 .shell
4492 .as_ref()?
4493 .discriminant() as usize])
4494 },
4495 write: |settings_content, value| {
4496 let Some(value) = value else {
4497 if let Some(terminal) = settings_content.terminal.as_mut() {
4498 terminal.project.shell = None;
4499 }
4500 return;
4501 };
4502 let settings_value = settings_content
4503 .terminal
4504 .get_or_insert_default()
4505 .project
4506 .shell
4507 .get_or_insert_with(|| settings::Shell::default());
4508 *settings_value = match value {
4509 settings::ShellDiscriminants::System => {
4510 settings::Shell::System
4511 },
4512 settings::ShellDiscriminants::Program => {
4513 let program = match settings_value {
4514 settings::Shell::Program(p) => p.clone(),
4515 settings::Shell::WithArguments { program, .. } => program.clone(),
4516 _ => String::from("sh"),
4517 };
4518 settings::Shell::Program(program)
4519 },
4520 settings::ShellDiscriminants::WithArguments => {
4521 let (program, args, title_override) = match settings_value {
4522 settings::Shell::Program(p) => (p.clone(), vec![], None),
4523 settings::Shell::WithArguments { program, args, title_override } => {
4524 (program.clone(), args.clone(), title_override.clone())
4525 },
4526 _ => (String::from("sh"), vec![], None),
4527 };
4528 settings::Shell::WithArguments {
4529 program,
4530 args,
4531 title_override,
4532 }
4533 },
4534 };
4535 },
4536 }),
4537 metadata: None,
4538 },
4539 pick_discriminant: |settings_content| {
4540 Some(settings_content.terminal.as_ref()?.project.shell.as_ref()?.discriminant() as usize)
4541 },
4542 fields: dynamic_variants::<settings::Shell>().into_iter().map(|variant| {
4543 match variant {
4544 settings::ShellDiscriminants::System => vec![],
4545 settings::ShellDiscriminants::Program => vec![
4546 SettingItem {
4547 files: USER | PROJECT,
4548 title: "Program",
4549 description: "The shell program to use.",
4550 field: Box::new(SettingField {
4551 json_path: Some("terminal.shell"),
4552 pick: |settings_content| {
4553 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4554 Some(settings::Shell::Program(program)) => Some(program),
4555 _ => None
4556 }
4557 },
4558 write: |settings_content, value| {
4559 let Some(value) = value else {
4560 return;
4561 };
4562 match settings_content
4563 .terminal
4564 .get_or_insert_default()
4565 .project
4566 .shell.as_mut() {
4567 Some(settings::Shell::Program(program)) => *program = value,
4568 _ => return
4569 }
4570 },
4571 }),
4572 metadata: None,
4573 }
4574 ],
4575 settings::ShellDiscriminants::WithArguments => vec![
4576 SettingItem {
4577 files: USER | PROJECT,
4578 title: "Program",
4579 description: "The shell program to run.",
4580 field: Box::new(SettingField {
4581 json_path: Some("terminal.shell.program"),
4582 pick: |settings_content| {
4583 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4584 Some(settings::Shell::WithArguments { program, .. }) => Some(program),
4585 _ => None
4586 }
4587 },
4588 write: |settings_content, value| {
4589 let Some(value) = value else {
4590 return;
4591 };
4592 match settings_content
4593 .terminal
4594 .get_or_insert_default()
4595 .project
4596 .shell.as_mut() {
4597 Some(settings::Shell::WithArguments { program, .. }) => *program = value,
4598 _ => return
4599 }
4600 },
4601 }),
4602 metadata: None,
4603 },
4604 SettingItem {
4605 files: USER | PROJECT,
4606 title: "Arguments",
4607 description: "The arguments to pass to the shell program.",
4608 field: Box::new(
4609 SettingField {
4610 json_path: Some("terminal.shell.args"),
4611 pick: |settings_content| {
4612 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4613 Some(settings::Shell::WithArguments { args, .. }) => Some(args),
4614 _ => None
4615 }
4616 },
4617 write: |settings_content, value| {
4618 let Some(value) = value else {
4619 return;
4620 };
4621 match settings_content
4622 .terminal
4623 .get_or_insert_default()
4624 .project
4625 .shell.as_mut() {
4626 Some(settings::Shell::WithArguments { args, .. }) => *args = value,
4627 _ => return
4628 }
4629 },
4630 }
4631 .unimplemented(),
4632 ),
4633 metadata: None,
4634 },
4635 SettingItem {
4636 files: USER | PROJECT,
4637 title: "Title Override",
4638 description: "An optional string to override the title of the terminal tab.",
4639 field: Box::new(SettingField {
4640 json_path: Some("terminal.shell.title_override"),
4641 pick: |settings_content| {
4642 match settings_content.terminal.as_ref()?.project.shell.as_ref() {
4643 Some(settings::Shell::WithArguments { title_override, .. }) => title_override.as_ref().or(DEFAULT_EMPTY_SHARED_STRING),
4644 _ => None
4645 }
4646 },
4647 write: |settings_content, value| {
4648 match settings_content
4649 .terminal
4650 .get_or_insert_default()
4651 .project
4652 .shell.as_mut() {
4653 Some(settings::Shell::WithArguments { title_override, .. }) => *title_override = value.filter(|s| !s.is_empty()),
4654 _ => return
4655 }
4656 },
4657 }),
4658 metadata: None,
4659 }
4660 ],
4661 }
4662 }).collect(),
4663 }),
4664 SettingsPageItem::DynamicItem(DynamicItem {
4665 discriminant: SettingItem {
4666 files: USER | PROJECT,
4667 title: "Working Directory",
4668 description: "What working directory to use when launching the terminal.",
4669 field: Box::new(SettingField {
4670 json_path: Some("terminal.working_directory$"),
4671 pick: |settings_content| {
4672 Some(&dynamic_variants::<settings::WorkingDirectory>()[
4673 settings_content
4674 .terminal
4675 .as_ref()?
4676 .project
4677 .working_directory
4678 .as_ref()?
4679 .discriminant() as usize])
4680 },
4681 write: |settings_content, value| {
4682 let Some(value) = value else {
4683 if let Some(terminal) = settings_content.terminal.as_mut() {
4684 terminal.project.working_directory = None;
4685 }
4686 return;
4687 };
4688 let settings_value = settings_content
4689 .terminal
4690 .get_or_insert_default()
4691 .project
4692 .working_directory
4693 .get_or_insert_with(|| settings::WorkingDirectory::CurrentProjectDirectory);
4694 *settings_value = match value {
4695 settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => {
4696 settings::WorkingDirectory::CurrentProjectDirectory
4697 },
4698 settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => {
4699 settings::WorkingDirectory::FirstProjectDirectory
4700 },
4701 settings::WorkingDirectoryDiscriminants::AlwaysHome => {
4702 settings::WorkingDirectory::AlwaysHome
4703 },
4704 settings::WorkingDirectoryDiscriminants::Always => {
4705 let directory = match settings_value {
4706 settings::WorkingDirectory::Always { .. } => return,
4707 _ => String::new(),
4708 };
4709 settings::WorkingDirectory::Always { directory }
4710 },
4711 };
4712 },
4713 }),
4714 metadata: None,
4715 },
4716 pick_discriminant: |settings_content| {
4717 Some(settings_content.terminal.as_ref()?.project.working_directory.as_ref()?.discriminant() as usize)
4718 },
4719 fields: dynamic_variants::<settings::WorkingDirectory>().into_iter().map(|variant| {
4720 match variant {
4721 settings::WorkingDirectoryDiscriminants::CurrentProjectDirectory => vec![],
4722 settings::WorkingDirectoryDiscriminants::FirstProjectDirectory => vec![],
4723 settings::WorkingDirectoryDiscriminants::AlwaysHome => vec![],
4724 settings::WorkingDirectoryDiscriminants::Always => vec![
4725 SettingItem {
4726 files: USER | PROJECT,
4727 title: "Directory",
4728 description: "The directory path to use (will be shell expanded).",
4729 field: Box::new(SettingField {
4730 json_path: Some("terminal.working_directory.always"),
4731 pick: |settings_content| {
4732 match settings_content.terminal.as_ref()?.project.working_directory.as_ref() {
4733 Some(settings::WorkingDirectory::Always { directory }) => Some(directory),
4734 _ => None
4735 }
4736 },
4737 write: |settings_content, value| {
4738 let value = value.unwrap_or_default();
4739 match settings_content
4740 .terminal
4741 .get_or_insert_default()
4742 .project
4743 .working_directory.as_mut() {
4744 Some(settings::WorkingDirectory::Always { directory }) => *directory = value,
4745 _ => return
4746 }
4747 },
4748 }),
4749 metadata: None,
4750 }
4751 ],
4752 }
4753 }).collect(),
4754 }),
4755 SettingsPageItem::SettingItem(SettingItem {
4756 title: "Environment Variables",
4757 description: "Key-value pairs to add to the terminal's environment.",
4758 field: Box::new(
4759 SettingField {
4760 json_path: Some("terminal.env"),
4761 pick: |settings_content| {
4762 settings_content.terminal.as_ref()?.project.env.as_ref()
4763 },
4764 write: |settings_content, value| {
4765 settings_content
4766 .terminal
4767 .get_or_insert_default()
4768 .project
4769 .env = value;
4770 },
4771 }
4772 .unimplemented(),
4773 ),
4774 metadata: None,
4775 files: USER | PROJECT,
4776 }),
4777 SettingsPageItem::SettingItem(SettingItem {
4778 title: "Detect Virtual Environment",
4779 description: "Activates the Python virtual environment, if one is found, in the terminal's working directory.",
4780 field: Box::new(
4781 SettingField {
4782 json_path: Some("terminal.detect_venv"),
4783 pick: |settings_content| {
4784 settings_content
4785 .terminal
4786 .as_ref()?
4787 .project
4788 .detect_venv
4789 .as_ref()
4790 },
4791 write: |settings_content, value| {
4792 settings_content
4793 .terminal
4794 .get_or_insert_default()
4795 .project
4796 .detect_venv = value;
4797 },
4798 }
4799 .unimplemented(),
4800 ),
4801 metadata: None,
4802 files: USER | PROJECT,
4803 }),
4804 SettingsPageItem::SectionHeader("Font"),
4805 SettingsPageItem::SettingItem(SettingItem {
4806 title: "Font Size",
4807 description: "Font size for terminal text. If not set, defaults to buffer font size.",
4808 field: Box::new(SettingField {
4809 json_path: Some("terminal.font_size"),
4810 pick: |settings_content| {
4811 settings_content
4812 .terminal
4813 .as_ref()
4814 .and_then(|terminal| terminal.font_size.as_ref())
4815 .or(settings_content.theme.buffer_font_size.as_ref())
4816 },
4817 write: |settings_content, value| {
4818 settings_content.terminal.get_or_insert_default().font_size = value;
4819 },
4820 }),
4821 metadata: None,
4822 files: USER,
4823 }),
4824 SettingsPageItem::SettingItem(SettingItem {
4825 title: "Font Family",
4826 description: "Font family for terminal text. If not set, defaults to buffer font family.",
4827 field: Box::new(SettingField {
4828 json_path: Some("terminal.font_family"),
4829 pick: |settings_content| {
4830 settings_content
4831 .terminal
4832 .as_ref()
4833 .and_then(|terminal| terminal.font_family.as_ref())
4834 .or(settings_content.theme.buffer_font_family.as_ref())
4835 },
4836 write: |settings_content, value| {
4837 settings_content
4838 .terminal
4839 .get_or_insert_default()
4840 .font_family = value;
4841 },
4842 }),
4843 metadata: None,
4844 files: USER,
4845 }),
4846 SettingsPageItem::SettingItem(SettingItem {
4847 title: "Font Fallbacks",
4848 description: "Font fallbacks for terminal text. If not set, defaults to buffer font fallbacks.",
4849 field: Box::new(
4850 SettingField {
4851 json_path: Some("terminal.font_fallbacks"),
4852 pick: |settings_content| {
4853 settings_content
4854 .terminal
4855 .as_ref()
4856 .and_then(|terminal| terminal.font_fallbacks.as_ref())
4857 .or(settings_content.theme.buffer_font_fallbacks.as_ref())
4858 },
4859 write: |settings_content, value| {
4860 settings_content
4861 .terminal
4862 .get_or_insert_default()
4863 .font_fallbacks = value;
4864 },
4865 }
4866 .unimplemented(),
4867 ),
4868 metadata: None,
4869 files: USER,
4870 }),
4871 SettingsPageItem::SettingItem(SettingItem {
4872 title: "Font Weight",
4873 description: "Font weight for terminal text in CSS weight units (100-900).",
4874 field: Box::new(SettingField {
4875 json_path: Some("terminal.font_weight"),
4876 pick: |settings_content| {
4877 settings_content.terminal.as_ref()?.font_weight.as_ref()
4878 },
4879 write: |settings_content, value| {
4880 settings_content
4881 .terminal
4882 .get_or_insert_default()
4883 .font_weight = value;
4884 },
4885 }),
4886 metadata: None,
4887 files: USER,
4888 }),
4889 SettingsPageItem::SettingItem(SettingItem {
4890 title: "Font Features",
4891 description: "Font features for terminal text.",
4892 field: Box::new(
4893 SettingField {
4894 json_path: Some("terminal.font_features"),
4895 pick: |settings_content| {
4896 settings_content
4897 .terminal
4898 .as_ref()
4899 .and_then(|terminal| terminal.font_features.as_ref())
4900 .or(settings_content.theme.buffer_font_features.as_ref())
4901 },
4902 write: |settings_content, value| {
4903 settings_content
4904 .terminal
4905 .get_or_insert_default()
4906 .font_features = value;
4907 },
4908 }
4909 .unimplemented(),
4910 ),
4911 metadata: None,
4912 files: USER,
4913 }),
4914 SettingsPageItem::SectionHeader("Display Settings"),
4915 SettingsPageItem::SettingItem(SettingItem {
4916 title: "Line Height",
4917 description: "Line height for terminal text.",
4918 field: Box::new(
4919 SettingField {
4920 json_path: Some("terminal.line_height"),
4921 pick: |settings_content| {
4922 settings_content.terminal.as_ref()?.line_height.as_ref()
4923 },
4924 write: |settings_content, value| {
4925 settings_content
4926 .terminal
4927 .get_or_insert_default()
4928 .line_height = value;
4929 },
4930 }
4931 .unimplemented(),
4932 ),
4933 metadata: None,
4934 files: USER,
4935 }),
4936 SettingsPageItem::SettingItem(SettingItem {
4937 title: "Cursor Shape",
4938 description: "Default cursor shape for the terminal (bar, block, underline, or hollow).",
4939 field: Box::new(SettingField {
4940 json_path: Some("terminal.cursor_shape"),
4941 pick: |settings_content| {
4942 settings_content.terminal.as_ref()?.cursor_shape.as_ref()
4943 },
4944 write: |settings_content, value| {
4945 settings_content
4946 .terminal
4947 .get_or_insert_default()
4948 .cursor_shape = value;
4949 },
4950 }),
4951 metadata: None,
4952 files: USER,
4953 }),
4954 SettingsPageItem::SettingItem(SettingItem {
4955 title: "Cursor Blinking",
4956 description: "Sets the cursor blinking behavior in the terminal.",
4957 field: Box::new(SettingField {
4958 json_path: Some("terminal.blinking"),
4959 pick: |settings_content| {
4960 settings_content.terminal.as_ref()?.blinking.as_ref()
4961 },
4962 write: |settings_content, value| {
4963 settings_content.terminal.get_or_insert_default().blinking = value;
4964 },
4965 }),
4966 metadata: None,
4967 files: USER,
4968 }),
4969 SettingsPageItem::SettingItem(SettingItem {
4970 title: "Alternate Scroll",
4971 description: "Whether alternate scroll mode is active by default (converts mouse scroll to arrow keys in apps like Vim).",
4972 field: Box::new(SettingField {
4973 json_path: Some("terminal.alternate_scroll"),
4974 pick: |settings_content| {
4975 settings_content
4976 .terminal
4977 .as_ref()?
4978 .alternate_scroll
4979 .as_ref()
4980 },
4981 write: |settings_content, value| {
4982 settings_content
4983 .terminal
4984 .get_or_insert_default()
4985 .alternate_scroll = value;
4986 },
4987 }),
4988 metadata: None,
4989 files: USER,
4990 }),
4991 SettingsPageItem::SettingItem(SettingItem {
4992 title: "Minimum Contrast",
4993 description: "The minimum APCA perceptual contrast between foreground and background colors (0-106).",
4994 field: Box::new(SettingField {
4995 json_path: Some("terminal.minimum_contrast"),
4996 pick: |settings_content| {
4997 settings_content
4998 .terminal
4999 .as_ref()?
5000 .minimum_contrast
5001 .as_ref()
5002 },
5003 write: |settings_content, value| {
5004 settings_content
5005 .terminal
5006 .get_or_insert_default()
5007 .minimum_contrast = value;
5008 },
5009 }),
5010 metadata: None,
5011 files: USER,
5012 }),
5013 SettingsPageItem::SectionHeader("Behavior Settings"),
5014 SettingsPageItem::SettingItem(SettingItem {
5015 title: "Option As Meta",
5016 description: "Whether the option key behaves as the meta key.",
5017 field: Box::new(SettingField {
5018 json_path: Some("terminal.option_as_meta"),
5019 pick: |settings_content| {
5020 settings_content.terminal.as_ref()?.option_as_meta.as_ref()
5021 },
5022 write: |settings_content, value| {
5023 settings_content
5024 .terminal
5025 .get_or_insert_default()
5026 .option_as_meta = value;
5027 },
5028 }),
5029 metadata: None,
5030 files: USER,
5031 }),
5032 SettingsPageItem::SettingItem(SettingItem {
5033 title: "Copy On Select",
5034 description: "Whether selecting text in the terminal automatically copies to the system clipboard.",
5035 field: Box::new(SettingField {
5036 json_path: Some("terminal.copy_on_select"),
5037 pick: |settings_content| {
5038 settings_content.terminal.as_ref()?.copy_on_select.as_ref()
5039 },
5040 write: |settings_content, value| {
5041 settings_content
5042 .terminal
5043 .get_or_insert_default()
5044 .copy_on_select = value;
5045 },
5046 }),
5047 metadata: None,
5048 files: USER,
5049 }),
5050 SettingsPageItem::SettingItem(SettingItem {
5051 title: "Keep Selection On Copy",
5052 description: "Whether to keep the text selection after copying it to the clipboard.",
5053 field: Box::new(SettingField {
5054 json_path: Some("terminal.keep_selection_on_copy"),
5055 pick: |settings_content| {
5056 settings_content
5057 .terminal
5058 .as_ref()?
5059 .keep_selection_on_copy
5060 .as_ref()
5061 },
5062 write: |settings_content, value| {
5063 settings_content
5064 .terminal
5065 .get_or_insert_default()
5066 .keep_selection_on_copy = value;
5067 },
5068 }),
5069 metadata: None,
5070 files: USER,
5071 }),
5072 SettingsPageItem::SectionHeader("Layout Settings"),
5073 SettingsPageItem::SettingItem(SettingItem {
5074 title: "Default Width",
5075 description: "Default width when the terminal is docked to the left or right (in pixels).",
5076 field: Box::new(SettingField {
5077 json_path: Some("terminal.default_width"),
5078 pick: |settings_content| {
5079 settings_content.terminal.as_ref()?.default_width.as_ref()
5080 },
5081 write: |settings_content, value| {
5082 settings_content
5083 .terminal
5084 .get_or_insert_default()
5085 .default_width = value;
5086 },
5087 }),
5088 metadata: None,
5089 files: USER,
5090 }),
5091 SettingsPageItem::SettingItem(SettingItem {
5092 title: "Default Height",
5093 description: "Default height when the terminal is docked to the bottom (in pixels).",
5094 field: Box::new(SettingField {
5095 json_path: Some("terminal.default_height"),
5096 pick: |settings_content| {
5097 settings_content.terminal.as_ref()?.default_height.as_ref()
5098 },
5099 write: |settings_content, value| {
5100 settings_content
5101 .terminal
5102 .get_or_insert_default()
5103 .default_height = value;
5104 },
5105 }),
5106 metadata: None,
5107 files: USER,
5108 }),
5109 SettingsPageItem::SectionHeader("Advanced Settings"),
5110 SettingsPageItem::SettingItem(SettingItem {
5111 title: "Max Scroll History Lines",
5112 description: "Maximum number of lines to keep in scrollback history (max: 100,000; 0 disables scrolling).",
5113 field: Box::new(SettingField {
5114 json_path: Some("terminal.max_scroll_history_lines"),
5115 pick: |settings_content| {
5116 settings_content
5117 .terminal
5118 .as_ref()?
5119 .max_scroll_history_lines
5120 .as_ref()
5121 },
5122 write: |settings_content, value| {
5123 settings_content
5124 .terminal
5125 .get_or_insert_default()
5126 .max_scroll_history_lines = value;
5127 },
5128 }),
5129 metadata: None,
5130 files: USER,
5131 }),
5132 SettingsPageItem::SectionHeader("Toolbar"),
5133 SettingsPageItem::SettingItem(SettingItem {
5134 title: "Breadcrumbs",
5135 description: "Display the terminal title in breadcrumbs inside the terminal pane.",
5136 field: Box::new(SettingField {
5137 json_path: Some("terminal.toolbar.breadcrumbs"),
5138 pick: |settings_content| {
5139 settings_content
5140 .terminal
5141 .as_ref()?
5142 .toolbar
5143 .as_ref()?
5144 .breadcrumbs
5145 .as_ref()
5146 },
5147 write: |settings_content, value| {
5148 settings_content
5149 .terminal
5150 .get_or_insert_default()
5151 .toolbar
5152 .get_or_insert_default()
5153 .breadcrumbs = value;
5154 },
5155 }),
5156 metadata: None,
5157 files: USER,
5158 }),
5159 SettingsPageItem::SectionHeader("Scrollbar"),
5160 SettingsPageItem::SettingItem(SettingItem {
5161 title: "Show Scrollbar",
5162 description: "When to show the scrollbar in the terminal.",
5163 field: Box::new(SettingField {
5164 json_path: Some("terminal.scrollbar.show"),
5165 pick: |settings_content| {
5166 show_scrollbar_or_editor(settings_content, |settings_content| {
5167 settings_content
5168 .terminal
5169 .as_ref()?
5170 .scrollbar
5171 .as_ref()?
5172 .show
5173 .as_ref()
5174 })
5175 },
5176 write: |settings_content, value| {
5177 settings_content
5178 .terminal
5179 .get_or_insert_default()
5180 .scrollbar
5181 .get_or_insert_default()
5182 .show = value;
5183 },
5184 }),
5185 metadata: None,
5186 files: USER,
5187 }),
5188 ],
5189 },
5190 SettingsPage {
5191 title: "Version Control",
5192 items: vec![
5193 SettingsPageItem::SectionHeader("Git Gutter"),
5194 SettingsPageItem::SettingItem(SettingItem {
5195 title: "Visibility",
5196 description: "Control whether Git status is shown in the editor's gutter.",
5197 field: Box::new(SettingField {
5198 json_path: Some("git.git_gutter"),
5199 pick: |settings_content| settings_content.git.as_ref()?.git_gutter.as_ref(),
5200 write: |settings_content, value| {
5201 settings_content.git.get_or_insert_default().git_gutter = value;
5202 },
5203 }),
5204 metadata: None,
5205 files: USER,
5206 }),
5207 // todo(settings_ui): Figure out the right default for this value in default.json
5208 SettingsPageItem::SettingItem(SettingItem {
5209 title: "Debounce",
5210 description: "Debounce threshold in milliseconds after which changes are reflected in the Git gutter.",
5211 field: Box::new(SettingField {
5212 json_path: Some("git.gutter_debounce"),
5213 pick: |settings_content| {
5214 settings_content.git.as_ref()?.gutter_debounce.as_ref()
5215 },
5216 write: |settings_content, value| {
5217 settings_content.git.get_or_insert_default().gutter_debounce = value;
5218 },
5219 }),
5220 metadata: None,
5221 files: USER,
5222 }),
5223 SettingsPageItem::SectionHeader("Inline Git Blame"),
5224 SettingsPageItem::SettingItem(SettingItem {
5225 title: "Enabled",
5226 description: "Whether or not to show Git blame data inline in the currently focused line.",
5227 field: Box::new(SettingField {
5228 json_path: Some("git.inline_blame.enabled"),
5229 pick: |settings_content| {
5230 settings_content
5231 .git
5232 .as_ref()?
5233 .inline_blame
5234 .as_ref()?
5235 .enabled
5236 .as_ref()
5237 },
5238 write: |settings_content, value| {
5239 settings_content
5240 .git
5241 .get_or_insert_default()
5242 .inline_blame
5243 .get_or_insert_default()
5244 .enabled = value;
5245 },
5246 }),
5247 metadata: None,
5248 files: USER,
5249 }),
5250 SettingsPageItem::SettingItem(SettingItem {
5251 title: "Delay",
5252 description: "The delay after which the inline blame information is shown.",
5253 field: Box::new(SettingField {
5254 json_path: Some("git.inline_blame.delay_ms"),
5255 pick: |settings_content| {
5256 settings_content
5257 .git
5258 .as_ref()?
5259 .inline_blame
5260 .as_ref()?
5261 .delay_ms
5262 .as_ref()
5263 },
5264 write: |settings_content, value| {
5265 settings_content
5266 .git
5267 .get_or_insert_default()
5268 .inline_blame
5269 .get_or_insert_default()
5270 .delay_ms = value;
5271 },
5272 }),
5273 metadata: None,
5274 files: USER,
5275 }),
5276 SettingsPageItem::SettingItem(SettingItem {
5277 title: "Padding",
5278 description: "Padding between the end of the source line and the start of the inline blame in columns.",
5279 field: Box::new(SettingField {
5280 json_path: Some("git.inline_blame.padding"),
5281 pick: |settings_content| {
5282 settings_content
5283 .git
5284 .as_ref()?
5285 .inline_blame
5286 .as_ref()?
5287 .padding
5288 .as_ref()
5289 },
5290 write: |settings_content, value| {
5291 settings_content
5292 .git
5293 .get_or_insert_default()
5294 .inline_blame
5295 .get_or_insert_default()
5296 .padding = value;
5297 },
5298 }),
5299 metadata: None,
5300 files: USER,
5301 }),
5302 SettingsPageItem::SettingItem(SettingItem {
5303 title: "Minimum Column",
5304 description: "The minimum column number at which to show the inline blame information.",
5305 field: Box::new(SettingField {
5306 json_path: Some("git.inline_blame.min_column"),
5307 pick: |settings_content| {
5308 settings_content
5309 .git
5310 .as_ref()?
5311 .inline_blame
5312 .as_ref()?
5313 .min_column
5314 .as_ref()
5315 },
5316 write: |settings_content, value| {
5317 settings_content
5318 .git
5319 .get_or_insert_default()
5320 .inline_blame
5321 .get_or_insert_default()
5322 .min_column = value;
5323 },
5324 }),
5325 metadata: None,
5326 files: USER,
5327 }),
5328 SettingsPageItem::SettingItem(SettingItem {
5329 title: "Show Commit Summary",
5330 description: "Show commit summary as part of the inline blame.",
5331 field: Box::new(SettingField {
5332 json_path: Some("git.inline_blame.show_commit_summary"),
5333 pick: |settings_content| {
5334 settings_content
5335 .git
5336 .as_ref()?
5337 .inline_blame
5338 .as_ref()?
5339 .show_commit_summary
5340 .as_ref()
5341 },
5342 write: |settings_content, value| {
5343 settings_content
5344 .git
5345 .get_or_insert_default()
5346 .inline_blame
5347 .get_or_insert_default()
5348 .show_commit_summary = value;
5349 },
5350 }),
5351 metadata: None,
5352 files: USER,
5353 }),
5354 SettingsPageItem::SectionHeader("Git Blame View"),
5355 SettingsPageItem::SettingItem(SettingItem {
5356 title: "Show Avatar",
5357 description: "Show the avatar of the author of the commit.",
5358 field: Box::new(SettingField {
5359 json_path: Some("git.blame.show_avatar"),
5360 pick: |settings_content| {
5361 settings_content
5362 .git
5363 .as_ref()?
5364 .blame
5365 .as_ref()?
5366 .show_avatar
5367 .as_ref()
5368 },
5369 write: |settings_content, value| {
5370 settings_content
5371 .git
5372 .get_or_insert_default()
5373 .blame
5374 .get_or_insert_default()
5375 .show_avatar = value;
5376 },
5377 }),
5378 metadata: None,
5379 files: USER,
5380 }),
5381 SettingsPageItem::SectionHeader("Branch Picker"),
5382 SettingsPageItem::SettingItem(SettingItem {
5383 title: "Show Author Name",
5384 description: "Show author name as part of the commit information in branch picker.",
5385 field: Box::new(SettingField {
5386 json_path: Some("git.branch_picker.show_author_name"),
5387 pick: |settings_content| {
5388 settings_content
5389 .git
5390 .as_ref()?
5391 .branch_picker
5392 .as_ref()?
5393 .show_author_name
5394 .as_ref()
5395 },
5396 write: |settings_content, value| {
5397 settings_content
5398 .git
5399 .get_or_insert_default()
5400 .branch_picker
5401 .get_or_insert_default()
5402 .show_author_name = value;
5403 },
5404 }),
5405 metadata: None,
5406 files: USER,
5407 }),
5408 SettingsPageItem::SectionHeader("Git Hunks"),
5409 SettingsPageItem::SettingItem(SettingItem {
5410 title: "Hunk Style",
5411 description: "How Git hunks are displayed visually in the editor.",
5412 field: Box::new(SettingField {
5413 json_path: Some("git.hunk_style"),
5414 pick: |settings_content| settings_content.git.as_ref()?.hunk_style.as_ref(),
5415 write: |settings_content, value| {
5416 settings_content.git.get_or_insert_default().hunk_style = value;
5417 },
5418 }),
5419 metadata: None,
5420 files: USER,
5421 }),
5422 ],
5423 },
5424 SettingsPage {
5425 title: "Collaboration",
5426 items: vec![
5427 SettingsPageItem::SectionHeader("Calls"),
5428 SettingsPageItem::SettingItem(SettingItem {
5429 title: "Mute On Join",
5430 description: "Whether the microphone should be muted when joining a channel or a call.",
5431 field: Box::new(SettingField {
5432 json_path: Some("calls.mute_on_join"),
5433 pick: |settings_content| {
5434 settings_content.calls.as_ref()?.mute_on_join.as_ref()
5435 },
5436 write: |settings_content, value| {
5437 settings_content.calls.get_or_insert_default().mute_on_join = value;
5438 },
5439 }),
5440 metadata: None,
5441 files: USER,
5442 }),
5443 SettingsPageItem::SettingItem(SettingItem {
5444 title: "Share On Join",
5445 description: "Whether your current project should be shared when joining an empty channel.",
5446 field: Box::new(SettingField {
5447 json_path: Some("calls.share_on_join"),
5448 pick: |settings_content| {
5449 settings_content.calls.as_ref()?.share_on_join.as_ref()
5450 },
5451 write: |settings_content, value| {
5452 settings_content.calls.get_or_insert_default().share_on_join = value;
5453 },
5454 }),
5455 metadata: None,
5456 files: USER,
5457 }),
5458 SettingsPageItem::SectionHeader("Experimental"),
5459 SettingsPageItem::SettingItem(SettingItem {
5460 title: "Rodio Audio",
5461 description: "Opt into the new audio system.",
5462 field: Box::new(SettingField {
5463 json_path: Some("audio.experimental.rodio_audio"),
5464 pick: |settings_content| {
5465 settings_content.audio.as_ref()?.rodio_audio.as_ref()
5466 },
5467 write: |settings_content, value| {
5468 settings_content.audio.get_or_insert_default().rodio_audio = value;
5469 },
5470 }),
5471 metadata: None,
5472 files: USER,
5473 }),
5474 SettingsPageItem::SettingItem(SettingItem {
5475 title: "Auto Microphone Volume",
5476 description: "Automatically adjust microphone volume (requires rodio audio).",
5477 field: Box::new(SettingField {
5478 json_path: Some("audio.experimental.auto_microphone_volume"),
5479 pick: |settings_content| {
5480 settings_content
5481 .audio
5482 .as_ref()?
5483 .auto_microphone_volume
5484 .as_ref()
5485 },
5486 write: |settings_content, value| {
5487 settings_content
5488 .audio
5489 .get_or_insert_default()
5490 .auto_microphone_volume = value;
5491 },
5492 }),
5493 metadata: None,
5494 files: USER,
5495 }),
5496 SettingsPageItem::SettingItem(SettingItem {
5497 title: "Auto Speaker Volume",
5498 description: "Automatically adjust volume of other call members (requires rodio audio).",
5499 field: Box::new(SettingField {
5500 json_path: Some("audio.experimental.auto_speaker_volume"),
5501 pick: |settings_content| {
5502 settings_content
5503 .audio
5504 .as_ref()?
5505 .auto_speaker_volume
5506 .as_ref()
5507 },
5508 write: |settings_content, value| {
5509 settings_content
5510 .audio
5511 .get_or_insert_default()
5512 .auto_speaker_volume = value;
5513 },
5514 }),
5515 metadata: None,
5516 files: USER,
5517 }),
5518 SettingsPageItem::SettingItem(SettingItem {
5519 title: "Denoise",
5520 description: "Remove background noises (requires rodio audio).",
5521 field: Box::new(SettingField {
5522 json_path: Some("audio.experimental.denoise"),
5523 pick: |settings_content| settings_content.audio.as_ref()?.denoise.as_ref(),
5524 write: |settings_content, value| {
5525 settings_content.audio.get_or_insert_default().denoise = value;
5526 },
5527 }),
5528 metadata: None,
5529 files: USER,
5530 }),
5531 SettingsPageItem::SettingItem(SettingItem {
5532 title: "Legacy Audio Compatible",
5533 description: "Use audio parameters compatible with previous versions (requires rodio audio).",
5534 field: Box::new(SettingField {
5535 json_path: Some("audio.experimental.legacy_audio_compatible"),
5536 pick: |settings_content| {
5537 settings_content
5538 .audio
5539 .as_ref()?
5540 .legacy_audio_compatible
5541 .as_ref()
5542 },
5543 write: |settings_content, value| {
5544 settings_content
5545 .audio
5546 .get_or_insert_default()
5547 .legacy_audio_compatible = value;
5548 },
5549 }),
5550 metadata: None,
5551 files: USER,
5552 }),
5553 ],
5554 },
5555 SettingsPage {
5556 title: "AI",
5557 items: {
5558 let mut items = vec![
5559 SettingsPageItem::SectionHeader("General"),
5560 SettingsPageItem::SettingItem(SettingItem {
5561 title: "Disable AI",
5562 description: "Whether to disable all AI features in Zed.",
5563 field: Box::new(SettingField {
5564 json_path: Some("disable_ai"),
5565 pick: |settings_content| settings_content.disable_ai.as_ref(),
5566 write: |settings_content, value| {
5567 settings_content.disable_ai = value;
5568 },
5569 }),
5570 metadata: None,
5571 files: USER,
5572 }),
5573 SettingsPageItem::SectionHeader("Agent Configuration"),
5574 SettingsPageItem::SettingItem(SettingItem {
5575 title: "Always Allow Tool Actions",
5576 description: "When enabled, the agent can run potentially destructive actions without asking for your confirmation. This setting has no effect on external agents.",
5577 field: Box::new(SettingField {
5578 json_path: Some("agent.always_allow_tool_actions"),
5579 pick: |settings_content| {
5580 settings_content
5581 .agent
5582 .as_ref()?
5583 .always_allow_tool_actions
5584 .as_ref()
5585 },
5586 write: |settings_content, value| {
5587 settings_content
5588 .agent
5589 .get_or_insert_default()
5590 .always_allow_tool_actions = value;
5591 },
5592 }),
5593 metadata: None,
5594 files: USER,
5595 }),
5596 SettingsPageItem::SettingItem(SettingItem {
5597 title: "Single File Review",
5598 description: "When enabled, agent edits will also be displayed in single-file buffers for review.",
5599 field: Box::new(SettingField {
5600 json_path: Some("agent.single_file_review"),
5601 pick: |settings_content| {
5602 settings_content.agent.as_ref()?.single_file_review.as_ref()
5603 },
5604 write: |settings_content, value| {
5605 settings_content
5606 .agent
5607 .get_or_insert_default()
5608 .single_file_review = value;
5609 },
5610 }),
5611 metadata: None,
5612 files: USER,
5613 }),
5614 SettingsPageItem::SettingItem(SettingItem {
5615 title: "Enable Feedback",
5616 description: "Show voting thumbs up/down icon buttons for feedback on agent edits.",
5617 field: Box::new(SettingField {
5618 json_path: Some("agent.enable_feedback"),
5619 pick: |settings_content| {
5620 settings_content.agent.as_ref()?.enable_feedback.as_ref()
5621 },
5622 write: |settings_content, value| {
5623 settings_content
5624 .agent
5625 .get_or_insert_default()
5626 .enable_feedback = value;
5627 },
5628 }),
5629 metadata: None,
5630 files: USER,
5631 }),
5632 SettingsPageItem::SettingItem(SettingItem {
5633 title: "Notify When Agent Waiting",
5634 description: "Where to show notifications when the agent has completed its response or needs confirmation before running a tool action.",
5635 field: Box::new(SettingField {
5636 json_path: Some("agent.notify_when_agent_waiting"),
5637 pick: |settings_content| {
5638 settings_content
5639 .agent
5640 .as_ref()?
5641 .notify_when_agent_waiting
5642 .as_ref()
5643 },
5644 write: |settings_content, value| {
5645 settings_content
5646 .agent
5647 .get_or_insert_default()
5648 .notify_when_agent_waiting = value;
5649 },
5650 }),
5651 metadata: None,
5652 files: USER,
5653 }),
5654 SettingsPageItem::SettingItem(SettingItem {
5655 title: "Play Sound When Agent Done",
5656 description: "Whether to play a sound when the agent has either completed its response, or needs user input.",
5657 field: Box::new(SettingField {
5658 json_path: Some("agent.play_sound_when_agent_done"),
5659 pick: |settings_content| {
5660 settings_content
5661 .agent
5662 .as_ref()?
5663 .play_sound_when_agent_done
5664 .as_ref()
5665 },
5666 write: |settings_content, value| {
5667 settings_content
5668 .agent
5669 .get_or_insert_default()
5670 .play_sound_when_agent_done = value;
5671 },
5672 }),
5673 metadata: None,
5674 files: USER,
5675 }),
5676 SettingsPageItem::SettingItem(SettingItem {
5677 title: "Expand Edit Card",
5678 description: "Whether to have edit cards in the agent panel expanded, showing a Preview of the diff.",
5679 field: Box::new(SettingField {
5680 json_path: Some("agent.expand_edit_card"),
5681 pick: |settings_content| {
5682 settings_content.agent.as_ref()?.expand_edit_card.as_ref()
5683 },
5684 write: |settings_content, value| {
5685 settings_content
5686 .agent
5687 .get_or_insert_default()
5688 .expand_edit_card = value;
5689 },
5690 }),
5691 metadata: None,
5692 files: USER,
5693 }),
5694 SettingsPageItem::SettingItem(SettingItem {
5695 title: "Expand Terminal Card",
5696 description: "Whether to have terminal cards in the agent panel expanded, showing the whole command output.",
5697 field: Box::new(SettingField {
5698 json_path: Some("agent.expand_terminal_card"),
5699 pick: |settings_content| {
5700 settings_content
5701 .agent
5702 .as_ref()?
5703 .expand_terminal_card
5704 .as_ref()
5705 },
5706 write: |settings_content, value| {
5707 settings_content
5708 .agent
5709 .get_or_insert_default()
5710 .expand_terminal_card = value;
5711 },
5712 }),
5713 metadata: None,
5714 files: USER,
5715 }),
5716 SettingsPageItem::SettingItem(SettingItem {
5717 title: "Use Modifier To Send",
5718 description: "Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages.",
5719 field: Box::new(SettingField {
5720 json_path: Some("agent.use_modifier_to_send"),
5721 pick: |settings_content| {
5722 settings_content
5723 .agent
5724 .as_ref()?
5725 .use_modifier_to_send
5726 .as_ref()
5727 },
5728 write: |settings_content, value| {
5729 settings_content
5730 .agent
5731 .get_or_insert_default()
5732 .use_modifier_to_send = value;
5733 },
5734 }),
5735 metadata: None,
5736 files: USER,
5737 }),
5738 SettingsPageItem::SettingItem(SettingItem {
5739 title: "Message Editor Min Lines",
5740 description: "Minimum number of lines to display in the agent message editor.",
5741 field: Box::new(SettingField {
5742 json_path: Some("agent.message_editor_min_lines"),
5743 pick: |settings_content| {
5744 settings_content
5745 .agent
5746 .as_ref()?
5747 .message_editor_min_lines
5748 .as_ref()
5749 },
5750 write: |settings_content, value| {
5751 settings_content
5752 .agent
5753 .get_or_insert_default()
5754 .message_editor_min_lines = value;
5755 },
5756 }),
5757 metadata: None,
5758 files: USER,
5759 }),
5760 ];
5761 items.extend(edit_prediction_language_settings_section());
5762 items.extend(
5763 [
5764 SettingsPageItem::SettingItem(SettingItem {
5765 title: "Display Mode",
5766 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.",
5767 field: Box::new(SettingField {
5768 json_path: Some("edit_prediction.display_mode"),
5769 pick: |settings_content| {
5770 settings_content.project.all_languages.edit_predictions.as_ref()?.mode.as_ref()
5771 },
5772 write: |settings_content, value| {
5773 settings_content.project.all_languages.edit_predictions.get_or_insert_default().mode = value;
5774 },
5775 }),
5776 metadata: None,
5777 files: USER,
5778 }),
5779 SettingsPageItem::SettingItem(SettingItem {
5780 title: "In Text Threads",
5781 description: "Whether edit predictions are enabled when editing text threads in the agent panel.",
5782 field: Box::new(SettingField {
5783 json_path: Some("edit_prediction.in_text_threads"),
5784 pick: |settings_content| {
5785 settings_content.project.all_languages.edit_predictions.as_ref()?.enabled_in_text_threads.as_ref()
5786 },
5787 write: |settings_content, value| {
5788 settings_content.project.all_languages.edit_predictions.get_or_insert_default().enabled_in_text_threads = value;
5789 },
5790 }),
5791 metadata: None,
5792 files: USER,
5793 }),
5794 SettingsPageItem::SettingItem(SettingItem {
5795 title: "Copilot Provider",
5796 description: "Use GitHub Copilot as your edit prediction provider.",
5797 field: Box::new(
5798 SettingField {
5799 json_path: Some("edit_prediction.copilot_provider"),
5800 pick: |settings_content| {
5801 settings_content.project.all_languages.edit_predictions.as_ref()?.copilot.as_ref()
5802 },
5803 write: |settings_content, value| {
5804 settings_content.project.all_languages.edit_predictions.get_or_insert_default().copilot = value;
5805 },
5806 }
5807 .unimplemented(),
5808 ),
5809 metadata: None,
5810 files: USER | PROJECT,
5811 }),
5812 SettingsPageItem::SettingItem(SettingItem {
5813 title: "Codestral Provider",
5814 description: "Use Mistral's Codestral as your edit prediction provider.",
5815 field: Box::new(
5816 SettingField {
5817 json_path: Some("edit_prediction.codestral_provider"),
5818 pick: |settings_content| {
5819 settings_content.project.all_languages.edit_predictions.as_ref()?.codestral.as_ref()
5820 },
5821 write: |settings_content, value| {
5822 settings_content.project.all_languages.edit_predictions.get_or_insert_default().codestral = value;
5823 },
5824 }
5825 .unimplemented(),
5826 ),
5827 metadata: None,
5828 files: USER | PROJECT,
5829 }),
5830 ]
5831 );
5832 items
5833 },
5834 },
5835 SettingsPage {
5836 title: "Network",
5837 items: vec![
5838 SettingsPageItem::SectionHeader("Network"),
5839 // todo(settings_ui): Proxy needs a default
5840 SettingsPageItem::SettingItem(SettingItem {
5841 title: "Proxy",
5842 description: "The proxy to use for network requests.",
5843 field: Box::new(
5844 SettingField {
5845 json_path: Some("proxy"),
5846 pick: |settings_content| settings_content.proxy.as_ref(),
5847 write: |settings_content, value| {
5848 settings_content.proxy = value;
5849 },
5850 }
5851 .unimplemented(),
5852 ),
5853 metadata: Some(Box::new(SettingsFieldMetadata {
5854 placeholder: Some("socks5h://localhost:10808"),
5855 ..Default::default()
5856 })),
5857 files: USER,
5858 }),
5859 SettingsPageItem::SettingItem(SettingItem {
5860 title: "Server URL",
5861 description: "The URL of the Zed server to connect to.",
5862 field: Box::new(SettingField {
5863 json_path: Some("server_url"),
5864 pick: |settings_content| settings_content.server_url.as_ref(),
5865 write: |settings_content, value| {
5866 settings_content.server_url = value;
5867 },
5868 }),
5869 metadata: Some(Box::new(SettingsFieldMetadata {
5870 placeholder: Some("https://zed.dev"),
5871 ..Default::default()
5872 })),
5873 files: USER,
5874 }),
5875 ],
5876 },
5877 ]
5878}
5879
5880const LANGUAGES_SECTION_HEADER: &'static str = "Languages";
5881
5882fn current_language() -> Option<SharedString> {
5883 sub_page_stack().iter().find_map(|page| {
5884 (page.section_header == LANGUAGES_SECTION_HEADER).then(|| page.link.title.clone())
5885 })
5886}
5887
5888fn language_settings_field<T>(
5889 settings_content: &SettingsContent,
5890 get: fn(&LanguageSettingsContent) -> Option<&T>,
5891) -> Option<&T> {
5892 let all_languages = &settings_content.project.all_languages;
5893 if let Some(current_language_name) = current_language() {
5894 if let Some(current_language) = all_languages.languages.0.get(¤t_language_name) {
5895 let value = get(current_language);
5896 if value.is_some() {
5897 return value;
5898 }
5899 }
5900 }
5901 let default_value = get(&all_languages.defaults);
5902 return default_value;
5903}
5904
5905fn language_settings_field_mut<T>(
5906 settings_content: &mut SettingsContent,
5907 value: Option<T>,
5908 write: fn(&mut LanguageSettingsContent, Option<T>),
5909) {
5910 let all_languages = &mut settings_content.project.all_languages;
5911 let language_content = if let Some(current_language) = current_language() {
5912 all_languages
5913 .languages
5914 .0
5915 .entry(current_language)
5916 .or_default()
5917 } else {
5918 &mut all_languages.defaults
5919 };
5920 write(language_content, value);
5921}
5922
5923fn language_settings_data() -> Vec<SettingsPageItem> {
5924 let mut items = vec![
5925 SettingsPageItem::SectionHeader("Indentation"),
5926 SettingsPageItem::SettingItem(SettingItem {
5927 title: "Tab Size",
5928 description: "How many columns a tab should occupy.",
5929 field: Box::new(SettingField {
5930 json_path: Some("languages.$(language).tab_size"), // TODO(cameron): not JQ syntax because not URL-safe
5931 pick: |settings_content| {
5932 language_settings_field(settings_content, |language| language.tab_size.as_ref())
5933 },
5934 write: |settings_content, value| {
5935 language_settings_field_mut(settings_content, value, |language, value| {
5936 language.tab_size = value;
5937 })
5938 },
5939 }),
5940 metadata: None,
5941 files: USER | PROJECT,
5942 }),
5943 SettingsPageItem::SettingItem(SettingItem {
5944 title: "Hard Tabs",
5945 description: "Whether to indent lines using tab characters, as opposed to multiple spaces.",
5946 field: Box::new(SettingField {
5947 json_path: Some("languages.$(language).hard_tabs"),
5948 pick: |settings_content| {
5949 language_settings_field(settings_content, |language| {
5950 language.hard_tabs.as_ref()
5951 })
5952 },
5953 write: |settings_content, value| {
5954 language_settings_field_mut(settings_content, value, |language, value| {
5955 language.hard_tabs = value;
5956 })
5957 },
5958 }),
5959 metadata: None,
5960 files: USER | PROJECT,
5961 }),
5962 SettingsPageItem::SettingItem(SettingItem {
5963 title: "Auto Indent",
5964 description: "Whether indentation should be adjusted based on the context whilst typing.",
5965 field: Box::new(SettingField {
5966 json_path: Some("languages.$(language).auto_indent"),
5967 pick: |settings_content| {
5968 language_settings_field(settings_content, |language| {
5969 language.auto_indent.as_ref()
5970 })
5971 },
5972 write: |settings_content, value| {
5973 language_settings_field_mut(settings_content, value, |language, value| {
5974 language.auto_indent = value;
5975 })
5976 },
5977 }),
5978 metadata: None,
5979 files: USER | PROJECT,
5980 }),
5981 SettingsPageItem::SettingItem(SettingItem {
5982 title: "Auto Indent On Paste",
5983 description: "Whether indentation of pasted content should be adjusted based on the context.",
5984 field: Box::new(SettingField {
5985 json_path: Some("languages.$(language).auto_indent_on_paste"),
5986 pick: |settings_content| {
5987 language_settings_field(settings_content, |language| {
5988 language.auto_indent_on_paste.as_ref()
5989 })
5990 },
5991 write: |settings_content, value| {
5992 language_settings_field_mut(settings_content, value, |language, value| {
5993 language.auto_indent_on_paste = value;
5994 })
5995 },
5996 }),
5997 metadata: None,
5998 files: USER | PROJECT,
5999 }),
6000 SettingsPageItem::SectionHeader("Wrapping"),
6001 SettingsPageItem::SettingItem(SettingItem {
6002 title: "Soft Wrap",
6003 description: "How to soft-wrap long lines of text.",
6004 field: Box::new(SettingField {
6005 json_path: Some("languages.$(language).soft_wrap"),
6006 pick: |settings_content| {
6007 language_settings_field(settings_content, |language| {
6008 language.soft_wrap.as_ref()
6009 })
6010 },
6011 write: |settings_content, value| {
6012 language_settings_field_mut(settings_content, value, |language, value| {
6013 language.soft_wrap = value;
6014 })
6015 },
6016 }),
6017 metadata: None,
6018 files: USER | PROJECT,
6019 }),
6020 SettingsPageItem::SettingItem(SettingItem {
6021 title: "Show Wrap Guides",
6022 description: "Show wrap guides in the editor.",
6023 field: Box::new(SettingField {
6024 json_path: Some("languages.$(language).show_wrap_guides"),
6025 pick: |settings_content| {
6026 language_settings_field(settings_content, |language| {
6027 language.show_wrap_guides.as_ref()
6028 })
6029 },
6030 write: |settings_content, value| {
6031 language_settings_field_mut(settings_content, value, |language, value| {
6032 language.show_wrap_guides = value;
6033 })
6034 },
6035 }),
6036 metadata: None,
6037 files: USER | PROJECT,
6038 }),
6039 SettingsPageItem::SettingItem(SettingItem {
6040 title: "Preferred Line Length",
6041 description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled.",
6042 field: Box::new(SettingField {
6043 json_path: Some("languages.$(language).preferred_line_length"),
6044 pick: |settings_content| {
6045 language_settings_field(settings_content, |language| {
6046 language.preferred_line_length.as_ref()
6047 })
6048 },
6049 write: |settings_content, value| {
6050 language_settings_field_mut(settings_content, value, |language, value| {
6051 language.preferred_line_length = value;
6052 })
6053 },
6054 }),
6055 metadata: None,
6056 files: USER | PROJECT,
6057 }),
6058 SettingsPageItem::SettingItem(SettingItem {
6059 title: "Wrap Guides",
6060 description: "Character counts at which to show wrap guides in the editor.",
6061 field: Box::new(
6062 SettingField {
6063 json_path: Some("languages.$(language).wrap_guides"),
6064 pick: |settings_content| {
6065 language_settings_field(settings_content, |language| {
6066 language.wrap_guides.as_ref()
6067 })
6068 },
6069 write: |settings_content, value| {
6070 language_settings_field_mut(settings_content, value, |language, value| {
6071 language.wrap_guides = value;
6072 })
6073 },
6074 }
6075 .unimplemented(),
6076 ),
6077 metadata: None,
6078 files: USER | PROJECT,
6079 }),
6080 SettingsPageItem::SettingItem(SettingItem {
6081 title: "Allow Rewrap",
6082 description: "Controls where the `editor::rewrap` action is allowed for this language.",
6083 field: Box::new(SettingField {
6084 json_path: Some("languages.$(language).allow_rewrap"),
6085 pick: |settings_content| {
6086 language_settings_field(settings_content, |language| {
6087 language.allow_rewrap.as_ref()
6088 })
6089 },
6090 write: |settings_content, value| {
6091 language_settings_field_mut(settings_content, value, |language, value| {
6092 language.allow_rewrap = value;
6093 })
6094 },
6095 }),
6096 metadata: None,
6097 files: USER | PROJECT,
6098 }),
6099 SettingsPageItem::SectionHeader("Indent Guides"),
6100 SettingsPageItem::SettingItem(SettingItem {
6101 title: "Enabled",
6102 description: "Display indent guides in the editor.",
6103 field: Box::new(SettingField {
6104 json_path: Some("languages.$(language).indent_guides.enabled"),
6105 pick: |settings_content| {
6106 language_settings_field(settings_content, |language| {
6107 language
6108 .indent_guides
6109 .as_ref()
6110 .and_then(|indent_guides| indent_guides.enabled.as_ref())
6111 })
6112 },
6113 write: |settings_content, value| {
6114 language_settings_field_mut(settings_content, value, |language, value| {
6115 language.indent_guides.get_or_insert_default().enabled = value;
6116 })
6117 },
6118 }),
6119 metadata: None,
6120 files: USER | PROJECT,
6121 }),
6122 SettingsPageItem::SettingItem(SettingItem {
6123 title: "Line Width",
6124 description: "The width of the indent guides in pixels, between 1 and 10.",
6125 field: Box::new(SettingField {
6126 json_path: Some("languages.$(language).indent_guides.line_width"),
6127 pick: |settings_content| {
6128 language_settings_field(settings_content, |language| {
6129 language
6130 .indent_guides
6131 .as_ref()
6132 .and_then(|indent_guides| indent_guides.line_width.as_ref())
6133 })
6134 },
6135 write: |settings_content, value| {
6136 language_settings_field_mut(settings_content, value, |language, value| {
6137 language.indent_guides.get_or_insert_default().line_width = value;
6138 })
6139 },
6140 }),
6141 metadata: None,
6142 files: USER | PROJECT,
6143 }),
6144 SettingsPageItem::SettingItem(SettingItem {
6145 title: "Active Line Width",
6146 description: "The width of the active indent guide in pixels, between 1 and 10.",
6147 field: Box::new(SettingField {
6148 json_path: Some("languages.$(language).indent_guides.active_line_width"),
6149 pick: |settings_content| {
6150 language_settings_field(settings_content, |language| {
6151 language
6152 .indent_guides
6153 .as_ref()
6154 .and_then(|indent_guides| indent_guides.active_line_width.as_ref())
6155 })
6156 },
6157 write: |settings_content, value| {
6158 language_settings_field_mut(settings_content, value, |language, value| {
6159 language
6160 .indent_guides
6161 .get_or_insert_default()
6162 .active_line_width = value;
6163 })
6164 },
6165 }),
6166 metadata: None,
6167 files: USER | PROJECT,
6168 }),
6169 SettingsPageItem::SettingItem(SettingItem {
6170 title: "Coloring",
6171 description: "Determines how indent guides are colored.",
6172 field: Box::new(SettingField {
6173 json_path: Some("languages.$(language).indent_guides.coloring"),
6174 pick: |settings_content| {
6175 language_settings_field(settings_content, |language| {
6176 language
6177 .indent_guides
6178 .as_ref()
6179 .and_then(|indent_guides| indent_guides.coloring.as_ref())
6180 })
6181 },
6182 write: |settings_content, value| {
6183 language_settings_field_mut(settings_content, value, |language, value| {
6184 language.indent_guides.get_or_insert_default().coloring = value;
6185 })
6186 },
6187 }),
6188 metadata: None,
6189 files: USER | PROJECT,
6190 }),
6191 SettingsPageItem::SettingItem(SettingItem {
6192 title: "Background Coloring",
6193 description: "Determines how indent guide backgrounds are colored.",
6194 field: Box::new(SettingField {
6195 json_path: Some("languages.$(language).indent_guides.background_coloring"),
6196 pick: |settings_content| {
6197 language_settings_field(settings_content, |language| {
6198 language
6199 .indent_guides
6200 .as_ref()
6201 .and_then(|indent_guides| indent_guides.background_coloring.as_ref())
6202 })
6203 },
6204 write: |settings_content, value| {
6205 language_settings_field_mut(settings_content, value, |language, value| {
6206 language
6207 .indent_guides
6208 .get_or_insert_default()
6209 .background_coloring = value;
6210 })
6211 },
6212 }),
6213 metadata: None,
6214 files: USER | PROJECT,
6215 }),
6216 SettingsPageItem::SectionHeader("Formatting"),
6217 SettingsPageItem::SettingItem(SettingItem {
6218 title: "Format On Save",
6219 description: "Whether or not to perform a buffer format before saving.",
6220 field: Box::new(
6221 // TODO(settings_ui): this setting should just be a bool
6222 SettingField {
6223 json_path: Some("languages.$(language).format_on_save"),
6224 pick: |settings_content| {
6225 language_settings_field(settings_content, |language| {
6226 language.format_on_save.as_ref()
6227 })
6228 },
6229 write: |settings_content, value| {
6230 language_settings_field_mut(settings_content, value, |language, value| {
6231 language.format_on_save = value;
6232 })
6233 },
6234 },
6235 ),
6236 metadata: None,
6237 files: USER | PROJECT,
6238 }),
6239 SettingsPageItem::SettingItem(SettingItem {
6240 title: "Remove Trailing Whitespace On Save",
6241 description: "Whether or not to remove any trailing whitespace from lines of a buffer before saving it.",
6242 field: Box::new(SettingField {
6243 json_path: Some("languages.$(language).remove_trailing_whitespace_on_save"),
6244 pick: |settings_content| {
6245 language_settings_field(settings_content, |language| {
6246 language.remove_trailing_whitespace_on_save.as_ref()
6247 })
6248 },
6249 write: |settings_content, value| {
6250 language_settings_field_mut(settings_content, value, |language, value| {
6251 language.remove_trailing_whitespace_on_save = value;
6252 })
6253 },
6254 }),
6255 metadata: None,
6256 files: USER | PROJECT,
6257 }),
6258 SettingsPageItem::SettingItem(SettingItem {
6259 title: "Ensure Final Newline On Save",
6260 description: "Whether or not to ensure there's a single newline at the end of a buffer when saving it.",
6261 field: Box::new(SettingField {
6262 json_path: Some("languages.$(language).ensure_final_newline_on_save"),
6263 pick: |settings_content| {
6264 language_settings_field(settings_content, |language| {
6265 language.ensure_final_newline_on_save.as_ref()
6266 })
6267 },
6268 write: |settings_content, value| {
6269 language_settings_field_mut(settings_content, value, |language, value| {
6270 language.ensure_final_newline_on_save = value;
6271 })
6272 },
6273 }),
6274 metadata: None,
6275 files: USER | PROJECT,
6276 }),
6277 SettingsPageItem::SettingItem(SettingItem {
6278 title: "Formatter",
6279 description: "How to perform a buffer format.",
6280 field: Box::new(
6281 SettingField {
6282 json_path: Some("languages.$(language).formatter"),
6283 pick: |settings_content| {
6284 language_settings_field(settings_content, |language| {
6285 language.formatter.as_ref()
6286 })
6287 },
6288 write: |settings_content, value| {
6289 language_settings_field_mut(settings_content, value, |language, value| {
6290 language.formatter = value;
6291 })
6292 },
6293 }
6294 .unimplemented(),
6295 ),
6296 metadata: None,
6297 files: USER | PROJECT,
6298 }),
6299 SettingsPageItem::SettingItem(SettingItem {
6300 title: "Use On Type Format",
6301 description: "Whether to use additional LSP queries to format (and amend) the code after every \"trigger\" symbol input, defined by LSP server capabilities",
6302 field: Box::new(SettingField {
6303 json_path: Some("languages.$(language).use_on_type_format"),
6304 pick: |settings_content| {
6305 language_settings_field(settings_content, |language| {
6306 language.use_on_type_format.as_ref()
6307 })
6308 },
6309 write: |settings_content, value| {
6310 language_settings_field_mut(settings_content, value, |language, value| {
6311 language.use_on_type_format = value;
6312 })
6313 },
6314 }),
6315 metadata: None,
6316 files: USER | PROJECT,
6317 }),
6318 SettingsPageItem::SettingItem(SettingItem {
6319 title: "Code Actions On Format",
6320 description: "Additional code actions to run when formatting.",
6321 field: Box::new(
6322 SettingField {
6323 json_path: Some("languages.$(language).code_actions_on_format"),
6324 pick: |settings_content| {
6325 language_settings_field(settings_content, |language| {
6326 language.code_actions_on_format.as_ref()
6327 })
6328 },
6329 write: |settings_content, value| {
6330 language_settings_field_mut(settings_content, value, |language, value| {
6331 language.code_actions_on_format = value;
6332 })
6333 },
6334 }
6335 .unimplemented(),
6336 ),
6337 metadata: None,
6338 files: USER | PROJECT,
6339 }),
6340 SettingsPageItem::SectionHeader("Autoclose"),
6341 SettingsPageItem::SettingItem(SettingItem {
6342 title: "Use Autoclose",
6343 description: "Whether to automatically type closing characters for you. For example, when you type '(', Zed will automatically add a closing ')' at the correct position.",
6344 field: Box::new(SettingField {
6345 json_path: Some("languages.$(language).use_autoclose"),
6346 pick: |settings_content| {
6347 language_settings_field(settings_content, |language| {
6348 language.use_autoclose.as_ref()
6349 })
6350 },
6351 write: |settings_content, value| {
6352 language_settings_field_mut(settings_content, value, |language, value| {
6353 language.use_autoclose = value;
6354 })
6355 },
6356 }),
6357 metadata: None,
6358 files: USER | PROJECT,
6359 }),
6360 SettingsPageItem::SettingItem(SettingItem {
6361 title: "Use Auto Surround",
6362 description: "Whether to automatically surround text with characters for you. For example, when you select text and type '(', Zed will automatically surround text with ().",
6363 field: Box::new(SettingField {
6364 json_path: Some("languages.$(language).use_auto_surround"),
6365 pick: |settings_content| {
6366 language_settings_field(settings_content, |language| {
6367 language.use_auto_surround.as_ref()
6368 })
6369 },
6370 write: |settings_content, value| {
6371 language_settings_field_mut(settings_content, value, |language, value| {
6372 language.use_auto_surround = value;
6373 })
6374 },
6375 }),
6376 metadata: None,
6377 files: USER | PROJECT,
6378 }),
6379 SettingsPageItem::SettingItem(SettingItem {
6380 title: "Always Treat Brackets As Autoclosed",
6381 description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted.",
6382 field: Box::new(SettingField {
6383 json_path: Some("languages.$(language).always_treat_brackets_as_autoclosed"),
6384 pick: |settings_content| {
6385 language_settings_field(settings_content, |language| {
6386 language.always_treat_brackets_as_autoclosed.as_ref()
6387 })
6388 },
6389 write: |settings_content, value| {
6390 language_settings_field_mut(settings_content, value, |language, value| {
6391 language.always_treat_brackets_as_autoclosed = value;
6392 })
6393 },
6394 }),
6395 metadata: None,
6396 files: USER | PROJECT,
6397 }),
6398 SettingsPageItem::SettingItem(SettingItem {
6399 title: "Jsx Tag Auto Close",
6400 description: "Whether to automatically close JSX tags.",
6401 field: Box::new(SettingField {
6402 json_path: Some("languages.$(language).jsx_tag_auto_close"),
6403 // TODO(settings_ui): this setting should just be a bool
6404 pick: |settings_content| {
6405 language_settings_field(settings_content, |language| {
6406 language.jsx_tag_auto_close.as_ref()?.enabled.as_ref()
6407 })
6408 },
6409 write: |settings_content, value| {
6410 language_settings_field_mut(settings_content, value, |language, value| {
6411 language.jsx_tag_auto_close.get_or_insert_default().enabled = value;
6412 })
6413 },
6414 }),
6415 metadata: None,
6416 files: USER | PROJECT,
6417 }),
6418 SettingsPageItem::SectionHeader("Whitespace"),
6419 SettingsPageItem::SettingItem(SettingItem {
6420 title: "Show Whitespaces",
6421 description: "Whether to show tabs and spaces in the editor.",
6422 field: Box::new(SettingField {
6423 json_path: Some("languages.$(language).show_whitespaces"),
6424 pick: |settings_content| {
6425 language_settings_field(settings_content, |language| {
6426 language.show_whitespaces.as_ref()
6427 })
6428 },
6429 write: |settings_content, value| {
6430 language_settings_field_mut(settings_content, value, |language, value| {
6431 language.show_whitespaces = value;
6432 })
6433 },
6434 }),
6435 metadata: None,
6436 files: USER | PROJECT,
6437 }),
6438 SettingsPageItem::SettingItem(SettingItem {
6439 title: "Space Whitespace Indicator",
6440 description: "Visible character used to render space characters when show_whitespaces is enabled (default: \"•\")",
6441 field: Box::new(
6442 SettingField {
6443 json_path: Some("languages.$(language).whitespace_map.space"),
6444 pick: |settings_content| {
6445 language_settings_field(settings_content, |language| {
6446 language.whitespace_map.as_ref()?.space.as_ref()
6447 })
6448 },
6449 write: |settings_content, value| {
6450 language_settings_field_mut(settings_content, value, |language, value| {
6451 language.whitespace_map.get_or_insert_default().space = value;
6452 })
6453 },
6454 }
6455 .unimplemented(),
6456 ),
6457 metadata: None,
6458 files: USER | PROJECT,
6459 }),
6460 SettingsPageItem::SettingItem(SettingItem {
6461 title: "Tab Whitespace Indicator",
6462 description: "Visible character used to render tab characters when show_whitespaces is enabled (default: \"→\")",
6463 field: Box::new(
6464 SettingField {
6465 json_path: Some("languages.$(language).whitespace_map.tab"),
6466 pick: |settings_content| {
6467 language_settings_field(settings_content, |language| {
6468 language.whitespace_map.as_ref()?.tab.as_ref()
6469 })
6470 },
6471 write: |settings_content, value| {
6472 language_settings_field_mut(settings_content, value, |language, value| {
6473 language.whitespace_map.get_or_insert_default().tab = value;
6474 })
6475 },
6476 }
6477 .unimplemented(),
6478 ),
6479 metadata: None,
6480 files: USER | PROJECT,
6481 }),
6482 SettingsPageItem::SectionHeader("Completions"),
6483 SettingsPageItem::SettingItem(SettingItem {
6484 title: "Show Completions On Input",
6485 description: "Whether to pop the completions menu while typing in an editor without explicitly requesting it.",
6486 field: Box::new(SettingField {
6487 json_path: Some("languages.$(language).show_completions_on_input"),
6488 pick: |settings_content| {
6489 language_settings_field(settings_content, |language| {
6490 language.show_completions_on_input.as_ref()
6491 })
6492 },
6493 write: |settings_content, value| {
6494 language_settings_field_mut(settings_content, value, |language, value| {
6495 language.show_completions_on_input = value;
6496 })
6497 },
6498 }),
6499 metadata: None,
6500 files: USER | PROJECT,
6501 }),
6502 SettingsPageItem::SettingItem(SettingItem {
6503 title: "Show Completion Documentation",
6504 description: "Whether to display inline and alongside documentation for items in the completions menu.",
6505 field: Box::new(SettingField {
6506 json_path: Some("languages.$(language).show_completion_documentation"),
6507 pick: |settings_content| {
6508 language_settings_field(settings_content, |language| {
6509 language.show_completion_documentation.as_ref()
6510 })
6511 },
6512 write: |settings_content, value| {
6513 language_settings_field_mut(settings_content, value, |language, value| {
6514 language.show_completion_documentation = value;
6515 })
6516 },
6517 }),
6518 metadata: None,
6519 files: USER | PROJECT,
6520 }),
6521 SettingsPageItem::SettingItem(SettingItem {
6522 title: "Colorize brackets",
6523 description: "Whether to colorize brackets in the editor.",
6524 field: Box::new(SettingField {
6525 json_path: Some("languages.$(language).colorize_brackets"),
6526 pick: |settings_content| {
6527 language_settings_field(settings_content, |language| {
6528 language.colorize_brackets.as_ref()
6529 })
6530 },
6531 write: |settings_content, value| {
6532 language_settings_field_mut(settings_content, value, |language, value| {
6533 language.colorize_brackets = value;
6534 })
6535 },
6536 }),
6537 metadata: None,
6538 files: USER | PROJECT,
6539 }),
6540 SettingsPageItem::SettingItem(SettingItem {
6541 title: "Words",
6542 description: "Controls how words are completed.",
6543 field: Box::new(SettingField {
6544 json_path: Some("languages.$(language).completions.words"),
6545 pick: |settings_content| {
6546 language_settings_field(settings_content, |language| {
6547 language.completions.as_ref()?.words.as_ref()
6548 })
6549 },
6550 write: |settings_content, value| {
6551 language_settings_field_mut(settings_content, value, |language, value| {
6552 language.completions.get_or_insert_default().words = value;
6553 })
6554 },
6555 }),
6556 metadata: None,
6557 files: USER | PROJECT,
6558 }),
6559 SettingsPageItem::SettingItem(SettingItem {
6560 title: "Words Min Length",
6561 description: "How many characters has to be in the completions query to automatically show the words-based completions.",
6562 field: Box::new(SettingField {
6563 json_path: Some("languages.$(language).completions.words_min_length"),
6564 pick: |settings_content| {
6565 language_settings_field(settings_content, |language| {
6566 language.completions.as_ref()?.words_min_length.as_ref()
6567 })
6568 },
6569 write: |settings_content, value| {
6570 language_settings_field_mut(settings_content, value, |language, value| {
6571 language
6572 .completions
6573 .get_or_insert_default()
6574 .words_min_length = value;
6575 })
6576 },
6577 }),
6578 metadata: None,
6579 files: USER | PROJECT,
6580 }),
6581 SettingsPageItem::SettingItem(SettingItem {
6582 title: "Completion Menu Scrollbar",
6583 description: "When to show the scrollbar in the completion menu.",
6584 field: Box::new(SettingField {
6585 json_path: Some("editor.completion_menu_scrollbar"),
6586 pick: |settings_content| settings_content.editor.completion_menu_scrollbar.as_ref(),
6587 write: |settings_content, value| {
6588 settings_content.editor.completion_menu_scrollbar = value;
6589 },
6590 }),
6591 metadata: None,
6592 files: USER,
6593 }),
6594 SettingsPageItem::SectionHeader("Inlay Hints"),
6595 SettingsPageItem::SettingItem(SettingItem {
6596 title: "Enabled",
6597 description: "Global switch to toggle hints on and off.",
6598 field: Box::new(SettingField {
6599 json_path: Some("languages.$(language).inlay_hints.enabled"),
6600 pick: |settings_content| {
6601 language_settings_field(settings_content, |language| {
6602 language.inlay_hints.as_ref()?.enabled.as_ref()
6603 })
6604 },
6605 write: |settings_content, value| {
6606 language_settings_field_mut(settings_content, value, |language, value| {
6607 language.inlay_hints.get_or_insert_default().enabled = value;
6608 })
6609 },
6610 }),
6611 metadata: None,
6612 files: USER | PROJECT,
6613 }),
6614 SettingsPageItem::SettingItem(SettingItem {
6615 title: "Show Value Hints",
6616 description: "Global switch to toggle inline values on and off when debugging.",
6617 field: Box::new(SettingField {
6618 json_path: Some("languages.$(language).inlay_hints.show_value_hints"),
6619 pick: |settings_content| {
6620 language_settings_field(settings_content, |language| {
6621 language.inlay_hints.as_ref()?.show_value_hints.as_ref()
6622 })
6623 },
6624 write: |settings_content, value| {
6625 language_settings_field_mut(settings_content, value, |language, value| {
6626 language
6627 .inlay_hints
6628 .get_or_insert_default()
6629 .show_value_hints = value;
6630 })
6631 },
6632 }),
6633 metadata: None,
6634 files: USER | PROJECT,
6635 }),
6636 SettingsPageItem::SettingItem(SettingItem {
6637 title: "Show Type Hints",
6638 description: "Whether type hints should be shown.",
6639 field: Box::new(SettingField {
6640 json_path: Some("languages.$(language).inlay_hints.show_type_hints"),
6641 pick: |settings_content| {
6642 language_settings_field(settings_content, |language| {
6643 language.inlay_hints.as_ref()?.show_type_hints.as_ref()
6644 })
6645 },
6646 write: |settings_content, value| {
6647 language_settings_field_mut(settings_content, value, |language, value| {
6648 language.inlay_hints.get_or_insert_default().show_type_hints = value;
6649 })
6650 },
6651 }),
6652 metadata: None,
6653 files: USER | PROJECT,
6654 }),
6655 SettingsPageItem::SettingItem(SettingItem {
6656 title: "Show Parameter Hints",
6657 description: "Whether parameter hints should be shown.",
6658 field: Box::new(SettingField {
6659 json_path: Some("languages.$(language).inlay_hints.show_parameter_hints"),
6660 pick: |settings_content| {
6661 language_settings_field(settings_content, |language| {
6662 language.inlay_hints.as_ref()?.show_parameter_hints.as_ref()
6663 })
6664 },
6665 write: |settings_content, value| {
6666 language_settings_field_mut(settings_content, value, |language, value| {
6667 language
6668 .inlay_hints
6669 .get_or_insert_default()
6670 .show_parameter_hints = value;
6671 })
6672 },
6673 }),
6674 metadata: None,
6675 files: USER | PROJECT,
6676 }),
6677 SettingsPageItem::SettingItem(SettingItem {
6678 title: "Show Other Hints",
6679 description: "Whether other hints should be shown.",
6680 field: Box::new(SettingField {
6681 json_path: Some("languages.$(language).inlay_hints.show_other_hints"),
6682 pick: |settings_content| {
6683 language_settings_field(settings_content, |language| {
6684 language.inlay_hints.as_ref()?.show_other_hints.as_ref()
6685 })
6686 },
6687 write: |settings_content, value| {
6688 language_settings_field_mut(settings_content, value, |language, value| {
6689 language
6690 .inlay_hints
6691 .get_or_insert_default()
6692 .show_other_hints = value;
6693 })
6694 },
6695 }),
6696 metadata: None,
6697 files: USER | PROJECT,
6698 }),
6699 SettingsPageItem::SettingItem(SettingItem {
6700 title: "Show Background",
6701 description: "Show a background for inlay hints.",
6702 field: Box::new(SettingField {
6703 json_path: Some("languages.$(language).inlay_hints.show_background"),
6704 pick: |settings_content| {
6705 language_settings_field(settings_content, |language| {
6706 language.inlay_hints.as_ref()?.show_background.as_ref()
6707 })
6708 },
6709 write: |settings_content, value| {
6710 language_settings_field_mut(settings_content, value, |language, value| {
6711 language.inlay_hints.get_or_insert_default().show_background = value;
6712 })
6713 },
6714 }),
6715 metadata: None,
6716 files: USER | PROJECT,
6717 }),
6718 SettingsPageItem::SettingItem(SettingItem {
6719 title: "Edit Debounce Ms",
6720 description: "Whether or not to debounce inlay hints updates after buffer edits (set to 0 to disable debouncing).",
6721 field: Box::new(SettingField {
6722 json_path: Some("languages.$(language).inlay_hints.edit_debounce_ms"),
6723 pick: |settings_content| {
6724 language_settings_field(settings_content, |language| {
6725 language.inlay_hints.as_ref()?.edit_debounce_ms.as_ref()
6726 })
6727 },
6728 write: |settings_content, value| {
6729 language_settings_field_mut(settings_content, value, |language, value| {
6730 language
6731 .inlay_hints
6732 .get_or_insert_default()
6733 .edit_debounce_ms = value;
6734 })
6735 },
6736 }),
6737 metadata: None,
6738 files: USER | PROJECT,
6739 }),
6740 SettingsPageItem::SettingItem(SettingItem {
6741 title: "Scroll Debounce Ms",
6742 description: "Whether or not to debounce inlay hints updates after buffer scrolls (set to 0 to disable debouncing).",
6743 field: Box::new(SettingField {
6744 json_path: Some("languages.$(language).inlay_hints.scroll_debounce_ms"),
6745 pick: |settings_content| {
6746 language_settings_field(settings_content, |language| {
6747 language.inlay_hints.as_ref()?.scroll_debounce_ms.as_ref()
6748 })
6749 },
6750 write: |settings_content, value| {
6751 language_settings_field_mut(settings_content, value, |language, value| {
6752 language
6753 .inlay_hints
6754 .get_or_insert_default()
6755 .scroll_debounce_ms = value;
6756 })
6757 },
6758 }),
6759 metadata: None,
6760 files: USER | PROJECT,
6761 }),
6762 SettingsPageItem::SettingItem(SettingItem {
6763 title: "Toggle On Modifiers Press",
6764 description: "Toggles inlay hints (hides or shows) when the user presses the modifiers specified.",
6765 field: Box::new(
6766 SettingField {
6767 json_path: Some("languages.$(language).inlay_hints.toggle_on_modifiers_press"),
6768 pick: |settings_content| {
6769 language_settings_field(settings_content, |language| {
6770 language
6771 .inlay_hints
6772 .as_ref()?
6773 .toggle_on_modifiers_press
6774 .as_ref()
6775 })
6776 },
6777 write: |settings_content, value| {
6778 language_settings_field_mut(settings_content, value, |language, value| {
6779 language
6780 .inlay_hints
6781 .get_or_insert_default()
6782 .toggle_on_modifiers_press = value;
6783 })
6784 },
6785 }
6786 .unimplemented(),
6787 ),
6788 metadata: None,
6789 files: USER | PROJECT,
6790 }),
6791 ];
6792 if current_language().is_none() {
6793 items.push(SettingsPageItem::SettingItem(SettingItem {
6794 title: "LSP Document Colors",
6795 description: "How to render LSP color previews in the editor.",
6796 field: Box::new(SettingField {
6797 json_path: Some("lsp_document_colors"),
6798 pick: |settings_content| settings_content.editor.lsp_document_colors.as_ref(),
6799 write: |settings_content, value| {
6800 settings_content.editor.lsp_document_colors = value;
6801 },
6802 }),
6803 metadata: None,
6804 files: USER,
6805 }))
6806 }
6807 items.extend([
6808 SettingsPageItem::SectionHeader("Tasks"),
6809 SettingsPageItem::SettingItem(SettingItem {
6810 title: "Enabled",
6811 description: "Whether tasks are enabled for this language.",
6812 field: Box::new(SettingField {
6813 json_path: Some("languages.$(language).tasks.enabled"),
6814 pick: |settings_content| {
6815 language_settings_field(settings_content, |language| {
6816 language.tasks.as_ref()?.enabled.as_ref()
6817 })
6818 },
6819 write: |settings_content, value| {
6820 language_settings_field_mut(settings_content, value, |language, value| {
6821 language.tasks.get_or_insert_default().enabled = value;
6822
6823 })
6824 },
6825 }),
6826 metadata: None,
6827 files: USER | PROJECT,
6828 }),
6829 SettingsPageItem::SettingItem(SettingItem {
6830 title: "Variables",
6831 description: "Extra task variables to set for a particular language.",
6832 field: Box::new(
6833 SettingField {
6834 json_path: Some("languages.$(language).tasks.variables"),
6835 pick: |settings_content| {
6836 language_settings_field(settings_content, |language| {
6837 language.tasks.as_ref()?.variables.as_ref()
6838 })
6839 },
6840 write: |settings_content, value| {
6841 language_settings_field_mut(settings_content, value, |language, value| {
6842 language.tasks.get_or_insert_default().variables = value;
6843
6844 })
6845 },
6846 }
6847 .unimplemented(),
6848 ),
6849 metadata: None,
6850 files: USER | PROJECT,
6851 }),
6852 SettingsPageItem::SettingItem(SettingItem {
6853 title: "Prefer LSP",
6854 description: "Use LSP tasks over Zed language extension tasks.",
6855 field: Box::new(SettingField {
6856 json_path: Some("languages.$(language).tasks.prefer_lsp"),
6857 pick: |settings_content| {
6858 language_settings_field(settings_content, |language| {
6859 language.tasks.as_ref()?.prefer_lsp.as_ref()
6860 })
6861 },
6862 write: |settings_content, value| {
6863 language_settings_field_mut(settings_content, value, |language, value| {
6864 language.tasks.get_or_insert_default().prefer_lsp = value;
6865
6866 })
6867 },
6868 }),
6869 metadata: None,
6870 files: USER | PROJECT,
6871 }),
6872 SettingsPageItem::SectionHeader("Miscellaneous"),
6873 SettingsPageItem::SettingItem(SettingItem {
6874 title: "Debuggers",
6875 description: "Preferred debuggers for this language.",
6876 field: Box::new(
6877 SettingField {
6878 json_path: Some("languages.$(language).debuggers"),
6879 pick: |settings_content| {
6880 language_settings_field(settings_content, |language| language.debuggers.as_ref())
6881 },
6882 write: |settings_content, value| {
6883 language_settings_field_mut(settings_content, value, |language, value| {
6884 language.debuggers = value;
6885
6886 })
6887 },
6888 }
6889 .unimplemented(),
6890 ),
6891 metadata: None,
6892 files: USER | PROJECT,
6893 }),
6894 SettingsPageItem::SettingItem(SettingItem {
6895 title: "Middle Click Paste",
6896 description: "Enable middle-click paste on Linux.",
6897 field: Box::new(SettingField {
6898 json_path: Some("languages.$(language).editor.middle_click_paste"),
6899 pick: |settings_content| settings_content.editor.middle_click_paste.as_ref(),
6900 write: |settings_content, value| {settings_content.editor.middle_click_paste = value;},
6901 }),
6902 metadata: None,
6903 files: USER,
6904 }),
6905 SettingsPageItem::SettingItem(SettingItem {
6906 title: "Extend Comment On Newline",
6907 description: "Whether to start a new line with a comment when a previous line is a comment as well.",
6908 field: Box::new(SettingField {
6909 json_path: Some("languages.$(language).extend_comment_on_newline"),
6910 pick: |settings_content| {
6911 language_settings_field(settings_content, |language| {
6912 language.extend_comment_on_newline.as_ref()
6913 })
6914 },
6915 write: |settings_content, value| {
6916 language_settings_field_mut(settings_content, value, |language, value| {
6917 language.extend_comment_on_newline = value;
6918
6919 })
6920 },
6921 }),
6922 metadata: None,
6923 files: USER | PROJECT,
6924 }),
6925 ]);
6926
6927 if current_language().is_none() {
6928 items.extend([
6929 SettingsPageItem::SettingItem(SettingItem {
6930 title: "Image Viewer",
6931 description: "The unit for image file sizes.",
6932 field: Box::new(SettingField {
6933 json_path: Some("image_viewer.unit"),
6934 pick: |settings_content| {
6935 settings_content.image_viewer.as_ref().and_then(|image_viewer| image_viewer.unit.as_ref())
6936 },
6937 write: |settings_content, value| {
6938 settings_content.image_viewer.get_or_insert_default().unit = value;
6939
6940 },
6941 }),
6942 metadata: None,
6943 files: USER,
6944 }),
6945 SettingsPageItem::SettingItem(SettingItem {
6946 title: "Auto Replace Emoji Shortcode",
6947 description: "Whether to automatically replace emoji shortcodes with emoji characters.",
6948 field: Box::new(SettingField {
6949 json_path: Some("message_editor.auto_replace_emoji_shortcode"),
6950 pick: |settings_content| {
6951 settings_content.message_editor.as_ref().and_then(|message_editor| message_editor.auto_replace_emoji_shortcode.as_ref())
6952 },
6953 write: |settings_content, value| {
6954 settings_content.message_editor.get_or_insert_default().auto_replace_emoji_shortcode = value;
6955
6956 },
6957 }),
6958 metadata: None,
6959 files: USER,
6960 }),
6961 SettingsPageItem::SettingItem(SettingItem {
6962 title: "Drop Size Target",
6963 description: "Relative size of the drop target in the editor that will open dropped file as a split pane.",
6964 field: Box::new(SettingField {
6965 json_path: Some("drop_target_size"),
6966 pick: |settings_content| {
6967 settings_content.workspace.drop_target_size.as_ref()
6968 },
6969 write: |settings_content, value| {
6970 settings_content.workspace.drop_target_size = value;
6971
6972 },
6973 }),
6974 metadata: None,
6975 files: USER,
6976 }),
6977 ]);
6978 }
6979 items
6980}
6981
6982/// LanguageSettings items that should be included in the "Languages & Tools" page
6983/// not the "Editor" page
6984fn non_editor_language_settings_data() -> Vec<SettingsPageItem> {
6985 vec![
6986 SettingsPageItem::SectionHeader("LSP"),
6987 SettingsPageItem::SettingItem(SettingItem {
6988 title: "Enable Language Server",
6989 description: "Whether to use language servers to provide code intelligence.",
6990 field: Box::new(SettingField {
6991 json_path: Some("languages.$(language).enable_language_server"),
6992 pick: |settings_content| {
6993 language_settings_field(settings_content, |language| {
6994 language.enable_language_server.as_ref()
6995 })
6996 },
6997 write: |settings_content, value| {
6998 language_settings_field_mut(settings_content, value, |language, value| {
6999 language.enable_language_server = value;
7000 })
7001 },
7002 }),
7003 metadata: None,
7004 files: USER | PROJECT,
7005 }),
7006 SettingsPageItem::SettingItem(SettingItem {
7007 title: "Language Servers",
7008 description: "The list of language servers to use (or disable) for this language.",
7009 field: Box::new(
7010 SettingField {
7011 json_path: Some("languages.$(language).language_servers"),
7012 pick: |settings_content| {
7013 language_settings_field(settings_content, |language| {
7014 language.language_servers.as_ref()
7015 })
7016 },
7017 write: |settings_content, value| {
7018 language_settings_field_mut(settings_content, value, |language, value| {
7019 language.language_servers = value;
7020 })
7021 },
7022 }
7023 .unimplemented(),
7024 ),
7025 metadata: None,
7026 files: USER | PROJECT,
7027 }),
7028 SettingsPageItem::SettingItem(SettingItem {
7029 title: "Linked Edits",
7030 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.",
7031 field: Box::new(SettingField {
7032 json_path: Some("languages.$(language).linked_edits"),
7033 pick: |settings_content| {
7034 language_settings_field(settings_content, |language| {
7035 language.linked_edits.as_ref()
7036 })
7037 },
7038 write: |settings_content, value| {
7039 language_settings_field_mut(settings_content, value, |language, value| {
7040 language.linked_edits = value;
7041 })
7042 },
7043 }),
7044 metadata: None,
7045 files: USER | PROJECT,
7046 }),
7047 SettingsPageItem::SettingItem(SettingItem {
7048 title: "Go To Definition Fallback",
7049 description: "Whether to follow-up empty Go to definition responses from the language server.",
7050 field: Box::new(SettingField {
7051 json_path: Some("go_to_definition_fallback"),
7052 pick: |settings_content| settings_content.editor.go_to_definition_fallback.as_ref(),
7053 write: |settings_content, value| {
7054 settings_content.editor.go_to_definition_fallback = value;
7055 },
7056 }),
7057 metadata: None,
7058 files: USER,
7059 }),
7060 SettingsPageItem::SectionHeader("LSP Completions"),
7061 SettingsPageItem::SettingItem(SettingItem {
7062 title: "Enabled",
7063 description: "Whether to fetch LSP completions or not.",
7064 field: Box::new(SettingField {
7065 json_path: Some("languages.$(language).completions.lsp"),
7066 pick: |settings_content| {
7067 language_settings_field(settings_content, |language| {
7068 language.completions.as_ref()?.lsp.as_ref()
7069 })
7070 },
7071 write: |settings_content, value| {
7072 language_settings_field_mut(settings_content, value, |language, value| {
7073 language.completions.get_or_insert_default().lsp = value;
7074 })
7075 },
7076 }),
7077 metadata: None,
7078 files: USER | PROJECT,
7079 }),
7080 SettingsPageItem::SettingItem(SettingItem {
7081 title: "Fetch Timeout (milliseconds)",
7082 description: "When fetching LSP completions, determines how long to wait for a response of a particular server (set to 0 to wait indefinitely).",
7083 field: Box::new(SettingField {
7084 json_path: Some("languages.$(language).completions.lsp_fetch_timeout_ms"),
7085 pick: |settings_content| {
7086 language_settings_field(settings_content, |language| {
7087 language.completions.as_ref()?.lsp_fetch_timeout_ms.as_ref()
7088 })
7089 },
7090 write: |settings_content, value| {
7091 language_settings_field_mut(settings_content, value, |language, value| {
7092 language
7093 .completions
7094 .get_or_insert_default()
7095 .lsp_fetch_timeout_ms = value;
7096 })
7097 },
7098 }),
7099 metadata: None,
7100 files: USER | PROJECT,
7101 }),
7102 SettingsPageItem::SettingItem(SettingItem {
7103 title: "Insert Mode",
7104 description: "Controls how LSP completions are inserted.",
7105 field: Box::new(SettingField {
7106 json_path: Some("languages.$(language).completions.lsp_insert_mode"),
7107 pick: |settings_content| {
7108 language_settings_field(settings_content, |language| {
7109 language.completions.as_ref()?.lsp_insert_mode.as_ref()
7110 })
7111 },
7112 write: |settings_content, value| {
7113 language_settings_field_mut(settings_content, value, |language, value| {
7114 language.completions.get_or_insert_default().lsp_insert_mode = value;
7115 })
7116 },
7117 }),
7118 metadata: None,
7119 files: USER | PROJECT,
7120 }),
7121 SettingsPageItem::SectionHeader("Debuggers"),
7122 SettingsPageItem::SettingItem(SettingItem {
7123 title: "Debuggers",
7124 description: "Preferred debuggers for this language.",
7125 field: Box::new(
7126 SettingField {
7127 json_path: Some("languages.$(language).debuggers"),
7128 pick: |settings_content| {
7129 language_settings_field(settings_content, |language| {
7130 language.debuggers.as_ref()
7131 })
7132 },
7133 write: |settings_content, value| {
7134 language_settings_field_mut(settings_content, value, |language, value| {
7135 language.debuggers = value;
7136 })
7137 },
7138 }
7139 .unimplemented(),
7140 ),
7141 metadata: None,
7142 files: USER | PROJECT,
7143 }),
7144 SettingsPageItem::SectionHeader("Prettier"),
7145 SettingsPageItem::SettingItem(SettingItem {
7146 title: "Allowed",
7147 description: "Enables or disables formatting with Prettier for a given language.",
7148 field: Box::new(SettingField {
7149 json_path: Some("languages.$(language).prettier.allowed"),
7150 pick: |settings_content| {
7151 language_settings_field(settings_content, |language| {
7152 language.prettier.as_ref()?.allowed.as_ref()
7153 })
7154 },
7155 write: |settings_content, value| {
7156 language_settings_field_mut(settings_content, value, |language, value| {
7157 language.prettier.get_or_insert_default().allowed = value;
7158 })
7159 },
7160 }),
7161 metadata: None,
7162 files: USER | PROJECT,
7163 }),
7164 SettingsPageItem::SettingItem(SettingItem {
7165 title: "Parser",
7166 description: "Forces Prettier integration to use a specific parser name when formatting files with the language.",
7167 field: Box::new(SettingField {
7168 json_path: Some("languages.$(language).prettier.parser"),
7169 pick: |settings_content| {
7170 language_settings_field(settings_content, |language| {
7171 language.prettier.as_ref()?.parser.as_ref()
7172 })
7173 },
7174 write: |settings_content, value| {
7175 language_settings_field_mut(settings_content, value, |language, value| {
7176 language.prettier.get_or_insert_default().parser = value;
7177 })
7178 },
7179 }),
7180 metadata: None,
7181 files: USER | PROJECT,
7182 }),
7183 SettingsPageItem::SettingItem(SettingItem {
7184 title: "Plugins",
7185 description: "Forces Prettier integration to use specific plugins when formatting files with the language.",
7186 field: Box::new(
7187 SettingField {
7188 json_path: Some("languages.$(language).prettier.plugins"),
7189 pick: |settings_content| {
7190 language_settings_field(settings_content, |language| {
7191 language.prettier.as_ref()?.plugins.as_ref()
7192 })
7193 },
7194 write: |settings_content, value| {
7195 language_settings_field_mut(settings_content, value, |language, value| {
7196 language.prettier.get_or_insert_default().plugins = value;
7197 })
7198 },
7199 }
7200 .unimplemented(),
7201 ),
7202 metadata: None,
7203 files: USER | PROJECT,
7204 }),
7205 SettingsPageItem::SettingItem(SettingItem {
7206 title: "Options",
7207 description: "Default Prettier options, in the format as in package.json section for Prettier.",
7208 field: Box::new(
7209 SettingField {
7210 json_path: Some("languages.$(language).prettier.options"),
7211 pick: |settings_content| {
7212 language_settings_field(settings_content, |language| {
7213 language.prettier.as_ref()?.options.as_ref()
7214 })
7215 },
7216 write: |settings_content, value| {
7217 language_settings_field_mut(settings_content, value, |language, value| {
7218 language.prettier.get_or_insert_default().options = value;
7219 })
7220 },
7221 }
7222 .unimplemented(),
7223 ),
7224 metadata: None,
7225 files: USER | PROJECT,
7226 }),
7227 ]
7228}
7229
7230fn edit_prediction_language_settings_section() -> Vec<SettingsPageItem> {
7231 vec![
7232 SettingsPageItem::SectionHeader("Edit Predictions"),
7233 SettingsPageItem::SettingItem(SettingItem {
7234 title: "Show Edit Predictions",
7235 description: "Controls whether edit predictions are shown immediately or manually by triggering `editor::showeditprediction` (false).",
7236 field: Box::new(SettingField {
7237 json_path: Some("languages.$(language).show_edit_predictions"),
7238 pick: |settings_content| {
7239 language_settings_field(settings_content, |language| {
7240 language.show_edit_predictions.as_ref()
7241 })
7242 },
7243 write: |settings_content, value| {
7244 language_settings_field_mut(settings_content, value, |language, value| {
7245 language.show_edit_predictions = value;
7246 })
7247 },
7248 }),
7249 metadata: None,
7250 files: USER | PROJECT,
7251 }),
7252 SettingsPageItem::SettingItem(SettingItem {
7253 title: "Edit Predictions Disabled In",
7254 description: "Controls whether edit predictions are shown in the given language scopes.",
7255 field: Box::new(
7256 SettingField {
7257 json_path: Some("languages.$(language).edit_predictions_disabled_in"),
7258 pick: |settings_content| {
7259 language_settings_field(settings_content, |language| {
7260 language.edit_predictions_disabled_in.as_ref()
7261 })
7262 },
7263 write: |settings_content, value| {
7264 language_settings_field_mut(settings_content, value, |language, value| {
7265 language.edit_predictions_disabled_in = value;
7266 })
7267 },
7268 }
7269 .unimplemented(),
7270 ),
7271 metadata: None,
7272 files: USER | PROJECT,
7273 }),
7274 ]
7275}
7276
7277fn show_scrollbar_or_editor(
7278 settings_content: &SettingsContent,
7279 show: fn(&SettingsContent) -> Option<&settings::ShowScrollbar>,
7280) -> Option<&settings::ShowScrollbar> {
7281 show(settings_content).or(settings_content
7282 .editor
7283 .scrollbar
7284 .as_ref()
7285 .and_then(|scrollbar| scrollbar.show.as_ref()))
7286}
7287
7288fn dynamic_variants<T>() -> &'static [T::Discriminant]
7289where
7290 T: strum::IntoDiscriminant,
7291 T::Discriminant: strum::VariantArray,
7292{
7293 <<T as strum::IntoDiscriminant>::Discriminant as strum::VariantArray>::VARIANTS
7294}