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 Gutter"),
5523 SettingsPageItem::SettingItem(SettingItem {
5524 title: "Visibility",
5525 description: "Control whether Git status is shown in the editor's gutter.",
5526 field: Box::new(SettingField {
5527 json_path: Some("git.git_gutter"),
5528 pick: |settings_content| settings_content.git.as_ref()?.git_gutter.as_ref(),
5529 write: |settings_content, value| {
5530 settings_content.git.get_or_insert_default().git_gutter = value;
5531 },
5532 }),
5533 metadata: None,
5534 files: USER,
5535 }),
5536 // todo(settings_ui): Figure out the right default for this value in default.json
5537 SettingsPageItem::SettingItem(SettingItem {
5538 title: "Debounce",
5539 description: "Debounce threshold in milliseconds after which changes are reflected in the Git gutter.",
5540 field: Box::new(SettingField {
5541 json_path: Some("git.gutter_debounce"),
5542 pick: |settings_content| {
5543 settings_content.git.as_ref()?.gutter_debounce.as_ref()
5544 },
5545 write: |settings_content, value| {
5546 settings_content.git.get_or_insert_default().gutter_debounce = value;
5547 },
5548 }),
5549 metadata: None,
5550 files: USER,
5551 }),
5552 SettingsPageItem::SectionHeader("Inline Git Blame"),
5553 SettingsPageItem::SettingItem(SettingItem {
5554 title: "Enabled",
5555 description: "Whether or not to show Git blame data inline in the currently focused line.",
5556 field: Box::new(SettingField {
5557 json_path: Some("git.inline_blame.enabled"),
5558 pick: |settings_content| {
5559 settings_content
5560 .git
5561 .as_ref()?
5562 .inline_blame
5563 .as_ref()?
5564 .enabled
5565 .as_ref()
5566 },
5567 write: |settings_content, value| {
5568 settings_content
5569 .git
5570 .get_or_insert_default()
5571 .inline_blame
5572 .get_or_insert_default()
5573 .enabled = value;
5574 },
5575 }),
5576 metadata: None,
5577 files: USER,
5578 }),
5579 SettingsPageItem::SettingItem(SettingItem {
5580 title: "Delay",
5581 description: "The delay after which the inline blame information is shown.",
5582 field: Box::new(SettingField {
5583 json_path: Some("git.inline_blame.delay_ms"),
5584 pick: |settings_content| {
5585 settings_content
5586 .git
5587 .as_ref()?
5588 .inline_blame
5589 .as_ref()?
5590 .delay_ms
5591 .as_ref()
5592 },
5593 write: |settings_content, value| {
5594 settings_content
5595 .git
5596 .get_or_insert_default()
5597 .inline_blame
5598 .get_or_insert_default()
5599 .delay_ms = value;
5600 },
5601 }),
5602 metadata: None,
5603 files: USER,
5604 }),
5605 SettingsPageItem::SettingItem(SettingItem {
5606 title: "Padding",
5607 description: "Padding between the end of the source line and the start of the inline blame in columns.",
5608 field: Box::new(SettingField {
5609 json_path: Some("git.inline_blame.padding"),
5610 pick: |settings_content| {
5611 settings_content
5612 .git
5613 .as_ref()?
5614 .inline_blame
5615 .as_ref()?
5616 .padding
5617 .as_ref()
5618 },
5619 write: |settings_content, value| {
5620 settings_content
5621 .git
5622 .get_or_insert_default()
5623 .inline_blame
5624 .get_or_insert_default()
5625 .padding = value;
5626 },
5627 }),
5628 metadata: None,
5629 files: USER,
5630 }),
5631 SettingsPageItem::SettingItem(SettingItem {
5632 title: "Minimum Column",
5633 description: "The minimum column number at which to show the inline blame information.",
5634 field: Box::new(SettingField {
5635 json_path: Some("git.inline_blame.min_column"),
5636 pick: |settings_content| {
5637 settings_content
5638 .git
5639 .as_ref()?
5640 .inline_blame
5641 .as_ref()?
5642 .min_column
5643 .as_ref()
5644 },
5645 write: |settings_content, value| {
5646 settings_content
5647 .git
5648 .get_or_insert_default()
5649 .inline_blame
5650 .get_or_insert_default()
5651 .min_column = value;
5652 },
5653 }),
5654 metadata: None,
5655 files: USER,
5656 }),
5657 SettingsPageItem::SettingItem(SettingItem {
5658 title: "Show Commit Summary",
5659 description: "Show commit summary as part of the inline blame.",
5660 field: Box::new(SettingField {
5661 json_path: Some("git.inline_blame.show_commit_summary"),
5662 pick: |settings_content| {
5663 settings_content
5664 .git
5665 .as_ref()?
5666 .inline_blame
5667 .as_ref()?
5668 .show_commit_summary
5669 .as_ref()
5670 },
5671 write: |settings_content, value| {
5672 settings_content
5673 .git
5674 .get_or_insert_default()
5675 .inline_blame
5676 .get_or_insert_default()
5677 .show_commit_summary = value;
5678 },
5679 }),
5680 metadata: None,
5681 files: USER,
5682 }),
5683 SettingsPageItem::SectionHeader("Git Blame View"),
5684 SettingsPageItem::SettingItem(SettingItem {
5685 title: "Show Avatar",
5686 description: "Show the avatar of the author of the commit.",
5687 field: Box::new(SettingField {
5688 json_path: Some("git.blame.show_avatar"),
5689 pick: |settings_content| {
5690 settings_content
5691 .git
5692 .as_ref()?
5693 .blame
5694 .as_ref()?
5695 .show_avatar
5696 .as_ref()
5697 },
5698 write: |settings_content, value| {
5699 settings_content
5700 .git
5701 .get_or_insert_default()
5702 .blame
5703 .get_or_insert_default()
5704 .show_avatar = value;
5705 },
5706 }),
5707 metadata: None,
5708 files: USER,
5709 }),
5710 SettingsPageItem::SectionHeader("Branch Picker"),
5711 SettingsPageItem::SettingItem(SettingItem {
5712 title: "Show Author Name",
5713 description: "Show author name as part of the commit information in branch picker.",
5714 field: Box::new(SettingField {
5715 json_path: Some("git.branch_picker.show_author_name"),
5716 pick: |settings_content| {
5717 settings_content
5718 .git
5719 .as_ref()?
5720 .branch_picker
5721 .as_ref()?
5722 .show_author_name
5723 .as_ref()
5724 },
5725 write: |settings_content, value| {
5726 settings_content
5727 .git
5728 .get_or_insert_default()
5729 .branch_picker
5730 .get_or_insert_default()
5731 .show_author_name = value;
5732 },
5733 }),
5734 metadata: None,
5735 files: USER,
5736 }),
5737 SettingsPageItem::SectionHeader("Git Hunks"),
5738 SettingsPageItem::SettingItem(SettingItem {
5739 title: "Hunk Style",
5740 description: "How Git hunks are displayed visually in the editor.",
5741 field: Box::new(SettingField {
5742 json_path: Some("git.hunk_style"),
5743 pick: |settings_content| settings_content.git.as_ref()?.hunk_style.as_ref(),
5744 write: |settings_content, value| {
5745 settings_content.git.get_or_insert_default().hunk_style = value;
5746 },
5747 }),
5748 metadata: None,
5749 files: USER,
5750 }),
5751 SettingsPageItem::SettingItem(SettingItem {
5752 title: "Path Style",
5753 description: "Should the name or path be displayed first in the git view.",
5754 field: Box::new(SettingField {
5755 json_path: Some("git.path_style"),
5756 pick: |settings_content| settings_content.git.as_ref()?.path_style.as_ref(),
5757 write: |settings_content, value| {
5758 settings_content.git.get_or_insert_default().path_style = value;
5759 },
5760 }),
5761 metadata: None,
5762 files: USER,
5763 }),
5764 ],
5765 },
5766 SettingsPage {
5767 title: "Collaboration",
5768 items: vec![
5769 SettingsPageItem::SectionHeader("Calls"),
5770 SettingsPageItem::SettingItem(SettingItem {
5771 title: "Mute On Join",
5772 description: "Whether the microphone should be muted when joining a channel or a call.",
5773 field: Box::new(SettingField {
5774 json_path: Some("calls.mute_on_join"),
5775 pick: |settings_content| {
5776 settings_content.calls.as_ref()?.mute_on_join.as_ref()
5777 },
5778 write: |settings_content, value| {
5779 settings_content.calls.get_or_insert_default().mute_on_join = value;
5780 },
5781 }),
5782 metadata: None,
5783 files: USER,
5784 }),
5785 SettingsPageItem::SettingItem(SettingItem {
5786 title: "Share On Join",
5787 description: "Whether your current project should be shared when joining an empty channel.",
5788 field: Box::new(SettingField {
5789 json_path: Some("calls.share_on_join"),
5790 pick: |settings_content| {
5791 settings_content.calls.as_ref()?.share_on_join.as_ref()
5792 },
5793 write: |settings_content, value| {
5794 settings_content.calls.get_or_insert_default().share_on_join = value;
5795 },
5796 }),
5797 metadata: None,
5798 files: USER,
5799 }),
5800 SettingsPageItem::SectionHeader("Experimental"),
5801 SettingsPageItem::SettingItem(SettingItem {
5802 title: "Rodio Audio",
5803 description: "Opt into the new audio system.",
5804 field: Box::new(SettingField {
5805 json_path: Some("audio.experimental.rodio_audio"),
5806 pick: |settings_content| {
5807 settings_content.audio.as_ref()?.rodio_audio.as_ref()
5808 },
5809 write: |settings_content, value| {
5810 settings_content.audio.get_or_insert_default().rodio_audio = value;
5811 },
5812 }),
5813 metadata: None,
5814 files: USER,
5815 }),
5816 SettingsPageItem::SettingItem(SettingItem {
5817 title: "Auto Microphone Volume",
5818 description: "Automatically adjust microphone volume (requires rodio audio).",
5819 field: Box::new(SettingField {
5820 json_path: Some("audio.experimental.auto_microphone_volume"),
5821 pick: |settings_content| {
5822 settings_content
5823 .audio
5824 .as_ref()?
5825 .auto_microphone_volume
5826 .as_ref()
5827 },
5828 write: |settings_content, value| {
5829 settings_content
5830 .audio
5831 .get_or_insert_default()
5832 .auto_microphone_volume = value;
5833 },
5834 }),
5835 metadata: None,
5836 files: USER,
5837 }),
5838 SettingsPageItem::SettingItem(SettingItem {
5839 title: "Auto Speaker Volume",
5840 description: "Automatically adjust volume of other call members (requires rodio audio).",
5841 field: Box::new(SettingField {
5842 json_path: Some("audio.experimental.auto_speaker_volume"),
5843 pick: |settings_content| {
5844 settings_content
5845 .audio
5846 .as_ref()?
5847 .auto_speaker_volume
5848 .as_ref()
5849 },
5850 write: |settings_content, value| {
5851 settings_content
5852 .audio
5853 .get_or_insert_default()
5854 .auto_speaker_volume = value;
5855 },
5856 }),
5857 metadata: None,
5858 files: USER,
5859 }),
5860 SettingsPageItem::SettingItem(SettingItem {
5861 title: "Denoise",
5862 description: "Remove background noises (requires rodio audio).",
5863 field: Box::new(SettingField {
5864 json_path: Some("audio.experimental.denoise"),
5865 pick: |settings_content| settings_content.audio.as_ref()?.denoise.as_ref(),
5866 write: |settings_content, value| {
5867 settings_content.audio.get_or_insert_default().denoise = value;
5868 },
5869 }),
5870 metadata: None,
5871 files: USER,
5872 }),
5873 SettingsPageItem::SettingItem(SettingItem {
5874 title: "Legacy Audio Compatible",
5875 description: "Use audio parameters compatible with previous versions (requires rodio audio).",
5876 field: Box::new(SettingField {
5877 json_path: Some("audio.experimental.legacy_audio_compatible"),
5878 pick: |settings_content| {
5879 settings_content
5880 .audio
5881 .as_ref()?
5882 .legacy_audio_compatible
5883 .as_ref()
5884 },
5885 write: |settings_content, value| {
5886 settings_content
5887 .audio
5888 .get_or_insert_default()
5889 .legacy_audio_compatible = value;
5890 },
5891 }),
5892 metadata: None,
5893 files: USER,
5894 }),
5895 ],
5896 },
5897 SettingsPage {
5898 title: "AI",
5899 items: {
5900 let mut items = vec![
5901 SettingsPageItem::SectionHeader("General"),
5902 SettingsPageItem::SettingItem(SettingItem {
5903 title: "Disable AI",
5904 description: "Whether to disable all AI features in Zed.",
5905 field: Box::new(SettingField {
5906 json_path: Some("disable_ai"),
5907 pick: |settings_content| settings_content.disable_ai.as_ref(),
5908 write: |settings_content, value| {
5909 settings_content.disable_ai = value;
5910 },
5911 }),
5912 metadata: None,
5913 files: USER,
5914 }),
5915 SettingsPageItem::SectionHeader("Agent Configuration"),
5916 SettingsPageItem::SettingItem(SettingItem {
5917 title: "Always Allow Tool Actions",
5918 description: "When enabled, the agent can run potentially destructive actions without asking for your confirmation. This setting has no effect on external agents.",
5919 field: Box::new(SettingField {
5920 json_path: Some("agent.always_allow_tool_actions"),
5921 pick: |settings_content| {
5922 settings_content
5923 .agent
5924 .as_ref()?
5925 .always_allow_tool_actions
5926 .as_ref()
5927 },
5928 write: |settings_content, value| {
5929 settings_content
5930 .agent
5931 .get_or_insert_default()
5932 .always_allow_tool_actions = value;
5933 },
5934 }),
5935 metadata: None,
5936 files: USER,
5937 }),
5938 SettingsPageItem::SettingItem(SettingItem {
5939 title: "Single File Review",
5940 description: "When enabled, agent edits will also be displayed in single-file buffers for review.",
5941 field: Box::new(SettingField {
5942 json_path: Some("agent.single_file_review"),
5943 pick: |settings_content| {
5944 settings_content.agent.as_ref()?.single_file_review.as_ref()
5945 },
5946 write: |settings_content, value| {
5947 settings_content
5948 .agent
5949 .get_or_insert_default()
5950 .single_file_review = value;
5951 },
5952 }),
5953 metadata: None,
5954 files: USER,
5955 }),
5956 SettingsPageItem::SettingItem(SettingItem {
5957 title: "Enable Feedback",
5958 description: "Show voting thumbs up/down icon buttons for feedback on agent edits.",
5959 field: Box::new(SettingField {
5960 json_path: Some("agent.enable_feedback"),
5961 pick: |settings_content| {
5962 settings_content.agent.as_ref()?.enable_feedback.as_ref()
5963 },
5964 write: |settings_content, value| {
5965 settings_content
5966 .agent
5967 .get_or_insert_default()
5968 .enable_feedback = value;
5969 },
5970 }),
5971 metadata: None,
5972 files: USER,
5973 }),
5974 SettingsPageItem::SettingItem(SettingItem {
5975 title: "Notify When Agent Waiting",
5976 description: "Where to show notifications when the agent has completed its response or needs confirmation before running a tool action.",
5977 field: Box::new(SettingField {
5978 json_path: Some("agent.notify_when_agent_waiting"),
5979 pick: |settings_content| {
5980 settings_content
5981 .agent
5982 .as_ref()?
5983 .notify_when_agent_waiting
5984 .as_ref()
5985 },
5986 write: |settings_content, value| {
5987 settings_content
5988 .agent
5989 .get_or_insert_default()
5990 .notify_when_agent_waiting = value;
5991 },
5992 }),
5993 metadata: None,
5994 files: USER,
5995 }),
5996 SettingsPageItem::SettingItem(SettingItem {
5997 title: "Play Sound When Agent Done",
5998 description: "Whether to play a sound when the agent has either completed its response, or needs user input.",
5999 field: Box::new(SettingField {
6000 json_path: Some("agent.play_sound_when_agent_done"),
6001 pick: |settings_content| {
6002 settings_content
6003 .agent
6004 .as_ref()?
6005 .play_sound_when_agent_done
6006 .as_ref()
6007 },
6008 write: |settings_content, value| {
6009 settings_content
6010 .agent
6011 .get_or_insert_default()
6012 .play_sound_when_agent_done = value;
6013 },
6014 }),
6015 metadata: None,
6016 files: USER,
6017 }),
6018 SettingsPageItem::SettingItem(SettingItem {
6019 title: "Expand Edit Card",
6020 description: "Whether to have edit cards in the agent panel expanded, showing a Preview of the diff.",
6021 field: Box::new(SettingField {
6022 json_path: Some("agent.expand_edit_card"),
6023 pick: |settings_content| {
6024 settings_content.agent.as_ref()?.expand_edit_card.as_ref()
6025 },
6026 write: |settings_content, value| {
6027 settings_content
6028 .agent
6029 .get_or_insert_default()
6030 .expand_edit_card = value;
6031 },
6032 }),
6033 metadata: None,
6034 files: USER,
6035 }),
6036 SettingsPageItem::SettingItem(SettingItem {
6037 title: "Expand Terminal Card",
6038 description: "Whether to have terminal cards in the agent panel expanded, showing the whole command output.",
6039 field: Box::new(SettingField {
6040 json_path: Some("agent.expand_terminal_card"),
6041 pick: |settings_content| {
6042 settings_content
6043 .agent
6044 .as_ref()?
6045 .expand_terminal_card
6046 .as_ref()
6047 },
6048 write: |settings_content, value| {
6049 settings_content
6050 .agent
6051 .get_or_insert_default()
6052 .expand_terminal_card = value;
6053 },
6054 }),
6055 metadata: None,
6056 files: USER,
6057 }),
6058 SettingsPageItem::SettingItem(SettingItem {
6059 title: "Use Modifier To Send",
6060 description: "Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages.",
6061 field: Box::new(SettingField {
6062 json_path: Some("agent.use_modifier_to_send"),
6063 pick: |settings_content| {
6064 settings_content
6065 .agent
6066 .as_ref()?
6067 .use_modifier_to_send
6068 .as_ref()
6069 },
6070 write: |settings_content, value| {
6071 settings_content
6072 .agent
6073 .get_or_insert_default()
6074 .use_modifier_to_send = value;
6075 },
6076 }),
6077 metadata: None,
6078 files: USER,
6079 }),
6080 SettingsPageItem::SettingItem(SettingItem {
6081 title: "Message Editor Min Lines",
6082 description: "Minimum number of lines to display in the agent message editor.",
6083 field: Box::new(SettingField {
6084 json_path: Some("agent.message_editor_min_lines"),
6085 pick: |settings_content| {
6086 settings_content
6087 .agent
6088 .as_ref()?
6089 .message_editor_min_lines
6090 .as_ref()
6091 },
6092 write: |settings_content, value| {
6093 settings_content
6094 .agent
6095 .get_or_insert_default()
6096 .message_editor_min_lines = value;
6097 },
6098 }),
6099 metadata: None,
6100 files: USER,
6101 }),
6102 ];
6103 items.extend(edit_prediction_language_settings_section());
6104 items.extend(
6105 [
6106 SettingsPageItem::SettingItem(SettingItem {
6107 title: "Display Mode",
6108 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.",
6109 field: Box::new(SettingField {
6110 json_path: Some("edit_prediction.display_mode"),
6111 pick: |settings_content| {
6112 settings_content.project.all_languages.edit_predictions.as_ref()?.mode.as_ref()
6113 },
6114 write: |settings_content, value| {
6115 settings_content.project.all_languages.edit_predictions.get_or_insert_default().mode = value;
6116 },
6117 }),
6118 metadata: None,
6119 files: USER,
6120 }),
6121 SettingsPageItem::SettingItem(SettingItem {
6122 title: "Display In Text Threads",
6123 description: "Whether edit predictions are enabled when editing text threads in the agent panel.",
6124 field: Box::new(SettingField {
6125 json_path: Some("edit_prediction.in_text_threads"),
6126 pick: |settings_content| {
6127 settings_content.project.all_languages.edit_predictions.as_ref()?.enabled_in_text_threads.as_ref()
6128 },
6129 write: |settings_content, value| {
6130 settings_content.project.all_languages.edit_predictions.get_or_insert_default().enabled_in_text_threads = value;
6131 },
6132 }),
6133 metadata: None,
6134 files: USER,
6135 }),
6136 ]
6137 );
6138 items
6139 },
6140 },
6141 SettingsPage {
6142 title: "Network",
6143 items: vec![
6144 SettingsPageItem::SectionHeader("Network"),
6145 // todo(settings_ui): Proxy needs a default
6146 SettingsPageItem::SettingItem(SettingItem {
6147 title: "Proxy",
6148 description: "The proxy to use for network requests.",
6149 field: Box::new(
6150 SettingField {
6151 json_path: Some("proxy"),
6152 pick: |settings_content| settings_content.proxy.as_ref(),
6153 write: |settings_content, value| {
6154 settings_content.proxy = value;
6155 },
6156 }
6157 .unimplemented(),
6158 ),
6159 metadata: Some(Box::new(SettingsFieldMetadata {
6160 placeholder: Some("socks5h://localhost:10808"),
6161 ..Default::default()
6162 })),
6163 files: USER,
6164 }),
6165 SettingsPageItem::SettingItem(SettingItem {
6166 title: "Server URL",
6167 description: "The URL of the Zed server to connect to.",
6168 field: Box::new(SettingField {
6169 json_path: Some("server_url"),
6170 pick: |settings_content| settings_content.server_url.as_ref(),
6171 write: |settings_content, value| {
6172 settings_content.server_url = value;
6173 },
6174 }),
6175 metadata: Some(Box::new(SettingsFieldMetadata {
6176 placeholder: Some("https://zed.dev"),
6177 ..Default::default()
6178 })),
6179 files: USER,
6180 }),
6181 ],
6182 },
6183 ]
6184}
6185
6186const LANGUAGES_SECTION_HEADER: &'static str = "Languages";
6187
6188fn current_language() -> Option<SharedString> {
6189 sub_page_stack().iter().find_map(|page| {
6190 (page.section_header == LANGUAGES_SECTION_HEADER).then(|| page.link.title.clone())
6191 })
6192}
6193
6194fn language_settings_field<T>(
6195 settings_content: &SettingsContent,
6196 get: fn(&LanguageSettingsContent) -> Option<&T>,
6197) -> Option<&T> {
6198 let all_languages = &settings_content.project.all_languages;
6199 if let Some(current_language_name) = current_language() {
6200 if let Some(current_language) = all_languages.languages.0.get(¤t_language_name) {
6201 let value = get(current_language);
6202 if value.is_some() {
6203 return value;
6204 }
6205 }
6206 }
6207 let default_value = get(&all_languages.defaults);
6208 return default_value;
6209}
6210
6211fn language_settings_field_mut<T>(
6212 settings_content: &mut SettingsContent,
6213 value: Option<T>,
6214 write: fn(&mut LanguageSettingsContent, Option<T>),
6215) {
6216 let all_languages = &mut settings_content.project.all_languages;
6217 let language_content = if let Some(current_language) = current_language() {
6218 all_languages
6219 .languages
6220 .0
6221 .entry(current_language)
6222 .or_default()
6223 } else {
6224 &mut all_languages.defaults
6225 };
6226 write(language_content, value);
6227}
6228
6229fn language_settings_data() -> Vec<SettingsPageItem> {
6230 let mut items = vec![
6231 SettingsPageItem::SectionHeader("Indentation"),
6232 SettingsPageItem::SettingItem(SettingItem {
6233 title: "Tab Size",
6234 description: "How many columns a tab should occupy.",
6235 field: Box::new(SettingField {
6236 json_path: Some("languages.$(language).tab_size"), // TODO(cameron): not JQ syntax because not URL-safe
6237 pick: |settings_content| {
6238 language_settings_field(settings_content, |language| language.tab_size.as_ref())
6239 },
6240 write: |settings_content, value| {
6241 language_settings_field_mut(settings_content, value, |language, value| {
6242 language.tab_size = value;
6243 })
6244 },
6245 }),
6246 metadata: None,
6247 files: USER | PROJECT,
6248 }),
6249 SettingsPageItem::SettingItem(SettingItem {
6250 title: "Hard Tabs",
6251 description: "Whether to indent lines using tab characters, as opposed to multiple spaces.",
6252 field: Box::new(SettingField {
6253 json_path: Some("languages.$(language).hard_tabs"),
6254 pick: |settings_content| {
6255 language_settings_field(settings_content, |language| {
6256 language.hard_tabs.as_ref()
6257 })
6258 },
6259 write: |settings_content, value| {
6260 language_settings_field_mut(settings_content, value, |language, value| {
6261 language.hard_tabs = value;
6262 })
6263 },
6264 }),
6265 metadata: None,
6266 files: USER | PROJECT,
6267 }),
6268 SettingsPageItem::SettingItem(SettingItem {
6269 title: "Auto Indent",
6270 description: "Whether indentation should be adjusted based on the context whilst typing.",
6271 field: Box::new(SettingField {
6272 json_path: Some("languages.$(language).auto_indent"),
6273 pick: |settings_content| {
6274 language_settings_field(settings_content, |language| {
6275 language.auto_indent.as_ref()
6276 })
6277 },
6278 write: |settings_content, value| {
6279 language_settings_field_mut(settings_content, value, |language, value| {
6280 language.auto_indent = value;
6281 })
6282 },
6283 }),
6284 metadata: None,
6285 files: USER | PROJECT,
6286 }),
6287 SettingsPageItem::SettingItem(SettingItem {
6288 title: "Auto Indent On Paste",
6289 description: "Whether indentation of pasted content should be adjusted based on the context.",
6290 field: Box::new(SettingField {
6291 json_path: Some("languages.$(language).auto_indent_on_paste"),
6292 pick: |settings_content| {
6293 language_settings_field(settings_content, |language| {
6294 language.auto_indent_on_paste.as_ref()
6295 })
6296 },
6297 write: |settings_content, value| {
6298 language_settings_field_mut(settings_content, value, |language, value| {
6299 language.auto_indent_on_paste = value;
6300 })
6301 },
6302 }),
6303 metadata: None,
6304 files: USER | PROJECT,
6305 }),
6306 SettingsPageItem::SectionHeader("Wrapping"),
6307 SettingsPageItem::SettingItem(SettingItem {
6308 title: "Soft Wrap",
6309 description: "How to soft-wrap long lines of text.",
6310 field: Box::new(SettingField {
6311 json_path: Some("languages.$(language).soft_wrap"),
6312 pick: |settings_content| {
6313 language_settings_field(settings_content, |language| {
6314 language.soft_wrap.as_ref()
6315 })
6316 },
6317 write: |settings_content, value| {
6318 language_settings_field_mut(settings_content, value, |language, value| {
6319 language.soft_wrap = value;
6320 })
6321 },
6322 }),
6323 metadata: None,
6324 files: USER | PROJECT,
6325 }),
6326 SettingsPageItem::SettingItem(SettingItem {
6327 title: "Show Wrap Guides",
6328 description: "Show wrap guides in the editor.",
6329 field: Box::new(SettingField {
6330 json_path: Some("languages.$(language).show_wrap_guides"),
6331 pick: |settings_content| {
6332 language_settings_field(settings_content, |language| {
6333 language.show_wrap_guides.as_ref()
6334 })
6335 },
6336 write: |settings_content, value| {
6337 language_settings_field_mut(settings_content, value, |language, value| {
6338 language.show_wrap_guides = value;
6339 })
6340 },
6341 }),
6342 metadata: None,
6343 files: USER | PROJECT,
6344 }),
6345 SettingsPageItem::SettingItem(SettingItem {
6346 title: "Preferred Line Length",
6347 description: "The column at which to soft-wrap lines, for buffers where soft-wrap is enabled.",
6348 field: Box::new(SettingField {
6349 json_path: Some("languages.$(language).preferred_line_length"),
6350 pick: |settings_content| {
6351 language_settings_field(settings_content, |language| {
6352 language.preferred_line_length.as_ref()
6353 })
6354 },
6355 write: |settings_content, value| {
6356 language_settings_field_mut(settings_content, value, |language, value| {
6357 language.preferred_line_length = value;
6358 })
6359 },
6360 }),
6361 metadata: None,
6362 files: USER | PROJECT,
6363 }),
6364 SettingsPageItem::SettingItem(SettingItem {
6365 title: "Wrap Guides",
6366 description: "Character counts at which to show wrap guides in the editor.",
6367 field: Box::new(
6368 SettingField {
6369 json_path: Some("languages.$(language).wrap_guides"),
6370 pick: |settings_content| {
6371 language_settings_field(settings_content, |language| {
6372 language.wrap_guides.as_ref()
6373 })
6374 },
6375 write: |settings_content, value| {
6376 language_settings_field_mut(settings_content, value, |language, value| {
6377 language.wrap_guides = value;
6378 })
6379 },
6380 }
6381 .unimplemented(),
6382 ),
6383 metadata: None,
6384 files: USER | PROJECT,
6385 }),
6386 SettingsPageItem::SettingItem(SettingItem {
6387 title: "Allow Rewrap",
6388 description: "Controls where the `editor::rewrap` action is allowed for this language.",
6389 field: Box::new(SettingField {
6390 json_path: Some("languages.$(language).allow_rewrap"),
6391 pick: |settings_content| {
6392 language_settings_field(settings_content, |language| {
6393 language.allow_rewrap.as_ref()
6394 })
6395 },
6396 write: |settings_content, value| {
6397 language_settings_field_mut(settings_content, value, |language, value| {
6398 language.allow_rewrap = value;
6399 })
6400 },
6401 }),
6402 metadata: None,
6403 files: USER | PROJECT,
6404 }),
6405 SettingsPageItem::SectionHeader("Indent Guides"),
6406 SettingsPageItem::SettingItem(SettingItem {
6407 title: "Enabled",
6408 description: "Display indent guides in the editor.",
6409 field: Box::new(SettingField {
6410 json_path: Some("languages.$(language).indent_guides.enabled"),
6411 pick: |settings_content| {
6412 language_settings_field(settings_content, |language| {
6413 language
6414 .indent_guides
6415 .as_ref()
6416 .and_then(|indent_guides| indent_guides.enabled.as_ref())
6417 })
6418 },
6419 write: |settings_content, value| {
6420 language_settings_field_mut(settings_content, value, |language, value| {
6421 language.indent_guides.get_or_insert_default().enabled = value;
6422 })
6423 },
6424 }),
6425 metadata: None,
6426 files: USER | PROJECT,
6427 }),
6428 SettingsPageItem::SettingItem(SettingItem {
6429 title: "Line Width",
6430 description: "The width of the indent guides in pixels, between 1 and 10.",
6431 field: Box::new(SettingField {
6432 json_path: Some("languages.$(language).indent_guides.line_width"),
6433 pick: |settings_content| {
6434 language_settings_field(settings_content, |language| {
6435 language
6436 .indent_guides
6437 .as_ref()
6438 .and_then(|indent_guides| indent_guides.line_width.as_ref())
6439 })
6440 },
6441 write: |settings_content, value| {
6442 language_settings_field_mut(settings_content, value, |language, value| {
6443 language.indent_guides.get_or_insert_default().line_width = value;
6444 })
6445 },
6446 }),
6447 metadata: None,
6448 files: USER | PROJECT,
6449 }),
6450 SettingsPageItem::SettingItem(SettingItem {
6451 title: "Active Line Width",
6452 description: "The width of the active indent guide in pixels, between 1 and 10.",
6453 field: Box::new(SettingField {
6454 json_path: Some("languages.$(language).indent_guides.active_line_width"),
6455 pick: |settings_content| {
6456 language_settings_field(settings_content, |language| {
6457 language
6458 .indent_guides
6459 .as_ref()
6460 .and_then(|indent_guides| indent_guides.active_line_width.as_ref())
6461 })
6462 },
6463 write: |settings_content, value| {
6464 language_settings_field_mut(settings_content, value, |language, value| {
6465 language
6466 .indent_guides
6467 .get_or_insert_default()
6468 .active_line_width = value;
6469 })
6470 },
6471 }),
6472 metadata: None,
6473 files: USER | PROJECT,
6474 }),
6475 SettingsPageItem::SettingItem(SettingItem {
6476 title: "Coloring",
6477 description: "Determines how indent guides are colored.",
6478 field: Box::new(SettingField {
6479 json_path: Some("languages.$(language).indent_guides.coloring"),
6480 pick: |settings_content| {
6481 language_settings_field(settings_content, |language| {
6482 language
6483 .indent_guides
6484 .as_ref()
6485 .and_then(|indent_guides| indent_guides.coloring.as_ref())
6486 })
6487 },
6488 write: |settings_content, value| {
6489 language_settings_field_mut(settings_content, value, |language, value| {
6490 language.indent_guides.get_or_insert_default().coloring = value;
6491 })
6492 },
6493 }),
6494 metadata: None,
6495 files: USER | PROJECT,
6496 }),
6497 SettingsPageItem::SettingItem(SettingItem {
6498 title: "Background Coloring",
6499 description: "Determines how indent guide backgrounds are colored.",
6500 field: Box::new(SettingField {
6501 json_path: Some("languages.$(language).indent_guides.background_coloring"),
6502 pick: |settings_content| {
6503 language_settings_field(settings_content, |language| {
6504 language
6505 .indent_guides
6506 .as_ref()
6507 .and_then(|indent_guides| indent_guides.background_coloring.as_ref())
6508 })
6509 },
6510 write: |settings_content, value| {
6511 language_settings_field_mut(settings_content, value, |language, value| {
6512 language
6513 .indent_guides
6514 .get_or_insert_default()
6515 .background_coloring = value;
6516 })
6517 },
6518 }),
6519 metadata: None,
6520 files: USER | PROJECT,
6521 }),
6522 SettingsPageItem::SectionHeader("Formatting"),
6523 SettingsPageItem::SettingItem(SettingItem {
6524 title: "Format On Save",
6525 description: "Whether or not to perform a buffer format before saving.",
6526 field: Box::new(
6527 // TODO(settings_ui): this setting should just be a bool
6528 SettingField {
6529 json_path: Some("languages.$(language).format_on_save"),
6530 pick: |settings_content| {
6531 language_settings_field(settings_content, |language| {
6532 language.format_on_save.as_ref()
6533 })
6534 },
6535 write: |settings_content, value| {
6536 language_settings_field_mut(settings_content, value, |language, value| {
6537 language.format_on_save = value;
6538 })
6539 },
6540 },
6541 ),
6542 metadata: None,
6543 files: USER | PROJECT,
6544 }),
6545 SettingsPageItem::SettingItem(SettingItem {
6546 title: "Remove Trailing Whitespace On Save",
6547 description: "Whether or not to remove any trailing whitespace from lines of a buffer before saving it.",
6548 field: Box::new(SettingField {
6549 json_path: Some("languages.$(language).remove_trailing_whitespace_on_save"),
6550 pick: |settings_content| {
6551 language_settings_field(settings_content, |language| {
6552 language.remove_trailing_whitespace_on_save.as_ref()
6553 })
6554 },
6555 write: |settings_content, value| {
6556 language_settings_field_mut(settings_content, value, |language, value| {
6557 language.remove_trailing_whitespace_on_save = value;
6558 })
6559 },
6560 }),
6561 metadata: None,
6562 files: USER | PROJECT,
6563 }),
6564 SettingsPageItem::SettingItem(SettingItem {
6565 title: "Ensure Final Newline On Save",
6566 description: "Whether or not to ensure there's a single newline at the end of a buffer when saving it.",
6567 field: Box::new(SettingField {
6568 json_path: Some("languages.$(language).ensure_final_newline_on_save"),
6569 pick: |settings_content| {
6570 language_settings_field(settings_content, |language| {
6571 language.ensure_final_newline_on_save.as_ref()
6572 })
6573 },
6574 write: |settings_content, value| {
6575 language_settings_field_mut(settings_content, value, |language, value| {
6576 language.ensure_final_newline_on_save = value;
6577 })
6578 },
6579 }),
6580 metadata: None,
6581 files: USER | PROJECT,
6582 }),
6583 SettingsPageItem::SettingItem(SettingItem {
6584 title: "Formatter",
6585 description: "How to perform a buffer format.",
6586 field: Box::new(
6587 SettingField {
6588 json_path: Some("languages.$(language).formatter"),
6589 pick: |settings_content| {
6590 language_settings_field(settings_content, |language| {
6591 language.formatter.as_ref()
6592 })
6593 },
6594 write: |settings_content, value| {
6595 language_settings_field_mut(settings_content, value, |language, value| {
6596 language.formatter = value;
6597 })
6598 },
6599 }
6600 .unimplemented(),
6601 ),
6602 metadata: None,
6603 files: USER | PROJECT,
6604 }),
6605 SettingsPageItem::SettingItem(SettingItem {
6606 title: "Use On Type Format",
6607 description: "Whether to use additional LSP queries to format (and amend) the code after every \"trigger\" symbol input, defined by LSP server capabilities",
6608 field: Box::new(SettingField {
6609 json_path: Some("languages.$(language).use_on_type_format"),
6610 pick: |settings_content| {
6611 language_settings_field(settings_content, |language| {
6612 language.use_on_type_format.as_ref()
6613 })
6614 },
6615 write: |settings_content, value| {
6616 language_settings_field_mut(settings_content, value, |language, value| {
6617 language.use_on_type_format = value;
6618 })
6619 },
6620 }),
6621 metadata: None,
6622 files: USER | PROJECT,
6623 }),
6624 SettingsPageItem::SettingItem(SettingItem {
6625 title: "Code Actions On Format",
6626 description: "Additional code actions to run when formatting.",
6627 field: Box::new(
6628 SettingField {
6629 json_path: Some("languages.$(language).code_actions_on_format"),
6630 pick: |settings_content| {
6631 language_settings_field(settings_content, |language| {
6632 language.code_actions_on_format.as_ref()
6633 })
6634 },
6635 write: |settings_content, value| {
6636 language_settings_field_mut(settings_content, value, |language, value| {
6637 language.code_actions_on_format = value;
6638 })
6639 },
6640 }
6641 .unimplemented(),
6642 ),
6643 metadata: None,
6644 files: USER | PROJECT,
6645 }),
6646 SettingsPageItem::SectionHeader("Autoclose"),
6647 SettingsPageItem::SettingItem(SettingItem {
6648 title: "Use Autoclose",
6649 description: "Whether to automatically type closing characters for you. For example, when you type '(', Zed will automatically add a closing ')' at the correct position.",
6650 field: Box::new(SettingField {
6651 json_path: Some("languages.$(language).use_autoclose"),
6652 pick: |settings_content| {
6653 language_settings_field(settings_content, |language| {
6654 language.use_autoclose.as_ref()
6655 })
6656 },
6657 write: |settings_content, value| {
6658 language_settings_field_mut(settings_content, value, |language, value| {
6659 language.use_autoclose = value;
6660 })
6661 },
6662 }),
6663 metadata: None,
6664 files: USER | PROJECT,
6665 }),
6666 SettingsPageItem::SettingItem(SettingItem {
6667 title: "Use Auto Surround",
6668 description: "Whether to automatically surround text with characters for you. For example, when you select text and type '(', Zed will automatically surround text with ().",
6669 field: Box::new(SettingField {
6670 json_path: Some("languages.$(language).use_auto_surround"),
6671 pick: |settings_content| {
6672 language_settings_field(settings_content, |language| {
6673 language.use_auto_surround.as_ref()
6674 })
6675 },
6676 write: |settings_content, value| {
6677 language_settings_field_mut(settings_content, value, |language, value| {
6678 language.use_auto_surround = value;
6679 })
6680 },
6681 }),
6682 metadata: None,
6683 files: USER | PROJECT,
6684 }),
6685 SettingsPageItem::SettingItem(SettingItem {
6686 title: "Always Treat Brackets As Autoclosed",
6687 description: "Controls whether the closing characters are always skipped over and auto-removed no matter how they were inserted.",
6688 field: Box::new(SettingField {
6689 json_path: Some("languages.$(language).always_treat_brackets_as_autoclosed"),
6690 pick: |settings_content| {
6691 language_settings_field(settings_content, |language| {
6692 language.always_treat_brackets_as_autoclosed.as_ref()
6693 })
6694 },
6695 write: |settings_content, value| {
6696 language_settings_field_mut(settings_content, value, |language, value| {
6697 language.always_treat_brackets_as_autoclosed = value;
6698 })
6699 },
6700 }),
6701 metadata: None,
6702 files: USER | PROJECT,
6703 }),
6704 SettingsPageItem::SettingItem(SettingItem {
6705 title: "JSX Tag Auto Close",
6706 description: "Whether to automatically close JSX tags.",
6707 field: Box::new(SettingField {
6708 json_path: Some("languages.$(language).jsx_tag_auto_close"),
6709 // TODO(settings_ui): this setting should just be a bool
6710 pick: |settings_content| {
6711 language_settings_field(settings_content, |language| {
6712 language.jsx_tag_auto_close.as_ref()?.enabled.as_ref()
6713 })
6714 },
6715 write: |settings_content, value| {
6716 language_settings_field_mut(settings_content, value, |language, value| {
6717 language.jsx_tag_auto_close.get_or_insert_default().enabled = value;
6718 })
6719 },
6720 }),
6721 metadata: None,
6722 files: USER | PROJECT,
6723 }),
6724 SettingsPageItem::SectionHeader("Whitespace"),
6725 SettingsPageItem::SettingItem(SettingItem {
6726 title: "Show Whitespaces",
6727 description: "Whether to show tabs and spaces in the editor.",
6728 field: Box::new(SettingField {
6729 json_path: Some("languages.$(language).show_whitespaces"),
6730 pick: |settings_content| {
6731 language_settings_field(settings_content, |language| {
6732 language.show_whitespaces.as_ref()
6733 })
6734 },
6735 write: |settings_content, value| {
6736 language_settings_field_mut(settings_content, value, |language, value| {
6737 language.show_whitespaces = value;
6738 })
6739 },
6740 }),
6741 metadata: None,
6742 files: USER | PROJECT,
6743 }),
6744 SettingsPageItem::SettingItem(SettingItem {
6745 title: "Space Whitespace Indicator",
6746 description: "Visible character used to render space characters when show_whitespaces is enabled (default: \"•\")",
6747 field: Box::new(
6748 SettingField {
6749 json_path: Some("languages.$(language).whitespace_map.space"),
6750 pick: |settings_content| {
6751 language_settings_field(settings_content, |language| {
6752 language.whitespace_map.as_ref()?.space.as_ref()
6753 })
6754 },
6755 write: |settings_content, value| {
6756 language_settings_field_mut(settings_content, value, |language, value| {
6757 language.whitespace_map.get_or_insert_default().space = value;
6758 })
6759 },
6760 }
6761 .unimplemented(),
6762 ),
6763 metadata: None,
6764 files: USER | PROJECT,
6765 }),
6766 SettingsPageItem::SettingItem(SettingItem {
6767 title: "Tab Whitespace Indicator",
6768 description: "Visible character used to render tab characters when show_whitespaces is enabled (default: \"→\")",
6769 field: Box::new(
6770 SettingField {
6771 json_path: Some("languages.$(language).whitespace_map.tab"),
6772 pick: |settings_content| {
6773 language_settings_field(settings_content, |language| {
6774 language.whitespace_map.as_ref()?.tab.as_ref()
6775 })
6776 },
6777 write: |settings_content, value| {
6778 language_settings_field_mut(settings_content, value, |language, value| {
6779 language.whitespace_map.get_or_insert_default().tab = value;
6780 })
6781 },
6782 }
6783 .unimplemented(),
6784 ),
6785 metadata: None,
6786 files: USER | PROJECT,
6787 }),
6788 SettingsPageItem::SectionHeader("Completions"),
6789 SettingsPageItem::SettingItem(SettingItem {
6790 title: "Show Completions On Input",
6791 description: "Whether to pop the completions menu while typing in an editor without explicitly requesting it.",
6792 field: Box::new(SettingField {
6793 json_path: Some("languages.$(language).show_completions_on_input"),
6794 pick: |settings_content| {
6795 language_settings_field(settings_content, |language| {
6796 language.show_completions_on_input.as_ref()
6797 })
6798 },
6799 write: |settings_content, value| {
6800 language_settings_field_mut(settings_content, value, |language, value| {
6801 language.show_completions_on_input = value;
6802 })
6803 },
6804 }),
6805 metadata: None,
6806 files: USER | PROJECT,
6807 }),
6808 SettingsPageItem::SettingItem(SettingItem {
6809 title: "Show Completion Documentation",
6810 description: "Whether to display inline and alongside documentation for items in the completions menu.",
6811 field: Box::new(SettingField {
6812 json_path: Some("languages.$(language).show_completion_documentation"),
6813 pick: |settings_content| {
6814 language_settings_field(settings_content, |language| {
6815 language.show_completion_documentation.as_ref()
6816 })
6817 },
6818 write: |settings_content, value| {
6819 language_settings_field_mut(settings_content, value, |language, value| {
6820 language.show_completion_documentation = value;
6821 })
6822 },
6823 }),
6824 metadata: None,
6825 files: USER | PROJECT,
6826 }),
6827 SettingsPageItem::SettingItem(SettingItem {
6828 title: "Words",
6829 description: "Controls how words are completed.",
6830 field: Box::new(SettingField {
6831 json_path: Some("languages.$(language).completions.words"),
6832 pick: |settings_content| {
6833 language_settings_field(settings_content, |language| {
6834 language.completions.as_ref()?.words.as_ref()
6835 })
6836 },
6837 write: |settings_content, value| {
6838 language_settings_field_mut(settings_content, value, |language, value| {
6839 language.completions.get_or_insert_default().words = value;
6840 })
6841 },
6842 }),
6843 metadata: None,
6844 files: USER | PROJECT,
6845 }),
6846 SettingsPageItem::SettingItem(SettingItem {
6847 title: "Words Min Length",
6848 description: "How many characters has to be in the completions query to automatically show the words-based completions.",
6849 field: Box::new(SettingField {
6850 json_path: Some("languages.$(language).completions.words_min_length"),
6851 pick: |settings_content| {
6852 language_settings_field(settings_content, |language| {
6853 language.completions.as_ref()?.words_min_length.as_ref()
6854 })
6855 },
6856 write: |settings_content, value| {
6857 language_settings_field_mut(settings_content, value, |language, value| {
6858 language
6859 .completions
6860 .get_or_insert_default()
6861 .words_min_length = value;
6862 })
6863 },
6864 }),
6865 metadata: None,
6866 files: USER | PROJECT,
6867 }),
6868 SettingsPageItem::SettingItem(SettingItem {
6869 title: "Completion Menu Scrollbar",
6870 description: "When to show the scrollbar in the completion menu.",
6871 field: Box::new(SettingField {
6872 json_path: Some("editor.completion_menu_scrollbar"),
6873 pick: |settings_content| settings_content.editor.completion_menu_scrollbar.as_ref(),
6874 write: |settings_content, value| {
6875 settings_content.editor.completion_menu_scrollbar = value;
6876 },
6877 }),
6878 metadata: None,
6879 files: USER,
6880 }),
6881 SettingsPageItem::SectionHeader("Inlay Hints"),
6882 SettingsPageItem::SettingItem(SettingItem {
6883 title: "Enabled",
6884 description: "Global switch to toggle hints on and off.",
6885 field: Box::new(SettingField {
6886 json_path: Some("languages.$(language).inlay_hints.enabled"),
6887 pick: |settings_content| {
6888 language_settings_field(settings_content, |language| {
6889 language.inlay_hints.as_ref()?.enabled.as_ref()
6890 })
6891 },
6892 write: |settings_content, value| {
6893 language_settings_field_mut(settings_content, value, |language, value| {
6894 language.inlay_hints.get_or_insert_default().enabled = value;
6895 })
6896 },
6897 }),
6898 metadata: None,
6899 files: USER | PROJECT,
6900 }),
6901 SettingsPageItem::SettingItem(SettingItem {
6902 title: "Show Value Hints",
6903 description: "Global switch to toggle inline values on and off when debugging.",
6904 field: Box::new(SettingField {
6905 json_path: Some("languages.$(language).inlay_hints.show_value_hints"),
6906 pick: |settings_content| {
6907 language_settings_field(settings_content, |language| {
6908 language.inlay_hints.as_ref()?.show_value_hints.as_ref()
6909 })
6910 },
6911 write: |settings_content, value| {
6912 language_settings_field_mut(settings_content, value, |language, value| {
6913 language
6914 .inlay_hints
6915 .get_or_insert_default()
6916 .show_value_hints = value;
6917 })
6918 },
6919 }),
6920 metadata: None,
6921 files: USER | PROJECT,
6922 }),
6923 SettingsPageItem::SettingItem(SettingItem {
6924 title: "Show Type Hints",
6925 description: "Whether type hints should be shown.",
6926 field: Box::new(SettingField {
6927 json_path: Some("languages.$(language).inlay_hints.show_type_hints"),
6928 pick: |settings_content| {
6929 language_settings_field(settings_content, |language| {
6930 language.inlay_hints.as_ref()?.show_type_hints.as_ref()
6931 })
6932 },
6933 write: |settings_content, value| {
6934 language_settings_field_mut(settings_content, value, |language, value| {
6935 language.inlay_hints.get_or_insert_default().show_type_hints = value;
6936 })
6937 },
6938 }),
6939 metadata: None,
6940 files: USER | PROJECT,
6941 }),
6942 SettingsPageItem::SettingItem(SettingItem {
6943 title: "Show Parameter Hints",
6944 description: "Whether parameter hints should be shown.",
6945 field: Box::new(SettingField {
6946 json_path: Some("languages.$(language).inlay_hints.show_parameter_hints"),
6947 pick: |settings_content| {
6948 language_settings_field(settings_content, |language| {
6949 language.inlay_hints.as_ref()?.show_parameter_hints.as_ref()
6950 })
6951 },
6952 write: |settings_content, value| {
6953 language_settings_field_mut(settings_content, value, |language, value| {
6954 language
6955 .inlay_hints
6956 .get_or_insert_default()
6957 .show_parameter_hints = value;
6958 })
6959 },
6960 }),
6961 metadata: None,
6962 files: USER | PROJECT,
6963 }),
6964 SettingsPageItem::SettingItem(SettingItem {
6965 title: "Show Other Hints",
6966 description: "Whether other hints should be shown.",
6967 field: Box::new(SettingField {
6968 json_path: Some("languages.$(language).inlay_hints.show_other_hints"),
6969 pick: |settings_content| {
6970 language_settings_field(settings_content, |language| {
6971 language.inlay_hints.as_ref()?.show_other_hints.as_ref()
6972 })
6973 },
6974 write: |settings_content, value| {
6975 language_settings_field_mut(settings_content, value, |language, value| {
6976 language
6977 .inlay_hints
6978 .get_or_insert_default()
6979 .show_other_hints = value;
6980 })
6981 },
6982 }),
6983 metadata: None,
6984 files: USER | PROJECT,
6985 }),
6986 SettingsPageItem::SettingItem(SettingItem {
6987 title: "Show Background",
6988 description: "Show a background for inlay hints.",
6989 field: Box::new(SettingField {
6990 json_path: Some("languages.$(language).inlay_hints.show_background"),
6991 pick: |settings_content| {
6992 language_settings_field(settings_content, |language| {
6993 language.inlay_hints.as_ref()?.show_background.as_ref()
6994 })
6995 },
6996 write: |settings_content, value| {
6997 language_settings_field_mut(settings_content, value, |language, value| {
6998 language.inlay_hints.get_or_insert_default().show_background = value;
6999 })
7000 },
7001 }),
7002 metadata: None,
7003 files: USER | PROJECT,
7004 }),
7005 SettingsPageItem::SettingItem(SettingItem {
7006 title: "Edit Debounce Ms",
7007 description: "Whether or not to debounce inlay hints updates after buffer edits (set to 0 to disable debouncing).",
7008 field: Box::new(SettingField {
7009 json_path: Some("languages.$(language).inlay_hints.edit_debounce_ms"),
7010 pick: |settings_content| {
7011 language_settings_field(settings_content, |language| {
7012 language.inlay_hints.as_ref()?.edit_debounce_ms.as_ref()
7013 })
7014 },
7015 write: |settings_content, value| {
7016 language_settings_field_mut(settings_content, value, |language, value| {
7017 language
7018 .inlay_hints
7019 .get_or_insert_default()
7020 .edit_debounce_ms = value;
7021 })
7022 },
7023 }),
7024 metadata: None,
7025 files: USER | PROJECT,
7026 }),
7027 SettingsPageItem::SettingItem(SettingItem {
7028 title: "Scroll Debounce Ms",
7029 description: "Whether or not to debounce inlay hints updates after buffer scrolls (set to 0 to disable debouncing).",
7030 field: Box::new(SettingField {
7031 json_path: Some("languages.$(language).inlay_hints.scroll_debounce_ms"),
7032 pick: |settings_content| {
7033 language_settings_field(settings_content, |language| {
7034 language.inlay_hints.as_ref()?.scroll_debounce_ms.as_ref()
7035 })
7036 },
7037 write: |settings_content, value| {
7038 language_settings_field_mut(settings_content, value, |language, value| {
7039 language
7040 .inlay_hints
7041 .get_or_insert_default()
7042 .scroll_debounce_ms = value;
7043 })
7044 },
7045 }),
7046 metadata: None,
7047 files: USER | PROJECT,
7048 }),
7049 SettingsPageItem::SettingItem(SettingItem {
7050 title: "Toggle On Modifiers Press",
7051 description: "Toggles inlay hints (hides or shows) when the user presses the modifiers specified.",
7052 field: Box::new(
7053 SettingField {
7054 json_path: Some("languages.$(language).inlay_hints.toggle_on_modifiers_press"),
7055 pick: |settings_content| {
7056 language_settings_field(settings_content, |language| {
7057 language
7058 .inlay_hints
7059 .as_ref()?
7060 .toggle_on_modifiers_press
7061 .as_ref()
7062 })
7063 },
7064 write: |settings_content, value| {
7065 language_settings_field_mut(settings_content, value, |language, value| {
7066 language
7067 .inlay_hints
7068 .get_or_insert_default()
7069 .toggle_on_modifiers_press = value;
7070 })
7071 },
7072 }
7073 .unimplemented(),
7074 ),
7075 metadata: None,
7076 files: USER | PROJECT,
7077 }),
7078 ];
7079 if current_language().is_none() {
7080 items.push(SettingsPageItem::SettingItem(SettingItem {
7081 title: "LSP Document Colors",
7082 description: "How to render LSP color previews in the editor.",
7083 field: Box::new(SettingField {
7084 json_path: Some("lsp_document_colors"),
7085 pick: |settings_content| settings_content.editor.lsp_document_colors.as_ref(),
7086 write: |settings_content, value| {
7087 settings_content.editor.lsp_document_colors = value;
7088 },
7089 }),
7090 metadata: None,
7091 files: USER,
7092 }))
7093 }
7094 items.extend([
7095 SettingsPageItem::SectionHeader("Tasks"),
7096 SettingsPageItem::SettingItem(SettingItem {
7097 title: "Enabled",
7098 description: "Whether tasks are enabled for this language.",
7099 field: Box::new(SettingField {
7100 json_path: Some("languages.$(language).tasks.enabled"),
7101 pick: |settings_content| {
7102 language_settings_field(settings_content, |language| {
7103 language.tasks.as_ref()?.enabled.as_ref()
7104 })
7105 },
7106 write: |settings_content, value| {
7107 language_settings_field_mut(settings_content, value, |language, value| {
7108 language.tasks.get_or_insert_default().enabled = value;
7109
7110 })
7111 },
7112 }),
7113 metadata: None,
7114 files: USER | PROJECT,
7115 }),
7116 SettingsPageItem::SettingItem(SettingItem {
7117 title: "Variables",
7118 description: "Extra task variables to set for a particular language.",
7119 field: Box::new(
7120 SettingField {
7121 json_path: Some("languages.$(language).tasks.variables"),
7122 pick: |settings_content| {
7123 language_settings_field(settings_content, |language| {
7124 language.tasks.as_ref()?.variables.as_ref()
7125 })
7126 },
7127 write: |settings_content, value| {
7128 language_settings_field_mut(settings_content, value, |language, value| {
7129 language.tasks.get_or_insert_default().variables = value;
7130
7131 })
7132 },
7133 }
7134 .unimplemented(),
7135 ),
7136 metadata: None,
7137 files: USER | PROJECT,
7138 }),
7139 SettingsPageItem::SettingItem(SettingItem {
7140 title: "Prefer LSP",
7141 description: "Use LSP tasks over Zed language extension tasks.",
7142 field: Box::new(SettingField {
7143 json_path: Some("languages.$(language).tasks.prefer_lsp"),
7144 pick: |settings_content| {
7145 language_settings_field(settings_content, |language| {
7146 language.tasks.as_ref()?.prefer_lsp.as_ref()
7147 })
7148 },
7149 write: |settings_content, value| {
7150 language_settings_field_mut(settings_content, value, |language, value| {
7151 language.tasks.get_or_insert_default().prefer_lsp = value;
7152
7153 })
7154 },
7155 }),
7156 metadata: None,
7157 files: USER | PROJECT,
7158 }),
7159 SettingsPageItem::SectionHeader("Miscellaneous"),
7160 SettingsPageItem::SettingItem(SettingItem {
7161 title: "Word Diff Enabled",
7162 description: "Whether to enable word diff highlighting in the editor. When enabled, changed words within modified lines are highlighted to show exactly what changed.",
7163 field: Box::new(SettingField {
7164 json_path: Some("languages.$(language).word_diff_enabled"),
7165 pick: |settings_content| {
7166 language_settings_field(settings_content, |language| {
7167 language.word_diff_enabled.as_ref()
7168 })
7169 },
7170 write: |settings_content, value| {
7171 language_settings_field_mut(settings_content, value, |language, value| {
7172 language.word_diff_enabled = value;
7173 })
7174 },
7175 }),
7176 metadata: None,
7177 files: USER | PROJECT,
7178 }),
7179 SettingsPageItem::SettingItem(SettingItem {
7180 title: "Debuggers",
7181 description: "Preferred debuggers for this language.",
7182 field: Box::new(
7183 SettingField {
7184 json_path: Some("languages.$(language).debuggers"),
7185 pick: |settings_content| {
7186 language_settings_field(settings_content, |language| language.debuggers.as_ref())
7187 },
7188 write: |settings_content, value| {
7189 language_settings_field_mut(settings_content, value, |language, value| {
7190 language.debuggers = value;
7191
7192 })
7193 },
7194 }
7195 .unimplemented(),
7196 ),
7197 metadata: None,
7198 files: USER | PROJECT,
7199 }),
7200 SettingsPageItem::SettingItem(SettingItem {
7201 title: "Middle Click Paste",
7202 description: "Enable middle-click paste on Linux.",
7203 field: Box::new(SettingField {
7204 json_path: Some("languages.$(language).editor.middle_click_paste"),
7205 pick: |settings_content| settings_content.editor.middle_click_paste.as_ref(),
7206 write: |settings_content, value| {settings_content.editor.middle_click_paste = value;},
7207 }),
7208 metadata: None,
7209 files: USER,
7210 }),
7211 SettingsPageItem::SettingItem(SettingItem {
7212 title: "Extend Comment On Newline",
7213 description: "Whether to start a new line with a comment when a previous line is a comment as well.",
7214 field: Box::new(SettingField {
7215 json_path: Some("languages.$(language).extend_comment_on_newline"),
7216 pick: |settings_content| {
7217 language_settings_field(settings_content, |language| {
7218 language.extend_comment_on_newline.as_ref()
7219 })
7220 },
7221 write: |settings_content, value| {
7222 language_settings_field_mut(settings_content, value, |language, value| {
7223 language.extend_comment_on_newline = value;
7224
7225 })
7226 },
7227 }),
7228 metadata: None,
7229 files: USER | PROJECT,
7230 }),
7231 SettingsPageItem::SettingItem(SettingItem {
7232 title: "Colorize Brackets",
7233 description: "Whether to colorize brackets in the editor.",
7234 field: Box::new(SettingField {
7235 json_path: Some("languages.$(language).colorize_brackets"),
7236 pick: |settings_content| {
7237 language_settings_field(settings_content, |language| {
7238 language.colorize_brackets.as_ref()
7239 })
7240 },
7241 write: |settings_content, value| {
7242 language_settings_field_mut(settings_content, value, |language, value| {
7243 language.colorize_brackets = value;
7244 })
7245 },
7246 }),
7247 metadata: None,
7248 files: USER | PROJECT,
7249 }),
7250 ]);
7251
7252 if current_language().is_none() {
7253 items.extend([
7254 SettingsPageItem::SettingItem(SettingItem {
7255 title: "Image Viewer",
7256 description: "The unit for image file sizes.",
7257 field: Box::new(SettingField {
7258 json_path: Some("image_viewer.unit"),
7259 pick: |settings_content| {
7260 settings_content.image_viewer.as_ref().and_then(|image_viewer| image_viewer.unit.as_ref())
7261 },
7262 write: |settings_content, value| {
7263 settings_content.image_viewer.get_or_insert_default().unit = value;
7264
7265 },
7266 }),
7267 metadata: None,
7268 files: USER,
7269 }),
7270 SettingsPageItem::SettingItem(SettingItem {
7271 title: "Auto Replace Emoji Shortcode",
7272 description: "Whether to automatically replace emoji shortcodes with emoji characters.",
7273 field: Box::new(SettingField {
7274 json_path: Some("message_editor.auto_replace_emoji_shortcode"),
7275 pick: |settings_content| {
7276 settings_content.message_editor.as_ref().and_then(|message_editor| message_editor.auto_replace_emoji_shortcode.as_ref())
7277 },
7278 write: |settings_content, value| {
7279 settings_content.message_editor.get_or_insert_default().auto_replace_emoji_shortcode = value;
7280
7281 },
7282 }),
7283 metadata: None,
7284 files: USER,
7285 }),
7286 SettingsPageItem::SettingItem(SettingItem {
7287 title: "Drop Size Target",
7288 description: "Relative size of the drop target in the editor that will open dropped file as a split pane.",
7289 field: Box::new(SettingField {
7290 json_path: Some("drop_target_size"),
7291 pick: |settings_content| {
7292 settings_content.workspace.drop_target_size.as_ref()
7293 },
7294 write: |settings_content, value| {
7295 settings_content.workspace.drop_target_size = value;
7296
7297 },
7298 }),
7299 metadata: None,
7300 files: USER,
7301 }),
7302 ]);
7303 }
7304 items
7305}
7306
7307/// LanguageSettings items that should be included in the "Languages & Tools" page
7308/// not the "Editor" page
7309fn non_editor_language_settings_data() -> Vec<SettingsPageItem> {
7310 vec![
7311 SettingsPageItem::SectionHeader("LSP"),
7312 SettingsPageItem::SettingItem(SettingItem {
7313 title: "Enable Language Server",
7314 description: "Whether to use language servers to provide code intelligence.",
7315 field: Box::new(SettingField {
7316 json_path: Some("languages.$(language).enable_language_server"),
7317 pick: |settings_content| {
7318 language_settings_field(settings_content, |language| {
7319 language.enable_language_server.as_ref()
7320 })
7321 },
7322 write: |settings_content, value| {
7323 language_settings_field_mut(settings_content, value, |language, value| {
7324 language.enable_language_server = value;
7325 })
7326 },
7327 }),
7328 metadata: None,
7329 files: USER | PROJECT,
7330 }),
7331 SettingsPageItem::SettingItem(SettingItem {
7332 title: "Language Servers",
7333 description: "The list of language servers to use (or disable) for this language.",
7334 field: Box::new(
7335 SettingField {
7336 json_path: Some("languages.$(language).language_servers"),
7337 pick: |settings_content| {
7338 language_settings_field(settings_content, |language| {
7339 language.language_servers.as_ref()
7340 })
7341 },
7342 write: |settings_content, value| {
7343 language_settings_field_mut(settings_content, value, |language, value| {
7344 language.language_servers = value;
7345 })
7346 },
7347 }
7348 .unimplemented(),
7349 ),
7350 metadata: None,
7351 files: USER | PROJECT,
7352 }),
7353 SettingsPageItem::SettingItem(SettingItem {
7354 title: "Linked Edits",
7355 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.",
7356 field: Box::new(SettingField {
7357 json_path: Some("languages.$(language).linked_edits"),
7358 pick: |settings_content| {
7359 language_settings_field(settings_content, |language| {
7360 language.linked_edits.as_ref()
7361 })
7362 },
7363 write: |settings_content, value| {
7364 language_settings_field_mut(settings_content, value, |language, value| {
7365 language.linked_edits = value;
7366 })
7367 },
7368 }),
7369 metadata: None,
7370 files: USER | PROJECT,
7371 }),
7372 SettingsPageItem::SettingItem(SettingItem {
7373 title: "Go To Definition Fallback",
7374 description: "Whether to follow-up empty Go to definition responses from the language server.",
7375 field: Box::new(SettingField {
7376 json_path: Some("go_to_definition_fallback"),
7377 pick: |settings_content| settings_content.editor.go_to_definition_fallback.as_ref(),
7378 write: |settings_content, value| {
7379 settings_content.editor.go_to_definition_fallback = value;
7380 },
7381 }),
7382 metadata: None,
7383 files: USER,
7384 }),
7385 SettingsPageItem::SectionHeader("LSP Completions"),
7386 SettingsPageItem::SettingItem(SettingItem {
7387 title: "Enabled",
7388 description: "Whether to fetch LSP completions or not.",
7389 field: Box::new(SettingField {
7390 json_path: Some("languages.$(language).completions.lsp"),
7391 pick: |settings_content| {
7392 language_settings_field(settings_content, |language| {
7393 language.completions.as_ref()?.lsp.as_ref()
7394 })
7395 },
7396 write: |settings_content, value| {
7397 language_settings_field_mut(settings_content, value, |language, value| {
7398 language.completions.get_or_insert_default().lsp = value;
7399 })
7400 },
7401 }),
7402 metadata: None,
7403 files: USER | PROJECT,
7404 }),
7405 SettingsPageItem::SettingItem(SettingItem {
7406 title: "Fetch Timeout (milliseconds)",
7407 description: "When fetching LSP completions, determines how long to wait for a response of a particular server (set to 0 to wait indefinitely).",
7408 field: Box::new(SettingField {
7409 json_path: Some("languages.$(language).completions.lsp_fetch_timeout_ms"),
7410 pick: |settings_content| {
7411 language_settings_field(settings_content, |language| {
7412 language.completions.as_ref()?.lsp_fetch_timeout_ms.as_ref()
7413 })
7414 },
7415 write: |settings_content, value| {
7416 language_settings_field_mut(settings_content, value, |language, value| {
7417 language
7418 .completions
7419 .get_or_insert_default()
7420 .lsp_fetch_timeout_ms = value;
7421 })
7422 },
7423 }),
7424 metadata: None,
7425 files: USER | PROJECT,
7426 }),
7427 SettingsPageItem::SettingItem(SettingItem {
7428 title: "Insert Mode",
7429 description: "Controls how LSP completions are inserted.",
7430 field: Box::new(SettingField {
7431 json_path: Some("languages.$(language).completions.lsp_insert_mode"),
7432 pick: |settings_content| {
7433 language_settings_field(settings_content, |language| {
7434 language.completions.as_ref()?.lsp_insert_mode.as_ref()
7435 })
7436 },
7437 write: |settings_content, value| {
7438 language_settings_field_mut(settings_content, value, |language, value| {
7439 language.completions.get_or_insert_default().lsp_insert_mode = value;
7440 })
7441 },
7442 }),
7443 metadata: None,
7444 files: USER | PROJECT,
7445 }),
7446 SettingsPageItem::SectionHeader("Debuggers"),
7447 SettingsPageItem::SettingItem(SettingItem {
7448 title: "Debuggers",
7449 description: "Preferred debuggers for this language.",
7450 field: Box::new(
7451 SettingField {
7452 json_path: Some("languages.$(language).debuggers"),
7453 pick: |settings_content| {
7454 language_settings_field(settings_content, |language| {
7455 language.debuggers.as_ref()
7456 })
7457 },
7458 write: |settings_content, value| {
7459 language_settings_field_mut(settings_content, value, |language, value| {
7460 language.debuggers = value;
7461 })
7462 },
7463 }
7464 .unimplemented(),
7465 ),
7466 metadata: None,
7467 files: USER | PROJECT,
7468 }),
7469 SettingsPageItem::SectionHeader("Prettier"),
7470 SettingsPageItem::SettingItem(SettingItem {
7471 title: "Allowed",
7472 description: "Enables or disables formatting with Prettier for a given language.",
7473 field: Box::new(SettingField {
7474 json_path: Some("languages.$(language).prettier.allowed"),
7475 pick: |settings_content| {
7476 language_settings_field(settings_content, |language| {
7477 language.prettier.as_ref()?.allowed.as_ref()
7478 })
7479 },
7480 write: |settings_content, value| {
7481 language_settings_field_mut(settings_content, value, |language, value| {
7482 language.prettier.get_or_insert_default().allowed = value;
7483 })
7484 },
7485 }),
7486 metadata: None,
7487 files: USER | PROJECT,
7488 }),
7489 SettingsPageItem::SettingItem(SettingItem {
7490 title: "Parser",
7491 description: "Forces Prettier integration to use a specific parser name when formatting files with the language.",
7492 field: Box::new(SettingField {
7493 json_path: Some("languages.$(language).prettier.parser"),
7494 pick: |settings_content| {
7495 language_settings_field(settings_content, |language| {
7496 language.prettier.as_ref()?.parser.as_ref()
7497 })
7498 },
7499 write: |settings_content, value| {
7500 language_settings_field_mut(settings_content, value, |language, value| {
7501 language.prettier.get_or_insert_default().parser = value;
7502 })
7503 },
7504 }),
7505 metadata: None,
7506 files: USER | PROJECT,
7507 }),
7508 SettingsPageItem::SettingItem(SettingItem {
7509 title: "Plugins",
7510 description: "Forces Prettier integration to use specific plugins when formatting files with the language.",
7511 field: Box::new(
7512 SettingField {
7513 json_path: Some("languages.$(language).prettier.plugins"),
7514 pick: |settings_content| {
7515 language_settings_field(settings_content, |language| {
7516 language.prettier.as_ref()?.plugins.as_ref()
7517 })
7518 },
7519 write: |settings_content, value| {
7520 language_settings_field_mut(settings_content, value, |language, value| {
7521 language.prettier.get_or_insert_default().plugins = value;
7522 })
7523 },
7524 }
7525 .unimplemented(),
7526 ),
7527 metadata: None,
7528 files: USER | PROJECT,
7529 }),
7530 SettingsPageItem::SettingItem(SettingItem {
7531 title: "Options",
7532 description: "Default Prettier options, in the format as in package.json section for Prettier.",
7533 field: Box::new(
7534 SettingField {
7535 json_path: Some("languages.$(language).prettier.options"),
7536 pick: |settings_content| {
7537 language_settings_field(settings_content, |language| {
7538 language.prettier.as_ref()?.options.as_ref()
7539 })
7540 },
7541 write: |settings_content, value| {
7542 language_settings_field_mut(settings_content, value, |language, value| {
7543 language.prettier.get_or_insert_default().options = value;
7544 })
7545 },
7546 }
7547 .unimplemented(),
7548 ),
7549 metadata: None,
7550 files: USER | PROJECT,
7551 }),
7552 ]
7553}
7554
7555fn edit_prediction_language_settings_section() -> Vec<SettingsPageItem> {
7556 vec![
7557 SettingsPageItem::SectionHeader("Edit Predictions"),
7558 SettingsPageItem::SubPageLink(SubPageLink {
7559 title: "Configure Providers".into(),
7560 json_path: Some("edit_predictions.providers"),
7561 description: Some("Set up different edit prediction providers in complement to Zed's built-in Zeta model.".into()),
7562 in_json: false,
7563 files: USER,
7564 render: Arc::new(|_, window, cx| {
7565 let settings_window = cx.entity();
7566 let page = window.use_state(cx, |_, _| {
7567 crate::pages::EditPredictionSetupPage::new(settings_window)
7568 });
7569 page.into_any_element()
7570 }),
7571 }),
7572 SettingsPageItem::SettingItem(SettingItem {
7573 title: "Show Edit Predictions",
7574 description: "Controls whether edit predictions are shown immediately or manually.",
7575 field: Box::new(SettingField {
7576 json_path: Some("languages.$(language).show_edit_predictions"),
7577 pick: |settings_content| {
7578 language_settings_field(settings_content, |language| {
7579 language.show_edit_predictions.as_ref()
7580 })
7581 },
7582 write: |settings_content, value| {
7583 language_settings_field_mut(settings_content, value, |language, value| {
7584 language.show_edit_predictions = value;
7585 })
7586 },
7587 }),
7588 metadata: None,
7589 files: USER | PROJECT,
7590 }),
7591 SettingsPageItem::SettingItem(SettingItem {
7592 title: "Disable in Language Scopes",
7593 description: "Controls whether edit predictions are shown in the given language scopes.",
7594 field: Box::new(
7595 SettingField {
7596 json_path: Some("languages.$(language).edit_predictions_disabled_in"),
7597 pick: |settings_content| {
7598 language_settings_field(settings_content, |language| {
7599 language.edit_predictions_disabled_in.as_ref()
7600 })
7601 },
7602 write: |settings_content, value| {
7603 language_settings_field_mut(settings_content, value, |language, value| {
7604 language.edit_predictions_disabled_in = value;
7605 })
7606 },
7607 }
7608 .unimplemented(),
7609 ),
7610 metadata: None,
7611 files: USER | PROJECT,
7612 }),
7613 ]
7614}
7615
7616fn show_scrollbar_or_editor(
7617 settings_content: &SettingsContent,
7618 show: fn(&SettingsContent) -> Option<&settings::ShowScrollbar>,
7619) -> Option<&settings::ShowScrollbar> {
7620 show(settings_content).or(settings_content
7621 .editor
7622 .scrollbar
7623 .as_ref()
7624 .and_then(|scrollbar| scrollbar.show.as_ref()))
7625}
7626
7627fn dynamic_variants<T>() -> &'static [T::Discriminant]
7628where
7629 T: strum::IntoDiscriminant,
7630 T::Discriminant: strum::VariantArray,
7631{
7632 <<T as strum::IntoDiscriminant>::Discriminant as strum::VariantArray>::VARIANTS
7633}