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