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