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