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